<commit_before>/**
 * @flow
 */

import type {BuildSpec, BuildTask, BuildConfig, BuildSandbox} from '../../types';

import * as path from 'path';
import * as fs from 'fs';
import {sync as mkdirp} from 'mkdirp';
import createLogger from 'debug';
import outdent from 'outdent';

import * as Graph from '../../graph';
import * as Config from '../../build-config';
import * as Task from '../../build-task';
import * as Makefile from '../../Makefile';
import {normalizePackageName} from '../../util';
import {renderEnv, renderSandboxSbConfig} from '../util';

const log = createLogger('esy:makefile-builder');
const CWD = process.cwd();

const RUNTIME = fs.readFileSync(path.join(__dirname, 'runtime.sh'), 'utf8');

const STORE_PATH = '$ESY_EJECT__STORE';
const SANDBOX_PATH = '$ESY_EJECT__SANDBOX';

const fastReplaceStringSrc = fs.readFileSync(
  require.resolve('fastreplacestring/fastreplacestring.cpp'),
  'utf8',
);

/**
 * Note that Makefile based builds defers exact locations of sandbox and store
 * to some later point because ejected builds can be transfered to other
 * machines.
 *
 * That means that build env is generated in a way which can be configured later
 * with `$ESY_EJECT__SANDBOX` and `$ESY__STORE` environment variables.
 */
export const buildConfig: BuildConfig = Config.createConfig({
  storePath: STORE_PATH,
  sandboxPath: SANDBOX_PATH,
});

/**
 * Render `build` as Makefile (+ related files) into the supplied `outputPath`.
 */
export function renderToMakefile(sandbox: BuildSandbox, outputPath: string) {
  log(`eject build environment into <ejectRootDir>=./${path.relative(CWD, outputPath)}`);
  const ruleSet: Makefile.MakeItem[] = [
    {
      type: 'raw',
      value: 'SHELL := env -i /bin/bash --norc --noprofile',
    },

    // ESY_EJECT__ROOT is the root directory of the ejected Esy build
    // environment.
    {
      type: 'raw',
      value: 'ESY_EJECT__ROOT := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))',
    },

    // ESY_EJECT__STORE is the directory where build artifacts should be stored.
    {
      type: 'raw',
      value: `ESY_EJECT__STORE ?= $(HOME)/.esy/${Config.ESY_STORE_VERSION}`,
    },

    // ESY_EJECT__SANDBOX is the sandbox directory, the directory where the root
    // package resides.
    {
      type: 'raw',
      value: 'ESY_EJECT__SANDBOX ?= $(CURDIR)',
    },

    // These are public API

    {
      type: 'rule',
      target: 'build',
      phony: true,
      dependencies: [createBuildRuleName(sandbox.root, 'build')],
    },
    {
      type: 'rule',
      target: 'build-shell',
      phony: true,
      dependencies: [createBuildRuleName(sandbox.root, 'shell')],
    },
    {
      type: 'rule',
      target: 'clean',
      phony: true,
      command: outdent`
        rm $(ESY_EJECT__SANDBOX)/_build
        rm $(ESY_EJECT__SANDBOX)/_install
      `,
    },

    // Create store directory structure
    {
      type: 'rule',
      target: [
        `$(ESY_EJECT__STORE)/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_STAGE_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_STAGE_TREE}`,
      ].join(' '),
      command: 'mkdir -p $(@)',
    },
    {
      type: 'rule',
      target: 'esy-store',
      phony: true,
      dependencies: [
        `$(ESY_EJECT__STORE)/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_STAGE_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_STAGE_TREE}`,
      ],
    },
    {
      type: 'rule',
      target: '$(ESY_EJECT__ROOT)/bin/realpath',
      dependencies: ['$(ESY_EJECT__ROOT)/bin/realpath.c'],
      shell: '/bin/bash',
      command: 'gcc -o $(@) -x c $(<) 2> /dev/null',
    },
    {
      type: 'rule',
      target: '$(ESY_EJECT__ROOT)/bin/fastreplacestring.exe',
      dependencies: ['$(ESY_EJECT__ROOT)/bin/fastreplacestring.cpp'],
      shell: '/bin/bash',
      command: 'g++ -Ofast -o $(@) $(<) 2> /dev/null',
    },
    {
      type: 'rule',
      target: 'esy-root',
      phony: true,
      dependencies: [
        '$(ESY_EJECT__ROOT)/bin/realpath',
        '$(ESY_EJECT__ROOT)/bin/fastreplacestring.exe',
      ],
    },
  ];

  function createBuildRuleName(build, target): string {
    return `${build.name}.${target}`;
  }

  function createBuildRule(
    build: BuildSpec,
    rule: {target: string, command: string, withBuildEnv?: boolean},
  ): Makefile.MakeItem {
    const command = [];
    if (rule.withBuildEnv) {
      command.push(
        outdent`
          $(shell_env_for__${normalizePackageName(build.name)}) source $(ESY_EJECT__ROOT)/bin/runtime.sh
          cd $esy_build__source_root
        `,
      );
    }
    command.push(rule.command);
    return {
      type: 'rule',
      target: createBuildRuleName(build, rule.target),
      dependencies: [
        'esy-store',
        'esy-root',
        ...Array.from(build.dependencies.values()).map(dep =>
          createBuildRuleName(dep, 'build'),
        ),
      ],
      phony: true,
      command,
    };
  }

  function visitTask(task: BuildTask) {
    log(`visit ${task.spec.name}`);

    const packagePath = task.spec.sourcePath.split(path.sep).filter(Boolean);

    function emitBuildFile({filename, contents}) {
      emitFile(outputPath, {filename: packagePath.concat(filename), contents});
    }

    // Emit env
    emitBuildFile({
      filename: 'eject-env',
      contents: renderEnv(task.env),
    });

    // Generate macOS sandbox configuration (sandbox-exec command)
    emitBuildFile({
      filename: 'sandbox.sb.in',
      contents: renderSandboxSbConfig(task.spec, buildConfig, {
        allowFileWrite: ['$TMPDIR', '$TMPDIR_GLOBAL'],
      }),
    });

    ruleSet.push({
      type: 'define',
      name: `shell_env_for__${normalizePackageName(task.spec.name)}`,
      value: [
        {
          CI: process.env.CI ? process.env.CI : null,
          TMPDIR: '$(TMPDIR)',
          ESY_EJECT__STORE: '$(ESY_EJECT__STORE)',
          ESY_EJECT__SANDBOX: '$(ESY_EJECT__SANDBOX)',
          ESY_EJECT__ROOT: '$(ESY_EJECT__ROOT)',
        },
        `source $(ESY_EJECT__ROOT)/${packagePath.join('/')}/eject-env`,
        {
          esy_build__eject: `$(ESY_EJECT__ROOT)/${packagePath.join('/')}`,
          esy_build__type: task.spec.mutatesSourcePath ? 'in-source' : 'out-of-source',
          esy_build__key: task.id,
          esy_build__command: renderBuildTaskCommand(task) || 'true',
          esy_build__source_root: path.join(
            buildConfig.sandboxPath,
            task.spec.sourcePath,
          ),
          esy_build__install: buildConfig.getFinalInstallPath(task.spec),
        },
      ],
    });

    ruleSet.push(
      createBuildRule(task.spec, {
        target: 'build',
        command: 'esy-build',
        withBuildEnv: true,
      }),
    );
    ruleSet.push(
      createBuildRule(task.spec, {
        target: 'shell',
        command: 'esy-shell',
        withBuildEnv: true,
      }),
    );
    ruleSet.push(
      createBuildRule(task.spec, {
        target: 'clean',
        command: 'esy-clean',
      }),
    );
  }

  // Emit build artefacts for packages
  log('process dependency graph');
  const rootTask = Task.fromBuildSandbox(sandbox, buildConfig);
  Graph.traverse(rootTask, visitTask);

  // Now emit all build-wise artefacts
  log('build environment');

  emitFile(outputPath, {
    filename: ['bin/render-env'],
    executable: true,
    contents: outdent`
      #!/bin/bash

      set -e
      set -o pipefail

      _TMPDIR_GLOBAL=$($ESY_EJECT__ROOT/bin/realpath "/tmp")

      if [ -d "$TMPDIR" ]; then
        _TMPDIR=$($ESY_EJECT__ROOT/bin/realpath "$TMPDIR")
      else
        _TMPDIR="/does/not/exist"
      fi

      sed \\
        -e "s|\\$ESY_EJECT__STORE|$ESY_EJECT__STORE|g"          \\
        -e "s|\\$ESY_EJECT__SANDBOX|$ESY_EJECT__SANDBOX|g"      \\
        -e "s|\\$ESY_EJECT__ROOT|$ESY_EJECT__ROOT|g"      \\
        -e "s|\\$TMPDIR_GLOBAL|$_TMPDIR_GLOBAL|g"   \\
        -e "s|\\$TMPDIR|$_TMPDIR|g"                 \\
        $1 > $2
    `,
  });

  emitFile(outputPath, {
    filename: ['bin', 'fastreplacestring.cpp'],
    contents: fastReplaceStringSrc,
  });

  emitFile(outputPath, {
    filename: ['bin', 'realpath.c'],
    contents: outdent`
      #include<stdlib.h>

      main(int cc, char**vargs) {
        puts(realpath(vargs[1], 0));
        exit(0);
      }
    `,
  });

  emitFile(outputPath, {
    filename: ['bin', 'runtime.sh'],
    contents: RUNTIME,
  });

  emitFile(outputPath, {
    filename: ['Makefile'],
    contents: Makefile.renderMakefile(ruleSet),
  });
}

function emitFile(
  outputPath: string,
  file: {filename: Array<string>, contents: string, executable?: boolean},
) {
  const filename = path.join(outputPath, ...file.filename);
  log(`emit <ejectRootDir>/${file.filename.join('/')}`);
  mkdirp(path.dirname(filename));
  fs.writeFileSync(filename, file.contents);
  if (file.executable) {
    // fs.constants only became supported in node 6.7 or so.
    const mode = fs.constants && fs.constants.S_IRWXU ? fs.constants.S_IRWXU : 448;
    fs.chmodSync(filename, mode);
  }
}

function renderBuildTaskCommand(task: BuildTask): ?string {
  if (task.command == null) {
    return null;
  }
  return task.command.map(c => c.renderedCommand).join(' && ');
}
<commit_msg>Make eject build output less verbose<commit_after>/**
 * @flow
 */

import type {BuildSpec, BuildTask, BuildConfig, BuildSandbox} from '../../types';

import * as path from 'path';
import * as fs from 'fs';
import {sync as mkdirp} from 'mkdirp';
import createLogger from 'debug';
import outdent from 'outdent';

import * as Graph from '../../graph';
import * as Config from '../../build-config';
import * as Task from '../../build-task';
import * as Makefile from '../../Makefile';
import {normalizePackageName} from '../../util';
import {renderEnv, renderSandboxSbConfig} from '../util';

const log = createLogger('esy:makefile-builder');
const CWD = process.cwd();

const RUNTIME = fs.readFileSync(path.join(__dirname, 'runtime.sh'), 'utf8');

const STORE_PATH = '$ESY_EJECT__STORE';
const SANDBOX_PATH = '$ESY_EJECT__SANDBOX';

const fastReplaceStringSrc = fs.readFileSync(
  require.resolve('fastreplacestring/fastreplacestring.cpp'),
  'utf8',
);

/**
 * Note that Makefile based builds defers exact locations of sandbox and store
 * to some later point because ejected builds can be transfered to other
 * machines.
 *
 * That means that build env is generated in a way which can be configured later
 * with `$ESY_EJECT__SANDBOX` and `$ESY__STORE` environment variables.
 */
