<commit_before>/**
 * @license
 * Copyright 2020 Google LLC. 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.
 * =============================================================================
 */

const BACKEND_FLAGS_MAP = {
  general: [],
  cpu: [],
  wasm: [
    'WASM_HAS_SIMD_SUPPORT',
    'WASM_HAS_MULTITHREAD_SUPPORT',
    'CHECK_COMPUTATION_FOR_ERRORS',
  ],
  webgl: [
    'WEBGL_VERSION', 'WEBGL_CPU_FORWARD', 'WEBGL_PACK',
    'WEBGL_FORCE_F16_TEXTURES', 'WEBGL_RENDER_FLOAT32_CAPABLE',
    'WEBGL_FLUSH_THRESHOLD', 'WEBGL_PACK_DEPTHWISECONV',
    'CHECK_COMPUTATION_FOR_ERRORS', 'WEBGL_USE_SHAPES_UNIFORMS'
  ],
};
if (tf.engine().backendNames().includes('webgpu')) {
  BACKEND_FLAGS_MAP['webgpu'] = ['WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE'];
}

const TUNABLE_FLAG_NAME_MAP = {
  PROD: 'production mode',
  WEBGL_VERSION: 'webgl version',
  WASM_HAS_SIMD_SUPPORT: 'wasm SIMD',
  WASM_HAS_MULTITHREAD_SUPPORT: 'wasm multithread',
  WEBGL_CPU_FORWARD: 'cpu forward',
  WEBGL_PACK: 'webgl pack',
  WEBGL_FORCE_F16_TEXTURES: 'enforce float16',
  WEBGL_RENDER_FLOAT32_CAPABLE: 'enable float32',
  WEBGL_FLUSH_THRESHOLD: 'GL flush wait time(ms)',
  WEBGL_PACK_DEPTHWISECONV: 'Packed depthwise Conv2d',
  WEBGL_USE_SHAPES_UNIFORMS: 'Use shapes uniforms',
  CHECK_COMPUTATION_FOR_ERRORS: 'Check each op result',
};
if (tf.engine().backendNames().includes('webgpu')) {
  TUNABLE_FLAG_NAME_MAP['WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE'] =
      'deferred submit batch size';
}

/**
 * Records each flag's default value under the runtime environment and is a
 * constant in runtime.
 */
let TUNABLE_FLAG_DEFAULT_VALUE_MAP;

/**
 * Set up flag settings under the UI element of `folderController`:
 * - If it is the first call, initialize the flags' default value and show flag
 * settings for both the general and the given backend.
 * - Else, clean up flag settings for the previous backend and show flag
 * settings for the new backend.
 *
 * @param {dat.gui.GUI} folderController
 * @param {string} backendName
 */
async function showFlagSettingsAndReturnTunableFlagControllers(
    folderController, backendName) {
  // Determine wether it is the first call.
  if (TUNABLE_FLAG_DEFAULT_VALUE_MAP == null) {
    await initDefaultValueMap();
    showBackendFlagSettingsAndReturnTunableFlagControllers(
        folderController, 'general');
  } else {
    // Clean up flag settings for the previous backend.
    // The first constroller under the `folderController` is the backend
    // setting.
    const fixedSelectionCount = BACKEND_FLAGS_MAP.general.length + 1;
    while (folderController.__controllers.length > fixedSelectionCount) {
      folderController.remove(
          folderController
              .__controllers[folderController.__controllers.length - 1]);
    }
  }

  // Show flag settings for the new backend and return the tunable flags
  // controllers.
  return showBackendFlagSettingsAndReturnTunableFlagControllers(
      folderController, backendName);
}

const stringValueMap = {};
/**
 * Show flag settings for the given backend under the UI element of
 * `folderController`.
 *
 * @param {dat.gui.GUI} folderController
 * @param {string} backendName
 */
function showBackendFlagSettingsAndReturnTunableFlagControllers(
    folderController, backendName) {
  const tunableFlags = BACKEND_FLAGS_MAP[backendName];
  const tunableFlagControllers = {};
  for (let index = 0; index < tunableFlags.length; index++) {
    const flag = tunableFlags[index];
    const flagName = TUNABLE_FLAG_NAME_MAP[flag] || flag;

    // When tunable (bool) and range (array) attributes of `flagRegistry` is
    // implemented, we can apply them to here.
    const flagValueRange = getTunableRange(flag);
    // Heuristically consider a flag with at least two options as tunable.
    if (flagValueRange.length < 2) {
      console.warn(
          `The ${flag} is considered as untunable, ` +
          `because its value range is [${flagValueRange}].`);
      continue;
    }

    let flagController;
    if (typeof flagValueRange[0] === 'boolean') {
      // Show checkbox for boolean flags.
      flagController = folderController.add(state.flags, flag);
    } else {
      // Show dropdown for other types of flags.
      flagController = folderController.add(state.flags, flag, flagValueRange);

      // Because dat.gui always casts dropdown option values to string, we need
      // `stringValueMap` and `onFinishChange()` to recover the value type.
      if (stringValueMap[flag] == null) {
        stringValueMap[flag] = {};
        for (let index = 0; index < flagValueRange.length; index++) {
          const realValue = flagValueRange[index];
          const stringValue = String(flagValueRange[index]);
          stringValueMap[flag][stringValue] = realValue;
        }
      }
      flagController.onFinishChange(stringValue => {
        state.flags[flag] = stringValueMap[flag][stringValue];
      });
    }
    flagController.name(flagName).onChange(() => {
      state.isFlagChanged = true;
    });
    tunableFlagControllers[flag] = flagController;
  }
  return tunableFlagControllers;
}

/**
 * Query all tunable flags' default value and populate `state.flags` with them.
 */
async function initDefaultValueMap() {
  // Clean up the cache to query tunable flags' default values.
  setEnvFlags({});
  TUNABLE_FLAG_DEFAULT_VALUE_MAP = {};
  for (const backend in BACKEND_FLAGS_MAP) {
    for (let index = 0; index < BACKEND_FLAGS_MAP[backend].length; index++) {
      const flag = BACKEND_FLAGS_MAP[backend][index];
      TUNABLE_FLAG_DEFAULT_VALUE_MAP[flag] = await tf.env().getAsync(flag);
    }
  }

  // Initialize state.flags with tunable flags' default values.
  for (const flag in TUNABLE_FLAG_DEFAULT_VALUE_MAP) {
    state.flags[flag] = TUNABLE_FLAG_DEFAULT_VALUE_MAP[flag];
  }
  state.isFlagChanged = false;
}

/**
 * Heuristically determine flag's value range based on flag's default value.
 *
 * Assume that the flag's default value has already chosen the best option for
 * the runtime environment, so users can only tune the flag value downwards.
 *
 * For example, if the default value of `WEBGL_RENDER_FLOAT32_CAPABLE` is false,
 * the tunable range is [false]; otherwise, the tunable range is [true. false].
 *
 * @param {string} flag
 */
function getTunableRange(flag) {
  const defaultValue = TUNABLE_FLAG_DEFAULT_VALUE_MAP[flag];
  if (flag === 'WEBGL_FORCE_F16_TEXTURES' ||
      flag === 'WEBGL_PACK_DEPTHWISECONV') {
    return [false, true];
  } else if (flag === 'WEBGL_VERSION') {
    const tunableRange = [];
    for (let value = 1; value <= defaultValue; value++) {
      tunableRange.push(value);
    }
    return tunableRange;
  } else if (flag === 'WEBGL_FLUSH_THRESHOLD') {
    const tunableRange = [-1];
    for (let value = 0; value <= 2; value += 0.25) {
      tunableRange.push(value);
    }
    return tunableRange;
  } else if (typeof defaultValue === 'boolean') {
    return defaultValue || flag === 'WEBGL_USE_SHAPES_UNIFORMS' ?
        [false, true] :
        [false];
  } else if (TUNABLE_FLAG_VALUE_RANGE_MAP[flag] != null) {
    return TUNABLE_FLAG_VALUE_RANGE_MAP[flag];
  } else {
    return [defaultValue];
  }
}
<commit_msg>[E2E] Set CHECK_COMPUTATION_FOR_ERRORS to false for WebGPU backend in (#5314)<commit_after>/**
 * @license
 * Copyright 2020 Google LLC. 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.
 * =============================================================================
 */

const BACKEND_FLAGS_MAP = {
  general: [],
  cpu: [],
  wasm: [
    'WASM_HAS_SIMD_SUPPORT',
    'WASM_HAS_MULTITHREAD_SUPPORT',
    'CHECK_COMPUTATION_FOR_ERRORS',
  ],
  webgl: [
    'WEBGL_VERSION', 'WEBGL_CPU_FORWARD', 'WEBGL_PACK',
    'WEBGL_FORCE_F16_TEXTURES', 'WEBGL_RENDER_FLOAT32_CAPABLE',
    'WEBGL_FLUSH_THRESHOLD', 'WEBGL_PACK_DEPTHWISECONV',
    'CHECK_COMPUTATION_FOR_ERRORS', 'WEBGL_USE_SHAPES_UNIFORMS'
  ],
};
if (tf.engine().backendNames().includes('webgpu')) {
  BACKEND_FLAGS_MAP['webgpu'] = ['WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE'];
}

const TUNABLE_FLAG_NAME_MAP = {
  PROD: 'production mode',
  WEBGL_VERSION: 'webgl version',
  WASM_HAS_SIMD_SUPPORT: 'wasm SIMD',
  WASM_HAS_MULTITHREAD_SUPPORT: 'wasm multithread',
  WEBGL_CPU_FORWARD: 'cpu forward',
  WEBGL_PACK: 'webgl pack',
  WEBGL_FORCE_F16_TEXTURES: 'enforce float16',
  WEBGL_RENDER_FLOAT32_CAPABLE: 'enable float32',
  WEBGL_FLUSH_THRESHOLD: 'GL flush wait time(ms)',
  WEBGL_PACK_DEPTHWISECONV: 'Packed depthwise Conv2d',
  WEBGL_USE_SHAPES_UNIFORMS: 'Use shapes uniforms',
  CHECK_COMPUTATION_FOR_ERRORS: 'Check each op result',
};
if (tf.engine().backendNames().includes('webgpu')) {
  TUNABLE_FLAG_NAME_MAP['WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE'] =
      'deferred submit batch size';
}

/**
 * Records each flag's default value under the runtime environment and is a
 * constant in runtime.
 */
let TUNABLE_FLAG_DEFAULT_VALUE_MAP;

/**
 * Set up flag settings under the UI element of `folderController`:
 * - If it is the first call, initialize the flags' default value and show flag
 * settings for both the general and the given backend.
 * - Else, clean up flag settings for the previous backend and show flag
 * settings for the new backend.
 *
 * @param {dat.gui.GUI} folderController
 * @param {string} backendName
 */
async function showFlagSettingsAndReturnTunableFlagControllers(
    folderController, backendName) {
  // Determine wether it is the first call.
  if (TUNABLE_FLAG_DEFAULT_VALUE_MAP == null) {
    await initDefaultValueMap();
    showBackendFlagSettingsAndReturnTunableFlagControllers(
        folderController, 'general');
  } else {
    // Clean up flag settings for the previous backend.
    // The first constroller under the `folderController` is the backend
    // setting.
    const fixedSelectionCount = BACKEND_FLAGS_MAP.general.length + 1;
    while (folderController.__controllers.length > fixedSelectionCount) {
      folderController.remove(
          folderController
              .__controllers[folderController.__controllers.length - 1]);
    }
  }

  // Show flag settings for the new backend and return the tunable flags
  // controllers.
  return showBackendFlagSettingsAndReturnTunableFlagControllers(
      folderController, backendName);
}

const stringValueMap = {};
/**
 * Show flag settings for the given backend under the UI element of
 * `folderController`.
 *
 * @param {dat.gui.GUI} folderController
 * @param {string} backendName
 */
function showBackendFlagSettingsAndReturnTunableFlagControllers(
    folderController, backendName) {
  const tunableFlags = BACKEND_FLAGS_MAP[backendName];
  const tunableFlagControllers = {};

  // Remove it once we figure out how to correctly read the tensor data
  // before the tensor is disposed in profiling mode.
  if (backendName === 'webgpu' &&
      state.flags['CHECK_COMPUTATION_FOR_ERRORS'] === true) {
    state.flags['CHECK_COMPUTATION_FOR_ERRORS'] = false;
    state.isFlagChanged = true;
  }

  for (let index = 0; index < tunableFlags.length; index++) {
    const flag = tunableFlags[index];
    const flagName = TUNABLE_FLAG_NAME_MAP[flag] || flag;

    // When tunable (bool) and range (array) attributes of `flagRegistry` is
    // implemented, we can apply them to here.
    const flagValueRange = getTunableRange(flag);
    // Heuristically consider a flag with at least two options as tunable.
    if (flagValueRange.length < 2) {
      console.warn(
          `The ${flag} is considered as untunable, ` +
          `because its value range is [${flagValueRange}].`);
      continue;
    }

    let flagController;
    if (typeof flagValueRange[0] === 'boolean') {
      // Show checkbox for boolean flags.
      flagController = folderController.add(state.flags, flag);
    } else {
      // Show dropdown for other types of flags.
      flagController = folderController.add(state.flags, flag, flagValueRange);

      // Because dat.gui always casts dropdown option values to string, we need
      // `stringValueMap` and `onFinishChange()` to recover the value type.
      if (stringValueMap[flag] == null) {
        stringValueMap[flag] = {};
        for (let index = 0; index < flagValueRange.length; index++) {
          const realValue = flagValueRange[index];
          const stringValue = String(flagValueRange[index]);
          stringValueMap[flag][stringValue] = realValue;
        }
      }
      flagController.onFinishChange(stringValue => {
        state.flags[flag] = stringValueMap[flag][stringValue];
      });
    }
    flagController.name(flagName).onChange(() => {
      state.isFlagChanged = true;
    });
    tunableFlagControllers[flag] = flagController;
  }
  return tunableFlagControllers;
}

/**
 * Query all tunable flags' default value and populate `state.flags` with them.
 */
async function initDefaultValueMap() {
  // Clean up the cache to query tunable flags' default values.
  setEnvFlags({});
  TUNABLE_FLAG_DEFAULT_VALUE_MAP = {};
  for (const backend in BACKEND_FLAGS_MAP) {
    for (let index = 0; index < BACKEND_FLAGS_MAP[backend].length; index++) {
      const flag = BACKEND_FLAGS_MAP[backend][index];
      TUNABLE_FLAG_DEFAULT_VALUE_MAP[flag] = await tf.env().getAsync(flag);
    }
  }

  // Initialize state.flags with tunable flags' default values.
  for (const flag in TUNABLE_FLAG_DEFAULT_VALUE_MAP) {
    state.flags[flag] = TUNABLE_FLAG_DEFAULT_VALUE_MAP[flag];
  }
  state.isFlagChanged = false;
}

/**
 * Heuristically determine flag's value range based on flag's default value.
 *
 * Assume that the flag's default value has already chosen the best option for
 * the runtime environment, so users can only tune the flag value downwards.
 *
 * For example, if the default value of `WEBGL_RENDER_FLOAT32_CAPABLE` is false,
 * the tunable range is [false]; otherwise, the tunable range is [true. false].
 *
 * @param {string} flag
 */
function getTunableRange(flag) {
  const defaultValue = TUNABLE_FLAG_DEFAULT_VALUE_MAP[flag];
  if (flag === 'WEBGL_FORCE_F16_TEXTURES' ||
      flag === 'WEBGL_PACK_DEPTHWISECONV') {
    return [false, true];
  } else if (flag === 'WEBGL_VERSION') {
    const tunableRange = [];
    for (let value = 1; value <= defaultValue; value++) {
      tunableRange.push(value);
    }
    return tunableRange;
  } else if (flag === 'WEBGL_FLUSH_THRESHOLD') {
    const tunableRange = [-1];
    for (let value = 0; value <= 2; value += 0.25) {
      tunableRange.push(value);
    }
    return tunableRange;
  } else if (typeof defaultValue === 'boolean') {
    return defaultValue || flag === 'WEBGL_USE_SHAPES_UNIFORMS' ?
        [false, true] :
        [false];
  } else if (TUNABLE_FLAG_VALUE_RANGE_MAP[flag] != null) {
    return TUNABLE_FLAG_VALUE_RANGE_MAP[flag];
  } else {
    return [defaultValue];
  }
}
<|endoftext|>


<commit_before>'use strict';

const XibleRegistryWrapper = require('xible-registry-wrapper');
const fsExtra = require('fs-extra');
const os = require('os');

module.exports = (XIBLE, EXPRESS_APP) => {
  const registryUrl = XIBLE.Config.getValue('registry.url');
  if (!registryUrl) {
    throw new Error('"registry.url" not found in config');
  }

  const xibleRegistry = new XibleRegistryWrapper(registryUrl);

  // the tmp path for downloading this node
  const TMP_REGISTRY_DIR = `${os.tmpdir() || '/tmp'}/xible-registry-`;

  function cleanUp(tmpRegDir) {
    if (!tmpRegDir) {
      return Promise.resolve();
    }

    return new Promise((resolve, reject) => {
      // remove the tmp dir
      fsExtra.remove(tmpRegDir, (err) => {
        if (err) {
          reject(err);
          return;
        }

        resolve();
      });
    });
  }

  /**
  * Installs a flow from a registry.
  * @param {String} altName The name to publish the flow with. Defaults to the flow name.
  * @returns {Promise}
  */
  xibleRegistry.Flow.prototype.install = function flowInstall(altName) {
    if (!XIBLE.Config.getValue('registry.flows.allowinstall')) {
      return Promise.reject('Your config does not allow to install flows from the registry');
    }

    let flowPath = XIBLE.Config.getValue('flows.path');
    if (!flowPath) {
      return Promise.reject('no "flows.path" configured');
    }
    flowPath = XIBLE.resolvePath(flowPath);

    if (altName) {
      if (!XIBLE.Flow.validateId(altName)) {
        return Promise.reject('flow _id/name cannot contain reserved/unsave characters');
      }
      this._id = altName;
      this.name = altName;
    }

    // remove fields specifically for the registry
    delete this.publishUserName;
    delete this.publishDate;

    return new Promise((resolve, reject) => {
      // write
      const flowDestPath = `${flowPath}/${this._id}.json`;
      fsExtra.writeFile(flowDestPath, JSON.stringify(this, null, '\t'), (err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve();
      });
    });
  };

  /**
  * Installs a nodepack from a registry.
  * @returns {Promise}
  */
  xibleRegistry.NodePack.prototype.install = function nodePackInstall() {
    if (!XIBLE.Config.getValue('registry.nodepacks.allowinstall')) {
      return Promise.reject('Your config does not allow to install nodepacks from the registry');
    }

    let tmpRegDir;
    let nodePath = XIBLE.Config.getValue('nodes.path');
    if (!nodePath) {
      return Promise.reject('no "nodes.path" configured');
    }
    nodePath = XIBLE.resolvePath(nodePath);

    // get the registrydata
    return this.getRegistryData()
    .then((registryData) => {
      if (!registryData.name) {
        return Promise.reject(`No "name" field found in the registry data for node "${this.name}"`);
      }

      return this.getTarballUrl()
      .then(tarballUrl => new Promise((resolve, reject) => {
        // check if the tarbalUrl is safe
        if (encodeURI(tarballUrl) !== tarballUrl) {
          reject(new Error('Package URL contains potentially unsafe characters'));
          return;
        }

        // create the tmp dir
        fsExtra.mkdtemp(TMP_REGISTRY_DIR, (err, mTmpRegDir) => {
          tmpRegDir = mTmpRegDir;
          if (err) {
            reject(err);
            return;
          }

          // create a package.json so npm knows where the root lies
          // remove the dependencies from the package so npm doesn't get confused
          const packageJson = require(`${__dirname}/../../package.json`);
          delete packageJson.dependencies;
          delete packageJson.devDependencies;

          // write off package.json
          fsExtra.writeFile(`${tmpRegDir}/package.json`, JSON.stringify(packageJson), (createPackageJsonErr) => {
            if (createPackageJsonErr) {
              reject(createPackageJsonErr);
              return;
            }

            // fork npm to install the registry url
            const fork = require('child_process').spawn;
            const npm = fork('npm', ['install', '--no-save', tarballUrl], {
              cwd: tmpRegDir,
              shell: true
            });

            npm.on('error', npmErr => reject(npmErr));

            npm.on('exit', (exitCode) => {
              if (exitCode) {
                reject(`exited with code: ${exitCode}`);
                return;
              }

              // specify the dir where this node will be installed
              const nodeDestDir = `${nodePath}/${this.name}`;

              // when success, resolve
              const onSuccess = () => XIBLE.Node
              .initFromPath(nodeDestDir)
              .then(() => cleanUp(tmpRegDir))
              .then(() => {
                // see if we can/need to reinit flows that are not runnable
                const flows = XIBLE.getFlows();
                for (const flowId in flows) {
                  if (!flows[flowId].runnable) {
                    flows[flowId].initJson(flows[flowId].json);
                  }
                }
              })
              .then(resolve)
              .catch((onSuccessErr) => {
                reject(onSuccessErr);
              });

              // remove existing node directory
              fsExtra.emptyDir(nodeDestDir, (removeExistingNodeErr) => {
                if (removeExistingNodeErr) {
                  reject(removeExistingNodeErr);
                  return;
                }

                // first move the node itself
                fsExtra.move(`${tmpRegDir}/node_modules/${registryData.name}`, nodeDestDir, {
                  overwrite: true
                }, (moveNodeErr) => {
                  if (moveNodeErr) {
                    reject(moveNodeErr);
                    return;
                  }

                  // check if there's anything left in node_modules
                  fsExtra.readdir(`${tmpRegDir}/node_modules`, (remainingNodeModulesErr, files) => {
                    if (remainingNodeModulesErr) {
                      reject(remainingNodeModulesErr);
                      return;
                    }

                    if (!files.length) {
                      onSuccess();
                      return;
                    }

                    // move the rest of the node_modules
                    fsExtra.move(`${tmpRegDir}/node_modules`, `${nodeDestDir}/node_modules`, {
                      overwrite: true
                    }, (moveNodeModulesErr) => {
                      if (moveNodeModulesErr) {
                        reject(moveNodeModulesErr);
                        return;
                      }

                      onSuccess();
                    });
                  });
                });
              });
            });

            npm.stdout.on('data', (data) => {
              console.log(data.toString());
            });

            npm.stderr.on('data', (data) => {
              console.log(data.toString());
            });
          });
        });
      }));
    })
    .catch(err =>
      cleanUp(tmpRegDir)
      .then(() => Promise.reject(err))
      .catch(() => Promise.reject(err))
    );
  };

  if (EXPRESS_APP) {
    require('./routes.js')(xibleRegistry, XIBLE, EXPRESS_APP);
  }

  return {
    Registry: xibleRegistry
  };
};
<commit_msg>do not log npm output to console<commit_after>'use strict';

const XibleRegistryWrapper = require('xible-registry-wrapper');
const fsExtra = require('fs-extra');
const os = require('os');

module.exports = (XIBLE, EXPRESS_APP) => {
  const registryUrl = XIBLE.Config.getValue('registry.url');
  if (!registryUrl) {
    throw new Error('"registry.url" not found in config');
  }

  const xibleRegistry = new XibleRegistryWrapper(registryUrl);

  // the tmp path for downloading this node
  const TMP_REGISTRY_DIR = `${os.tmpdir() || '/tmp'}/xible-registry-`;

  function cleanUp(tmpRegDir) {
    if (!tmpRegDir) {
      return Promise.resolve();
    }

    return new Promise((resolve, reject) => {
      // remove the tmp dir
      fsExtra.remove(tmpRegDir, (err) => {
        if (err) {
          reject(err);
          return;
        }

        resolve();
      });
    });
  }

  /**
  * Installs a flow from a registry.
  * @param {String} altName The name to publish the flow with. Defaults to the flow name.
  * @returns {Promise}
  */
  xibleRegistry.Flow.prototype.install = function flowInstall(altName) {
    if (!XIBLE.Config.getValue('registry.flows.allowinstall')) {
      return Promise.reject('Your config does not allow to install flows from the registry');
    }

    let flowPath = XIBLE.Config.getValue('flows.path');
    if (!flowPath) {
      return Promise.reject('no "flows.path" configured');
    }
    flowPath = XIBLE.resolvePath(flowPath);

    if (altName) {
      if (!XIBLE.Flow.validateId(altName)) {
        return Promise.reject('flow _id/name cannot contain reserved/unsave characters');
      }
      this._id = altName;
      this.name = altName;
    }

    // remove fields specifically for the registry
    delete this.publishUserName;
    delete this.publishDate;

    return new Promise((resolve, reject) => {
      // write
      const flowDestPath = `${flowPath}/${this._id}.json`;
      fsExtra.writeFile(flowDestPath, JSON.stringify(this, null, '\t'), (err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve();
      });
    });
  };

  /**
  * Installs a nodepack from a registry.
  * @returns {Promise}
  */
  xibleRegistry.NodePack.prototype.install = function nodePackInstall() {
    if (!XIBLE.Config.getValue('registry.nodepacks.allowinstall')) {
      return Promise.reject('Your config does not allow to install nodepacks from the registry');
    }

    let tmpRegDir;
    let nodePath = XIBLE.Config.getValue('nodes.path');
    if (!nodePath) {
      return Promise.reject('no "nodes.path" configured');
    }
    nodePath = XIBLE.resolvePath(nodePath);

    // get the registrydata
    return this.getRegistryData()
    .then((registryData) => {
      if (!registryData.name) {
        return Promise.reject(`No "name" field found in the registry data for node "${this.name}"`);
      }

      return this.getTarballUrl()
      .then(tarballUrl => new Promise((resolve, reject) => {
        // check if the tarbalUrl is safe
        if (encodeURI(tarballUrl) !== tarballUrl) {
          reject(new Error('Package URL contains potentially unsafe characters'));
          return;
        }

        // create the tmp dir
        fsExtra.mkdtemp(TMP_REGISTRY_DIR, (err, mTmpRegDir) => {
          tmpRegDir = mTmpRegDir;
          if (err) {
            reject(err);
            return;
          }

          // create a package.json so npm knows where the root lies
          // remove the dependencies from the package so npm doesn't get confused
          const packageJson = require(`${__dirname}/../../package.json`);
          delete packageJson.dependencies;
          delete packageJson.devDependencies;

          // write off package.json
          fsExtra.writeFile(`${tmpRegDir}/package.json`, JSON.stringify(packageJson), (createPackageJsonErr) => {
            if (createPackageJsonErr) {
              reject(createPackageJsonErr);
              return;
            }

            // fork npm to install the registry url
            const fork = require('child_process').spawn;
            const npm = fork('npm', ['install', '--no-save', tarballUrl], {
              cwd: tmpRegDir,
              shell: true
            });

            npm.on('error', npmErr => reject(npmErr));

            npm.on('exit', (exitCode) => {
              if (exitCode) {
                reject(`exited with code: ${exitCode}`);
                return;
              }

              // specify the dir where this node will be installed
              const nodeDestDir = `${nodePath}/${this.name}`;

              // when success, resolve
              const onSuccess = () => XIBLE.Node
              .initFromPath(nodeDestDir)
              .then(() => cleanUp(tmpRegDir))
              .then(() => {
                // see if we can/need to reinit flows that are not runnable
                const flows = XIBLE.getFlows();
                for (const flowId in flows) {
                  if (!flows[flowId].runnable) {
                    flows[flowId].initJson(flows[flowId].json);
                  }
                }
              })
              .then(resolve)
              .catch((onSuccessErr) => {
                reject(onSuccessErr);
              });

              // remove existing node directory
              fsExtra.emptyDir(nodeDestDir, (removeExistingNodeErr) => {
                if (removeExistingNodeErr) {
                  reject(removeExistingNodeErr);
                  return;
                }

                // first move the node itself
                fsExtra.move(`${tmpRegDir}/node_modules/${registryData.name}`, nodeDestDir, {
                  overwrite: true
                }, (moveNodeErr) => {
                  if (moveNodeErr) {
                    reject(moveNodeErr);
                    return;
                  }

                  // check if there's anything left in node_modules
                  fsExtra.readdir(`${tmpRegDir}/node_modules`, (remainingNodeModulesErr, files) => {
                    if (remainingNodeModulesErr) {
                      reject(remainingNodeModulesErr);
                      return;
                    }

                    if (!files.length) {
                      onSuccess();
                      return;
                    }

                    // move the rest of the node_modules
                    fsExtra.move(`${tmpRegDir}/node_modules`, `${nodeDestDir}/node_modules`, {
                      overwrite: true
                    }, (moveNodeModulesErr) => {
                      if (moveNodeModulesErr) {
                        reject(moveNodeModulesErr);
                        return;
                      }

                      onSuccess();
                    });
                  });
                });
              });
            });

            npm.stdout.on('data', (data) => {
              // console.log(data.toString());
            });

            npm.stderr.on('data', (data) => {
              console.log(data.toString());
            });
          });
        });
      }));
    })
    .catch(err =>
      cleanUp(tmpRegDir)
      .then(() => Promise.reject(err))
      .catch(() => Promise.reject(err))
    );
  };

  if (EXPRESS_APP) {
    require('./routes.js')(xibleRegistry, XIBLE, EXPRESS_APP);
  }

  return {
    Registry: xibleRegistry
  };
};
<|endoftext|>


<commit_before>import circular from 'circular';
import Hook from 'Ractive/prototype/shared/hooks/Hook';
import removeFromArray from 'utils/removeFromArray';
import Promise from 'utils/Promise';
import resolveRef from 'shared/resolveRef';
import TransitionManager from 'global/TransitionManager';

var batch, runloop, unresolved = [], changeHook = new Hook( 'change' );

runloop = {
	start: function ( instance, returnPromise ) {
		var promise, fulfilPromise;

		if ( returnPromise ) {
			promise = new Promise( f => ( fulfilPromise = f ) );
		}

		batch = {
			previousBatch: batch,
			transitionManager: new TransitionManager( fulfilPromise, batch && batch.transitionManager ),
			views: [],
			tasks: [],
			viewmodels: []
		};

		if ( instance ) {
			batch.viewmodels.push( instance.viewmodel );
		}

		return promise;
	},

	end: function () {
		flushChanges();

		batch.transitionManager.init();
		batch = batch.previousBatch;
	},

	addViewmodel: function ( viewmodel ) {
		if ( batch ) {
			if ( batch.viewmodels.indexOf( viewmodel ) === -1 ) {
				batch.viewmodels.push( viewmodel );
			}
		} else {
			viewmodel.applyChanges();
		}
	},

	registerTransition: function ( transition ) {
		transition._manager = batch.transitionManager;
		batch.transitionManager.add( transition );
	},

	addView: function ( view ) {
		batch.views.push( view );
	},

	addUnresolved: function ( thing ) {
		unresolved.push( thing );
	},

	removeUnresolved: function ( thing ) {
		removeFromArray( unresolved, thing );
	},

	// synchronise node detachments with transition ends
	detachWhenReady: function ( thing ) {
		batch.transitionManager.detachQueue.push( thing );
	},

	scheduleTask: function ( task, postRender ) {
		var _batch;

		if ( !batch ) {
			task();
		} else {
			_batch = batch;
			while ( postRender && _batch.previousBatch ) {
				// this can't happen until the DOM has been fully updated
				// otherwise in some situations (with components inside elements)
				// transitions and decorators will initialise prematurely
				_batch = _batch.previousBatch;
			}

			_batch.tasks.push( task );
		}
	}
};

circular.runloop = runloop;
export default runloop;

function flushChanges () {
	var i, thing, changeHash;

	for ( i = 0; i < batch.viewmodels.length; i += 1 ) {
		thing = batch.viewmodels[i];
		changeHash = thing.applyChanges();

		if ( changeHash ) {
			changeHook.fire( thing.ractive, changeHash );
		}
	}
	batch.viewmodels.length = 0;

	attemptKeypathResolution();

	// Now that changes have been fully propagated, we can update the DOM
	// and complete other tasks
	for ( i = 0; i < batch.views.length; i += 1 ) {
		batch.views[i].update();
	}
	batch.views.length = 0;

	for ( i = 0; i < batch.tasks.length; i += 1 ) {
		batch.tasks[i]();
	}
	batch.tasks.length = 0;

	// If updating the view caused some model blowback - e.g. a triple
	// containing <option> elements caused the binding on the <select>
	// to update - then we start over
	if ( batch.viewmodels.length ) return flushChanges();
}

function attemptKeypathResolution () {
	var i, item, keypath, resolved;

	i = unresolved.length;

	// see if we can resolve any unresolved references
	while ( i-- ) {
		item = unresolved[i];

		if ( item.keypath ) {
			// it resolved some other way. TODO how? two-way binding? Seems
			// weird that we'd still end up here
			unresolved.splice( i, 1 );
		}

		if ( keypath = resolveRef( item.root, item.ref, item.parentFragment ) ) {
			( resolved || ( resolved = [] ) ).push({
				item: item,
				keypath: keypath
			});

			unresolved.splice( i, 1 );
		}
	}

	if ( resolved ) {
		resolved.forEach( resolve );
	}
}

function resolve ( resolved ) {
	resolved.item.resolve( resolved.keypath );
}
<commit_msg>make sure the viewmodel change queue is clear after complete turn of the runloop<commit_after>import circular from 'circular';
import Hook from 'Ractive/prototype/shared/hooks/Hook';
import removeFromArray from 'utils/removeFromArray';
import Promise from 'utils/Promise';
import resolveRef from 'shared/resolveRef';
import TransitionManager from 'global/TransitionManager';

var batch, runloop, unresolved = [], changeHook = new Hook( 'change' );

runloop = {
	start: function ( instance, returnPromise ) {
		var promise, fulfilPromise;

		if ( returnPromise ) {
			promise = new Promise( f => ( fulfilPromise = f ) );
		}

		batch = {
			previousBatch: batch,
			transitionManager: new TransitionManager( fulfilPromise, batch && batch.transitionManager ),
			views: [],
			tasks: [],
			viewmodels: [],
			instance: instance
		};

		if ( instance ) {
			batch.viewmodels.push( instance.viewmodel );
		}

		return promise;
	},

	end: function () {
		flushChanges();

		batch.transitionManager.init();
		if ( !batch.previousBatch && !!batch.instance ) batch.instance.viewmodel.changes = [];
		batch = batch.previousBatch;
	},

	addViewmodel: function ( viewmodel ) {
		if ( batch ) {
			if ( batch.viewmodels.indexOf( viewmodel ) === -1 ) {
				batch.viewmodels.push( viewmodel );
			}
		} else {
			viewmodel.applyChanges();
		}
	},

	registerTransition: function ( transition ) {
		transition._manager = batch.transitionManager;
		batch.transitionManager.add( transition );
	},

	addView: function ( view ) {
		batch.views.push( view );
	},

	addUnresolved: function ( thing ) {
		unresolved.push( thing );
	},

	removeUnresolved: function ( thing ) {
		removeFromArray( unresolved, thing );
	},

	// synchronise node detachments with transition ends
	detachWhenReady: function ( thing ) {
		batch.transitionManager.detachQueue.push( thing );
	},

	scheduleTask: function ( task, postRender ) {
		var _batch;

		if ( !batch ) {
			task();
		} else {
			_batch = batch;
			while ( postRender && _batch.previousBatch ) {
				// this can't happen until the DOM has been fully updated
				// otherwise in some situations (with components inside elements)
				// transitions and decorators will initialise prematurely
				_batch = _batch.previousBatch;
			}

			_batch.tasks.push( task );
		}
	}
};

circular.runloop = runloop;
export default runloop;

function flushChanges () {
	var i, thing, changeHash;

	for ( i = 0; i < batch.viewmodels.length; i += 1 ) {
		thing = batch.viewmodels[i];
		changeHash = thing.applyChanges();

		if ( changeHash ) {
			changeHook.fire( thing.ractive, changeHash );
		}
	}
	batch.viewmodels.length = 0;

	attemptKeypathResolution();

	// Now that changes have been fully propagated, we can update the DOM
	// and complete other tasks
	for ( i = 0; i < batch.views.length; i += 1 ) {
		batch.views[i].update();
	}
	batch.views.length = 0;

	for ( i = 0; i < batch.tasks.length; i += 1 ) {
		batch.tasks[i]();
	}
	batch.tasks.length = 0;

	// If updating the view caused some model blowback - e.g. a triple
	// containing <option> elements caused the binding on the <select>
	// to update - then we start over
	if ( batch.viewmodels.length ) return flushChanges();
}

function attemptKeypathResolution () {
	var i, item, keypath, resolved;

	i = unresolved.length;

	// see if we can resolve any unresolved references
	while ( i-- ) {
		item = unresolved[i];

		if ( item.keypath ) {
			// it resolved some other way. TODO how? two-way binding? Seems
			// weird that we'd still end up here
			unresolved.splice( i, 1 );
		}

		if ( keypath = resolveRef( item.root, item.ref, item.parentFragment ) ) {
			( resolved || ( resolved = [] ) ).push({
				item: item,
				keypath: keypath
			});

			unresolved.splice( i, 1 );
		}
	}

	if ( resolved ) {
		resolved.forEach( resolve );
	}
}

function resolve ( resolved ) {
	resolved.item.resolve( resolved.keypath );
}
<|endoftext|>


<commit_before>var width = 720;
var height = 720;

module.exports = {
    width: width,
    height: height,
	bullet: {
		radius: 2,
		speed: 8
	},
    fighterInitializer: function(fighter){
        fighter.position({ 'x': 50, 'y': 100 });
        fighter.radius(10);
        fighter.velocity({ 'speed': '0.5', 'heading': Math.PI/12 });
        fighter.orientation(Math.PI/12);
    },
    asteroidInitializer: function(asteroid){
        asteroid.position({ 'x': width * Math.random(), 'y': height * Math.random() });
		asteroid.radius(12 + 6 * Math.random());
        asteroid.velocity({ 'speed': '3', 'heading': 2*Math.PI * Math.random() });
    },
    asteroidCount: 10
}
<commit_msg>give asteroids omega<commit_after>var width = 720;
var height = 720;

module.exports = {
    width: width,
    height: height,
	bullet: {
		radius: 2,
		speed: 8
	},
    fighterInitializer: function(fighter){
        fighter.position({ 'x': 50, 'y': 100 });
        fighter.radius(10);
        fighter.velocity({ 'speed': '0.5', 'heading': Math.PI/12 });
        fighter.orientation(Math.PI/12);
    },
    asteroidInitializer: function(asteroid){
        asteroid.position({ 'x': width * Math.random(), 'y': height * Math.random() });
		asteroid.radius(12 + 6 * Math.random());
        asteroid.velocity({ 'speed': '3', 'heading': 2*Math.PI * Math.random(), omega: Math.PI/100 * (1 + 2 * Math.random()) });
    },
    asteroidCount: 10
}
<|endoftext|>


<commit_before>import fs from 'fs';
import test from 'ava';
import semver from 'semver';
import moment from 'moment';

import buildRevision from '../index';

test('build revision is semver compatible', async t => {
    const option = {
        cwd: 'test/fixture/package-valid/target'
    };

    const revision = await buildRevision(option);
    t.truthy(semver.valid(revision), 'semver could not parse a valid version');
});

test('throws error for package with missing version', async t => {
    const option = {
        cwd: 'test/fixture/package-invalid/target'
    };

    return buildRevision(option).then((res) => {
        t.fail('invalid package did not throw error');
    }, (err) => {
        t.truthy(err instanceof TypeError, err.message);
    });
});

test('buildinfo prefix is configurable', async t => {
    const PREFIX = 'REV'
    const option = {
        prefix: PREFIX,
        cwd: 'test/fixture/package-valid/target'
    };

    const revision = await buildRevision(option);
    t.truthy(semver.valid(revision) && revision.includes('+' + PREFIX), 'configured buildinfo prefix not set');
});

test('updates the existing buildinfo fragment of semver', async t => {
    const option = {
        cwd: 'test/fixture/package-with-buildinfo/target'
    };
    const fixtureVersion = require('./fixture/package-with-buildinfo/package.json').version;

    t.true((fixtureVersion.match(/\+/g) || []).length === 1, 'test fixture does not include buildinfo')
    const revision = await buildRevision(option);
    t.true(semver.valid(revision) && (revision.match(/\+/g) || []).length === 1, 'invalid version with multiple buildfragments generated');
});

test('generates ISO 8601 UTC timestamp for dirty builds', async t => {
    const option = {
        cwd: 'test/fixture/package-valid/target'
    };

    // Test Setup: Add a file to the fixtures direcory to make the repository it dirty
    fs.writeFileSync('test/fixture/package-valid/change.txt', 'dummychange');

    const revision = await buildRevision(option);
    const timestamp = revision.split('.').pop();
    t.true(moment(timestamp).isValid(), 'could not parse a valid timestamp');

    // Test Teardown: Reset repository
    fs.unlink('test/fixture/package-valid/change.txt', (err) => {
        if (err) {
            t.fail('Could not reset test setup, other tests might be affected')
            throw err;
        }
    });
});

test.todo('throws error when project is not a git clone');
test.todo('throws error when no SHA is found (e.g. localbuilds before initial git commit)');
<commit_msg>:art: Fix typo in comments<commit_after>import fs from 'fs';
import test from 'ava';
import semver from 'semver';
import moment from 'moment';

import buildRevision from '../index';

test('build revision is semver compatible', async t => {
    const option = {
        cwd: 'test/fixture/package-valid/target'
    };

    const revision = await buildRevision(option);
    t.truthy(semver.valid(revision), 'semver could not parse a valid version');
});

test('throws error for package with missing version', async t => {
    const option = {
        cwd: 'test/fixture/package-invalid/target'
    };

    return buildRevision(option).then((res) => {
        t.fail('invalid package did not throw error');
    }, (err) => {
        t.truthy(err instanceof TypeError, err.message);
    });
});

test('buildinfo prefix is configurable', async t => {
    const PREFIX = 'REV';
    const option = {
        prefix: PREFIX,
        cwd: 'test/fixture/package-valid/target'
    };

    const revision = await buildRevision(option);
    t.truthy(semver.valid(revision) && revision.includes('+' + PREFIX), 'configured buildinfo prefix not set');
});

test('updates the existing buildinfo fragment of semver', async t => {
    const option = {
        cwd: 'test/fixture/package-with-buildinfo/target'
    };
    const fixtureVersion = require('./fixture/package-with-buildinfo/package.json').version;

    t.true((fixtureVersion.match(/\+/g) || []).length === 1, 'test fixture does not include buildinfo')
    const revision = await buildRevision(option);
    t.true(semver.valid(revision) && (revision.match(/\+/g) || []).length === 1, 'invalid version with multiple buildfragments generated');
});

test('generates ISO 8601 UTC timestamp for dirty builds', async t => {
    const option = {
        cwd: 'test/fixture/package-valid/target'
    };

    // Test Setup: Emulate a dirty repository by adding a file to the fixtures directory
    fs.writeFileSync('test/fixture/package-valid/change.txt', 'dummychange');

    const revision = await buildRevision(option);
    const timestamp = revision.split('.').pop();
    t.true(moment(timestamp).isValid(), 'could not parse a valid timestamp');

    // Test Teardown: Reset repository
    fs.unlink('test/fixture/package-valid/change.txt', (err) => {
        if (err) {
            t.fail('Could not reset test setup, other tests might be affected')
            throw err;
        }
    });
});

test.todo('throws error when project is not a git clone');
test.todo('throws error when no SHA is found (e.g. localbuilds before initial git commit)');
<|endoftext|>


<commit_before>"use strict";

const camelcase = {
    allow: ["^UNSAFE_"], // Allows React UNSAFE_ methods
    ignoreDestructuring: false,
    properties: "always",
};

module.exports = {
    /* eslint-enable sort-keys */
    ["camelcase"]: camelcase,
    ["comma-spacing"]: {
        after: true,
        before: false,
    },
    ["indent"]: {
        ArrayExpression: 1,
        CallExpression: {
            arguments: 1,
        },
        FunctionDeclaration: {
            body: 1,
            parameters: 1,
        },
        FunctionExpression: {
            body: 1,
            parameters: 1,
        },
        MemberExpression: 1,
        ObjectExpression: 1,
        SwitchCase: 1,
        VariableDeclarator: 1,
        // JSX nodes are handled by react/jsx-indent and should be excluded from this rule
        // See https://github.com/yannickcr/eslint-plugin-react/issues/1679#issuecomment-363908562
        ignoredNodes: [
            "JSXElement",
            "JSXElement > *",
            "JSXAttribute",
            "JSXIdentifier",
            "JSXNamespacedName",
            "JSXMemberExpression",
            "JSXSpreadAttribute",
            "JSXExpressionContainer",
            "JSXOpeningElement",
            "JSXClosingElement",
            "JSXText",
            "JSXEmptyExpression",
            "JSXSpreadChild",
        ],
        outerIIFEBody: 1,
    },
    ["lines-between-class-members"]: {
        exceptAfterSingleLine: true,
    },
    ["max-lines"]: {
        max: 700,
        skipBlankLines: true,
        skipComments: true,
    },
    ["no-unused-expressions"]: {
        allowShortCircuit: true,
        allowTernary: true,
    },
    ["no-unused-vars"]: {
        // Sometimes you want to keep the function parameters for future usage
        args: "none",
        // Handling errors doesn't always mean that you need to use the error
        caughtErrors: "none",
        // This pattern is pretty common
        ignoreRestSiblings: true,
        vars: "all",
    },
    ["quotes"]: {
        avoidEscape: true,
    },
    ["space-before-function-paren"]: {
        anonymous: "always",
        named: "never",
    },
    ["@typescript-eslint/ban-types"]: {
        types: {
            // Default options taken from https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/rules/ban-types.ts
            String: {
                message: "Use string instead",
                fixWith: "string",
            },
            Boolean: {
                message: "Use boolean instead",
                fixWith: "boolean",
            },
            Number: {
                message: "Use number instead",
                fixWith: "number",
            },
            Object: {
                message: "Use Record<string, unknown> instead",
                fixWith: "Record<string, unknown>",
            },
            Symbol: {
                message: "Use symbol instead",
                fixWith: "symbol",
            },
        },
    },
    ["@typescript-eslint/camelcase"]: {
        ...camelcase,
        genericType: "always",
    },
    ["@typescript-eslint/naming-convention"]: (() => {
        const options = {
            default: {
                format: ["camelCase", "PascalCase", "UPPER_CASE"],
                leadingUnderscore: "allow",
                selector: "default",
                trailingUnderscore: "allow",
            },
            function: {
                format: ["camelCase"],
                leadingUnderscore: "allow",
                selector: "function",
                trailingUnderscore: "allow",
            },
            parameter: {
                format: ["camelCase", "PascalCase"],
                leadingUnderscore: "allow",
                selector: "parameter",
                trailingUnderscore: "allow",
            },
            method: {
                format: ["camelCase"],
                leadingUnderscore: "allow",
                selector: "method",
                trailingUnderscore: "allow",
            },
            typeLike: {
                format: ["PascalCase"],
                leadingUnderscore: "allow",
                selector: "typeLike",
                trailingUnderscore: "allow",
            },
            enumMember: {
                format: ["PascalCase"],
                leadingUnderscore: "allow",
                selector: "enumMember",
                trailingUnderscore: "allow",
            },
        };

        // By enumerating all selectors explicitly we increase the
        // specificity of these rules.
        const escapeHatches = [
            "variable",
            "function",
            "parameter",
            "property",
            "parameterProperty",
            "method",
            "accessor",
            "enumMember",
            "class",
            "interface",
            "typeAlias",
            "enum",
            "typeParameter",
        ].map((selector) => ({
            filter: {
                match: true,
                // UNSAFE_ is a prefix used by React for all lifecycle hooks that are about to be deprecated
                regex: "^(__|UNSAFE_).+$",
            },
            format: null,
            selector,
        }));

        options.defaultRules = [...Object.values(options), ...escapeHatches];

        options.ignoreProperties = {
            selector: "property",
            format: null,
        };

        return options;
    })(),
    /* eslint-disable sort-keys */
};
<commit_msg>fix(TypeScript): Relax @typescript-eslint/naming-convention<commit_after>"use strict";

const camelcase = {
    allow: ["^UNSAFE_"], // Allows React UNSAFE_ methods
    ignoreDestructuring: false,
    properties: "always",
};

module.exports = {
    /* eslint-enable sort-keys */
    ["camelcase"]: camelcase,
    ["comma-spacing"]: {
        after: true,
        before: false,
    },
    ["indent"]: {
        ArrayExpression: 1,
        CallExpression: {
            arguments: 1,
        },
        FunctionDeclaration: {
            body: 1,
            parameters: 1,
        },
        FunctionExpression: {
            body: 1,
            parameters: 1,
        },
        MemberExpression: 1,
        ObjectExpression: 1,
        SwitchCase: 1,
        VariableDeclarator: 1,
        // JSX nodes are handled by react/jsx-indent and should be excluded from this rule
        // See https://github.com/yannickcr/eslint-plugin-react/issues/1679#issuecomment-363908562
        ignoredNodes: [
            "JSXElement",
            "JSXElement > *",
            "JSXAttribute",
            "JSXIdentifier",
            "JSXNamespacedName",
            "JSXMemberExpression",
            "JSXSpreadAttribute",
            "JSXExpressionContainer",
            "JSXOpeningElement",
            "JSXClosingElement",
            "JSXText",
            "JSXEmptyExpression",
            "JSXSpreadChild",
        ],
        outerIIFEBody: 1,
    },
    ["lines-between-class-members"]: {
        exceptAfterSingleLine: true,
    },
    ["max-lines"]: {
        max: 700,
        skipBlankLines: true,
        skipComments: true,
    },
    ["no-unused-expressions"]: {
        allowShortCircuit: true,
        allowTernary: true,
    },
    ["no-unused-vars"]: {
        // Sometimes you want to keep the function parameters for future usage
        args: "none",
        // Handling errors doesn't always mean that you need to use the error
        caughtErrors: "none",
        // This pattern is pretty common
        ignoreRestSiblings: true,
        vars: "all",
    },
    ["quotes"]: {
        avoidEscape: true,
    },
    ["space-before-function-paren"]: {
        anonymous: "always",
        named: "never",
    },
    ["@typescript-eslint/ban-types"]: {
        types: {
            // Default options taken from https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/rules/ban-types.ts
            String: {
                message: "Use string instead",
                fixWith: "string",
            },
            Boolean: {
                message: "Use boolean instead",
                fixWith: "boolean",
            },
            Number: {
                message: "Use number instead",
                fixWith: "number",
            },
            Object: {
                message: "Use Record<string, unknown> instead",
                fixWith: "Record<string, unknown>",
            },
            Symbol: {
                message: "Use symbol instead",
                fixWith: "symbol",
            },
        },
    },
    ["@typescript-eslint/camelcase"]: {
        ...camelcase,
        genericType: "always",
    },
    ["@typescript-eslint/naming-convention"]: (() => {
        const options = {
            default: {
                selector: "default",
                format: ["camelCase", "PascalCase", "UPPER_CASE"],
                leadingUnderscore: "allow",
                trailingUnderscore: "allow",
            },
            function: {
                selector: "function",
                format: ["camelCase"],
                leadingUnderscore: "allow",
                trailingUnderscore: "allow",
            },
            parameter: {
                selector: "parameter",
                format: ["camelCase", "PascalCase"],
                leadingUnderscore: "allow",
                trailingUnderscore: "allow",
            },
            method: {
                selector: "method",
                format: ["camelCase"],
                leadingUnderscore: "allow",
                trailingUnderscore: "allow",
            },
            typeLike: {
                selector: "typeLike",
                format: ["PascalCase"],
                leadingUnderscore: "allow",
                trailingUnderscore: "allow",
            },
            enumMember: {
                selector: "enumMember",
                format: ["PascalCase"],
                leadingUnderscore: "allow",
                trailingUnderscore: "allow",
            },
            // In case it's destructured, we don't want to force the developer to change the casing
            destructuring: {
                selector: "variable",
                modifiers: ["destructured"],
                format: null,
            },
            // In case the property name requires quotes, we don't enforce any convention
            requiresQuites: {
                selector: [
                    "classProperty",
                    "objectLiteralProperty",
                    "typeProperty",
                    "classMethod",
                    "objectLiteralMethod",
                    "typeMethod",
                    "accessor",
                    "enumMember",
                ],
                modifiers: ["requiresQuotes"],
                format: null,
            },
            // We don't enforce any convention on object literals since these are often used
            // for data object where we're not in control of the type (e.g. an api that takes camel_case properties)
            objectLiteralProperty: {
                selector: "objectLiteralProperty",
                format: null,
            },
        };

        // By enumerating all selectors explicitly we increase the
        // specificity of these rules.
        const escapeHatches = [
            "variable",
            "function",
            "parameter",
            "property",
            "parameterProperty",
            "method",
            "accessor",
            "enumMember",
            "class",
            "interface",
            "typeAlias",
            "enum",
            "typeParameter",
        ].map((selector) => ({
            filter: {
                match: true,
                // UNSAFE_ is a prefix used by React for all lifecycle hooks that are about to be deprecated
                regex: "^(__|UNSAFE_).+$",
            },
            format: null,
            selector,
        }));

        options.defaultRules = [...Object.values(options), ...escapeHatches];

        options.ignoreProperties = {
            selector: "property",
            format: null,
        };

        return options;
    })(),
    /* eslint-disable sort-keys */
};
<|endoftext|>


<commit_before> module.exports = (config => {

  var c = config || {},
  defaults = require('./config/config'),
  Editor = require('editor'),
  PluginManager = require('plugin_manager');

  var plugins = new PluginManager();
  var editors = [];

  return {

    editors,

    plugins,

    /**
     * Initializes an editor based on passed options
     * @param {Object} config Configuration object
     * @param {string} config.container Selector which indicates where render the editor
     * @param {Object|string} config.components='' HTML string or Component model in JSON format
     * @param {Object|string} config.style='' CSS string or CSS model in JSON format
     * @param {Boolean} [config.fromElement=false] If true, will fetch HTML and CSS from selected container
     * @param {Boolean} [config.copyPaste=true] Enable/Disable the possibility to copy(ctrl+c) & paste(ctrl+v) components
     * @param {Boolean} [config.undoManager=true] Enable/Disable undo manager
     * @param {Array} [config.plugins=[]] Array of plugins to execute on start
     * @return {grapesjs.Editor} GrapesJS editor instance
     * @example
     * var editor = grapesjs.init({
     *   container: '#myeditor',
     *   components: '
Hello world
',
     *   style: '.hello{color: red}',
     * })
     */
    init(config) {
      var c = config || {};
      var els = c.container;

      // Set default options
      for (var name in defaults) {
        if (!(name in c))
          c[name] = defaults[name];
      }

      if(!els)
        throw new Error("'container' is required");

      c.el = document.querySelector(els);
      var editor = new Editor(c).init();

      // Execute all plugins
      var plugs = plugins.getAll();
      for (var id in plugs){
        // Check if plugin is requested
        if(c.plugins.indexOf(id) < 0)
          continue;

        var opts = c.pluginsOpts[id] || {};
        var plug = plugins.get(id);
        plug(editor, opts);
      }

      if(c.autorender)
        editor.render();

      editors.push(editor);
      return editor;
    },

  };

})();
<commit_msg>Fix plugin order execution<commit_after> module.exports = (config => {

  var c = config || {},
  defaults = require('./config/config'),
  Editor = require('editor'),
  PluginManager = require('plugin_manager');

  var plugins = new PluginManager();
  var editors = [];

  return {

    editors,

    plugins,

    /**
     * Initializes an editor based on passed options
     * @param {Object} config Configuration object
     * @param {string} config.container Selector which indicates where render the editor
     * @param {Object|string} config.components='' HTML string or Component model in JSON format
     * @param {Object|string} config.style='' CSS string or CSS model in JSON format
     * @param {Boolean} [config.fromElement=false] If true, will fetch HTML and CSS from selected container
     * @param {Boolean} [config.copyPaste=true] Enable/Disable the possibility to copy(ctrl+c) & paste(ctrl+v) components
     * @param {Boolean} [config.undoManager=true] Enable/Disable undo manager
     * @param {Array} [config.plugins=[]] Array of plugins to execute on start
     * @return {grapesjs.Editor} GrapesJS editor instance
     * @example
     * var editor = grapesjs.init({
     *   container: '#myeditor',
     *   components: '
Hello world
',
     *   style: '.hello{color: red}',
     * })
     */
    init(config) {
      var c = config || {};
      var els = c.container;

      // Set default options
      for (var name in defaults) {
        if (!(name in c))
          c[name] = defaults[name];
      }

      if(!els)
        throw new Error("'container' is required");

      c.el = document.querySelector(els);
      var editor = new Editor(c).init();

      // Execute plugins
      var plugs = plugins.getAll();

      c.plugins.forEach((pluginId) => {
        let plugin = plugins.get(pluginId);

        if (plugin) {
          plugin(editor, c.pluginsOpts[pluginId] || {});
        } else {
          console.warn(`Plugin ${pluginId} not found`);
        }
      });

      if(c.autorender)
        editor.render();

      editors.push(editor);
      return editor;
    },

  };

})();
<|endoftext|>


<commit_before>//
// test/dork.js
//
// Copyright (c) 2012 Lee Olayvar <leeolayvar@gmail.com>
// MIT Licensed
//
/*jshint asi: true, laxcomma: true*/
var should = require('should')

// These are here so my IDE will shut the hell up.
var before = global.before
  , before_each = global.beforeEach
  , describe = global.describe
  , it = global.it

describe('test', function () {
  var test_lib = require('../lib/test')

  describe('#()', function () {
    var test

    before_each(function () {
      test = test_lib.create('foo', 'bar', function () {})
    })

    it('should return a test object instance', function () {
      // To assert it's identity we're just going to make sure
      // some basic test functions exist.
      should.exist(test.description)
      should.exist(test.fn)
      // And since the test object is not that unique, lets make sure it's
      // not a suite object.
      should.not.exist(test.add_suite)
      should.not.exist(test.add_test)
    })

    it('should be a unique object each execution', function () {
      var new_test = test_lib.create()
        , old_test = test

      old_test.foo = 'bar'
      should.not.exist(new_test.foo)
    })
  })
})
<commit_msg>Fixed a typo.<commit_after>//
// test/test.js
//
// Copyright (c) 2012 Lee Olayvar <leeolayvar@gmail.com>
// MIT Licensed
//
/*jshint asi: true, laxcomma: true*/
var should = require('should')

// These are here so my IDE will shut the hell up.
var before = global.before
  , before_each = global.beforeEach
  , describe = global.describe
  , it = global.it

describe('test', function () {
  var test_lib = require('../lib/test')

  describe('#()', function () {
    var test

    before_each(function () {
      test = test_lib.create('foo', 'bar', function () {})
    })

    it('should return a test object instance', function () {
      // To assert it's identity we're just going to make sure
      // some basic test functions exist.
      should.exist(test.description)
      should.exist(test.fn)
      // And since the test object is not that unique, lets make sure it's
      // not a suite object.
      should.not.exist(test.add_suite)
      should.not.exist(test.add_test)
    })

    it('should be a unique object each execution', function () {
      var new_test = test_lib.create()
        , old_test = test

      old_test.foo = 'bar'
      should.not.exist(new_test.foo)
    })
  })
})
<|endoftext|>


<commit_before>var _Action = new function () {
    var availableActions = new Array('none', 'addpoint', 'removepoint', 'addconnection', 'removeconnection');
    this.current = 'none'
    this.change = function (action) {
        if (typeof action != 'undefined') {
            action = action.toLowerCase();

            if (availableActions.indexOf(action) != -1) {
                var body = $('body');

                body.removeClass(this.current);
                if (action != 'none') {
                    body.addClass(action);
                }

                this.current = action;
            } else {
                _Action.toDefault();
                throw 'Action not exists!';
            }
        }
    };
    this.toDefault = function () {
        this.change('none');
    };
    this.currentIs = function (action) {
        return (this.current == action.toLowerCase());
    };
    this.getCurrent = function () {
        return this.current;
    };
};

var _Stage = new function () {
    this.stage = undefined;
    this.create = function () {
        if (typeof this.stage == 'undefined') {
            this.stage = new Kinetic.Stage({
                container: 'canvas-area',
                height: 500,
                width: 1000
            });

            var baseLayer = new Kinetic.Layer();

            var connectionsLayer = new Kinetic.Layer();

            var pointsLayer = new Kinetic.Layer();

            this.stage
                .add(baseLayer)
                .add(connectionsLayer)
                .add(pointsLayer)
                .draw();
        } else {
            throw 'Stage exists!';
        }
    };
    this.getConnectionsLayer = function () {
        return this.stage
                   .children[1];
    };
    this.refreshConnectionsLayer = function () {
        this.getConnectionsLayer()
            .draw();
    };
    this.getPointsLayer = function () {
        return this.stage
                   .children[2];
    };
    this.refreshPointsLayer = function () {
        this.getPointsLayer()
            .draw();
    };
    this.clear = function () {
        if (typeof this.stage != 'undefined') {
            this.getConnectionsLayer()
                .removeChildren()
                .draw();
            _Connections.clear();

            this.getPointsLayer()
                .removeChildren()
                .draw();
            _Points.clear();
        }
    };
    this.reload = function (graphName) {
        if (graphName == '') {
            throw 'Graph name is empty!';
        } else {
            this.clear();

            var pointsLayer = this.getPointsLayer();

            this.loadGraph(graphName);
            _Points.eachOne(function (point) {
                pointsLayer.add(_Points[a]);
            });
            pointsLayer.draw();
        }
    };
    this.loadGraph = function (name) {
        $.ajax({
            data: 'graphName=' + name,
            dataType: 'json',
            method: 'post',
            url: '/load-graph',
            success: function (data) {
                if (data.success) {
                    for (var a = 0; a < data.pointscount; a++) {
                        _Points.add(data.points[a].x, data.points[a].y);
                    }

                    for (var a = 0; a < data.connectionscount; a++) {
                        try {
                            _Points.getPoint(data.connections[a].from);
                            _Points.getPoint(data.connections[a].to);

                            _Connection.add(data.connections[a].from);
                            _Connection.add(data.connections[a].to);
                        } catch (e) {
                            console.log(e);
                        }
                    }
                }
            }
        });
    };
    this.add = function (element) {
        return this.stage
                   .add(element);
    };
    this.draw = function () {
        return this.stage
                   .draw();
    };
};

var _Points = new function (points) {
    this.points = new Array();
    this.getPoint = function(n) {
        if (this.points.length == 0) {
            throw 'Points array is clear!';
        } else {
            if ((n < this.points.length) && (n >= 0)) {
                return this.points[n];
            } else {
                throw 'Point not exists!';
            }
        }
    };
    this.eachOne = function (func) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                func(this.points[a]);
            }
        }
    };
    this.check = function (x, y) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                if ((this.points[a].getX() == x) && (this.points[a].getY() == y)) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    };
    this.clear = function () {
        if (typeof this.points != 'undefined') {
            delete this.points;
            this.points = new Array();
        }
    };
    this.add = function (x, y) {
        if (this.check(x, y)) {
            var point = new Kinetic.Circle({
                fill: '#fff',
                radius: 6,
                stroke: '#000',
                strokeWidth: 1,
                x: x,
                y: y
            });

            point.on('click', function () {
                switch (_Action.getCurrent()) {
                    case 'removepoint':
                        _Points.remove(this.getX(), this.getY());

                        _Stage.refreshPointsLayer();
                        _Stage.refreshConnectionsLayer();
                        break;
                    case 'addconnection':
                        _Connection.add(_Points.points
                                               .indexOf(this));
                        break;
                }
            });

            this.points
                .push(point);

            _Stage.getPointsLayer()
                  .add(point)
                  .draw();
        } else {
            alert('Point on position (' + x + ', ' + y + ') exists!');
        }
    };
    this.remove = function (x, y) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                if ((this.points[a].getX() == x) && (this.points[a].getY() == y)) {
                    this.points[a]
                        .remove();
                    delete this.points[a];

                    this.points = this.points.slice(0, a)
                                      .concat(this.points
                                                  .slice(a + 1));

                    _Connections.removeFromPoint(a);
                    break;
                }
            }
        }
    };
    this.toSave = function () {
        var saveString = '';
        for (var a = 0; a < this.points.length; a++) {
            if (saveString != '') {
                saveString += ',';
            }

            saveString += this.points[a]
                              .getX() +
                          ':' +
                          this.points[a]
                              .getY();
        }
        return saveString;
    };
    this.getID = function (x, y) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                if ((this.points[a].getX() == x) && (this.points[a].getY() == y)) {
                    return a;
                }
            }

            return -1;
        } else {
            return -1;
        }
    };
};