export const buildConfig: BuildConfig = Config.createConfig({
  storePath: STORE_PATH,
  sandboxPath: SANDBOX_PATH,
});

/**
 * Render `build` as Makefile (+ related files) into the supplied `outputPath`.
 */
export function renderToMakefile(sandbox: BuildSandbox, outputPath: string) {
  log(`eject build environment into <ejectRootDir>=./${path.relative(CWD, outputPath)}`);
  const ruleSet: Makefile.MakeItem[] = [
    {
      type: 'raw',
      value: 'SHELL := env -i /bin/bash --norc --noprofile',
    },

    // ESY_EJECT__ROOT is the root directory of the ejected Esy build
    // environment.
    {
      type: 'raw',
      value: 'ESY_EJECT__ROOT := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))',
    },

    // ESY_EJECT__STORE is the directory where build artifacts should be stored.
    {
      type: 'raw',
      value: `ESY_EJECT__STORE ?= $(HOME)/.esy/${Config.ESY_STORE_VERSION}`,
    },

    // ESY_EJECT__SANDBOX is the sandbox directory, the directory where the root
    // package resides.
    {
      type: 'raw',
      value: 'ESY_EJECT__SANDBOX ?= $(CURDIR)',
    },

    // These are public API

    {
      type: 'rule',
      target: 'build',
      phony: true,
      dependencies: [createBuildRuleName(sandbox.root, 'build')],
    },
    {
      type: 'rule',
      target: 'build-shell',
      phony: true,
      dependencies: [createBuildRuleName(sandbox.root, 'shell')],
    },
    {
      type: 'rule',
      target: 'clean',
      phony: true,
      command: outdent`
        rm $(ESY_EJECT__SANDBOX)/_build
        rm $(ESY_EJECT__SANDBOX)/_install
      `,
    },

    // Create store directory structure
    {
      type: 'rule',
      target: [
        `$(ESY_EJECT__STORE)/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_STAGE_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_STAGE_TREE}`,
      ].join(' '),
      command: '@mkdir -p $(@)',
    },
    {
      type: 'rule',
      target: 'esy-store',
      phony: true,
      dependencies: [
        `$(ESY_EJECT__STORE)/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__STORE)/${Config.STORE_STAGE_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_BUILD_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_INSTALL_TREE}`,
        `$(ESY_EJECT__SANDBOX)/node_modules/.cache/_esy/store/${Config.STORE_STAGE_TREE}`,
      ],
    },
    {
      type: 'rule',
      target: '$(ESY_EJECT__ROOT)/bin/realpath',
      dependencies: ['$(ESY_EJECT__ROOT)/bin/realpath.c'],
      shell: '/bin/bash',
      command: '@gcc -o $(@) -x c $(<) 2> /dev/null',
    },
    {
      type: 'rule',
      target: '$(ESY_EJECT__ROOT)/bin/fastreplacestring.exe',
      dependencies: ['$(ESY_EJECT__ROOT)/bin/fastreplacestring.cpp'],
      shell: '/bin/bash',
      command: '@g++ -Ofast -o $(@) $(<) 2> /dev/null',
    },
    {
      type: 'rule',
      target: 'esy-root',
      phony: true,
      dependencies: [
        '$(ESY_EJECT__ROOT)/bin/realpath',
        '$(ESY_EJECT__ROOT)/bin/fastreplacestring.exe',
      ],
    },
  ];

  function createBuildRuleName(build, target): string {
    return `${build.name}.${target}`;
  }

  function createBuildRule(
    build: BuildSpec,
    rule: {target: string, command: string, withBuildEnv?: boolean},
  ): Makefile.MakeItem {
    const command = [];
    if (rule.withBuildEnv) {
      command.push(outdent`
        @$(shell_env_for__${normalizePackageName(build.name)}) source $(ESY_EJECT__ROOT)/bin/runtime.sh
        cd $esy_build__source_root
      `);
    }
    command.push(rule.command);
    return {
      type: 'rule',
      target: createBuildRuleName(build, rule.target),
      dependencies: [
        'esy-store',
        'esy-root',
        ...Array.from(build.dependencies.values()).map(dep =>
          createBuildRuleName(dep, 'build'),
        ),
      ],
      phony: true,
      command,
    };
  }

  function visitTask(task: BuildTask) {
    log(`visit ${task.spec.name}`);

    const packagePath = task.spec.sourcePath.split(path.sep).filter(Boolean);

    function emitBuildFile({filename, contents}) {
      emitFile(outputPath, {filename: packagePath.concat(filename), contents});
    }

    // Emit env
    emitBuildFile({
      filename: 'eject-env',
      contents: renderEnv(task.env),
    });

    // Generate macOS sandbox configuration (sandbox-exec command)
    emitBuildFile({
      filename: 'sandbox.sb.in',
      contents: renderSandboxSbConfig(task.spec, buildConfig, {
        allowFileWrite: ['$TMPDIR', '$TMPDIR_GLOBAL'],
      }),
    });

    ruleSet.push({
      type: 'define',
      name: `shell_env_for__${normalizePackageName(task.spec.name)}`,
      value: [
        {
          CI: process.env.CI ? process.env.CI : null,
          TMPDIR: '$(TMPDIR)',
          ESY_EJECT__STORE: '$(ESY_EJECT__STORE)',
          ESY_EJECT__SANDBOX: '$(ESY_EJECT__SANDBOX)',
          ESY_EJECT__ROOT: '$(ESY_EJECT__ROOT)',
        },
        `source $(ESY_EJECT__ROOT)/${packagePath.join('/')}/eject-env`,
        {
          esy_build__eject: `$(ESY_EJECT__ROOT)/${packagePath.join('/')}`,
          esy_build__type: task.spec.mutatesSourcePath ? 'in-source' : 'out-of-source',
          esy_build__key: task.id,
          esy_build__command: renderBuildTaskCommand(task) || 'true',
          esy_build__source_root: path.join(
            buildConfig.sandboxPath,
            task.spec.sourcePath,
          ),
          esy_build__install: buildConfig.getFinalInstallPath(task.spec),
        },
      ],
    });

    ruleSet.push(
      createBuildRule(task.spec, {
        target: 'build',
        command: 'esy-build',
        withBuildEnv: true,
      }),
    );
    ruleSet.push(
      createBuildRule(task.spec, {
        target: 'shell',
        command: 'esy-shell',
        withBuildEnv: true,
      }),
    );
    ruleSet.push(
      createBuildRule(task.spec, {
        target: 'clean',
        command: 'esy-clean',
      }),
    );
  }

  // Emit build artefacts for packages
  log('process dependency graph');
  const rootTask = Task.fromBuildSandbox(sandbox, buildConfig);
  Graph.traverse(rootTask, visitTask);

  // Now emit all build-wise artefacts
  log('build environment');

  emitFile(outputPath, {
    filename: ['bin/render-env'],
    executable: true,
    contents: outdent`
      #!/bin/bash

      set -e
      set -o pipefail

      _TMPDIR_GLOBAL=$($ESY_EJECT__ROOT/bin/realpath "/tmp")

      if [ -d "$TMPDIR" ]; then
        _TMPDIR=$($ESY_EJECT__ROOT/bin/realpath "$TMPDIR")
      else
        _TMPDIR="/does/not/exist"
      fi

      sed \\
        -e "s|\\$ESY_EJECT__STORE|$ESY_EJECT__STORE|g"          \\
        -e "s|\\$ESY_EJECT__SANDBOX|$ESY_EJECT__SANDBOX|g"      \\
        -e "s|\\$ESY_EJECT__ROOT|$ESY_EJECT__ROOT|g"      \\
        -e "s|\\$TMPDIR_GLOBAL|$_TMPDIR_GLOBAL|g"   \\
        -e "s|\\$TMPDIR|$_TMPDIR|g"                 \\
        $1 > $2
    `,
  });

  emitFile(outputPath, {
    filename: ['bin', 'fastreplacestring.cpp'],
    contents: fastReplaceStringSrc,
  });

  emitFile(outputPath, {
    filename: ['bin', 'realpath.c'],
    contents: outdent`
      #include<stdlib.h>

      main(int cc, char**vargs) {
        puts(realpath(vargs[1], 0));
        exit(0);
      }
    `,
  });

  emitFile(outputPath, {
    filename: ['bin', 'runtime.sh'],
    contents: RUNTIME,
  });

  emitFile(outputPath, {
    filename: ['Makefile'],
    contents: Makefile.renderMakefile(ruleSet),
  });
}

function emitFile(
  outputPath: string,
  file: {filename: Array<string>, contents: string, executable?: boolean},
) {
  const filename = path.join(outputPath, ...file.filename);
  log(`emit <ejectRootDir>/${file.filename.join('/')}`);
  mkdirp(path.dirname(filename));
  fs.writeFileSync(filename, file.contents);
  if (file.executable) {
    // fs.constants only became supported in node 6.7 or so.
    const mode = fs.constants && fs.constants.S_IRWXU ? fs.constants.S_IRWXU : 448;
    fs.chmodSync(filename, mode);
  }
}

function renderBuildTaskCommand(task: BuildTask): ?string {
  if (task.command == null) {
    return null;
  }
  return task.command.map(c => c.renderedCommand).join(' && ');
}
<|endoftext|>


<commit_before>/*
 * test_phyx.js: Test all PHYX files in this repository.
 */

const BASE_DIR = 'phyx/';

// Javascript libraries.
const fs = require('fs');
const path = require('path');
const chai = require('chai');
const assert = chai.assert;

/*
 * Returns a list of PHYX files that we can test in the provided directory.
 *
 * We use a simple flatMap to search for these files. Since flatMap isn't in
 * Node.js yet, I use a map to recursively find the files and then flatten it
 * using reduce() and concat().
 *
 * This could be implemented asynchronously, but we need a list of files to
 * test each one individually in Mocha, so we need a synchronous implementation
 * to get that list before we start testing.
 */
function findPHYXFiles(dirPath) {
    return fs.readdirSync(dirPath).map(function(filename) {
        const filePath = path.join(dirPath, filename);

        if(fs.lstatSync(filePath).isDirectory()) {
            // Recurse into this directory.
            return findPHYXFiles(filePath);
        } else {
            // Look for .json files (but not for '_as_owl.json' files, for historical reasons).
            if(filePath.endsWith('.json') && !filePath.endsWith('_as_owl.json')) {
                return [filePath];
            } else {
                return [];
            }
        }
   }).reduce((x, y) => x.concat(y), []); // This flattens the list of results.
}

// Test each input file.
describe('Test PHYX files in repository', function() {
    findPHYXFiles(BASE_DIR).forEach(function(filename) {
        describe('PHYX file: ' + filename, function() {
            const stats = fs.lstatSync(filename);

            it('is not empty', function() {
                assert.notEqual(stats["size"], 0);
            });

            const data = fs.readFileSync(filename).slice(0, 9);
            if(data.equals(Buffer.from("\x00GITCRYPT"))) {
                it.skip('is git-crypt encrypted');
                return;
            }

            it('is not git-crypt encrypted');
        });
    });
});

//  2. Skip files that start with "\x00GITCRYPT", which means they are Git encrypted.
<commit_msg>Test for PHYX2JSONLD conversion from updated curation-tool phyx.js.<commit_after>/*
 * test_phyx.js: Test all PHYX files in this repository.
 */

const BASE_DIR = 'phyx/';

// Our libraries.
const phyx2jsonld = require('../curation-tool/js/phyx2jsonld.js');