var _Connections = new function () {
    this.connections = new Array();
    this.add = function (connection) {
        _Action.toDefault();

        try {
            if ((connection.getEnd(0) != -1) && (connection.getEnd(1) != -1) && (connection.getEnd(0) != connection.getEnd(1))) {
                var first = _Points.getPoint(connection.getEnd(0)),
                    second = _Points.getPoint(connection.getEnd(1));

                var line = new Kinetic.Line({
                    points: [first.getX(), first.getY(), second.getX(), second.getY()],
                    stroke: '#000',
                    strokeWidth: 1.2
                });

                line.idxs = new Array(connection.getEnd(0), connection.getEnd(1));

                line.on('click', function () {
                    console.log('try to delete line');
                    if (_Action.getCurrent() == 'removeconnection') {
                        _Connections.remove(this.idxs);

                        _Stage.refreshConnectionsLayer();
                    }
                });

                this.connections
                    .push(line);

                _Stage.getConnectionsLayer()
                      .add(line)
                      .draw();
            }

            _Connection.clear();
        } catch (e) {
            _Connection.clear();
            throw 'Wrong connection object!';
        }
    };
    this.clear = function () {
        if (typeof this.connections != 'undefined') {
            delete this.connections;
            this.connections = new Array();
        }
    };
    this.toSave = function () {
        var saveString = '';
        for (var a = 0; a < this.connections.length; a++) {
            if (saveString != '') {
                saveString += ',';
            }

            saveString += this.connections[a]
                              .idxs[0] +
                          ':' +
                          this.connections[a]
                              .idxs[1];
        }
        return saveString;
    };
    this.removeFromPoint = function (pointN) {
        var newConnections = new Array();

        for (var a = 0; a < this.connections.length; a++) {
            if ((this.connections[a].idxs[0] == pointN) || (this.connections[a].idxs[1] == pointN)) {
                this.connections[a]
                    .remove();
                delete this.connections[a];
            } else {
                if (this.connections[a].idxs[0] > pointN) {
                    this.connections[a]
                        .idxs[0]--;
                }
                if (this.connections[a].idxs[1] > pointN) {
                    this.connections[a]
                        .idxs[1]--;
                }

                newConnections.push(this.connections[a]);
            }
        }

        this.connections = newConnections;
    };
    this.remove = function (idxs) {
        for (var a = 0; a < this.connections.length; a++) {
            if ((this.connections[a].idxs[0] == idxs[0]) && (this.connections[a].idxs[1] == idxs[1])) {
                this.connections[a]
                    .remove();
                delete this.connections[a];

                this.connections = this.connections.slice(0, a)
                                       .concat(this.connections
                                                   .slice(a + 1));
            }
        }
    };
    this.checkConnection = function (id1, id2) {
        for (var a = 0; a < this.connections.length; a++) {
            if (((this.connections[a].idxs[0] == id1) && (this.connections[a].idxs[1] == id2)) ||
                ((this.connections[a].idxs[0] == id2) && (this.connections[a].idxs[1] == id1))) {
                return false;
            }
        }

        return true;
    };
};

var _Connection = new function () {
    this.ends = new Array(-1, -1);
    this.add = function (id) {
        if (this.ends[0] == -1) {
            this.ends[0] = id;
        } else {
            _Action.toDefault();

            if (id == this.ends[0]) {
                this.clear();
            } else {
                this.ends[1] = id;

                if (_Connections.checkConnection(this.ends[0], this.ends[1])) {
                    _Connections.add(this);
                } else {
                    this.clear();
                }
            }
        }
    };
    this.clear = function () {
        this.ends[0] = this.ends[1]
                     = -1;
        _Action.toDefault();
    };
    this.getEnd = function (n) {
        return this.ends[n];
    };
};
<commit_msg>Debug code removed<commit_after>var _Action = new function () {
    var availableActions = new Array('none', 'addpoint', 'removepoint', 'addconnection', 'removeconnection');
    this.current = 'none'
    this.change = function (action) {
        if (typeof action != 'undefined') {
            action = action.toLowerCase();

            if (availableActions.indexOf(action) != -1) {
                var body = $('body');

                body.removeClass(this.current);
                if (action != 'none') {
                    body.addClass(action);
                }

                this.current = action;
            } else {
                _Action.toDefault();
                throw 'Action not exists!';
            }
        }
    };
    this.toDefault = function () {
        this.change('none');
    };
    this.currentIs = function (action) {
        return (this.current == action.toLowerCase());
    };
    this.getCurrent = function () {
        return this.current;
    };
};