// Javascript libraries.
const child_process = require('child_process');
const fs = require('fs');
const path = require('path');
const chai = require('chai');
const assert = chai.assert;

/*
 * Returns a list of PHYX files that we can test in the provided directory.
 *
 * We use a simple flatMap to search for these files. Since flatMap isn't in
 * Node.js yet, I use a map to recursively find the files and then flatten it
 * using reduce() and concat().
 *
 * This could be implemented asynchronously, but we need a list of files to
 * test each one individually in Mocha, so we need a synchronous implementation
 * to get that list before we start testing.
 */
function findPHYXFiles(dirPath) {
    return fs.readdirSync(dirPath).map(function(filename) {
        const filePath = path.join(dirPath, filename);

        if(fs.lstatSync(filePath).isDirectory()) {
            // Recurse into this directory.
            return findPHYXFiles(filePath);
        } else {
            // Look for .json files (but not for '_as_owl.json' files, for historical reasons).
            if(filePath.endsWith('.json') && !filePath.endsWith('_as_owl.json')) {
                return [filePath];
            } else {
                return [];
            }
        }
   }).reduce((x, y) => x.concat(y), []); // This flattens the list of results.
}

// Test each input file.
describe('Test PHYX files in repository', function() {
    findPHYXFiles(BASE_DIR).forEach(function(filename) {
        describe('PHYX file: ' + filename, function() {
            it('is not empty', function() {
              const stats = fs.lstatSync(filename);
              assert.notEqual(stats["size"], 0);
            });

            it('can be converted into JSON-LD and reasoned over (skipped if git-crypt encrypted)', function() {
              // Load the PHYX data. Check to see if it is git-crypt encrypted.
              const data = fs.readFileSync(filename);
              const gitcrypt = data.slice(0, 9);
              if(gitcrypt.equals(Buffer.from("\x00GITCRYPT"))) {
                  this.skip(); // Hopefully they will eventually let us write out a message here.
                  return;
              }

              // Read the PHYX data as 'UTF-8' and convert it into JSON-LD.
              const phyx = data.toString('utf-8');
              const jsonld = phyx2jsonld.convertPHYXToJSONLD(phyx);
              assert.isNotEmpty(jsonld);
            });
        });
    });
});

//  2. Skip files that start with "\x00GITCRYPT", which means they are Git encrypted.
<|endoftext|>


<commit_before>/**
 * Created with JetBrains RubyMine.
 * User: teamco
 * Date: 11/17/12
 * Time: 4:10 PM
 * To change this template use File | Settings | File Templates.
 */

define([
    'config/anthill',
    'modules/controller'
], function defineLayoutController(AntHill, BaseController) {

    /**
     * Define layout controller
     * @class LayoutController
     * @extends AntHill
     * @extends BaseController
     * @constructor
     */
    var LayoutController = function LayoutController() {

    };

    return LayoutController.extend('LayoutController', {

        /**
         * Before nested organizer
         * @member LayoutController
         * @param {boolean} silent
         */
        beforeNestedOrganizer: function beforeNestedOrganizer(silent) {

            if (!silent) {
                this.controller.getContainment().controller.banAddWidget();
                this.logger.debug(this.i18n.t('before.nested.organizer'));
            }

            this.logger.debug(this.i18n.t('silent.add.widget'));
        },

        /**
         * After nested organizer
         * @member LayoutController
         */
        afterNestedOrganizer: function afterNestedOrganizer() {

            /**
             * Define controller instance
             * @type {LayoutController}
             */
            var controller = this.controller;

            /**
             * Get containment
             * @type {Page|*}
             */
            var containment = controller.getContainment();

            containment.controller.allowAddWidget();

            controller.store(
                controller.root()
            );

            this.logger.debug(this.i18n.t('after.nested.organizer'));
        },

        /**
         * Update cell size on resize container
         * @member LayoutController
         * @returns {*}
         */
        updateMinCellWidth: function updateMinCellWidth() {
            delete this.config.grid.minCellWidth;
            return this.controller.minCellWidth();
        },

        /**
         * Calculate cell size
         * @member LayoutController
         * @returns {Number}
         */
        minCellWidth: function minCellWidth() {
            var scope = this.scope,
                config = scope.config.grid;
            if (this.base.isDefined(config.minCellWidth)) {
                return config.minCellWidth;
            }
            var columns = config.columns,
                margin = config.margin;

            var elements = scope.controller.getContainment().view.elements,
                $page = elements.$page || elements.$template,
                $widgets = elements.$widgets;

            var pl = $widgets.getPaddingLeft(),
                pr = $widgets.getPaddingRight(),
                ml = $widgets.getMarginLeft(),
                mr = $widgets.getMarginRight();

            var width = $page.getWidth() - pl - pr - ml - mr;

            config.minCellWidth = (width - margin * columns) / columns;

            scope.logger.debug('Calculated cell size (px)', config.minCellWidth);

            return config.minCellWidth;
        },

        /**
         * Get grid width
         * @member LayoutController
         * @returns {number}
         */
        getGridWidth: function getGridWidth() {
            var config = this.scope.config.grid,
                cell = this.minCellWidth();

            return (cell + config.margin) * config.columns;
        },

        /**
         * Get next position
         * @member LayoutController
         * @param {{column: Number, row: Number}} dom
         * @returns {{left: Number, top: Number}}
         */
        getNextPosition: function getNextPosition(dom) {
            var $widgets = this.scope.controller.getContainment().controller.getWidgetsContainer(),
                top = $widgets.getTopDelta(),
                left = $widgets.getLeftDelta();

            var layout = this.scope,
                cell = layout.controller.minCellWidth(),
                margin = layout.config.grid.margin;

            /**
             * Get next position
             * @param {Number} pos
             * @returns {Number}
             * @private
             */
            function _getNextPosition(pos) {
                return pos * cell + (margin * (pos + 1));
            }

            return {
                left: _getNextPosition(dom.column) + left,
                top: _getNextPosition(dom.row) + top
            };

        },

        /**
         * Get layout Behavior mode
         * @member LayoutController
         * @returns {String}
         */
        getBehaviorMode: function getBehaviorMode() {
            return this.scope.config.mode;
        },

        /**
         * Set layout Behavior mode
         * @member LayoutController
         * @param {string} mode
         * @returns {String}
         */
        setBehaviorMode: function setBehaviorMode(mode) {
            this.logger.warn(
                'Behavior mode was changed',
                this.controller.getBehaviorMode(),
                mode
            );

            /**
             * Define Behavior mode
             * @type {string}
             */
            this.config.mode = mode;
        },

        /**
         * Check if mode is Snap to Grid
         * @member LayoutController
         * @returns {boolean}
         */
        isSnap2Grid: function isSnap2Grid() {
            return this.getBehaviorMode() ===
                this.getContainment().LAYOUT_MODES.snap2grid;
        },

        /**
         * Check if mode is Snap to Grid
         * @member LayoutController
         * @returns {boolean}
         */
        isUIGrid: function isUIGrid() {
            return this.getBehaviorMode() ===
                this.getContainment().LAYOUT_MODES.jqUIGrid;
        },

        /**
         * Check if mode is Free Style
         * @member LayoutController
         * @returns {boolean}
         */
        isFreeStyle: function isFreeStyle() {
            return this.getBehaviorMode() ===
                this.getContainment().LAYOUT_MODES.freeStyle;
        },

        /**
         * Check if overlapping allowed
         * @member LayoutController
         * @returns {boolean}
         */
        isOverlappingAllowed: function isOverlappingAllowed() {
            return this._getLayoutMode('organize') !==
                this.getContainment().ORGANIZE_MODES.none;
        },

        /**
         * Get layout behavior mode
         * @member LayoutController
         * @returns {*}
         */
        getBehavior: function getBehavior() {
            return this.scope.config.behavior[this.getBehaviorMode()];
        },

        /**
         * Set behavior empty spaces mode
         * @member LayoutController
         * @param {String} mode
         */
        setEmptySpacesMode: function setEmptySpacesMode(mode) {
            this.controller._setLayoutMode('emptySpaces', mode);
        },

        /**
         * Set behavior organize mode
         * @member LayoutController
         * @param {String} mode
         */
        setOrganizeMode: function setOrganizeMode(mode) {
            this.controller._setLayoutMode('organize', mode);
        },

        /**
         * Set layout mode
         * @member LayoutController
         * @param {string} type
         * @param {string|boolean} mode
         * @private
         */
        _setLayoutMode: function _setLayoutMode(type, mode) {
            this.scope.logger.warn(
                    type.toUnderscore().capitalize() + ' was changed',
                this._getLayoutMode(type),
                mode
            );
            this._updateLayoutMode(type, mode);
        },

        /**
         * Get layout mode
         * @member LayoutController
         * @param {string} type
         * @returns {*|Overlapping}
         * @private
         */
        _getLayoutMode: function _getLayoutMode(type) {
            return this.getBehavior()[type];
        },

        /**
         * Update layout mode
         * @member LayoutController
         * @param mode
         * @param {string} type
         * @private
         * @returns {*|Overlapping}
         */
        _updateLayoutMode: function _updateLayoutMode(type, mode) {
            this.scope.config.behavior[this.getBehaviorMode()][type] = mode;

            return this._getLayoutMode(type);
        }

    }, AntHill.prototype, BaseController.prototype);
});<commit_msg>fix zindex onloading - done<commit_after>/**
 * Created with JetBrains RubyMine.
 * User: teamco
 * Date: 11/17/12
 * Time: 4:10 PM
 * To change this template use File | Settings | File Templates.
 */

define([
    'config/anthill',
    'modules/controller'
], function defineLayoutController(AntHill, BaseController) {

    /**
     * Define layout controller
     * @class LayoutController
     * @extends AntHill
     * @extends BaseController
     * @constructor
     */
    var LayoutController = function LayoutController() {

    };

    return LayoutController.extend('LayoutController', {

        /**
         * Before nested organizer
         * @member LayoutController
         * @param {boolean} silent
         */
        beforeNestedOrganizer: function beforeNestedOrganizer(silent) {

            if (!silent) {
                this.controller.getContainment().controller.banAddWidget();
                this.logger.debug(this.i18n.t('before.nested.organizer'));
            }

            this.logger.debug(this.i18n.t('silent.add.widget'));
        },

        /**
         * After nested organizer
         * @member LayoutController
         */
        afterNestedOrganizer: function afterNestedOrganizer() {

            /**
             * Define controller instance
             * @type {LayoutController}
             */
            var controller = this.controller;

            /**
             * Get containment
             * @type {Page|*}
             */
            var containment = controller.getContainment();

            containment.controller.allowAddWidget();

            controller.store(
                controller.root()
            );

            this.logger.debug(this.i18n.t('after.nested.organizer'));
        },

        /**
         * Update cell size on resize container
         * @member LayoutController
         * @returns {*}
         */
        updateMinCellWidth: function updateMinCellWidth() {
            delete this.config.grid.minCellWidth;
            return this.controller.minCellWidth();
        },

        /**
         * Calculate cell size
         * @member LayoutController
         * @returns {Number}
         */
        minCellWidth: function minCellWidth() {
            var scope = this.scope,
                config = scope.config.grid;
            if (this.base.isDefined(config.minCellWidth)) {
                return config.minCellWidth;
            }
            var columns = config.columns,
                margin = config.margin;

            var elements = scope.controller.getContainment().view.elements,
                $page = elements.$page || elements.$template,
                $widgets = elements.$widgets;

            var pl = $widgets.getPaddingLeft(),
                pr = $widgets.getPaddingRight(),
                ml = $widgets.getMarginLeft(),
                mr = $widgets.getMarginRight();

            var width = $page.getWidth() - pl - pr - ml - mr;

            config.minCellWidth = (width - margin * columns) / columns;

            scope.logger.debug('Calculated cell size (px)', config.minCellWidth);

            return config.minCellWidth;
        },

        /**
         * Get grid width
         * @member LayoutController
         * @returns {number}
         */
        getGridWidth: function getGridWidth() {
            var config = this.scope.config.grid,
                cell = this.minCellWidth();

            return (cell + config.margin) * config.columns;
        },

        /**
         * Get next position
         * @member LayoutController
         * @param {{column: Number, row: Number}} dom
         * @returns {{left: Number, top: Number}}
         */
        getNextPosition: function getNextPosition(dom) {
            var $widgets = this.scope.controller.getContainment().controller.getWidgetsContainer(),
                top = $widgets.getTopDelta(),
                left = $widgets.getLeftDelta();

            var layout = this.scope,
                cell = layout.controller.minCellWidth(),
                margin = layout.config.grid.margin;

            /**
             * Get next position
             * @param {Number} pos
             * @returns {Number}
             * @private
             */
            function _getNextPosition(pos) {
                return pos * cell + (margin * (pos + 1));
            }

            return {
                left: _getNextPosition(dom.column) + left,
                top: _getNextPosition(dom.row) + top,
                zIndex: dom.zIndex
            };

        },

        /**
         * Get layout Behavior mode
         * @member LayoutController
         * @returns {String}
         */
        getBehaviorMode: function getBehaviorMode() {
            return this.scope.config.mode;
        },

        /**
         * Set layout Behavior mode
         * @member LayoutController
         * @param {string} mode
         * @returns {String}
         */
        setBehaviorMode: function setBehaviorMode(mode) {
            this.logger.warn(
                'Behavior mode was changed',
                this.controller.getBehaviorMode(),
                mode
            );

            /**
             * Define Behavior mode
             * @type {string}
             */
            this.config.mode = mode;
        },

        /**
         * Check if mode is Snap to Grid
         * @member LayoutController
         * @returns {boolean}
         */
        isSnap2Grid: function isSnap2Grid() {
            return this.getBehaviorMode() ===
                this.getContainment().LAYOUT_MODES.snap2grid;
        },

        /**
         * Check if mode is Snap to Grid
         * @member LayoutController
         * @returns {boolean}
         */
        isUIGrid: function isUIGrid() {
            return this.getBehaviorMode() ===
                this.getContainment().LAYOUT_MODES.jqUIGrid;
        },

        /**
         * Check if mode is Free Style
         * @member LayoutController
         * @returns {boolean}
         */
        isFreeStyle: function isFreeStyle() {
            return this.getBehaviorMode() ===
                this.getContainment().LAYOUT_MODES.freeStyle;
        },

        /**
         * Check if overlapping allowed
         * @member LayoutController
         * @returns {boolean}
         */
        isOverlappingAllowed: function isOverlappingAllowed() {
            return this._getLayoutMode('organize') !==
                this.getContainment().ORGANIZE_MODES.none;
        },

        /**
         * Get layout behavior mode
         * @member LayoutController
         * @returns {*}
         */
        getBehavior: function getBehavior() {
            return this.scope.config.behavior[this.getBehaviorMode()];
        },

        /**
         * Set behavior empty spaces mode
         * @member LayoutController
         * @param {String} mode
         */
        setEmptySpacesMode: function setEmptySpacesMode(mode) {
            this.controller._setLayoutMode('emptySpaces', mode);
        },

        /**
         * Set behavior organize mode
         * @member LayoutController
         * @param {String} mode
         */
        setOrganizeMode: function setOrganizeMode(mode) {
            this.controller._setLayoutMode('organize', mode);
        },

        /**
         * Set layout mode
         * @member LayoutController
         * @param {string} type
         * @param {string|boolean} mode
         * @private
         */
        _setLayoutMode: function _setLayoutMode(type, mode) {
            this.scope.logger.warn(
                    type.toUnderscore().capitalize() + ' was changed',
                this._getLayoutMode(type),
                mode
            );
            this._updateLayoutMode(type, mode);
        },

        /**
         * Get layout mode
         * @member LayoutController
         * @param {string} type
         * @returns {*|Overlapping}
         * @private
         */
        _getLayoutMode: function _getLayoutMode(type) {
            return this.getBehavior()[type];
        },

        /**
         * Update layout mode
         * @member LayoutController
         * @param mode
         * @param {string} type
         * @private
         * @returns {*|Overlapping}
         */
        _updateLayoutMode: function _updateLayoutMode(type, mode) {
            this.scope.config.behavior[this.getBehaviorMode()][type] = mode;

            return this._getLayoutMode(type);
        }

    }, AntHill.prototype, BaseController.prototype);
});<|endoftext|>


<commit_before>'use strict';
import ControllerBase from './controller_base';
import _ from 'lodash';
import Models from '@hoist/model';
class UsersController extends ControllerBase {
  constructor() {
    super();
    this.name = "Users";
    this.routes = this.routes.concat([{
      method: 'GET',
      path: '/users',
      config: {
        handler: this.index,
        auth: {
          strategy: 'session'
        }
      }
    }, {
      method: ['GET'],
      path: '/user/{id}',
      config: {
        handler: this.details,
        auth: {
          strategy: 'session'
        }
      }
    }]);
  }
  index(request, reply) {
    return Models.HoistUser.findAsync({})
      .then((users) => {
        reply.view('users/index', {
          users: users,
          title: 'Users'
        });
      });

  }
  details(request, reply) {
    var user;
    var organisations;
    var applications;
    return Models.HoistUser.findOneAsync({
        _id: request.params.id
      })
      .then((_user) => {
        user = _user;
        return Models.Organisation.findAsync({
          _id: {$in: user.organisations}
        });
      })
      .then((_organisations) => {
        organisations = _organisations;
        return Models.Application.findAsync({
          organisation: { $in:
            _.map(organisations, function(o) {
              return o._id;
            })
          }
        });
      })
      .then((_applications) => {
        applications = _applications;
        return reply.view('users/details', {
          user: user,
          rawUser: user,
          organisations: organisations,
          applications: applications,
          title: user.name,
          breadcrumbs: [{
            'name': 'Users',
            'url': '/users'
          }]
        });
      });
  }
}

export default UsersController;
<commit_msg>a few changes<commit_after>'use strict';
import ControllerBase from './controller_base';
import {
  HoistUser, Organisation, Application
}
from '@hoist/model';
class UsersController extends ControllerBase {
  constructor() {
    super();
    this.name = "Users";
    this.routes = this.routes.concat([{
      method: 'GET',
      path: '/users',
      config: {
        handler: this.index,
        auth: {
          strategy: 'session'
        }
      }
    }, {
      method: ['GET'],
      path: '/user/{id}',
      config: {
        handler: this.details,
        auth: {
          strategy: 'session'
        }
      }
    }]);
  }
  index(request, reply) {
    return HoistUser.findAsync({})
      .then((users) => {
        reply.view('users/index', {
          users: users,
          title: 'Users'
        });
      });

  }
  details(request, reply) {
    var user;
    var organisations;
    var applications;
    return HoistUser.findOneAsync({
        _id: request.params.id
      })
      .then((_user) => {
        user = _user;
        return Organisation.findAsync({
          _id: {
            $in: user.organisations
          }
        });
      })
      .then((_organisations) => {
        organisations = _organisations;
        return Application.findAsync({
          organisation: {
            $in: organisations.map((o) => {
              return o._id;
            })
          }
        });
      })
      .then((_applications) => {
        applications = _applications;
        return reply.view('users/details', {
          user: user,
          rawUser: user,
          organisations: organisations,
          applications: applications,
          title: user.name,
          breadcrumbs: [{
            'name': 'Users',
            'url': '/users'
          }]
        });
      });
  }
}

export default UsersController;
<|endoftext|>


<commit_before>
import * as data from '../data.json';
import * as http from 'http';
import * as https from 'https';

describe('project', function () {
  const projects = Object.keys(data.projects).reduce(((acc, category) =>
    acc.concat(data.projects[category])
  ), []);

  describe('github URLs', function () {
    context('when not null', function () {
      projects.forEach((project) => {
        it('should respond with 200 OK', function (done) {
          if (project.github === null) {
            done();
          }
          else if (project.github.startsWith('https')) {
            https.get(project.github, (res) => {
              res.resume();
              if (res.statusCode === 200) {
                done();
              } else {
                const err = new Error(`Request failed with status code ${res.statusCode}`);
                done(err);
              }
            });
          }
          else {
            http.get(project.github, done);
          }
        });
      })
    });
  });

  describe('website URLs', function () {
    context('when not null', function () {
      projects.forEach((project) => {
        it('should respond with 200 OK', function (done) {
          if (project.website === null) {
            done();
          }
          else if (project.website.startsWith('https')) {
            https.get(project.website, (res) => {
              res.resume();
              if (res.statusCode === 200) {
                done();
              } else {
                const err = new Error(`Request failed with status code ${res.statusCode}`);
                done(err);
              }
            });
          }
          else {
            http.get(project.website, done);
          }
        });
      })
    });
  });
  describe('image URLs', function () {
    context('when not null', function () {
      projects.forEach((project) => {
        it('should respond with 200 OK', function (done) {
          if (project.image === null) {
            done();
          }
          else if (project.image.startsWith('https')) {
            https.get(project.image, (res) => {
              res.resume();
              if (res.statusCode === 200) {
                done();
              } else {
                const err = new Error(`Request failed with status code ${res.statusCode}`);
                done(err);
              }
            });
          }
          else {
            http.get(project.image, done);
          }
        });
      })
    });
  });
});
<commit_msg>Improve detail of website and github tests; check for undefined websites<commit_after>
import * as http from 'http';
import * as https from 'https';

import * as should from 'should';

import * as data from '../data.json';

function httpx_get(url, done) {
  function callback(res) {
    res.resume();
    if (res.statusCode === 200) {
      done();
    } else {
      const err = new Error(`Request for ${url} failed with status code ${res.statusCode}`);
      done(err);
    }
  }

  if (url.startsWith('https'))
    https.get(url, callback);
  else
    http.get(url, callback);
}

describe('project', function () {
  const projects = Object.keys(data.projects).reduce(((acc, category) =>
    acc.concat(data.projects[category])
  ), []);

  describe('github URLs', function () {
    context('when not null', function () {
      projects.filter((project) => project.github !== null)
        .forEach((project) => {
          context(project.github, function () {
            it('should respond with 200 OK', function (done) {
              httpx_get(project.github, done);
            });
          });
        });
    });
  });

  describe('website URLs', function () {
    projects.filter((project) => project.website !== null)
      .forEach((project) => {
        context(`${project.name}`, function () {
          it('should not be undefined'), function () {
            project.name.should.not.be.undefined();
          }
        });
      });

    context('when not null', function () {
      projects.filter((project) => project.website !== null)
        .forEach((project) => {
          context(`${project.name} (${project.website})`, function () {
            it('should respond with 200 OK', function (done) {
              httpx_get(project.website, done);
            });
          });
        });
    });
  });

  describe('image URLs', function () {
    context('when not null', function () {
      projects.forEach((project) => {
        it('should respond with 200 OK', function (done) {
          if (project.image === null) {
            done();
          }
          else if (project.image.startsWith('https')) {
            https.get(project.image, (res) => {
              res.resume();
              if (res.statusCode === 200) {
                done();
              } else {
                const err = new Error(`Request failed with status code ${res.statusCode}`);
                done(err);
              }
            });
          }
          else {
            http.get(project.image, done);
          }
        });
      })
    });
  });
});
<|endoftext|>