var _Stage = new function () {
    this.stage = undefined;
    this.create = function () {
        if (typeof this.stage == 'undefined') {
            this.stage = new Kinetic.Stage({
                container: 'canvas-area',
                height: 500,
                width: 1000
            });

            var baseLayer = new Kinetic.Layer();

            var connectionsLayer = new Kinetic.Layer();

            var pointsLayer = new Kinetic.Layer();

            this.stage
                .add(baseLayer)
                .add(connectionsLayer)
                .add(pointsLayer)
                .draw();
        } else {
            throw 'Stage exists!';
        }
    };
    this.getConnectionsLayer = function () {
        return this.stage
                   .children[1];
    };
    this.refreshConnectionsLayer = function () {
        this.getConnectionsLayer()
            .draw();
    };
    this.getPointsLayer = function () {
        return this.stage
                   .children[2];
    };
    this.refreshPointsLayer = function () {
        this.getPointsLayer()
            .draw();
    };
    this.clear = function () {
        if (typeof this.stage != 'undefined') {
            this.getConnectionsLayer()
                .removeChildren()
                .draw();
            _Connections.clear();

            this.getPointsLayer()
                .removeChildren()
                .draw();
            _Points.clear();
        }
    };
    this.reload = function (graphName) {
        if (graphName == '') {
            throw 'Graph name is empty!';
        } else {
            this.clear();

            var pointsLayer = this.getPointsLayer();

            this.loadGraph(graphName);
            _Points.eachOne(function (point) {
                pointsLayer.add(_Points[a]);
            });
            pointsLayer.draw();
        }
    };
    this.loadGraph = function (name) {
        $.ajax({
            data: 'graphName=' + name,
            dataType: 'json',
            method: 'post',
            url: '/load-graph',
            success: function (data) {
                if (data.success) {
                    for (var a = 0; a < data.pointscount; a++) {
                        _Points.add(data.points[a].x, data.points[a].y);
                    }

                    for (var a = 0; a < data.connectionscount; a++) {
                        try {
                            _Points.getPoint(data.connections[a].from);
                            _Points.getPoint(data.connections[a].to);

                            _Connection.add(data.connections[a].from);
                            _Connection.add(data.connections[a].to);
                        } catch (e) {
                            console.log(e);
                        }
                    }
                }
            }
        });
    };
    this.add = function (element) {
        return this.stage
                   .add(element);
    };
    this.draw = function () {
        return this.stage
                   .draw();
    };
};

var _Points = new function (points) {
    this.points = new Array();
    this.getPoint = function(n) {
        if (this.points.length == 0) {
            throw 'Points array is clear!';
        } else {
            if ((n < this.points.length) && (n >= 0)) {
                return this.points[n];
            } else {
                throw 'Point not exists!';
            }
        }
    };
    this.eachOne = function (func) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                func(this.points[a]);
            }
        }
    };
    this.check = function (x, y) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                if ((this.points[a].getX() == x) && (this.points[a].getY() == y)) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    };
    this.clear = function () {
        if (typeof this.points != 'undefined') {
            delete this.points;
            this.points = new Array();
        }
    };
    this.add = function (x, y) {
        if (this.check(x, y)) {
            var point = new Kinetic.Circle({
                fill: '#fff',
                radius: 6,
                stroke: '#000',
                strokeWidth: 1,
                x: x,
                y: y
            });

            point.on('click', function () {
                switch (_Action.getCurrent()) {
                    case 'removepoint':
                        _Points.remove(this.getX(), this.getY());

                        _Stage.refreshPointsLayer();
                        _Stage.refreshConnectionsLayer();
                        break;
                    case 'addconnection':
                        _Connection.add(_Points.points
                                               .indexOf(this));
                        break;
                }
            });

            this.points
                .push(point);

            _Stage.getPointsLayer()
                  .add(point)
                  .draw();
        } else {
            alert('Point on position (' + x + ', ' + y + ') exists!');
        }
    };
    this.remove = function (x, y) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                if ((this.points[a].getX() == x) && (this.points[a].getY() == y)) {
                    this.points[a]
                        .remove();
                    delete this.points[a];

                    this.points = this.points.slice(0, a)
                                      .concat(this.points
                                                  .slice(a + 1));

                    _Connections.removeFromPoint(a);
                    break;
                }
            }
        }
    };
    this.toSave = function () {
        var saveString = '';
        for (var a = 0; a < this.points.length; a++) {
            if (saveString != '') {
                saveString += ',';
            }

            saveString += this.points[a]
                              .getX() +
                          ':' +
                          this.points[a]
                              .getY();
        }
        return saveString;
    };
    this.getID = function (x, y) {
        if (this.points.length > 0) {
            for (var a = 0; a < this.points.length; a++) {
                if ((this.points[a].getX() == x) && (this.points[a].getY() == y)) {
                    return a;
                }
            }

            return -1;
        } else {
            return -1;
        }
    };
};