<commit_before>$(function() {
	'use strict';

	module('PowerTip Core');

	test('powerTip defined', function() {
		var element = $('');
		strictEqual(typeof element.powerTip, 'function', 'powerTip is defined');
	});

	test('expose default settings', function() {
		ok($.fn.powerTip.defaults, 'defaults is defined');
		ok($.fn.powerTip.defaults.hasOwnProperty('fadeInTime'), 'fadeInTime exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('fadeOutTime'), 'fadeOutTime exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('followMouse'), 'followMouse exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('popupId'), 'popupId exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('intentSensitivity'), 'intentSensitivity exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('intentPollInterval'), 'intentPollInterval exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('closeDelay'), 'closeDelay exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('placement'), 'placement exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('smartPlacement'), 'smartPlacement exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('offset'), 'offset exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('mouseOnToPopup'), 'mouseOnToPopup exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('manual'), 'manual exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('openEvents'), 'openEvents exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('closeEvents'), 'closeEvents exists');
	});

	test('expose smart placement lists', function() {
		ok($.fn.powerTip.smartPlacementLists, 'smartPlacementLists is defined');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('n'), 'n exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('e'), 'e exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('s'), 's exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('w'), 'w exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('ne'), 'ne exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('nw'), 'nw exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('se'), 'se exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('sw'), 'sw exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('ne-alt'), 'ne-alt exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('nw-alt'), 'nw-alt exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('se-alt'), 'se-alt exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('sw-alt'), 'sw-alt exists');
	});

	test('powerTip', function() {
		var div = $('
'),
			empty = $('#thisDoesntExist'),
			element = $('').powerTip();

		deepEqual(div.powerTip(), div, 'original jQuery object returned for matched selector');
		deepEqual(empty.powerTip(), empty, 'original jQuery object returned for empty selector');
		deepEqual(div.powerTip('show'), div, 'original jQuery object returned for show');
		deepEqual(div.powerTip('hide'), div, 'original jQuery object returned for hide');
		deepEqual(div.powerTip('toggle'), div, 'original jQuery object returned for toggle');
		deepEqual(div.powerTip('resetPosition'), div, 'original jQuery object returned for resetPosition');
		deepEqual(div.powerTip('destroy'), div, 'original jQuery object returned for destroy');
		ok(!element.attr('title'), 'title attribute was removed');
		ok(element.data(DATA_DISPLAYCONTROLLER), 'new DisplayController created and added to data');
	});

	test('powerTip hooks events', function() {
		var openEvents = [ 'mouseenter', 'focus', 'customOpenEvent' ],
			closeEvents = [ 'mouseleave', 'blur', 'customCloseEvent' ],
			element = $('TEXT').powerTip({
				openEvents: openEvents,
				closeEvents: closeEvents
			}),
			showTriggered = false,
			hideTriggered = false;

		element.data(
			DATA_DISPLAYCONTROLLER,
			new MockDisplayController(
				function() {
					showTriggered = true;
				},
				function() {
					hideTriggered = true;
				}
			)
		);

		// jquery 1.9 will not trigger a focus event on an element that cannot
		// be focused, so we have to append the test element to the document
		// before the focus test will work
		$('body').prepend(element);

		// test open events
		$.each(openEvents, function(idx, eventName) {
			showTriggered = false;
			element.trigger(eventName);
			strictEqual(showTriggered, true, eventName + ' event calls DisplayController.show');
		});

		// test close events
		$.each(closeEvents, function(idx, eventName) {
			hideTriggered = false;
			element.trigger('mouseleave');
			strictEqual(hideTriggered, true, eventName + ' event calls DisplayController.hide');
		});

		// test escape key
		hideTriggered = false;
		element.trigger($.Event('keydown', { keyCode: 27 }));
		strictEqual(hideTriggered, true, 'keydown event for key code 27 calls DisplayController.hide');

		// cleanup test element
		element.remove();
	});

	test('expose API', function() {
		strictEqual(typeof $.powerTip.show, 'function', 'show is defined');
		strictEqual(typeof $.powerTip.reposition, 'function', 'reposition is defined');
		strictEqual(typeof $.powerTip.hide, 'function', 'hide is defined');
		strictEqual(typeof $.powerTip.toggle, 'function', 'toggle is defined');
		strictEqual(typeof $.powerTip.destroy, 'function', 'destroy is defined');
		// deprecated
		strictEqual(typeof $.powerTip.showTip, 'function', 'showTip is defined');
		strictEqual(typeof $.powerTip.closeTip, 'function', 'closeTip is defined');
	});

	test('API show method should call DisplayController.show', function() {
		var showCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					function() {
						showCalled = true;
					}
				));

		$.powerTip.show(element);

		ok(showCalled, 'show method was called');
	});

	test('API reposition method should call DisplayController.resetPosition', function() {
		var resetCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					null,
					null,
					null,
					function() {
						resetCalled = true;
					}
				));

		$.powerTip.reposition(element);

		ok(resetCalled, 'reposition method was called');
	});

	test('API hide method should call DisplayController.hide', function() {
		var hideCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					null,
					function() {
						hideCalled = true;
					}
				));

		$.powerTip.hide(element);

		ok(hideCalled, 'hide method was called');
	});

	test('API toggle method should call DisplayController.show to open and DisplayController.hide to close', function() {
		var showCalled = false,
			hideCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					function() {
						showCalled = true;
						// toggle checks activeHover to determine action
						session.activeHover = element;
					},
					function() {
						hideCalled = true;
					}
				));

		$.powerTip.toggle(element); // simulate show
		$.powerTip.toggle(element); // simulate hide

		ok(showCalled, 'show method was called');
		ok(hideCalled, 'hide method was called');

		// reset activeHover
		session.activeHover = null;
	});

	test('API destroy method rolls back PowerTip changes', function() {
		var element = $('').powerTip(),
			elementDataAttr = $('').powerTip(),
			showTriggered = false,
			hideTriggered = false;

		element.data(
			DATA_DISPLAYCONTROLLER,
			new MockDisplayController(
				function() {
					showTriggered = true;
				},
				function() {
					hideTriggered = true;
				}
			)
		);

		element.powerTip('destroy');
		elementDataAttr.powerTip('destroy');

		// attributes
		strictEqual(element.attr('title'), 'This is the tooltip text', 'destory method rolled back the title attribute');
		ok(!element.data(DATA_POWERTIP), 'destroy method removed powertip data attribute');
		strictEqual(elementDataAttr.data(DATA_POWERTIP), 'This is the tooltip text', 'destroy method did not remove manually set powertip data attribute');

		// events
		element.trigger($.Event('mouseenter', { pageX: 10, pageY: 10 }));
		ok(!showTriggered, 'mouseenter event was unhooked after destroy');
		showTriggered = false;

		element.trigger('mouseleave');
		ok(!hideTriggered, 'mouseleave event was unhooked after destroy');
		hideTriggered = false;

		element.trigger('focus');
		ok(!showTriggered, 'focus event was unhooked after destroy');
		showTriggered = false;

		element.trigger('blur');
		ok(!hideTriggered, 'blur event was unhooked after destroy');
		hideTriggered = false;

		element.trigger($.Event('keydown', { keyCode: 27 }));
		ok(!hideTriggered, 'keydown event was unhooked after destroy');
		hideTriggered = false;
	});

	test('API destroy method with no arguments rolls back all PowerTip changes', function() {
		// run PowerTip
		$('').powerTip();

		// destroy everything
		$.powerTip.destroy();

		// tooltip element
		strictEqual($('#' + $.fn.powerTip.defaults.popupId).length, 0, 'tooltip element removed');

		// document event (mouse tracking)
		session.currentX = 1;
		$(document).trigger($.Event('mousemove', { pageX: 2, pageY: 3 }));
		strictEqual(session.currentX, 1, 'document event removed');
	});

	function MockDisplayController(show, hide, cancel, resetPosition) {
		this.show = show || $.noop;
		this.hide = hide || $.noop;
		this.cancel = cancel || $.noop;
		this.resetPosition = resetPosition || $.noop;
	}
});
<commit_msg>Changed powerTip() hide unit test to be atomic.<commit_after>$(function() {
	'use strict';

	module('PowerTip Core');

	test('powerTip defined', function() {
		var element = $('');
		strictEqual(typeof element.powerTip, 'function', 'powerTip is defined');
	});

	test('expose default settings', function() {
		ok($.fn.powerTip.defaults, 'defaults is defined');
		ok($.fn.powerTip.defaults.hasOwnProperty('fadeInTime'), 'fadeInTime exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('fadeOutTime'), 'fadeOutTime exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('followMouse'), 'followMouse exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('popupId'), 'popupId exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('intentSensitivity'), 'intentSensitivity exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('intentPollInterval'), 'intentPollInterval exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('closeDelay'), 'closeDelay exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('placement'), 'placement exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('smartPlacement'), 'smartPlacement exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('offset'), 'offset exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('mouseOnToPopup'), 'mouseOnToPopup exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('manual'), 'manual exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('openEvents'), 'openEvents exists');
		ok($.fn.powerTip.defaults.hasOwnProperty('closeEvents'), 'closeEvents exists');
	});

	test('expose smart placement lists', function() {
		ok($.fn.powerTip.smartPlacementLists, 'smartPlacementLists is defined');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('n'), 'n exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('e'), 'e exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('s'), 's exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('w'), 'w exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('ne'), 'ne exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('nw'), 'nw exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('se'), 'se exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('sw'), 'sw exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('ne-alt'), 'ne-alt exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('nw-alt'), 'nw-alt exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('se-alt'), 'se-alt exists');
		ok($.fn.powerTip.smartPlacementLists.hasOwnProperty('sw-alt'), 'sw-alt exists');
	});

	test('powerTip', function() {
		var div = $('
'),
			empty = $('#thisDoesntExist'),
			element = $('').powerTip();

		deepEqual(div.powerTip(), div, 'original jQuery object returned for matched selector');
		deepEqual(empty.powerTip(), empty, 'original jQuery object returned for empty selector');
		deepEqual(div.powerTip('show'), div, 'original jQuery object returned for show');
		deepEqual(div.powerTip('hide', true), div, 'original jQuery object returned for hide');
		deepEqual(div.powerTip('toggle'), div, 'original jQuery object returned for toggle');
		deepEqual(div.powerTip('resetPosition'), div, 'original jQuery object returned for resetPosition');
		deepEqual(div.powerTip('destroy'), div, 'original jQuery object returned for destroy');
		ok(!element.attr('title'), 'title attribute was removed');
		ok(element.data(DATA_DISPLAYCONTROLLER), 'new DisplayController created and added to data');
	});

	test('powerTip hooks events', function() {
		var openEvents = [ 'mouseenter', 'focus', 'customOpenEvent' ],
			closeEvents = [ 'mouseleave', 'blur', 'customCloseEvent' ],
			element = $('TEXT').powerTip({
				openEvents: openEvents,
				closeEvents: closeEvents
			}),
			showTriggered = false,
			hideTriggered = false;

		element.data(
			DATA_DISPLAYCONTROLLER,
			new MockDisplayController(
				function() {
					showTriggered = true;
				},
				function() {
					hideTriggered = true;
				}
			)
		);

		// jquery 1.9 will not trigger a focus event on an element that cannot
		// be focused, so we have to append the test element to the document
		// before the focus test will work
		$('body').prepend(element);

		// test open events
		$.each(openEvents, function(idx, eventName) {
			showTriggered = false;
			element.trigger(eventName);
			strictEqual(showTriggered, true, eventName + ' event calls DisplayController.show');
		});

		// test close events
		$.each(closeEvents, function(idx, eventName) {
			hideTriggered = false;
			element.trigger('mouseleave');
			strictEqual(hideTriggered, true, eventName + ' event calls DisplayController.hide');
		});

		// test escape key
		hideTriggered = false;
		element.trigger($.Event('keydown', { keyCode: 27 }));
		strictEqual(hideTriggered, true, 'keydown event for key code 27 calls DisplayController.hide');

		// cleanup test element
		element.remove();
	});

	test('expose API', function() {
		strictEqual(typeof $.powerTip.show, 'function', 'show is defined');
		strictEqual(typeof $.powerTip.reposition, 'function', 'reposition is defined');
		strictEqual(typeof $.powerTip.hide, 'function', 'hide is defined');
		strictEqual(typeof $.powerTip.toggle, 'function', 'toggle is defined');
		strictEqual(typeof $.powerTip.destroy, 'function', 'destroy is defined');
		// deprecated
		strictEqual(typeof $.powerTip.showTip, 'function', 'showTip is defined');
		strictEqual(typeof $.powerTip.closeTip, 'function', 'closeTip is defined');
	});

	test('API show method should call DisplayController.show', function() {
		var showCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					function() {
						showCalled = true;
					}
				));

		$.powerTip.show(element);

		ok(showCalled, 'show method was called');
	});

	test('API reposition method should call DisplayController.resetPosition', function() {
		var resetCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					null,
					null,
					null,
					function() {
						resetCalled = true;
					}
				));

		$.powerTip.reposition(element);

		ok(resetCalled, 'reposition method was called');
	});

	test('API hide method should call DisplayController.hide', function() {
		var hideCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					null,
					function() {
						hideCalled = true;
					}
				));

		$.powerTip.hide(element);

		ok(hideCalled, 'hide method was called');
	});

	test('API toggle method should call DisplayController.show to open and DisplayController.hide to close', function() {
		var showCalled = false,
			hideCalled = false,
			element = $('')
				.data(DATA_DISPLAYCONTROLLER, new MockDisplayController(
					function() {
						showCalled = true;
						// toggle checks activeHover to determine action
						session.activeHover = element;
					},
					function() {
						hideCalled = true;
					}
				));

		$.powerTip.toggle(element); // simulate show
		$.powerTip.toggle(element); // simulate hide

		ok(showCalled, 'show method was called');
		ok(hideCalled, 'hide method was called');

		// reset activeHover
		session.activeHover = null;
	});

	test('API destroy method rolls back PowerTip changes', function() {
		var element = $('').powerTip(),
			elementDataAttr = $('').powerTip(),
			showTriggered = false,
			hideTriggered = false;

		element.data(
			DATA_DISPLAYCONTROLLER,
			new MockDisplayController(
				function() {
					showTriggered = true;
				},
				function() {
					hideTriggered = true;
				}
			)
		);

		element.powerTip('destroy');
		elementDataAttr.powerTip('destroy');

		// attributes
		strictEqual(element.attr('title'), 'This is the tooltip text', 'destory method rolled back the title attribute');
		ok(!element.data(DATA_POWERTIP), 'destroy method removed powertip data attribute');
		strictEqual(elementDataAttr.data(DATA_POWERTIP), 'This is the tooltip text', 'destroy method did not remove manually set powertip data attribute');

		// events
		element.trigger($.Event('mouseenter', { pageX: 10, pageY: 10 }));
		ok(!showTriggered, 'mouseenter event was unhooked after destroy');
		showTriggered = false;

		element.trigger('mouseleave');
		ok(!hideTriggered, 'mouseleave event was unhooked after destroy');
		hideTriggered = false;

		element.trigger('focus');
		ok(!showTriggered, 'focus event was unhooked after destroy');
		showTriggered = false;

		element.trigger('blur');
		ok(!hideTriggered, 'blur event was unhooked after destroy');
		hideTriggered = false;

		element.trigger($.Event('keydown', { keyCode: 27 }));
		ok(!hideTriggered, 'keydown event was unhooked after destroy');
		hideTriggered = false;
	});

	test('API destroy method with no arguments rolls back all PowerTip changes', function() {
		// run PowerTip
		$('').powerTip();

		// destroy everything
		$.powerTip.destroy();

		// tooltip element
		strictEqual($('#' + $.fn.powerTip.defaults.popupId).length, 0, 'tooltip element removed');

		// document event (mouse tracking)
		session.currentX = 1;
		$(document).trigger($.Event('mousemove', { pageX: 2, pageY: 3 }));
		strictEqual(session.currentX, 1, 'document event removed');
	});

	function MockDisplayController(show, hide, cancel, resetPosition) {
		this.show = show || $.noop;
		this.hide = hide || $.noop;
		this.cancel = cancel || $.noop;
		this.resetPosition = resetPosition || $.noop;
	}
});
<|endoftext|>