var _Connections = new function () {
    this.connections = new Array();
    this.add = function (connection) {
        _Action.toDefault();

        try {
            if ((connection.getEnd(0) != -1) && (connection.getEnd(1) != -1) && (connection.getEnd(0) != connection.getEnd(1))) {
                var first = _Points.getPoint(connection.getEnd(0)),
                    second = _Points.getPoint(connection.getEnd(1));

                var line = new Kinetic.Line({
                    points: [first.getX(), first.getY(), second.getX(), second.getY()],
                    stroke: '#000',
                    strokeWidth: 1.2
                });

                line.idxs = new Array(connection.getEnd(0), connection.getEnd(1));

                line.on('click', function () {
                    if (_Action.getCurrent() == 'removeconnection') {
                        _Connections.remove(this.idxs);

                        _Stage.refreshConnectionsLayer();
                    }
                });

                this.connections
                    .push(line);

                _Stage.getConnectionsLayer()
                      .add(line)
                      .draw();
            }

            _Connection.clear();
        } catch (e) {
            _Connection.clear();
            throw 'Wrong connection object!';
        }
    };
    this.clear = function () {
        if (typeof this.connections != 'undefined') {
            delete this.connections;
            this.connections = new Array();
        }
    };
    this.toSave = function () {
        var saveString = '';
        for (var a = 0; a < this.connections.length; a++) {
            if (saveString != '') {
                saveString += ',';
            }

            saveString += this.connections[a]
                              .idxs[0] +
                          ':' +
                          this.connections[a]
                              .idxs[1];
        }
        return saveString;
    };
    this.removeFromPoint = function (pointN) {
        var newConnections = new Array();

        for (var a = 0; a < this.connections.length; a++) {
            if ((this.connections[a].idxs[0] == pointN) || (this.connections[a].idxs[1] == pointN)) {
                this.connections[a]
                    .remove();
                delete this.connections[a];
            } else {
                if (this.connections[a].idxs[0] > pointN) {
                    this.connections[a]
                        .idxs[0]--;
                }
                if (this.connections[a].idxs[1] > pointN) {
                    this.connections[a]
                        .idxs[1]--;
                }

                newConnections.push(this.connections[a]);
            }
        }

        this.connections = newConnections;
    };
    this.remove = function (idxs) {
        for (var a = 0; a < this.connections.length; a++) {
            if ((this.connections[a].idxs[0] == idxs[0]) && (this.connections[a].idxs[1] == idxs[1])) {
                this.connections[a]
                    .remove();
                delete this.connections[a];

                this.connections = this.connections.slice(0, a)
                                       .concat(this.connections
                                                   .slice(a + 1));
            }
        }
    };
    this.checkConnection = function (id1, id2) {
        for (var a = 0; a < this.connections.length; a++) {
            if (((this.connections[a].idxs[0] == id1) && (this.connections[a].idxs[1] == id2)) ||
                ((this.connections[a].idxs[0] == id2) && (this.connections[a].idxs[1] == id1))) {
                return false;
            }
        }

        return true;
    };
};