<commit_before>//option1
// app.controller('CustomersController', function($scope){
//       $scope.sortBy = 'name'; // default values for sorting by
//       $scope.reverse = false; //default values for sorting

//       $scope.customers = [
//       {joined:'2000-01-02', name:'John', city:'San Francisco', orderTotal:5.23432},
//       {joined:'2000-02-02', name:'Larry', city:'Atlanta', orderTotal:7.23432},
//       {joined:'2000-12-02', name:'Miguel', city:'New York City', orderTotal:8.23432},
//       {joined:'2000-12-02', name:'Calvin', city:'San Francisco', orderTotal:8.23432},];
//       $scope.doSort = function(propName){
//         $scope.sortBy = propName;
//         $scope.reverse = !$scope.reverse;
//       };
// });

// option2

// (function(){

//   angular.module('customersApp')
//   .controller('CustomersController', function($scope){
//       $scope.sortBy = 'name'; // default values for sorting by
//       $scope.reverse = false; //default values for sorting

//       $scope.customers = [
//       {joined:'2000-01-02', name:'John', city:'San Francisco', orderTotal:5.23432},
//       {joined:'2000-02-02', name:'Larry', city:'Atlanta', orderTotal:7.23432},
//       {joined:'2000-12-02', name:'Miguel', city:'New York City', orderTotal:8.23432},
//       {joined:'2000-12-02', name:'Calvin', city:'San Francisco', orderTotal:8.23432},];
//       $scope.doSort = function(propName){
//         $scope.sortBy = propName;
//         $scope.reverse = !$scope.reverse;
//       };
//   });

// }())

// option3

(function(){

  var CustomersController = function($scope){
    $scope.sortBy = 'name'; // default values for sorting by
      $scope.reverse = false; //default values for sorting

      $scope.customers = [
      {joined:'2000-01-02', name:'John', city:'San Francisco', orderTotal:5.23432},
      {joined:'2000-02-02', name:'Larry', city:'Atlanta', orderTotal:7.23432},
      {joined:'2000-12-02', name:'Miguel', city:'New York City', orderTotal:8.23432},
      {joined:'2000-12-02', name:'Calvin', city:'San Francisco', orderTotal:8.23432},];
      $scope.doSort = function(propName){
        $scope.sortBy = propName;
        $scope.reverse = !$scope.reverse;
      };
  };

  angular.module('customersApp')
  .controller('CustomersController', CustomersController);

}())
<commit_msg>add inject to avoid problems with script minification<commit_after>//option1
// app.controller('CustomersController', function($scope){
//       $scope.sortBy = 'name'; // default values for sorting by
//       $scope.reverse = false; //default values for sorting

//       $scope.customers = [
//       {joined:'2000-01-02', name:'John', city:'San Francisco', orderTotal:5.23432},
//       {joined:'2000-02-02', name:'Larry', city:'Atlanta', orderTotal:7.23432},
//       {joined:'2000-12-02', name:'Miguel', city:'New York City', orderTotal:8.23432},
//       {joined:'2000-12-02', name:'Calvin', city:'San Francisco', orderTotal:8.23432},];
//       $scope.doSort = function(propName){
//         $scope.sortBy = propName;
//         $scope.reverse = !$scope.reverse;
//       };
// });

// option2

// (function(){

//   angular.module('customersApp')
//   .controller('CustomersController', function($scope){
//       $scope.sortBy = 'name'; // default values for sorting by
//       $scope.reverse = false; //default values for sorting

//       $scope.customers = [
//       {joined:'2000-01-02', name:'John', city:'San Francisco', orderTotal:5.23432},
//       {joined:'2000-02-02', name:'Larry', city:'Atlanta', orderTotal:7.23432},
//       {joined:'2000-12-02', name:'Miguel', city:'New York City', orderTotal:8.23432},
//       {joined:'2000-12-02', name:'Calvin', city:'San Francisco', orderTotal:8.23432},];
//       $scope.doSort = function(propName){
//         $scope.sortBy = propName;
//         $scope.reverse = !$scope.reverse;
//       };
//   });

// }())

// option3

(function(){

  var CustomersController = function($scope){
    $scope.sortBy = 'name'; // default values for sorting by
      $scope.reverse = false; //default values for sorting

      $scope.customers = [
      {joined:'2000-01-02', name:'John', city:'San Francisco', orderTotal:5.23432},
      {joined:'2000-02-02', name:'Larry', city:'Atlanta', orderTotal:7.23432},
      {joined:'2000-12-02', name:'Miguel', city:'New York City', orderTotal:8.23432},
      {joined:'2000-12-02', name:'Calvin', city:'San Francisco', orderTotal:8.23432},];
      $scope.doSort = function(propName){
        $scope.sortBy = propName;
        $scope.reverse = !$scope.reverse;
      };
  };

  CustomersController.$inject = ['$scope'];

  angular.module('customersApp')
  .controller('CustomersController', CustomersController);

}())

// avoiding problems with script minification

<|endoftext|>


<commit_before>var connect4GameBoard = require("../models/connect4/Connect4GameBoard.js");

exports.Connect4GameController = function Connect4GameController()
{

};

exports.Connect4GameController.CreateGame() {

};

exports.Connect4GameController.CompleteGame() {

};

exports.Connect4GameController.RequestMove(move) {
	// 1. read game from database using gameID to get Connect4GameBoard object
	// faked for now
	var gameBoard = new connect4GameBoard.Connect4GameBoard();

	// 2. get proper placement of move based on the column
	var updatedConnect4Move = gameBoard.GetLocationIfDropGamePieceAtCol(move.col);

	if (gameBoard.IsPlayersTurn(move)) {
		if (updatedConnect4Move != null) {
			// 3. Place the move on the game board
			gameBoard.PlayMoveOnBoard(move.row, move.col);
			// 4. Check for a winner
			var isGameWon = gameBoard.IsWinner();

			if (isGameWon) {
				// send message to winner and opponent saying the game has been won
			}
			else if (gameBoard.IsDraw()) {
				// send message to both players saying the game is a draw
			}
			else {
				// send message to opponent with updated game board state
			}
		}
		else {
			// move is invalid because column is already full
			// send message to client saying that this is an invalid move
		}
	}
	else {
		// move is invalid because it was made out of turn
	}
};
<commit_msg>tiny fixes<commit_after>var connect4GameBoard = require("../models/connect4/Connect4GameBoard.js");

exports.Connect4GameController = function Connect4GameController() {

};

exports.Connect4GameController = function CreateGame()
{

};

exports.Connect4GameController = function CompleteGame(){

};

exports.Connect4GameController.RequestMove(move) {
	// 1. read game from database using gameID to get Connect4GameBoard object
	// faked for now
	var gameBoard = new connect4GameBoard.Connect4GameBoard();

	// 2. get proper placement of move based on the column
	var updatedConnect4Move = gameBoard.GetLocationIfDropGamePieceAtCol(move.col);

	if (gameBoard.IsPlayersTurn(move)) {
		if (updatedConnect4Move != null) {
			// 3. Place the move on the game board
			gameBoard.PlayMoveOnBoard(move.row, move.col);
			// 4. Check for a winner
			var isGameWon = gameBoard.IsWinner();

			if (isGameWon) {
				// send message to winner and opponent saying the game has been won
			}
			else if (gameBoard.IsDraw()) {
				// send message to both players saying the game is a draw
			}
			else {
				// send message to opponent with updated game board state
			}
		}
		else {
			// move is invalid because column is already full
			// send message to client saying that this is an invalid move
		}
	}
	else {
		// move is invalid because it was made out of turn
	}
};
<|endoftext|>


<commit_before>const DrawCard = require('../../drawcard.js');

class InsultToInjury extends DrawCard {
    setupCardAbilities(ability) {
        this.reaction({
            title: 'Dishonor the loser of a duel',
            when: {
                afterDuel: (event, context) => event.winnder && event.winner.hasTrait('duelist') && event.winner.controller === context.player
            },
            gameAction: ability.actions.dishonor(context => ({ target: context.event.loser }))
        });
    }
}

InsultToInjury.id = 'insult-to-injury';

module.exports = InsultToInjury;
<commit_msg>Update InsultToInjury.js<commit_after>const DrawCard = require('../../drawcard.js');

class InsultToInjury extends DrawCard {
    setupCardAbilities(ability) {
        this.reaction({
            title: 'Dishonor the loser of a duel',
            when: {
                afterDuel: (event, context) => event.winner && event.winner.hasTrait('duelist') && event.winner.controller === context.player
            },
            gameAction: ability.actions.dishonor(context => ({ target: context.event.loser }))
        });
    }
}

InsultToInjury.id = 'insult-to-injury';

module.exports = InsultToInjury;
<|endoftext|>


<commit_before>'use strict';

var test = require('tap').test;
var fs = require('fs');
var path = require('path');
var temp = require('temp');
var dirdiff = require('dirdiff');
var unzip = require('../');

test("uncompressed archive", function (t) {
  var archive = path.join(__dirname, '../testData/uncompressed/archive.zip');

  temp.mkdir('node-unzip-', function (err, dirPath) {
    if (err) {
      throw err;
    }
    var unzipExtractor = unzip.Extract({ path: dirPath });
    unzipExtractor.on('error', function(err) {
      throw err;
    });
    unzipExtractor.on('end', testExtractionResults);

    fs.createReadStream(archive).pipe(unzipExtractor);

    function testExtractionResults() {
      dirdiff(path.join(__dirname, '../testData/uncompressed/inflated'), dirPath, {
        fileContents: true
      }, function (err, diffs) {
        if (err) {
          throw err;
        }
        t.equal(0, diffs.length, 'extracted directory contents');
        t.end();
      });
    }
  });
});

test("compressed archive", function (t) {
  var archive = path.join(__dirname, '../testData/compressed/archive.zip');

  temp.mkdir('node-unzip-', function (err, dirPath) {
    if (err) {
      throw err;
    }
    var unzipExtractor = unzip.Extract({ path: dirPath });
    unzipExtractor.on('error', function(err) {
      throw err;
    });
    unzipExtractor.on('end', testExtractionResults);

    fs.createReadStream(archive).pipe(unzipExtractor);

    function testExtractionResults() {
      dirdiff(path.join(__dirname, '../testData/compressed/inflated'), dirPath, {
        fileContents: true
      }, function (err, diffs) {
        if (err) {
          throw err;
        }
        t.equal(0, diffs.length, 'extracted directory contents');
        t.end();
      });
    }
  });
});
<commit_msg>Fix test expected/actual ordering<commit_after>'use strict';

var test = require('tap').test;
var fs = require('fs');
var path = require('path');
var temp = require('temp');
var dirdiff = require('dirdiff');
var unzip = require('../');

test("uncompressed archive", function (t) {
  var archive = path.join(__dirname, '../testData/uncompressed/archive.zip');

  temp.mkdir('node-unzip-', function (err, dirPath) {
    if (err) {
      throw err;
    }
    var unzipExtractor = unzip.Extract({ path: dirPath });
    unzipExtractor.on('error', function(err) {
      throw err;
    });
    unzipExtractor.on('end', testExtractionResults);

    fs.createReadStream(archive).pipe(unzipExtractor);

    function testExtractionResults() {
      dirdiff(path.join(__dirname, '../testData/uncompressed/inflated'), dirPath, {
        fileContents: true
      }, function (err, diffs) {
        if (err) {
          throw err;
        }
        t.equal(diffs.length, 0, 'extracted directory contents');
        t.end();
      });
    }
  });
});

test("compressed archive", function (t) {
  var archive = path.join(__dirname, '../testData/compressed/archive.zip');

  temp.mkdir('node-unzip-', function (err, dirPath) {
    if (err) {
      throw err;
    }
    var unzipExtractor = unzip.Extract({ path: dirPath });
    unzipExtractor.on('error', function(err) {
      throw err;
    });
    unzipExtractor.on('end', testExtractionResults);

    fs.createReadStream(archive).pipe(unzipExtractor);

    function testExtractionResults() {
      dirdiff(path.join(__dirname, '../testData/compressed/inflated'), dirPath, {
        fileContents: true
      }, function (err, diffs) {
        if (err) {
          throw err;
        }
        t.equal(diffs.length, 0, 'extracted directory contents');
        t.end();
      });
    }
  });
});
<|endoftext|>


<commit_before>import debug from 'debug';
import config from 'config';
import jwt from 'jsonwebtoken';
import passport from 'passport';
import request from 'request-promise';
import { get, omitBy, isNil } from 'lodash';
import { URLSearchParams } from 'url';

import models from '../../models';
import errors from '../../lib/errors';
import logger from '../../lib/logger';
import paymentProviders from '../../paymentProviders';
import {
  createOrUpdate as createOrUpdateConnectedAccount,
  disconnect as disconnectConnectedAccount,
} from '../../controllers/connectedAccounts';

const { User } = models;

const { BadRequest, CustomError } = errors;

const { jwtSecret } = config.keys.opencollective;

/**
 * Middleware related to authentication.
 *
 * Identification is provided through two vectors:
 * - api_key URL parameter which uniquely identifies an application
 * - JSON web token JWT payload which contains 3 items:
 *   - sub: user ID
 *   - scope: user scope (e.g. 'subscriptions')
 *
 * Thus:
 * - a user is identified with a JWT
 */

/**
 * Express-jwt will either force all routes to have auth and throw
 * errors for public routes. Or authorize all the routes and not throw
 * expirations errors. This is a cleaned up version of that code that only
 * decodes the token (expected behaviour).
 */
export const parseJwtNoExpiryCheck = (req, res, next) => {
  let token = req.params.access_token || req.query.access_token || req.body.access_token;
  if (!token) {
    const header = req.headers && req.headers.authorization;
    if (!header) return next();

    const parts = header.split(' ');
    const scheme = parts[0];
    token = parts[1];
    if (!/^Bearer$/i.test(scheme) || !token) {
      return next(new BadRequest('Format is Authorization: Bearer [token]'));
    }
  }

  jwt.verify(token, jwtSecret, (err, decoded) => {
    // JWT library either returns an error or the decoded version
    if (err && err.name === 'TokenExpiredError') {
      req.jwtExpired = true;
      req.jwtPayload = jwt.decode(token, jwtSecret); // we need to decode again
    } else if (err) {
      return next(new BadRequest(err.message));
    } else {
      req.jwtPayload = decoded;
    }

    return next();
  });
};

export const checkJwtExpiry = (req, res, next) => {
  if (req.jwtExpired) {
    return next(new CustomError(401, 'jwt_expired', 'jwt expired'));
  }

  return next();
};

/**
 * Authenticate the user using the JWT token and populates:
 *  - req.remoteUser
 *  - req.remoteUser.memberships[CollectiveId] = [roles]
 */
export const _authenticateUserByJwt = (req, res, next) => {
  if (!req.jwtPayload) return next();
  const userid = Number(req.jwtPayload.sub);
  User.findByPk(userid)
    .then(user => {
      if (!user) {
        throw errors.Unauthorized(`User id ${userid} not found`);
      }

      /**
       * Functionality for one-time login links. We check that the lastLoginAt
       * in the JWT matches the lastLoginAt in the db. If so, we allow the user
       * to log in, and update the lastLoginAt.
       */
      if (user.lastLoginAt) {
        if (!req.jwtPayload.lastLoginAt) {
          // This should only happen with pre-migration tokens, that don't have this field.
          // Should be turned into an error in the future.
          logger.warn('Using a token without `lastLoginAt`');
        } else if (user.lastLoginAt.getTime() !== req.jwtPayload.lastLoginAt) {
          throw errors.Unauthorized('This login link is expired or has already been used');
        }
      }

      const now = new Date();
      return user.update({ lastLoginAt: now }).then(user => {
        req.remoteUser = user;
        return user.populateRoles();
      });
    })
    .then(() => {
      debug('auth')('logged in user', req.remoteUser.id, 'roles:', req.remoteUser.rolesByCollectiveId);
      next();
      return null;
    })
    .catch(next);
};

/**
 * Authenticate the user with the JWT token if any, otherwise continues
 *
 * @PRE: Request with a `Authorization: Bearer [token]` with a valid token
 * @POST: req.remoteUser is set to the logged in user or null if authentication failed
 * @ERROR: Will return an error if a JWT token is provided and invalid
 */
export function authenticateUser(req, res, next) {
  if (req.remoteUser && req.remoteUser.id) return next();

  parseJwtNoExpiryCheck(req, res, e => {
    // If a token was submitted but is invalid, we continue without authenticating the user
    if (e) {
      debug('auth')('>>> checkJwtExpiry invalid error', e);
      return next();
    }

    checkJwtExpiry(req, res, e => {
      // If a token was submitted and is expired, we continue without authenticating the user
      if (e) {
        debug('auth')('>>> checkJwtExpiry expiry error', e);
        return next();
      }
      _authenticateUserByJwt(req, res, next);
    });
  });
}

export const authenticateService = (req, res, next) => {
  const { service } = req.params;
  const opts = { callbackURL: getOAuthCallbackUrl(req) };

  if (service === 'github') {
    /*
      'repo' gives us access to org repos and private repos (latter is an issue for some people)
      'public_repo' should give us all public_repos but in some cases users report not
        being able to see their repos.

      We have fluctuated back and forth. With the new simplified GitHub signup flow,
      it's possible that 'public_repo' is enough.

      Update: removing public_repo as well, since technically we shouldn't need it.
    */

    opts.scope = ['user:email', 'public_repo', 'read:org'];
    return passport.authenticate(service, opts)(req, res, next);
  }

  if (!req.remoteUser || !req.remoteUser.isAdmin(req.query.CollectiveId)) {
    throw new errors.Unauthorized('Please login as an admin of this collective to add a connected account');
  }

  if (!req.query.CollectiveId) {
    return next(new errors.ValidationFailed('Please provide a CollectiveId as a query parameter'));
  }

  if (paymentProviders[service]) {
    return paymentProviders[service].oauth
      .redirectUrl(req.remoteUser, req.query.CollectiveId, req.query)
      .then(redirectUrl => res.send({ redirectUrl }))
      .catch(next);
  }

  if (service === 'meetup') {
    opts.scope = 'ageless';
  }

  return passport.authenticate(service, opts)(req, res, next);
};