var _Connection = new function () {
    this.ends = new Array(-1, -1);
    this.add = function (id) {
        if (this.ends[0] == -1) {
            this.ends[0] = id;
        } else {
            _Action.toDefault();

            if (id == this.ends[0]) {
                this.clear();
            } else {
                this.ends[1] = id;

                if (_Connections.checkConnection(this.ends[0], this.ends[1])) {
                    _Connections.add(this);
                } else {
                    this.clear();
                }
            }
        }
    };
    this.clear = function () {
        this.ends[0] = this.ends[1]
                     = -1;
        _Action.toDefault();
    };
    this.getEnd = function (n) {
        return this.ends[n];
    };
};
<|endoftext|>


<commit_before>'use strict'
var test = require('tape')
var StateMachine = require('../')

test('summary', function (t) {
  var validMoves = [
    { from: 'one', to: 'two' },
    { from: 'two', to: 'three' },
    { from: [ 'one', 'three' ], to: 'four'}
  ]

  var sm = new StateMachine({
    validMoves: validMoves,
    state: 'one'
  })

  t.strictEqual(sm.state, 'one', 'state is one')

  /* valid change to 'two' */
  sm.once('state', function (state) {
    if (state === 'two') t.pass("'two' state set")
  })
  var failMessage = sm._setState('two')
  t.strictEqual(failMessage, null, 'failMessage is null')
  t.strictEqual(sm.state, 'two', 'state is two')

  sm.removeAllListeners()

  /* invalid change to 'four' */
  sm.once('state', function (state) {
    if (state === 'four') t.fail("'fail' state should not set")
  })
  sm.once('change', function (from, to) {
    t.fail('change should not fire')
  })
  try {
    sm._setState('four')
  } catch (e) {
    t.strictEqual(e.message, "Can only move to 'four' from 'one' or 'three'", 'change to four failMessage')
  }
  t.strictEqual(sm.state, 'two', 'state is two')

  sm.removeAllListeners()

  /* valid change to 'four' */
  sm._setState('three')
  t.strictEqual(sm.state, 'three', 'state is three')
  sm.once('state', function (state, prev) {
    if (state === 'four') t.pass('change from three to four fired')
    t.strictEqual(state, 'four', 'state is four')
    t.strictEqual(prev, 'three', 'prev is three')
  })
  failMessage = sm._setState('four')
  t.strictEqual(failMessage, null, 'failMessage is null')
  t.strictEqual(sm.state, 'four', 'state is four')
  t.end()
})
<commit_msg>test fix<commit_after>'use strict'
var test = require('tape')
var StateMachine = require('../')

test('summary', function (t) {
  var validMoves = [
    { from: 'one', to: 'two' },
    { from: 'two', to: 'three' },
    { from: [ 'one', 'three' ], to: 'four'}
  ]

  var sm = new StateMachine({
    validMoves: validMoves,
    state: 'one'
  })

  t.strictEqual(sm.state, 'one', 'state is one')

  /* valid change to 'two' */
  sm.once('state', function (state) {
    if (state === 'two') t.pass("'two' state event emitted")
  })
  var failMessage = sm._setState('two')
  t.strictEqual(failMessage, null, 'failMessage is null')
  t.strictEqual(sm.state, 'two', 'state is two')

  sm.removeAllListeners()

  /* invalid change to 'four' */
  sm.once('state', function (state) {
    if (state === 'four') t.fail("'fail' state event should not be emitted")
  })
  sm.once('change', function (from, to) {
    t.fail('change should not fire')
  })
  try {
    sm._setState('four')
  } catch (e) {
    t.strictEqual(e.message, "Can only move to 'four' from 'one' or 'three' (not 'two')", 'change to four failMessage')
  }
  t.strictEqual(sm.state, 'two', 'state is two')

  sm.removeAllListeners()

  /* valid change to 'three' */
  sm._setState('three')
  t.strictEqual(sm.state, 'three', 'state is three')

  /* valid change to 'four' */
  sm.once('state', function (state, prev) {
    if (state === 'four') t.pass('"state" event fired, from three to four')
    t.strictEqual(state, 'four', 'state is four')
    t.strictEqual(prev, 'three', 'prev is three')
  })
  failMessage = sm._setState('four')
  t.strictEqual(failMessage, null, 'failMessage is null')
  t.strictEqual(sm.state, 'four', 'state is four')
  t.end()
})
<|endoftext|>


<commit_before>//var assert = require("assert");

// TODO: create tests:
//   - create fake Elasticsearch and Core Traversal data
//   - test config file
//   - test search parameters
//   - test JSON LD context insertion
//   - test Elasticsearch query creation
<commit_msg>removed old test stub<commit_after><|endoftext|>