export const authenticateServiceCallback = (req, res, next) => {
  const { service } = req.params;

  if (get(paymentProviders, `${service}.oauth.callback`)) {
    return paymentProviders[service].oauth.callback(req, res, next);
  }

  const opts = { callbackURL: getOAuthCallbackUrl(req) };

  passport.authenticate(service, opts, async (err, accessToken, data) => {
    if (err) {
      return next(err);
    }
    if (!accessToken) {
      return res.redirect(config.host.website);
    }
    let emails;
    if (service === 'github' && !req.remoteUser) {
      emails = await getGithubEmails(accessToken);
    }
    createOrUpdateConnectedAccount(req, res, next, accessToken, data, emails).catch(next);
  })(req, res, next);
};

export const authenticateServiceDisconnect = (req, res) => {
  disconnectConnectedAccount(req, res);
};

function getOAuthCallbackUrl(req) {
  const { utm_source, CollectiveId, access_token, redirect } = req.query;
  const { service } = req.params;

  const params = new URLSearchParams(omitBy({ access_token, redirect, CollectiveId, utm_source }, isNil));

  return `${config.host.website}/api/connected-accounts/${service}/callback?${params.toString()}`;
}

function getGithubEmails(accessToken) {
  return request({
    uri: 'https://api.github.com/user/emails',
    qs: { access_token: accessToken },
    headers: { 'User-Agent': 'OpenCollective' },
    json: true,
  }).then(json => json.map(entry => entry.email));
}
<commit_msg>fix(authentication): Don't fail if token lastLoginAt is invalid<commit_after>import debug from 'debug';
import config from 'config';
import jwt from 'jsonwebtoken';
import passport from 'passport';
import request from 'request-promise';
import { get, omitBy, isNil } from 'lodash';
import { URLSearchParams } from 'url';

import models from '../../models';
import errors from '../../lib/errors';
import logger from '../../lib/logger';
import paymentProviders from '../../paymentProviders';
import {
  createOrUpdate as createOrUpdateConnectedAccount,
  disconnect as disconnectConnectedAccount,
} from '../../controllers/connectedAccounts';

const { User } = models;

const { BadRequest, CustomError } = errors;

const { jwtSecret } = config.keys.opencollective;

/**
 * Middleware related to authentication.
 *
 * Identification is provided through two vectors:
 * - api_key URL parameter which uniquely identifies an application
 * - JSON web token JWT payload which contains 3 items:
 *   - sub: user ID
 *   - scope: user scope (e.g. 'subscriptions')
 *
 * Thus:
 * - a user is identified with a JWT
 */

/**
 * Express-jwt will either force all routes to have auth and throw
 * errors for public routes. Or authorize all the routes and not throw
 * expirations errors. This is a cleaned up version of that code that only
 * decodes the token (expected behaviour).
 */
export const parseJwtNoExpiryCheck = (req, res, next) => {
  let token = req.params.access_token || req.query.access_token || req.body.access_token;
  if (!token) {
    const header = req.headers && req.headers.authorization;
    if (!header) return next();

    const parts = header.split(' ');
    const scheme = parts[0];
    token = parts[1];
    if (!/^Bearer$/i.test(scheme) || !token) {
      return next(new BadRequest('Format is Authorization: Bearer [token]'));
    }
  }

  jwt.verify(token, jwtSecret, (err, decoded) => {
    // JWT library either returns an error or the decoded version
    if (err && err.name === 'TokenExpiredError') {
      req.jwtExpired = true;
      req.jwtPayload = jwt.decode(token, jwtSecret); // we need to decode again
    } else if (err) {
      return next(new BadRequest(err.message));
    } else {
      req.jwtPayload = decoded;
    }

    return next();
  });
};

export const checkJwtExpiry = (req, res, next) => {
  if (req.jwtExpired) {
    return next(new CustomError(401, 'jwt_expired', 'jwt expired'));
  }

  return next();
};

/**
 * Authenticate the user using the JWT token and populates:
 *  - req.remoteUser
 *  - req.remoteUser.memberships[CollectiveId] = [roles]
 */
export const _authenticateUserByJwt = (req, res, next) => {
  if (!req.jwtPayload) return next();
  const userid = Number(req.jwtPayload.sub);
  User.findByPk(userid)
    .then(user => {
      if (!user) {
        throw errors.Unauthorized(`User id ${userid} not found`);
      }

      /**
       * Functionality for one-time login links. We check that the lastLoginAt
       * in the JWT matches the lastLoginAt in the db. If so, we allow the user
       * to log in, and update the lastLoginAt.
       */
      if (user.lastLoginAt) {
        if (!req.jwtPayload.lastLoginAt) {
          // This should only happen with pre-migration tokens, that don't have this field.
          // Should be turned into an error in the future.
          if (process.env.NODE_ENV === 'production') {
            logger.warn('Using a token without `lastLoginAt`');
          }
        } else if (user.lastLoginAt.getTime() !== req.jwtPayload.lastLoginAt) {
          logger.error('This login link is expired or has already been used');
        }
      }

      const now = new Date();
      return user.update({ lastLoginAt: now }).then(user => {
        req.remoteUser = user;
        return user.populateRoles();
      });
    })
    .then(() => {
      debug('auth')('logged in user', req.remoteUser.id, 'roles:', req.remoteUser.rolesByCollectiveId);
      next();
      return null;
    })
    .catch(next);
};

/**
 * Authenticate the user with the JWT token if any, otherwise continues
 *
 * @PRE: Request with a `Authorization: Bearer [token]` with a valid token
 * @POST: req.remoteUser is set to the logged in user or null if authentication failed
 * @ERROR: Will return an error if a JWT token is provided and invalid
 */
export function authenticateUser(req, res, next) {
  if (req.remoteUser && req.remoteUser.id) return next();

  parseJwtNoExpiryCheck(req, res, e => {
    // If a token was submitted but is invalid, we continue without authenticating the user
    if (e) {
      debug('auth')('>>> checkJwtExpiry invalid error', e);
      return next();
    }

    checkJwtExpiry(req, res, e => {
      // If a token was submitted and is expired, we continue without authenticating the user
      if (e) {
        debug('auth')('>>> checkJwtExpiry expiry error', e);
        return next();
      }
      _authenticateUserByJwt(req, res, next);
    });
  });
}

export const authenticateService = (req, res, next) => {
  const { service } = req.params;
  const opts = { callbackURL: getOAuthCallbackUrl(req) };

  if (service === 'github') {
    /*
      'repo' gives us access to org repos and private repos (latter is an issue for some people)
      'public_repo' should give us all public_repos but in some cases users report not
        being able to see their repos.

      We have fluctuated back and forth. With the new simplified GitHub signup flow,
      it's possible that 'public_repo' is enough.

      Update: removing public_repo as well, since technically we shouldn't need it.
    */

    opts.scope = ['user:email', 'public_repo', 'read:org'];
    return passport.authenticate(service, opts)(req, res, next);
  }

  if (!req.remoteUser || !req.remoteUser.isAdmin(req.query.CollectiveId)) {
    throw new errors.Unauthorized('Please login as an admin of this collective to add a connected account');
  }

  if (!req.query.CollectiveId) {
    return next(new errors.ValidationFailed('Please provide a CollectiveId as a query parameter'));
  }

  if (paymentProviders[service]) {
    return paymentProviders[service].oauth
      .redirectUrl(req.remoteUser, req.query.CollectiveId, req.query)
      .then(redirectUrl => res.send({ redirectUrl }))
      .catch(next);
  }

  if (service === 'meetup') {
    opts.scope = 'ageless';
  }

  return passport.authenticate(service, opts)(req, res, next);
};

export const authenticateServiceCallback = (req, res, next) => {
  const { service } = req.params;

  if (get(paymentProviders, `${service}.oauth.callback`)) {
    return paymentProviders[service].oauth.callback(req, res, next);
  }

  const opts = { callbackURL: getOAuthCallbackUrl(req) };

  passport.authenticate(service, opts, async (err, accessToken, data) => {
    if (err) {
      return next(err);
    }
    if (!accessToken) {
      return res.redirect(config.host.website);
    }
    let emails;
    if (service === 'github' && !req.remoteUser) {
      emails = await getGithubEmails(accessToken);
    }
    createOrUpdateConnectedAccount(req, res, next, accessToken, data, emails).catch(next);
  })(req, res, next);
};

export const authenticateServiceDisconnect = (req, res) => {
  disconnectConnectedAccount(req, res);
};

function getOAuthCallbackUrl(req) {
  const { utm_source, CollectiveId, access_token, redirect } = req.query;
  const { service } = req.params;

  const params = new URLSearchParams(omitBy({ access_token, redirect, CollectiveId, utm_source }, isNil));

  return `${config.host.website}/api/connected-accounts/${service}/callback?${params.toString()}`;
}

function getGithubEmails(accessToken) {
  return request({
    uri: 'https://api.github.com/user/emails',
    qs: { access_token: accessToken },
    headers: { 'User-Agent': 'OpenCollective' },
    json: true,
  }).then(json => json.map(entry => entry.email));
}
<|endoftext|>


<commit_before>const util = require('../src/util');

describe('buildTempFolderName method', () => {
    it('returns the correct temporary folder name', () => {
        let expected = 'tmp-/';

        expect(util.buildTempFolderName('')).toBe(expected);

        expected = 'tmp-sample/';

        expect(util.buildTempFolderName('sample')).toBe(expected);
    });
});

<commit_msg>lint fix<commit_after>const util = require('../src/util');

describe('buildTempFolderName method', () => {
    it('returns the correct temporary folder name', () => {
        let expected = 'tmp-/';

        expect(util.buildTempFolderName('')).toBe(expected);

        expected = 'tmp-sample/';

        expect(util.buildTempFolderName('sample')).toBe(expected);
    });
});

<|endoftext|>


<commit_before>import jsdom from 'jsdom';
import jquery from 'jquery';
const defaultFunction = () => {};
// setup the simplest document possible
const doc = jsdom.jsdom('<!doctype html>');

// get the window object out of the document
const win = doc.defaultView;

// set globals for mocha that make access to document and window feel
// natural in the test environment
global.document = doc;
global.window = win;
global.$ = jquery(win);
// to mock out semantic methods
$.fn.dropdown = defaultFunction;

// take all properties of the window object and also attach it to the
// mocha global object

// adapted from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80
Object.keys(window).forEach(key => {
  if (!(key in global)) {
    global[key] = window[key];
  }
});
<commit_msg>injected localhost:8080 to use as a fake host for nock.<commit_after>import jsdom from 'jsdom';
import jquery from 'jquery';
const defaultFunction = () => {};
// setup the simplest document possible
const doc = jsdom.jsdom('<!doctype html>', { url: 'http://localhost:8080' });

// get the window object out of the document
const win = doc.defaultView;

// set globals for mocha that make access to document and window feel
// natural in the test environment
global.document = doc;
global.window = win;
global.$ = jquery(win);
// to mock out semantic methods
$.fn.dropdown = defaultFunction;

// take all properties of the window object and also attach it to the
// mocha global object

// adapted from mocha-jsdom https://github.com/rstacruz/mocha-jsdom/blob/master/index.js#L80
Object.keys(window).forEach(key => {
  if (!(key in global)) {
    global[key] = window[key];
  }
});
<|endoftext|>