<commit_before>/*
 * common.js: Common methods used in `forever-monitor`.
 *
 * (C) 2010 Nodejitsu Inc.
 * MIT LICENCE
 *
 */

var psTree = require('ps-tree'),
    spawn = require('child_process').spawn;

//
// ### function checkProcess (pid, callback)
// #### @pid {string} pid of the process to check
// #### @callback {function} Continuation to pass control backto.
// Utility function to check to see if a pid is running
//
exports.checkProcess = function (pid) {
  if (!pid) {
    return false;
  }

  try {
    //
    // Trying to kill non-existent process here raises a ESRCH - no such
    // process exception. Also, signal 0 doesn't do no harm to a process - it
    // only checks if sending a signal to a given process is possible.
    //
    process.kill(pid, 0);
    return true;
  }
  catch (err) {
    return false;
  }
};

exports.kill = function (pid, killTree, signal, callback) {
  if (killTree) {
    psTree(pid, function (err, children) {
      var pids = children.map(function (p) {
        return p.PID;
      });

      pids.unshift(pid);
      spawn('kill', ['-' + signal].concat(pids)).on('exit', callback || function () {});
    });
  }
  else {
    try { process.kill(pid, signal) }
    catch (ex) { }

    if (callback) {
      callback();
    }
  }
};<commit_msg>[fix] Dont spawn `kill` for Windows compatibility. Fixes #27.<commit_after>/*
 * common.js: Common methods used in `forever-monitor`.
 *
 * (C) 2010 Nodejitsu Inc.
 * MIT LICENCE
 *
 */

var psTree = require('ps-tree'),
    spawn = require('child_process').spawn;

//
// ### function checkProcess (pid, callback)
// #### @pid {string} pid of the process to check
// #### @callback {function} Continuation to pass control backto.
// Utility function to check to see if a pid is running
//
exports.checkProcess = function (pid) {
  if (!pid) {
    return false;
  }

  try {
    //
    // Trying to kill non-existent process here raises a ESRCH - no such
    // process exception. Also, signal 0 doesn't do no harm to a process - it
    // only checks if sending a signal to a given process is possible.
    //
    process.kill(pid, 0);
    return true;
  }
  catch (err) {
    return false;
  }
};

exports.kill = function (pid, killTree, signal, callback) {
  signal   = signal   || 'SIGKILL';
  callback = callback || function () {};

  if (killTree) {
    psTree(pid, function (err, children) {
      [pid].concat(
        children.map(function (p) {
          return p.PID;
        })
      ).forEach(function (tpid) {
        try { process.kill(tpid, signal) }
        catch (ex) { }
      });

      callback();
    });
  }
  else {
    try { process.kill(pid, signal) }
    catch (ex) { }
    callback();
  }
};<|endoftext|>


<commit_before>import React from 'react';

import Analyzer from 'Parser/Core/Analyzer';
import Combatants from 'Parser/Core/Modules/Combatants';

import SPELLS from 'common/SPELLS';
import StatisticBox from 'Main/StatisticBox';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';

/*
 * Your Sentinel watches over the target area for 18 sec, applying Hunter's Mark to all enemies every 6 sec.
 */
const MS_BUFFER = 100;

const SENTINEL_DURATION = 18000;

const TIME_BETWEEN_TICKS = 6000;

const TICKS_PER_CAST = 4;

class Sentinel extends Analyzer {
  static dependencies = {
    combatants: Combatants,

  };
  damage = 0;
  applyDebuffTimestamp = null;
  sentinelCasts = 0;
  sentinelTicks = 0;
  appliedDebuffsFromSentinel = 0;
  wastedApplications = 0;
  wastedTicks = 0;
  lastBadTickTimestamp = 0;
  lastSentinelCastTimestamp = 0;
  lostTicksFromCombatEnd = 0;

  on_initialized() {
    this.active = this.combatants.selected.hasTalent(SPELLS.SENTINEL_TALENT.id);
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SENTINEL_TICK.id && spellId !== SPELLS.SENTINEL_TALENT.id) {
      return;
    }
    if (spellId === SPELLS.SENTINEL_TALENT.id) {
      this.lastSentinelCastTimestamp = event.timestamp;
      this.sentinelCasts++;
    }
    if (spellId === SPELLS.SENTINEL_TICK.id) {
      this.applyDebuffTimestamp = event.timestamp;
      this.sentinelTicks++;
    }
  }
  on_byPlayer_applydebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.HUNTERS_MARK_DEBUFF.id) {
      return;
    }
    if (event.timestamp < this.applyDebuffTimestamp + MS_BUFFER && event.timestamp >= this.applyDebuffTimestamp) {
      this.appliedDebuffsFromSentinel++;
    }
  }
  on_byPlayer_refreshdebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.HUNTERS_MARK_DEBUFF.id) {
      return;
    }
    if (event.timestamp < this.applyDebuffTimestamp + MS_BUFFER && event.timestamp >= this.applyDebuffTimestamp) {
      this.wastedApplications++;
      if (this.lastBadTickTimestamp !== event.timestamp) {
        this.wastedTicks++;
        this.lastBadTickTimestamp = event.timestamp;
      }
    }
  }

  get debuffsPerCast() {
    return (this.appliedDebuffsFromSentinel / this.sentinelCasts).toFixed(1);
  }
  get totalPossibleTicks() {
    return (this.sentinelCasts * TICKS_PER_CAST) - this.lostTicksFromCombatEnd;
  }
  get buggedTicks() {
    return this.totalPossibleTicks - this.sentinelTicks;
  }
  get goodTicks() {
    return this.totalPossibleTicks - this.buggedTicks - this.wastedTicks;
  }

  on_finished() {
    if (this.lastSentinelCastTimestamp > (this.owner.fight.end_time - SENTINEL_DURATION)) {
      const timeLostOnSentinel = this.owner.fight.end_time - this.lastSentinelCastTimestamp;
      this.lostTicksFromCombatEnd = Math.floor(timeLostOnSentinel / TIME_BETWEEN_TICKS);
    }
  }

  statistic() {
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.SENTINEL_TALENT.id} />}
        value={`${this.goodTicks}/${this.totalPossibleTicks}`}
        label={`flawless ticks + ${this.buggedTicks} bugged`}
        tooltip={`You applied Hunter's Mark with Sentinel ${this.appliedDebuffsFromSentinel} times spread over ${this.sentinelCasts} casts of Sentinel. This gives an average of ${this.debuffsPerCast} debuffs per cast.
 You wasted ${this.wastedApplications} possible applications with Sentinel ticking on targets who already had Hunter's Mark debuff.
 Out of ${this.totalPossibleTicks} possible ticks:

${this.goodTicks} ticks were good ticks where no target already had Hunter's Mark when it ticked.

${this.wastedTicks} ticks had one or more targets already with Hunter's Mark on them.

${this.buggedTicks} ticks bugged and didn't happen. This bug can somewhat be circumvented by not casting any spells right before you're meant to get a proc (every 6 seconds after cast).

`}
        footer={(

            <div
              className="stat-health-bg"
              style={{ width: `${(100 - formatPercentage((this.wastedTicks + this.buggedTicks) / this.totalPossibleTicks))}%` }}
              data-tip={`<b>${100 - formatPercentage((this.wastedTicks + this.buggedTicks) / this.totalPossibleTicks)}%</b> of your Sentinel ticks happened while none of the targets had a hunter's mark on them, good job!`}
            >

            <div
              className="DeathKnight-bg"
              style={{ width: `${formatPercentage(this.wastedApplications / this.totalPossibleTicks)}%` }}
              data-tip={`<b>${formatPercentage(this.wastedApplications / this.totalPossibleTicks)}%</b> of your Sentinel ticks happened while one of the targets already a hunter's mark on them.`}
            >

            <div
              className="Druid-bg"
              style={{ width: `${formatPercentage(this.buggedTicks / this.totalPossibleTicks)}%` }}
              data-tip={`${formatPercentage(this.buggedTicks / this.totalPossibleTicks)}% of your expected Sentinel ticks bugged and didn't happen. This bug can somewhat be circumvented by not casting any spells right before you're meant to get a proc (every 6 seconds after cast).`}
            >

        )}
        footerStyle={{ overflow: 'hidden' }}
      />
    );
  }
}

export default Sentinel;
<commit_msg>a bit more<commit_after>import React from 'react';

import Analyzer from 'Parser/Core/Analyzer';
import Combatants from 'Parser/Core/Modules/Combatants';

import SPELLS from 'common/SPELLS';
import StatisticBox from 'Main/StatisticBox';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';

/*
 * Your Sentinel watches over the target area for 18 sec, applying Hunter's Mark to all enemies every 6 sec.
 */
const MS_BUFFER = 100;

const SENTINEL_DURATION = 18000;

const TIME_BETWEEN_TICKS = 6000;

const TICKS_PER_CAST = 4;

class Sentinel extends Analyzer {
  static dependencies = {
    combatants: Combatants,

  };
  damage = 0;
  applyDebuffTimestamp = null;
  sentinelCasts = 0;
  sentinelTicks = 0;
  appliedDebuffsFromSentinel = 0;
  wastedApplications = 0;
  wastedTicks = 0;
  lastBadTickTimestamp = 0;
  lastSentinelCastTimestamp = 0;
  lostTicksFromCombatEnd = 0;

  on_initialized() {
    this.active = this.combatants.selected.hasTalent(SPELLS.SENTINEL_TALENT.id);
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.SENTINEL_TICK.id && spellId !== SPELLS.SENTINEL_TALENT.id) {
      return;
    }
    if (spellId === SPELLS.SENTINEL_TALENT.id) {
      this.lastSentinelCastTimestamp = event.timestamp;
      this.sentinelCasts++;
    }
    if (spellId === SPELLS.SENTINEL_TICK.id) {
      this.applyDebuffTimestamp = event.timestamp;
      this.sentinelTicks++;
    }
  }
  on_byPlayer_applydebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.HUNTERS_MARK_DEBUFF.id) {
      return;
    }
    if (event.timestamp < this.applyDebuffTimestamp + MS_BUFFER && event.timestamp >= this.applyDebuffTimestamp) {
      this.appliedDebuffsFromSentinel++;
    }
  }
  on_byPlayer_refreshdebuff(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.HUNTERS_MARK_DEBUFF.id) {
      return;
    }
    if (event.timestamp < this.applyDebuffTimestamp + MS_BUFFER && event.timestamp >= this.applyDebuffTimestamp) {
      this.wastedApplications++;
      if (this.lastBadTickTimestamp !== event.timestamp) {
        this.wastedTicks++;
        this.lastBadTickTimestamp = event.timestamp;
      }
    }
  }

  get debuffsPerCast() {
    return (this.appliedDebuffsFromSentinel / this.sentinelCasts).toFixed(1);
  }
  get totalPossibleTicks() {
    return (this.sentinelCasts * TICKS_PER_CAST) - this.lostTicksFromCombatEnd;
  }
  get buggedTicks() {
    return this.totalPossibleTicks - this.sentinelTicks;
  }
  get goodTicks() {
    return this.totalPossibleTicks - this.buggedTicks - this.wastedTicks;
  }

  on_finished() {
    if (this.lastSentinelCastTimestamp > (this.owner.fight.end_time - SENTINEL_DURATION)) {
      const timeLostOnSentinel = this.owner.fight.end_time - this.lastSentinelCastTimestamp;
      this.lostTicksFromCombatEnd = Math.floor(timeLostOnSentinel / TIME_BETWEEN_TICKS);
    }
  }

  statistic() {
    return (
      <StatisticBox
        icon={<SpellIcon id={SPELLS.SENTINEL_TALENT.id} />}
        value={`${this.goodTicks}/${this.totalPossibleTicks}`}
        label={`flawless ticks + ${this.buggedTicks} bugged`}
        tooltip={`You applied Hunter's Mark with Sentinel ${this.appliedDebuffsFromSentinel} times spread over ${this.sentinelCasts} casts of Sentinel. This gives an average of ${this.debuffsPerCast} debuffs per cast.
 You wasted ${this.wastedApplications} possible applications with Sentinel ticking on targets who already had Hunter's Mark debuff.
 Out of ${this.totalPossibleTicks} possible ticks:

${this.goodTicks} ticks were good ticks where no target already had Hunter's Mark when it ticked.

${this.wastedTicks} ticks had one or more targets already with Hunter's Mark on them.

${this.buggedTicks} ticks bugged and didn't happen. It's a bug on Blizzard's end, and we can only hope it gets fixed soon. This bug can somewhat be circumvented by not casting any spells right before you're meant to get a proc (every 6 seconds after cast).

`}
        footer={(

            <div
              className="stat-health-bg"
              style={{ width: `${(100 - formatPercentage((this.wastedTicks + this.buggedTicks) / this.totalPossibleTicks))}%` }}
              data-tip={`<b>${100 - formatPercentage((this.wastedTicks + this.buggedTicks) / this.totalPossibleTicks)}%</b> of your Sentinel ticks happened while none of the targets had a hunter's mark on them, good job!`}
            >

            <div
              className="DeathKnight-bg"
              style={{ width: `${formatPercentage(this.wastedApplications / this.totalPossibleTicks)}%` }}
              data-tip={`<b>${formatPercentage(this.wastedApplications / this.totalPossibleTicks)}%</b> of your Sentinel ticks happened while one of the targets already a hunter's mark on them.`}
            >

            <div
              className="Druid-bg"
              style={{ width: `${formatPercentage(this.buggedTicks / this.totalPossibleTicks)}%` }}
              data-tip={`${formatPercentage(this.buggedTicks / this.totalPossibleTicks)}% of your expected Sentinel ticks bugged and didn't happen. It's a bug on Blizzard's end, and we can only hope it gets fixed soon.  This bug can somewhat be circumvented by not casting any spells right before you're meant to get a proc (every 6 seconds after cast).`}
            >

        )}
        footerStyle={{ overflow: 'hidden' }}
      />
    );
  }
}

export default Sentinel;
<|endoftext|>


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

test('return undefined when no change', () => {
  expect(
    diffToSemver(
      { color: '#000000', bg: '#000000' },
      { bg: '#000000', color: '#000000' }
    )
  ).toBeUndefined();
});

test("return 'major' when there is a breaking change on current keys", () => {
  expect(
    diffToSemver(
      { color: '#000000', bg: '#000000' },
      { supercolor: '#000000', bg: '#000000' }
    )
  ).toBe('major');
});

test("return 'minor' new keys are added", () => {
  expect(
    diffToSemver(
      { color: '#000000' },
      { color: '#000000', supercolor: '#000000' }
    )
  ).toBe('minor');
});

test("return 'patch' new values are changed", () => {
  expect(
    diffToSemver(
      { color: '#000000', bg: '#000000' },
      { bg: '#000000', color: '#000001' }
    )
  ).toBe('patch');
});
<commit_msg>moare tests for the diffToSemver resolver<commit_after>const diffToSemver = require('../diffToSemver');

test('return undefined when no change', () => {
  expect(
    diffToSemver(
      { color: '#000000', bg: '#000000' },
      { bg: '#000000', color: '#000000' }
    )
  ).toBeUndefined();
});

test("return 'major' when there is a breaking change on current keys", () => {
  expect(
    diffToSemver(
      { color: '#000000', bg: '#000000' },
      { supercolor: '#000000', bg: '#000000' }
    )
  ).toBe('major');

  expect(
    diffToSemver({ color: '#000000', bg: '#000000' }, { bg: '#000000' })
  ).toBe('major');
});

test("return 'minor' new keys are added", () => {
  expect(
    diffToSemver(
      { color: '#000000' },
      { color: '#000000', supercolor: '#000000' }
    )
  ).toBe('minor');
});

test("return 'patch' new values are changed", () => {
  expect(
    diffToSemver(
      { color: '#000000', bg: '#000000' },
      { bg: '#000000', color: '#000001' }
    )
  ).toBe('patch');
});
<|endoftext|>


<commit_before>import path from 'path';

import {CompositeDisposable} from 'atom';

import {GitProcess} from 'git-kitchen-sink';
import {parse as parseDiff} from 'what-the-diff';

import GitPromptServer from './git-prompt-server';
import AsyncQueue from './async-queue';
import {readFile, fsStat} from './helpers';

const LINE_ENDING_REGEX = /\r?\n/;

const GPG_HELPER_PATH = path.resolve(__dirname, '..', 'bin', 'gpg-no-tty.sh');

export class GitError extends Error {
  constructor(message, stdErr) {
    super(message);
    this.message = message;
    this.stdErr = stdErr;
    this.stack = new Error().stack;
  }
}

/**
 * Prepend the git arguments that will intercept any `gpg` calls with the `gpg-no-tty.sh` script.
 */
function withGpgScript(args) {
  return ['-c', `gpg.program=${GPG_HELPER_PATH}`].concat(args);
}

export default class GitShellOutStrategy {
  constructor(workingDir) {
    this.workingDir = workingDir;
    this.commandQueue = new AsyncQueue();
  }

  // Execute a command and read the output using the embedded Git environment
  exec(args, stdin = null, useGitPromptServer = false) {
    /* eslint-disable no-console */
    const subscriptions = new CompositeDisposable();
    return this.commandQueue.push(async () => {
      const formattedArgs = `git ${args.join(' ')} in ${this.workingDir}`;
      let gitPromptServer;
      const env = {};
      if (useGitPromptServer) {
        gitPromptServer = new GitPromptServer();
        const {socket, electron, launcher, helper} = await gitPromptServer.start();
        env.GIT_ASKPASS = launcher;
        env.ATOM_GITHUB_ELECTRON_PATH = electron;
        env.ATOM_GITHUB_CREDENTIAL_HELPER_SCRIPT_PATH = helper;
        env.ATOM_GITHUB_CREDENTIAL_HELPER_SOCK_PATH = socket;
      }

      const options = {
        env,
        processCallback: child => {
          child.on('error', err => {
            console.error('Error executing: ' + formattedArgs);
            console.error(err.stack);
          });
          child.stdin.on('error', err => {
            console.error('Error writing to process: ' + formattedArgs);
            console.error(err.stack);
            console.error('Tried to write: ' + stdin);
          });
          if (gitPromptServer) {
            subscriptions.add(gitPromptServer.onDidCancel(() => {
              require('tree-kill')(child.pid);
            }));
          }
        },
      };

      if (stdin) {
        options.stdin = stdin;
        options.stdinEncoding = 'utf8';
      }

      if (process.env.PRINT_GIT_TIMES) {
        console.time(`git:${formattedArgs}`);
      }
      return GitProcess.exec(args, this.workingDir, options)
        .then(({stdout, stderr, exitCode}) => {
          if (process.env.PRINT_GIT_TIMES) {
            console.timeEnd(`git:${formattedArgs}`);
          }
          if (gitPromptServer) {
            gitPromptServer.terminate();
          }
          subscriptions.dispose();
          if (exitCode) {
            const err = new GitError(
              `${formattedArgs} exited with code ${exitCode}\nstdout: ${stdout}\nstderr: ${stderr}`,
              stderr,
            );
            err.code = exitCode;
            err.command = formattedArgs;
            return Promise.reject(err);
          }
          return stdout;
        });
    });
    /* eslint-enable no-console */
  }

  /**
   * Execute a git command that may create a commit. If the command fails because the GPG binary was invoked and unable
   * to acquire a passphrase (because the pinentry program attempted to use a tty), retry with a `GitPromptServer`.
   */
  gpgExec(args, stdin = null) {
    const gpgArgs = withGpgScript(args);
    return this.exec(gpgArgs, stdin).catch(err => {
      if (err.code === 128 && /gpg failed/.test(err.stdErr)) {
        // Retry with a GitPromptServer
        return this.exec(gpgArgs, stdin, true);
      } else {
        throw err;
      }
    });
  }

  async isGitRepository() {
    try {
      await this.exec(['rev-parse', '--resolve-git-dir', path.join(this.workingDir, '.git')]);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * Staging/Unstaging files and patches and committing
   */
  stageFiles(paths) {
    if (paths.length === 0) { return null; }
    const args = ['add'].concat(paths);
    return this.exec(args);
  }

  unstageFiles(paths, commit = 'HEAD') {
    if (paths.length === 0) { return null; }
    const args = ['reset', commit, '--'].concat(paths);
    return this.exec(args);
  }

  applyPatchToIndex(patch) {
    return this.exec(['apply', '--cached', '-'], patch);
  }

  commit(message, {allowEmpty, amend} = {}) {
    const args = ['commit', '-m', message];
    if (amend) { args.push('--amend'); }
    if (allowEmpty) { args.push('--allow-empty'); }
    return this.gpgExec(args);
  }

  /**
   * File Status and Diffs
   */
  async getStatusesForChangedFiles() {
    const output = await this.exec(['status', '--untracked-files=all', '-z']);

    const statusMap = {
      'A': 'added',
      'M': 'modified',
      'D': 'deleted',
      'U': 'modified',
      '?': 'added',
    };

    const stagedFiles = {};
    const unstagedFiles = {};
    const mergeConflictFiles = {};
    let statusToHead;

    if (output) {
      const lines = output.split('\0');
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        if (line === '') { continue; }
        const [_, x, y, filePath] = line.match(/(.)(.)\s(.*)/); // eslint-disable-line no-unused-vars
        if (x === 'U' || y === 'U' || (x === 'A' && y === 'A')) {
          // Skipping this check here because we only run a single `await`
          // and we only run it in the main, synchronous body of the for loop.
          // eslint-disable-next-line babel/no-await-in-loop
          if (!statusToHead) { statusToHead = await this.diffFileStatus({target: 'HEAD'}); }
          mergeConflictFiles[filePath] = {
            ours: statusMap[x],
            theirs: statusMap[y],
            file: statusToHead[filePath] || 'equivalent',
          };
          continue;
        }
        if (x === 'R') {
          stagedFiles[filePath] = 'added';
          stagedFiles[lines[++i]] = 'deleted';
          continue;
        }
        if (y !== ' ') {
          unstagedFiles[filePath] = statusMap[y];
        }
        if (x !== ' ' && x !== '?') {
          stagedFiles[filePath] = statusMap[x];
        }
      }
    }

    return {stagedFiles, unstagedFiles, mergeConflictFiles};
  }

  async diffFileStatus(options = {}) {
    const args = ['diff', '--name-status', '--no-renames'];
    if (options.staged) { args.push('--staged'); }
    if (options.target) { args.push(options.target); }
    if (options.diffFilter === 'unmerged') { args.push('--diff-filter=U'); }
    const output = await this.exec(args);

    const statusMap = {
      A: 'added',
      M: 'modified',
      D: 'deleted',
      U: 'unmerged',
    };

    const fileStatuses = {};
    output && output.trim().split(LINE_ENDING_REGEX).forEach(line => {
      const [status, filePath] = line.split('\t');
      fileStatuses[filePath] = statusMap[status];
    });
    if (!options.staged) {
      const untracked = await this.getUntrackedFiles();
      untracked.forEach(filePath => { fileStatuses[filePath] = 'added'; });
    }
    return fileStatuses;
  }

  async getUntrackedFiles() {
    const output = await this.exec(['ls-files', '--others', '--exclude-standard']);
    if (output.trim() === '') { return []; }
    return output.trim().split(LINE_ENDING_REGEX);
  }

  async getDiffForFilePath(filePath, {staged, baseCommit} = {}) {
    let args = ['diff', '--no-prefix', '--no-renames', '--diff-filter=u'];
    if (staged) { args.push('--staged'); }
    if (baseCommit) { args.push(baseCommit); }
    args = args.concat(['--', filePath]);
    const output = await this.exec(args);

    let rawDiffs = [];
    if (output) { rawDiffs = parseDiff(output).filter(rawDiff => rawDiff.status !== 'unmerged'); }

    if (!staged && (await this.getUntrackedFiles()).includes(filePath)) {
      // add untracked file
      const absPath = path.join(this.workingDir, filePath);
      const stats = await fsStat(absPath);
      const contents = await readFile(absPath);
      rawDiffs.push(buildAddedFilePatch(filePath, contents, stats));
    }
    if (rawDiffs.length > 1) { throw new Error(`Expected 0 or 1 diffs for ${filePath} but got ${rawDiffs.length}`); }
    return rawDiffs[0];
  }

  /**
   * Miscellaneous getters
   */
  async getCommit(ref) {
    const output = await this.exec(['log', '--pretty=%H%x00%B%x00', '--no-abbrev-commit', '-1', ref]);
    const [sha, message] = (output).split('\0');
    return {sha, message: message.trim()};
  }

  getHeadCommit() {
    return this.getCommit('HEAD');
  }

  readFileFromIndex(filePath) {
    return this.exec(['show', `:${filePath}`]);
  }

  /**
   * Merge
   */
  merge(branchName) {
    return this.exec(['merge', branchName]);
  }

  async isMerging() {
    try {
      await readFile(path.join(this.workingDir, '.git', 'MERGE_HEAD'));
      return true;
    } catch (e) {
      return false;
    }
  }

  abortMerge() {
    return this.exec(['merge', '--abort']);
  }

  /**
   * Remote interactions
   */
  clone(remoteUrl, options = {}) {
    const args = ['clone', '--no-local', remoteUrl, this.workingDir];
    if (options.bare) { args.push('--bare'); }
    return this.exec(args);
  }

  async getRemoteForBranch(branchName) {
    try {
      const output = await this.exec(['config', `branch.${branchName}.remote`]);
      return output.trim();
    } catch (e) {
      return null;
    }
  }

  async fetch(branchName) {
    const remote = await this.getRemoteForBranch(branchName);
    return this.exec(['fetch', remote, branchName], null, true);
  }

  async pull(branchName) {
    const remote = await this.getRemoteForBranch(branchName);
    return this.exec(['pull', remote, branchName], null, true);
  }

  async push(branchName, options = {}) {
    const remote = await this.getRemoteForBranch(branchName);
    const args = ['push', remote || 'origin', branchName];
    if (options.setUpstream) { args.push('--set-upstream'); }
    if (options.force) { args.push('--force'); }
    return this.exec(args, null, true);
  }

  async getAheadCount(branchName) {
    try {
      const pushTrackingBranch = await this.exec(['rev-parse', '--symbolic-full-name', `${branchName}@{push}`]);
      const output = await this.exec(['rev-list', `${pushTrackingBranch.trim()}..heads/${branchName}`]);
      return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length;
    } catch (e) {
      return null;
    }
  }

  async getBehindCount(branchName) {
    try {
      const upstreamTrackingBranch = await this.exec(['rev-parse', '--symbolic-full-name', `${branchName}@{upstream}`]);
      const output = await this.exec(['rev-list', `heads/${branchName}..${upstreamTrackingBranch.trim()}`]);
      return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length;
    } catch (e) {
      return null;
    }
  }

  /**
   * Branches
   */
  async getCurrentBranch() {
    const output = await this.exec(['rev-parse', '--abbrev-ref', 'HEAD']);
    return output.trim();
  }

  checkout(branchName, options = {}) {
    const args = ['checkout'];
    if (options.createNew) { args.push('-b'); }
    return this.exec(args.concat(branchName));
  }

  async getBranches() {
    const output = await this.exec(['branch']);
    return output.trim().split(LINE_ENDING_REGEX)
      .map(branchName => branchName.trim().replace(/^\* /, ''));
  }
}

function buildAddedFilePatch(filePath, contents, stats) {
  const hunks = [];
  if (contents) {
    const noNewLine = contents[contents.length - 1] !== '\n';
    const lines = contents.trim().split(LINE_ENDING_REGEX).map(line => `+${line}`);
    if (noNewLine) { lines.push('\\ No newline at end of file'); }
    hunks.push({
      lines,
      oldStartLine: 0,
      oldLineCount: 0,
      newStartLine: 1,
      newLineCount: noNewLine ? lines.length - 1 : lines.length,
    });
  }
  const executable = Boolean((stats >> 6) && 1); // eslint-disable-line no-bitwise
  return {
    oldPath: null,
    newPath: filePath,
    oldMode: null,
    newMode: executable ? '100755' : '100644',
    status: 'added',
    hunks,
  };
}
<commit_msg>Use `gpgExec()` for other methods that may create commits<commit_after>import path from 'path';

import {CompositeDisposable} from 'atom';

import {GitProcess} from 'git-kitchen-sink';
import {parse as parseDiff} from 'what-the-diff';

import GitPromptServer from './git-prompt-server';
import AsyncQueue from './async-queue';
import {readFile, fsStat} from './helpers';

const LINE_ENDING_REGEX = /\r?\n/;

const GPG_HELPER_PATH = path.resolve(__dirname, '..', 'bin', 'gpg-no-tty.sh');

export class GitError extends Error {
  constructor(message, stdErr) {
    super(message);
    this.message = message;
    this.stdErr = stdErr;
    this.stack = new Error().stack;
  }
}

/**
 * Prepend the git arguments that will intercept any `gpg` calls with the `gpg-no-tty.sh` script.
 */
function withGpgScript(args) {
  return ['-c', `gpg.program=${GPG_HELPER_PATH}`].concat(args);
}

export default class GitShellOutStrategy {
  constructor(workingDir) {
    this.workingDir = workingDir;
    this.commandQueue = new AsyncQueue();
  }

  // Execute a command and read the output using the embedded Git environment
  exec(args, stdin = null, useGitPromptServer = false) {
    /* eslint-disable no-console */
    const subscriptions = new CompositeDisposable();
    return this.commandQueue.push(async () => {
      const formattedArgs = `git ${args.join(' ')} in ${this.workingDir}`;
      let gitPromptServer;
      const env = {};
      if (useGitPromptServer) {
        gitPromptServer = new GitPromptServer();
        const {socket, electron, launcher, helper} = await gitPromptServer.start();
        env.GIT_ASKPASS = launcher;
        env.ATOM_GITHUB_ELECTRON_PATH = electron;
        env.ATOM_GITHUB_CREDENTIAL_HELPER_SCRIPT_PATH = helper;
        env.ATOM_GITHUB_CREDENTIAL_HELPER_SOCK_PATH = socket;
      }

      const options = {
        env,
        processCallback: child => {
          child.on('error', err => {
            console.error('Error executing: ' + formattedArgs);
            console.error(err.stack);
          });
          child.stdin.on('error', err => {
            console.error('Error writing to process: ' + formattedArgs);
            console.error(err.stack);
            console.error('Tried to write: ' + stdin);
          });
          if (gitPromptServer) {
            subscriptions.add(gitPromptServer.onDidCancel(() => {
              require('tree-kill')(child.pid);
            }));
          }
        },
      };

      if (stdin) {
        options.stdin = stdin;
        options.stdinEncoding = 'utf8';
      }

      if (process.env.PRINT_GIT_TIMES) {
        console.time(`git:${formattedArgs}`);
      }
      return GitProcess.exec(args, this.workingDir, options)
        .then(({stdout, stderr, exitCode}) => {
          if (process.env.PRINT_GIT_TIMES) {
            console.timeEnd(`git:${formattedArgs}`);
          }
          if (gitPromptServer) {
            gitPromptServer.terminate();
          }
          subscriptions.dispose();
          if (exitCode) {
            const err = new GitError(
              `${formattedArgs} exited with code ${exitCode}\nstdout: ${stdout}\nstderr: ${stderr}`,
              stderr,
            );
            err.code = exitCode;
            err.command = formattedArgs;
            return Promise.reject(err);
          }
          return stdout;
        });
    });
    /* eslint-enable no-console */
  }

  /**
   * Execute a git command that may create a commit. If the command fails because the GPG binary was invoked and unable
   * to acquire a passphrase (because the pinentry program attempted to use a tty), retry with a `GitPromptServer`.
   */
  gpgExec(args, stdin = null) {
    const gpgArgs = withGpgScript(args);
    return this.exec(gpgArgs, stdin).catch(err => {
      if (err.code === 128 && /gpg failed/.test(err.stdErr)) {
        // Retry with a GitPromptServer
        return this.exec(gpgArgs, stdin, true);
      } else {
        throw err;
      }
    });
  }

  async isGitRepository() {
    try {
      await this.exec(['rev-parse', '--resolve-git-dir', path.join(this.workingDir, '.git')]);
      return true;
    } catch (e) {
      return false;
    }
  }

  /**
   * Staging/Unstaging files and patches and committing
   */
  stageFiles(paths) {
    if (paths.length === 0) { return null; }
    const args = ['add'].concat(paths);
    return this.exec(args);
  }

  unstageFiles(paths, commit = 'HEAD') {
    if (paths.length === 0) { return null; }
    const args = ['reset', commit, '--'].concat(paths);
    return this.exec(args);
  }

  applyPatchToIndex(patch) {
    return this.exec(['apply', '--cached', '-'], patch);
  }

  commit(message, {allowEmpty, amend} = {}) {
    const args = ['commit', '-m', message];
    if (amend) { args.push('--amend'); }
    if (allowEmpty) { args.push('--allow-empty'); }
    return this.gpgExec(args);
  }

  /**
   * File Status and Diffs
   */
  async getStatusesForChangedFiles() {
    const output = await this.exec(['status', '--untracked-files=all', '-z']);

    const statusMap = {
      'A': 'added',
      'M': 'modified',
      'D': 'deleted',
      'U': 'modified',
      '?': 'added',
    };

    const stagedFiles = {};
    const unstagedFiles = {};
    const mergeConflictFiles = {};
    let statusToHead;

    if (output) {
      const lines = output.split('\0');
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        if (line === '') { continue; }
        const [_, x, y, filePath] = line.match(/(.)(.)\s(.*)/); // eslint-disable-line no-unused-vars
        if (x === 'U' || y === 'U' || (x === 'A' && y === 'A')) {
          // Skipping this check here because we only run a single `await`
          // and we only run it in the main, synchronous body of the for loop.
          // eslint-disable-next-line babel/no-await-in-loop
          if (!statusToHead) { statusToHead = await this.diffFileStatus({target: 'HEAD'}); }
          mergeConflictFiles[filePath] = {
            ours: statusMap[x],
            theirs: statusMap[y],
            file: statusToHead[filePath] || 'equivalent',
          };
          continue;
        }
        if (x === 'R') {
          stagedFiles[filePath] = 'added';
          stagedFiles[lines[++i]] = 'deleted';
          continue;
        }
        if (y !== ' ') {
          unstagedFiles[filePath] = statusMap[y];
        }
        if (x !== ' ' && x !== '?') {
          stagedFiles[filePath] = statusMap[x];
        }
      }
    }

    return {stagedFiles, unstagedFiles, mergeConflictFiles};
  }

  async diffFileStatus(options = {}) {
    const args = ['diff', '--name-status', '--no-renames'];
    if (options.staged) { args.push('--staged'); }
    if (options.target) { args.push(options.target); }
    if (options.diffFilter === 'unmerged') { args.push('--diff-filter=U'); }
    const output = await this.exec(args);

    const statusMap = {
      A: 'added',
      M: 'modified',
      D: 'deleted',
      U: 'unmerged',
    };

    const fileStatuses = {};
    output && output.trim().split(LINE_ENDING_REGEX).forEach(line => {
      const [status, filePath] = line.split('\t');
      fileStatuses[filePath] = statusMap[status];
    });
    if (!options.staged) {
      const untracked = await this.getUntrackedFiles();
      untracked.forEach(filePath => { fileStatuses[filePath] = 'added'; });
    }
    return fileStatuses;
  }

  async getUntrackedFiles() {
    const output = await this.exec(['ls-files', '--others', '--exclude-standard']);
    if (output.trim() === '') { return []; }
    return output.trim().split(LINE_ENDING_REGEX);
  }

  async getDiffForFilePath(filePath, {staged, baseCommit} = {}) {
    let args = ['diff', '--no-prefix', '--no-renames', '--diff-filter=u'];
    if (staged) { args.push('--staged'); }
    if (baseCommit) { args.push(baseCommit); }
    args = args.concat(['--', filePath]);
    const output = await this.exec(args);

    let rawDiffs = [];
    if (output) { rawDiffs = parseDiff(output).filter(rawDiff => rawDiff.status !== 'unmerged'); }

    if (!staged && (await this.getUntrackedFiles()).includes(filePath)) {
      // add untracked file
      const absPath = path.join(this.workingDir, filePath);
      const stats = await fsStat(absPath);
      const contents = await readFile(absPath);
      rawDiffs.push(buildAddedFilePatch(filePath, contents, stats));
    }
    if (rawDiffs.length > 1) { throw new Error(`Expected 0 or 1 diffs for ${filePath} but got ${rawDiffs.length}`); }
    return rawDiffs[0];
  }

  /**
   * Miscellaneous getters
   */
  async getCommit(ref) {
    const output = await this.exec(['log', '--pretty=%H%x00%B%x00', '--no-abbrev-commit', '-1', ref]);
    const [sha, message] = (output).split('\0');
    return {sha, message: message.trim()};
  }

  getHeadCommit() {
    return this.getCommit('HEAD');
  }

  readFileFromIndex(filePath) {
    return this.exec(['show', `:${filePath}`]);
  }

  /**
   * Merge
   */
  merge(branchName) {
    return this.gpgExec(['merge', branchName]);
  }

  async isMerging() {
    try {
      await readFile(path.join(this.workingDir, '.git', 'MERGE_HEAD'));
      return true;
    } catch (e) {
      return false;
    }
  }

  abortMerge() {
    return this.exec(['merge', '--abort']);
  }

  /**
   * Remote interactions
   */
  clone(remoteUrl, options = {}) {
    const args = ['clone', '--no-local', remoteUrl, this.workingDir];
    if (options.bare) { args.push('--bare'); }
    return this.exec(args);
  }

  async getRemoteForBranch(branchName) {
    try {
      const output = await this.exec(['config', `branch.${branchName}.remote`]);
      return output.trim();
    } catch (e) {
      return null;
    }
  }

  async fetch(branchName) {
    const remote = await this.getRemoteForBranch(branchName);
    return this.exec(['fetch', remote, branchName], null, true);
  }

  async pull(branchName) {
    const remote = await this.getRemoteForBranch(branchName);
    return this.gpgExec(['pull', remote, branchName], null, true);
  }

  async push(branchName, options = {}) {
    const remote = await this.getRemoteForBranch(branchName);
    const args = ['push', remote || 'origin', branchName];
    if (options.setUpstream) { args.push('--set-upstream'); }
    if (options.force) { args.push('--force'); }
    return this.exec(args, null, true);
  }

  async getAheadCount(branchName) {
    try {
      const pushTrackingBranch = await this.exec(['rev-parse', '--symbolic-full-name', `${branchName}@{push}`]);
      const output = await this.exec(['rev-list', `${pushTrackingBranch.trim()}..heads/${branchName}`]);
      return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length;
    } catch (e) {
      return null;
    }
  }

  async getBehindCount(branchName) {
    try {
      const upstreamTrackingBranch = await this.exec(['rev-parse', '--symbolic-full-name', `${branchName}@{upstream}`]);
      const output = await this.exec(['rev-list', `heads/${branchName}..${upstreamTrackingBranch.trim()}`]);
      return output.trim().split(LINE_ENDING_REGEX).filter(s => s.trim()).length;
    } catch (e) {
      return null;
    }
  }

  /**
   * Branches
   */
  async getCurrentBranch() {
    const output = await this.exec(['rev-parse', '--abbrev-ref', 'HEAD']);
    return output.trim();
  }

  checkout(branchName, options = {}) {
    const args = ['checkout'];
    if (options.createNew) { args.push('-b'); }
    return this.exec(args.concat(branchName));
  }

  async getBranches() {
    const output = await this.exec(['branch']);
    return output.trim().split(LINE_ENDING_REGEX)
      .map(branchName => branchName.trim().replace(/^\* /, ''));
  }
}

function buildAddedFilePatch(filePath, contents, stats) {
  const hunks = [];
  if (contents) {
    const noNewLine = contents[contents.length - 1] !== '\n';
    const lines = contents.trim().split(LINE_ENDING_REGEX).map(line => `+${line}`);
    if (noNewLine) { lines.push('\\ No newline at end of file'); }
    hunks.push({
      lines,
      oldStartLine: 0,
      oldLineCount: 0,
      newStartLine: 1,
      newLineCount: noNewLine ? lines.length - 1 : lines.length,
    });
  }
  const executable = Boolean((stats >> 6) && 1); // eslint-disable-line no-bitwise
  return {
    oldPath: null,
    newPath: filePath,
    oldMode: null,
    newMode: executable ? '100755' : '100644',
    status: 'added',
    hunks,
  };
}
<|endoftext|>


<commit_before>var CollideSpriteVsGroup = function (sprite, group, collideCallback, processCallback, callbackContext, overlapOnly)
{
    if (group.length === 0)
    {
        return;
    }

    var bodyA = sprite.body;

    //  Does sprite collide with anything?

    var minMax = this.treeMinMax;

    minMax.minX = bodyA.left;
    minMax.minY = bodyA.top;
    minMax.maxX = bodyA.right;
    minMax.maxY = bodyA.bottom;

    var results = this.tree.search(minMax);

    if (results.length < 2)
    {
        return;
    }

    var children = group.getChildren();

    for (var i = 0; i < children.length; i++)
    {
        var bodyB = children[i].body;

        if (!bodyB || bodyA === bodyB || results.indexOf(bodyB) === -1)
        {
            continue;
        }

        if (this.separate(bodyA, bodyB, processCallback, callbackContext, overlapOnly))
        {
            if (collideCallback)
            {
                collideCallback.call(callbackContext, bodyA.gameObject, bodyB.gameObject);
            }

            this._total++;
        }
    }
};

module.exports = CollideSpriteVsGroup;
<commit_msg>Now searches either the dynamic or static trees.<commit_after>var CONST = require('../const');

var CollideSpriteVsGroup = function (sprite, group, collideCallback, processCallback, callbackContext, overlapOnly)
{
    if (group.length === 0)
    {
        return;
    }

    var bodyA = sprite.body;

    //  Does sprite collide with anything?

    var minMax = this.treeMinMax;

    minMax.minX = bodyA.left;
    minMax.minY = bodyA.top;
    minMax.maxX = bodyA.right;
    minMax.maxY = bodyA.bottom;

    var results = (group.physicsType === CONST.DYNAMIC_BODY) ? this.tree.search(minMax) : this.staticTree.search(minMax);

    if (results.length === 0)
    {
        return;
    }

    var children = group.getChildren();

    for (var i = 0; i < children.length; i++)
    {
        var bodyB = children[i].body;

        if (!bodyB || bodyA === bodyB || results.indexOf(bodyB) === -1)
        {
            continue;
        }

        if (this.separate(bodyA, bodyB, processCallback, callbackContext, overlapOnly))
        {
            if (collideCallback)
            {
                collideCallback.call(callbackContext, bodyA.gameObject, bodyB.gameObject);
            }

            this._total++;
        }
    }
};

module.exports = CollideSpriteVsGroup;
<|endoftext|>


<commit_before>var app = angular.module('app', ['ngRoute','portal-filters', 'groupFactory', 'textAngular','angularFileUpload', 'profile_components'], function($interpolateProvider){
	$interpolateProvider.startSymbol('[[');
	$interpolateProvider.endSymbol(']]');
});

app.config(['$routeProvider', '$locationProvider',
  function($routeProvider, $locationProvider) {
	$routeProvider.
	  when('/groups', {
		templateUrl: base_url+'assets/group/templates/groups.html',
		controller: 'GroupsCtrl'
	  }).
	  when('/groups/:group', {
		templateUrl: base_url+'assets/group/templates/group.html',
		controller: 'groupCtrl'
	  }).
	  otherwise({
		redirectTo: '/groups'
	  });
  }]);

app.controller('GroupsCtrl', function($scope, groupFactory, $log){
	$scope.status = 'loading';
	groupFactory.get().then(function(data){
		$scope.status = 'done';
		$scope.groups = data.groups;
		// $log.debug($scope.groups);
	});
});

app.controller('groupCtrl', function($scope, groupFactory, $log, $routeParams, profile_factory, $upload){

	$scope.base_url = base_url;
	$scope.tatoolbar = [['h1','h2','h3'],['bold','italics','underline'],['insertLink'],['ul', 'ol'],['insertImage']];

	groupFactory.get($routeParams.group).then(function(data){
        if(data.status=='ERROR') {
            $scope.error_upload_msg = data.message;
            $log.debug(data.message);
            location.href = 'cms#';
        }else{
            $scope.group = data;
        }
	});

	profile_factory.get_user().then(function(data){
		$scope.user = data;
		// $log.debug($scope.user);
		if($scope.user.function.indexOf('REGISTRY_SUPERUSER')!=-1) $scope.superuser = true;
		// $log.debug($scope.superuser);
	});

	$scope.save = function(state){

		$scope.saveMessage = 'loading...';
		// $log.debug(state);
		if(state) $scope.group.status = state;
		delete $scope.group.nodata;

		if(!$scope.group.data) $scope.group.data = {};
		if(!$scope.group.status) $scope.group.status = 'DRAFT';
		// $log.debug($scope.group);
		groupFactory.save($scope.group.name, $scope.group).then(function(data){
			$scope.saveMessage = data.message;
            $scope.contributor_form.$setPristine();
		});
	}

	//identifier operation deprecated in favor of html fields for identifiers
	$scope.addIdentifier = function() {
		if(!$scope.group.data) $scope.group.data = {};
		if($scope.group.data.identifiers) {
			$scope.group.data.identifiers.push(
				{type:'',value:''}
			)
		} else {
			$scope.group.data.identifiers = [
				{type:'',value:''}
			]
		}
	}

	$scope.upload = function(files) {
		if (files && files.length) {
			for (var i = 0; i < files.length; i++) {
				var file = files[i];
				$scope.uploading = true;
				delete $scope.error_upload_msg;
				$upload.upload({
					url: base_url+'group/upload',
					file: file
				}).progress(function (evt) {
					var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
					// $log.debug('progress: ' + progressPercentage + '% ' + evt.config.file.name);
				}).success(function (data, status, headers, config) {
					$scope.uploading = false;
					if(data.status == 'OK' && data.url) {
						if(!$scope.group.data) $scope.group.data = {};
						$scope.group.data.logo = data.url;
					} else if(data.status=='ERROR') {
						$scope.error_upload_msg = data.message;
					}
				});
			}
		}
	}
	$scope.removeIdentifier = function(index) {
		// $log.debug('removing identifier at index', index);
		$scope.group.data.identifiers.splice(index, 1);
	}
    $scope.$on('$locationChangeStart', function(ev, nextUrl) {
        if($scope.contributor_form.$dirty)
        {
            var r = confirm('You have unsaved changes. Would you like to save these before continuing?')
            if (r == true) {
                $scope.save();
            }
        }
    });
});

app.directive('resolveUser', function($log, $http, profile_factory) {
	return {
		template: '{{name}}',
		scope: {
			roleid: '='
		},
		transclude: true,
		link: function(scope) {
			scope.name = scope.roleid;
			scope.$watch('roleid', function(newv){
				if (newv) {
					profile_factory.get_specific_user(scope.roleid).then(function(data){
						if(data.name) scope.name = data.name;
					});
				}
			});
		}
	}
});<commit_msg>saved date and user refresh when contributor page saved<commit_after>var app = angular.module('app', ['ngRoute','portal-filters', 'groupFactory', 'textAngular','angularFileUpload', 'profile_components'], function($interpolateProvider){
	$interpolateProvider.startSymbol('[[');
	$interpolateProvider.endSymbol(']]');
});

app.config(['$routeProvider', '$locationProvider',
  function($routeProvider, $locationProvider) {
	$routeProvider.
	  when('/groups', {
		templateUrl: base_url+'assets/group/templates/groups.html',
		controller: 'GroupsCtrl'
	  }).
	  when('/groups/:group', {
		templateUrl: base_url+'assets/group/templates/group.html',
		controller: 'groupCtrl'
	  }).
	  otherwise({
		redirectTo: '/groups'
	  });
  }]);

app.controller('GroupsCtrl', function($scope, groupFactory, $log){
	$scope.status = 'loading';
	groupFactory.get().then(function(data){
		$scope.status = 'done';
		$scope.groups = data.groups;
		// $log.debug($scope.groups);
	});
});

app.controller('groupCtrl', function($scope, groupFactory, $log, $routeParams, profile_factory, $upload){

	$scope.base_url = base_url;
	$scope.tatoolbar = [['h1','h2','h3'],['bold','italics','underline'],['insertLink'],['ul', 'ol'],['insertImage']];

	groupFactory.get($routeParams.group).then(function(data){
        if(data.status=='ERROR') {
            $scope.error_upload_msg = data.message;
            $log.debug(data.message);
            location.href = 'cms#';
        }else{
            $scope.group = data;
        }
	});

	profile_factory.get_user().then(function(data){
		$scope.user = data;
		if($scope.user.function.indexOf('REGISTRY_SUPERUSER')!=-1) $scope.superuser = true;
		// $log.debug($scope.superuser);
	});

	$scope.save = function(state){

		$scope.saveMessage = 'loading...';
		// $log.debug(state);
		if(state) $scope.group.status = state;
		delete $scope.group.nodata;

		if(!$scope.group.data) $scope.group.data = {};
		if(!$scope.group.status) $scope.group.status = 'DRAFT';
        $scope.group.date_modified = new Date().toISOString();
        $scope.group.modified_who = $scope.user.name;
		// $log.debug($scope.group);
		groupFactory.save($scope.group.name, $scope.group).then(function(data){
			$scope.saveMessage = data.message;
            $scope.contributor_form.$setPristine();
		});
	}

	//identifier operation deprecated in favor of html fields for identifiers
	$scope.addIdentifier = function() {
		if(!$scope.group.data) $scope.group.data = {};
		if($scope.group.data.identifiers) {
			$scope.group.data.identifiers.push(
				{type:'',value:''}
			)
		} else {
			$scope.group.data.identifiers = [
				{type:'',value:''}
			]
		}
	}

	$scope.upload = function(files) {
		if (files && files.length) {
			for (var i = 0; i < files.length; i++) {
				var file = files[i];
				$scope.uploading = true;
				delete $scope.error_upload_msg;
				$upload.upload({
					url: base_url+'group/upload',
					file: file
				}).progress(function (evt) {
					var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
					// $log.debug('progress: ' + progressPercentage + '% ' + evt.config.file.name);
				}).success(function (data, status, headers, config) {
					$scope.uploading = false;
					if(data.status == 'OK' && data.url) {
						if(!$scope.group.data) $scope.group.data = {};
						$scope.group.data.logo = data.url;
					} else if(data.status=='ERROR') {
						$scope.error_upload_msg = data.message;
					}
				});
			}
		}
	}
	$scope.removeIdentifier = function(index) {
		// $log.debug('removing identifier at index', index);
		$scope.group.data.identifiers.splice(index, 1);
	}
    $scope.$on('$locationChangeStart', function(ev, nextUrl) {
        if($scope.contributor_form.$dirty)
        {
            var r = confirm('You have unsaved changes. Would you like to save these before continuing?')
            if (r == true) {
                $scope.save();
            }
        }
    });
});

app.directive('resolveUser', function($log, $http, profile_factory) {
	return {
		template: '{{name}}',
		scope: {
			roleid: '='
		},
		transclude: true,
		link: function(scope) {
			scope.name = scope.roleid;
			scope.$watch('roleid', function(newv){
				if (newv) {
					profile_factory.get_specific_user(scope.roleid).then(function(data){
						if(data.name) scope.name = data.name;
					});
				}
			});
		}
	}
});<|endoftext|>


<commit_before>/**
 * Bootstrap Modal wrapper for use with Backbone.
 *
 * Takes care of instantiation, manages multiple modals,
 * adds several options and removes the element from the DOM when closed
 *
 * @author Charles Davison <charlie@powmedia.co.uk>
 *
 * Events:
 * shown: Fired when the modal has finished animating in
 * hidden: Fired when the modal has finished animating out
 * cancel: The user dismissed the modal
 * ok: The user clicked OK
 */
(function($, _, Backbone) {

  //Set custom template settings
  var _interpolateBackup = _.templateSettings;
  _.templateSettings = {
    interpolate: /\{\{(.+?)\}\}/g,
    evaluate: /<%([\s\S]+?)%>/g
  }

  var template = _.template('\

\
    <% if (title) { %>\

\
        <% if (allowCancel) { %>\
          ×\
        <% } %>\

{{title}}
\

\
    <% } %>\

{{content}}
\

\
      <% if (allowCancel) { %>\
        <% if (cancelText) { %>\
          {{cancelText}}\
        <% } %>\
      <% } %>\
      {{okText}}\

\

\
  ');

  //Reset to users' template settings
  _.templateSettings = _interpolateBackup;

  var Modal = Backbone.View.extend({

    className: 'modal',

    events: {
      'click .close': function(event) {
        event.preventDefault();

        this.trigger('cancel');

        if (this.options.content && this.options.content.trigger) {
          this.options.content.trigger('cancel', this);
        }
      },
      'click .cancel': function(event) {
        event.preventDefault();

        this.trigger('cancel');

        if (this.options.content && this.options.content.trigger) {
          this.options.content.trigger('cancel', this);
        }
      },
      'click .ok': function(event) {
        event.preventDefault();

        this.trigger('ok');

        if (this.options.content && this.options.content.trigger) {
          this.options.content.trigger('ok', this);
        }

        if (this.options.okCloses) {
          this.close();
        }
      }
    },

    /**
     * Creates an instance of a Bootstrap Modal
     *
     * @see http://twitter.github.com/bootstrap/javascript.html#modals
     *
     * @param {Object} options
     * @param {String|View} [options.content] Modal content. Default: none
     * @param {String} [options.title]        Title. Default: none
     * @param {String} [options.okText]       Text for the OK button. Default: 'OK'
     * @param {String} [options.cancelText]   Text for the cancel button. Default: 'Cancel'. If passed a falsey value, the button will be removed
     * @param {Boolean} [options.allowCancel  Whether the modal can be closed, other than by pressing OK. Default: true
     * @param {Boolean} [options.escape]      Whether the 'esc' key can dismiss the modal. Default: true, but false if options.cancellable is true
     * @param {Boolean} [options.animate]     Whether to animate in/out. Default: false
     * @param {Function} [options.template]   Compiled underscore template to override the default one
     */
    initialize: function(options) {
      this.options = _.extend({
        title: null,
        okText: 'OK',
        focusOk: true,
        okCloses: true,
        cancelText: 'Cancel',
        allowCancel: true,
        escape: true,
        animate: false,
        template: template
      }, options);
    },

    /**
     * Creates the DOM element
     *
     * @api private
     */
    render: function() {
      var $el = this.$el,
          options = this.options,
          content = options.content;

      //Create the modal container
      $el.html(options.template(options));

      var $content = this.$content = $el.find('.modal-body')

      //Insert the main content if it's a view
      if (content.$el) {
        content.render();
        $el.find('.modal-body').html(content.$el);
      }

      if (options.animate) $el.addClass('fade');

      this.isRendered = true;

      return this;
    },

    /**
     * Renders and shows the modal
     *
     * @param {Function} [cb]     Optional callback that runs only when OK is pressed.
     */
    open: function(cb) {
      if (!this.isRendered) this.render();

      var self = this,
          $el = this.$el;

      //Create it
      $el.modal(_.extend({
        keyboard: this.options.allowCancel,
        backdrop: this.options.allowCancel ? true : 'static'
      }, this.options.modalOptions));

      //Focus OK button
      $el.one('shown', function() {
        if (self.options.focusOk) {
          $el.find('.btn.ok').focus();
        }

        if (self.options.content && self.options.content.trigger) {
          self.options.content.trigger('shown', self);
        }

        self.trigger('shown');
      });

      //Adjust the modal and backdrop z-index; for dealing with multiple modals
      var numModals = Modal.count,
          $backdrop = $('.modal-backdrop:eq('+numModals+')'),
          backdropIndex = parseInt($backdrop.css('z-index'),10),
          elIndex = parseInt($backdrop.css('z-index'), 10);

      $backdrop.css('z-index', backdropIndex + numModals);
      this.$el.css('z-index', elIndex + numModals);

      if (this.options.allowCancel) {
        $backdrop.one('click', function() {
          if (self.options.content && self.options.content.trigger) {
            self.options.content.trigger('cancel', self);
          }

          self.trigger('cancel');
        });

        $(document).one('keyup.dismiss.modal', function (e) {
          e.which == 27 && self.trigger('cancel');

          if (self.options.content && self.options.content.trigger) {
            e.which == 27 && self.options.content.trigger('shown', self);
          }
        });
      }

      this.on('cancel', function() {
        self.close();
      });

      Modal.count++;

      //Run callback on OK if provided
      if (cb) {
        self.on('ok', cb);
      }

      return this;
    },

    /**
     * Closes the modal
     */
    close: function() {
      var self = this,
          $el = this.$el;

      //Check if the modal should stay open
      if (this._preventClose) {
        this._preventClose = false;
        return;
      }

      $el.one('hidden', function onHidden(e) {
        // Ignore events propagated from interior objects, like bootstrap tooltips
        if(e.target !== e.currentTarget){
          return $el.one('hidden', onHidden);
        }
        self.remove();

        if (self.options.content && self.options.content.trigger) {
          self.options.content.trigger('hidden', self);
        }

        self.trigger('hidden');
      });

      $el.modal('hide');

      Modal.count--;
    },

    /**
     * Stop the modal from closing.
     * Can be called from within a 'close' or 'ok' event listener.
     */
    preventClose: function() {
      this._preventClose = true;
    }
  }, {
    //STATICS

    //The number of modals on display
    count: 0
  });

  //EXPORTS
  //CommonJS
  if (typeof require == 'function' && typeof module !== 'undefined' && exports) {
    module.exports = Modal;
  }

  //AMD / RequireJS
  if (typeof define === 'function' && define.amd) {
    return define(function() {
      Backbone.BootstrapModal = Modal;
    })
  }

  //Regular; add to Backbone.Bootstrap.Modal
  else {
    Backbone.BootstrapModal = Modal;
  }

})(jQuery, _, Backbone);
<commit_msg>modal header fixes<commit_after>/**
 * Bootstrap Modal wrapper for use with Backbone.
 *
 * Takes care of instantiation, manages multiple modals,
 * adds several options and removes the element from the DOM when closed
 *
 * @author Charles Davison <charlie@powmedia.co.uk>
 *
 * Events:
 * shown: Fired when the modal has finished animating in
 * hidden: Fired when the modal has finished animating out
 * cancel: The user dismissed the modal
 * ok: The user clicked OK
 */
(function($, _, Backbone) {

  //Set custom template settings
  var _interpolateBackup = _.templateSettings;
  _.templateSettings = {
    interpolate: /\{\{(.+?)\}\}/g,
    evaluate: /<%([\s\S]+?)%>/g
  }

  var template = _.template('\

\
    <% if (title) { %>\

\
        <% if (allowCancel) { %>\
          ×\
        <% } %>\

{{title}}
\

\
    <% } %>\

{{content}}
\

\
      <% if (allowCancel) { %>\
        <% if (cancelText) { %>\
          {{cancelText}}\
        <% } %>\
      <% } %>\
      {{okText}}\

\

\
  ');

  //Reset to users' template settings
  _.templateSettings = _interpolateBackup;

  var Modal = Backbone.View.extend({

    className: 'modal',

    events: {
      'click .close': function(event) {
        event.preventDefault();

        this.trigger('cancel');

        if (this.options.content && this.options.content.trigger) {
          this.options.content.trigger('cancel', this);
        }
      },
      'click .cancel': function(event) {
        event.preventDefault();

        this.trigger('cancel');

        if (this.options.content && this.options.content.trigger) {
          this.options.content.trigger('cancel', this);
        }
      },
      'click .ok': function(event) {
        event.preventDefault();

        this.trigger('ok');

        if (this.options.content && this.options.content.trigger) {
          this.options.content.trigger('ok', this);
        }

        if (this.options.okCloses) {
          this.close();
        }
      }
    },

    /**
     * Creates an instance of a Bootstrap Modal
     *
     * @see http://twitter.github.com/bootstrap/javascript.html#modals
     *
     * @param {Object} options
     * @param {String|View} [options.content] Modal content. Default: none
     * @param {String} [options.title]        Title. Default: none
     * @param {String} [options.okText]       Text for the OK button. Default: 'OK'
     * @param {String} [options.cancelText]   Text for the cancel button. Default: 'Cancel'. If passed a falsey value, the button will be removed
     * @param {Boolean} [options.allowCancel  Whether the modal can be closed, other than by pressing OK. Default: true
     * @param {Boolean} [options.escape]      Whether the 'esc' key can dismiss the modal. Default: true, but false if options.cancellable is true
     * @param {Boolean} [options.animate]     Whether to animate in/out. Default: false
     * @param {Function} [options.template]   Compiled underscore template to override the default one
     */
    initialize: function(options) {
      this.options = _.extend({
        title: null,
        okText: 'OK',
        focusOk: true,
        okCloses: true,
        cancelText: 'Cancel',
        allowCancel: true,
        escape: true,
        animate: false,
        template: template
      }, options);
    },

    /**
     * Creates the DOM element
     *
     * @api private
     */
    render: function() {
      var $el = this.$el,
          options = this.options,
          content = options.content;

      //Create the modal container
      $el.html(options.template(options));

      var $content = this.$content = $el.find('.modal-body')

      //Insert the main content if it's a view
      if (content.$el) {
        content.render();
        $el.find('.modal-body').html(content.$el);
      }

      if (options.animate) $el.addClass('fade');

      this.isRendered = true;

      return this;
    },

    /**
     * Renders and shows the modal
     *
     * @param {Function} [cb]     Optional callback that runs only when OK is pressed.
     */
    open: function(cb) {
      if (!this.isRendered) this.render();

      var self = this,
          $el = this.$el;

      //Create it
      $el.modal(_.extend({
        keyboard: this.options.allowCancel,
        backdrop: this.options.allowCancel ? true : 'static'
      }, this.options.modalOptions));

      //Focus OK button
      $el.one('shown', function() {
        if (self.options.focusOk) {
          $el.find('.btn.ok').focus();
        }

        if (self.options.content && self.options.content.trigger) {
          self.options.content.trigger('shown', self);
        }

        self.trigger('shown');
      });

      //Adjust the modal and backdrop z-index; for dealing with multiple modals
      var numModals = Modal.count,
          $backdrop = $('.modal-backdrop:eq('+numModals+')'),
          backdropIndex = parseInt($backdrop.css('z-index'),10),
          elIndex = parseInt($backdrop.css('z-index'), 10);

      $backdrop.css('z-index', backdropIndex + numModals);
      this.$el.css('z-index', elIndex + numModals);

      if (this.options.allowCancel) {
        $backdrop.one('click', function() {
          if (self.options.content && self.options.content.trigger) {
            self.options.content.trigger('cancel', self);
          }

          self.trigger('cancel');
        });

        $(document).one('keyup.dismiss.modal', function (e) {
          e.which == 27 && self.trigger('cancel');

          if (self.options.content && self.options.content.trigger) {
            e.which == 27 && self.options.content.trigger('shown', self);
          }
        });
      }

      this.on('cancel', function() {
        self.close();
      });

      Modal.count++;

      //Run callback on OK if provided
      if (cb) {
        self.on('ok', cb);
      }

      return this;
    },

    /**
     * Closes the modal
     */
    close: function() {
      var self = this,
          $el = this.$el;

      //Check if the modal should stay open
      if (this._preventClose) {
        this._preventClose = false;
        return;
      }

      $el.one('hidden', function onHidden(e) {
        // Ignore events propagated from interior objects, like bootstrap tooltips
        if(e.target !== e.currentTarget){
          return $el.one('hidden', onHidden);
        }
        self.remove();

        if (self.options.content && self.options.content.trigger) {
          self.options.content.trigger('hidden', self);
        }

        self.trigger('hidden');
      });

      $el.modal('hide');

      Modal.count--;
    },

    /**
     * Stop the modal from closing.
     * Can be called from within a 'close' or 'ok' event listener.
     */
    preventClose: function() {
      this._preventClose = true;
    }
  }, {
    //STATICS

    //The number of modals on display
    count: 0
  });

  //EXPORTS
  //CommonJS
  if (typeof require == 'function' && typeof module !== 'undefined' && exports) {
    module.exports = Modal;
  }

  //AMD / RequireJS
  if (typeof define === 'function' && define.amd) {
    return define(function() {
      Backbone.BootstrapModal = Modal;
    })
  }

  //Regular; add to Backbone.Bootstrap.Modal
  else {
    Backbone.BootstrapModal = Modal;
  }

})(jQuery, _, Backbone);
<|endoftext|>


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

sc_require('components/graph/utilities/graph_drop_target');
sc_require('views/raphael_base');

/** @class  DG.PlotBackgroundView - The base class view for a plot.

  @extends DG.RaphaelBaseView
*/
DG.PlotBackgroundView = DG.RaphaelBaseView.extend( DG.GraphDropTarget,
/** @scope DG.PlotBackgroundView.prototype */
{
  autoDestroyProperties: [ '_backgroundForClick' ],

  displayProperties: ['xAxisView.model.lowerBound', 'xAxisView.model.upperBound',
                      'yAxisView.model.lowerBound', 'yAxisView.model.upperBound',
                      'xAxisView.model.attributeDescription.attributeStats.categoricalStats.numberOfCells',
                      'yAxisView.model.attributeDescription.attributeStats.categoricalStats.numberOfCells'],

  /**
   * @property {DG.GraphModel}
   */
  graphModel: null,

  /**
    @property { DG.AxisView}
  */
  xAxisView: null,
  /**
    @property { DG.AxisView }
  */
  yAxisView: null,

  // Private properties
  _backgroundForClick: null,  // We make this once and keep it sized properly.

  /**
   * Additional setup after creating the view
   */
  didCreateLayer:function () {
    var tGraphView = this.get( 'parentView' );
    sc_super();
    tGraphView.get( 'plotViews' ).forEach( function ( iPlotView ) {
      iPlotView.didCreateLayer();
    } );
    tGraphView.drawPlots();
  },

  /**
   * Subclasses can override calling sc_super() and then adding layers at will.
   */
  initLayerManager: function() {
    sc_super();

    var ln = DG.LayerNames;
    this.get('layerManager').addNamedLayer( ln.kBackground )
                  .addNamedLayer( ln.kGrid )
                  .addNamedLayer( ln.kIntervalShading )
                  .addNamedLayer( ln.kClick )
                  .addNamedLayer( ln.kGhost )
                  .addNamedLayer( ln.kConnectingLines )
                  .addNamedLayer( ln.kPoints )
                  .addNamedLayer( ln.kSelectedPoints )
                  .addNamedLayer( ln.kAdornments )
                  .addNamedLayer( ln.kDataTip );
  },

  /**
    We just have the background to draw. But it has a marquee behavior and a background click
    behavior to install.
  */
  doDraw: function doDraw() {
    var this_ = this,
        tFrame = this.get('frame' ),
        tXAxisView = this.get('xAxisView'),
        tYAxisView = this.get('yAxisView'),
        tBackgroundLayer = this.getPath('layerManager.' + DG.LayerNames.kBackground ),
        tGridLayer = this.getPath('layerManager.' + DG.LayerNames.kGrid),
        tBothWaysNumeric =( tXAxisView.get('isNumeric') && tYAxisView.get('isNumeric')),
        tMarquee,
        tStartPt,
        tBaseSelection = [],
        tHaveShowZoomTip = false,
        tToolTip;

    function createRulerLines() {

      function vLine( iX, iColor, iWidth) {
        tGridLayer.push(
          this_._paper.line( iX, tFrame.height, iX, 0)
                .attr( { stroke: iColor, 'stroke-width': iWidth }));
      }

      function hLine( iY, iColor, iWidth) {
        tGridLayer.push(
          this_._paper.line( 0, iY, tFrame.width, iY)
                  .attr( { stroke: iColor, 'stroke-width': iWidth }));
      }

      function drawVRule( iValue, iX) {
        vLine( iX, DG.PlotUtilities.kRuleColor, DG.PlotUtilities.kRuleWidth);
      }

      function drawHRule( iValue, iY) {
        hLine( iY, DG.PlotUtilities.kRuleColor, DG.PlotUtilities.kRuleWidth);
      }

      function drawZeroLines() {

        function drawLine( iAxisView, iDrawingFunc) {
          var tZeroCoord = iAxisView.get('zeroPixel');
          if( tZeroCoord)
            iDrawingFunc( tZeroCoord, DG.PlotUtilities.kZeroLineColor, DG.PlotUtilities.kZeroLineWidth);
        }

        drawLine( tXAxisView, vLine);
        drawLine( tYAxisView, hLine);
      }

      if( tBothWaysNumeric ) {
        tXAxisView.forEachTickDo( drawVRule);
        tYAxisView.forEachTickDo( drawHRule);
        drawZeroLines();
      } // else suppress numeric grid lines for dot plots (numeric only on one axis), because it interferes with mean/median lines, etc.
    } // createRulerLines

    function startMarquee( iWindowX, iWindowY, iEvent) {
      // It's a little weird to put this altKey handling here because it makes the assumption
      //  that all subclasses have a different meaning for altKey dragging.
      if( iEvent.altKey)
        return; // Alt key has a different meaning

      if( iEvent.shiftKey)
        tBaseSelection = this_.getPath( 'graphModel.selection').toArray();
      else
        this_.get('graphModel').selectAll( false);
      tStartPt = DG.ViewUtilities.windowToViewCoordinates(
                    { x: iWindowX, y: iWindowY }, this_);
      tMarquee = this_._paper.rect( tStartPt.x, tStartPt.y, 0, 0)
              .attr( { fill: DG.PlotUtilities.kMarqueeColor,
                    stroke: DG.RenderingUtilities.kTransparent });
      this_.getPath('layerManager.' + DG.LayerNames.kAdornments ).push( tMarquee);
    }

    function continueMarquee( idX, idY) {
      if( SC.none( tMarquee))
        return; // Alt key was down when we started

      var tX = (idX > 0) ? tStartPt.x : tStartPt.x + idX,
        tY = (idY > 0) ? tStartPt.y : tStartPt.y + idY,
        tWidth = Math.abs( idX),
        tHeight = Math.abs( idY),
        tRect = { x: tX, y: tY, width: tWidth, height: tHeight };
      tMarquee.attr( tRect);
      this_.get('parentView' ).selectPointsInRect( tRect, tBaseSelection);
    }

    function endMarquee( idX, idY) {
      if( SC.none( tMarquee))
        return; // Alt key was down when we started

      this_.getPath('layerManager').removeElement( tMarquee);
      tMarquee = null;
      tBaseSelection = [];

      var tNumCases = this_.getPath( 'graphModel.casesController.selection.length');
      if( tNumCases > 0)  // We must have something > 0
        DG.logUser("marqueeSelection: %@", tNumCases);
    }

    function showCursor( iEvent) {
      if( iEvent.altKey) {
        var magnifyPlusCursorUrl = static_url('cursors/MagnifyPlus.cur'),
            magnifyMinusCursorUrl = static_url('cursors/MagnifyMinus.cur'),
            cursorUrl = iEvent.shiftKey ? magnifyMinusCursorUrl : magnifyPlusCursorUrl;
        this.attr( { cursor: DG.Browser.customCursorStr( cursorUrl, 8, 8) });
      }
      else
        this.attr( { cursor: 'auto' });
    }

    function destroyZoomTip() {
      if( tToolTip) {
        tToolTip.hide();
        tToolTip.destroy();
        tToolTip = null;
      }
    }

/*
    function mouseOver( iEvent) {
      if( !tHaveShowZoomTip) {
        var tZoomTipText = 'DG.GraphView.zoomTip'.loc();
        tToolTip = DG.ToolTip.create( { paperSource: this_,
                                            text: tZoomTipText,
                                            tipOrigin: {x: iEvent.layerX, y: iEvent.layerY},
            layerName: 'dataTip' });
        tToolTip.show();
        tHaveShowZoomTip = true;
        this_.invokeLater( destroyZoomTip, 5000);
      }
    }
*/

    var drawCellBands = function() {
      var tPaper = this.get('paper' ),
          tXView = this.get('xAxisView'),
          tYView = this.get('yAxisView'),
          tNumSecCells = tXView.getPath('model.numberOfCells'),
          tNumPrimaryCells = tYView.getPath('model.numberOfCells'),
          tSecCellWidth = tXView.get('fullCellWidth'),
          tPrimaryCellWidth = tYView.get('fullCellWidth'),
          tIsVertical = this.getPath('model.orientation') === 'vertical',
          tHeight = tIsVertical ? tSecCellWidth : tPrimaryCellWidth,
          tWidth = tIsVertical ? tPrimaryCellWidth : tSecCellWidth,
          tSecIndex, tPrimaryIndex,
          tXCoord, tYCoord, tLeft, tTop;
      if(SC.none( tPaper))
        return;

      for( tPrimaryIndex = 0; tPrimaryIndex < tNumPrimaryCells; tPrimaryIndex++) {
        if( tIsVertical){
          tXCoord = tYView.cellToCoordinate( tPrimaryIndex);
          tLeft = tXCoord - tPrimaryCellWidth / 2;
        }
        else {
          tYCoord = tYView.cellToCoordinate( tPrimaryIndex);
          tTop = tYCoord - tPrimaryCellWidth / 2;
        }
        for( tSecIndex = 0; tSecIndex < tNumSecCells; tSecIndex++) {
          if( tIsVertical) {
            tYCoord = tXView.cellToCoordinate( tSecIndex);
            tTop = tYCoord - tSecCellWidth / 2;
          }
          else {
            tXCoord = tXView.cellToCoordinate( tSecIndex);
            tLeft = tXCoord - tSecCellWidth / 2;
          }
          if( (tPrimaryIndex + tSecIndex) / 2 !== Math.floor((tPrimaryIndex + tSecIndex) / 2))
            tBackgroundLayer.push(
              tPaper.rect( tLeft, tTop, tWidth, tHeight)
                .attr( { fill: DG.PlotUtilities.kPlotCellFill, opacity: 0.8,
                  stroke:DG.RenderingUtilities.kTransparent} ));
        }
      }
    }.bind( this); // drawCellBands

    tGridLayer.clear();
    tBackgroundLayer.clear();

    createRulerLines();

    drawCellBands();

    if( SC.none( this._backgroundForClick)) {
      this._backgroundForClick = this.getPath('layerManager.' + DG.LayerNames.kClick).push(
        this._paper.rect( 0, 0, 0, 0 )
                .attr( { fill: DG.RenderingUtilities.kSeeThrough,
                         stroke: DG.RenderingUtilities.kTransparent })
                .click( function( iEvent) {
                          this_.get('parentView').handleBackgroundClick( iEvent);
                        })
                .dblclick( function( iEvent) {
                          this_.get('parentView').handleBackgroundDblClick( iEvent);
                        })
                .drag( continueMarquee, startMarquee, endMarquee)
                .mousemove( showCursor)
                // The mouseover hint is annoying, and probably not useful.
                /*.mouseover( mouseOver)*/);
    }

    this._backgroundForClick.attr( { width: this.get('drawWidth'),
                                    height: this.get('drawHeight') } );

  }

});

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

sc_require('components/graph/utilities/graph_drop_target');
sc_require('views/raphael_base');

/** @class  DG.PlotBackgroundView - The base class view for a plot.

  @extends DG.RaphaelBaseView
*/
DG.PlotBackgroundView = DG.RaphaelBaseView.extend( DG.GraphDropTarget,
/** @scope DG.PlotBackgroundView.prototype */
{
  autoDestroyProperties: [ '_backgroundForClick' ],

  displayProperties: ['xAxisView.model.lowerBound', 'xAxisView.model.upperBound',
                      'yAxisView.model.lowerBound', 'yAxisView.model.upperBound',
                      'xAxisView.model.attributeDescription.attributeStats.categoricalStats.numberOfCells',
                      'yAxisView.model.attributeDescription.attributeStats.categoricalStats.numberOfCells'],

  /**
   * @property {DG.GraphModel}
   */
  graphModel: null,

  /**
    @property { DG.AxisView}
  */
  xAxisView: null,
  /**
    @property { DG.AxisView }
  */
  yAxisView: null,

  // Private properties
  _backgroundForClick: null,  // We make this once and keep it sized properly.

  /**
   * Additional setup after creating the view
   */
  didCreateLayer:function () {
    var tGraphView = this.get( 'parentView' );
    sc_super();
    tGraphView.get( 'plotViews' ).forEach( function ( iPlotView ) {
      iPlotView.didCreateLayer();
    } );
    tGraphView.drawPlots();
  },

  /**
   * Subclasses can override calling sc_super() and then adding layers at will.
   */
  initLayerManager: function() {
    sc_super();

    var ln = DG.LayerNames;
    this.get('layerManager').addNamedLayer( ln.kBackground )
                  .addNamedLayer( ln.kGrid )
                  .addNamedLayer( ln.kIntervalShading )
                  .addNamedLayer( ln.kClick )
                  .addNamedLayer( ln.kGhost )
                  .addNamedLayer( ln.kConnectingLines )
                  .addNamedLayer( ln.kPoints )
                  .addNamedLayer( ln.kSelectedPoints )
                  .addNamedLayer( ln.kAdornments )
                  .addNamedLayer( ln.kDataTip );
  },

  /**
    We just have the background to draw. But it has a marquee behavior and a background click
    behavior to install.
  */
  doDraw: function doDraw() {
    var this_ = this,
        tFrame = this.get('frame' ),
        tXAxisView = this.get('xAxisView'),
        tYAxisView = this.get('yAxisView'),
        tBackgroundLayer = this.getPath('layerManager.' + DG.LayerNames.kBackground ),
        tGridLayer = this.getPath('layerManager.' + DG.LayerNames.kGrid),
        tBothWaysNumeric =( tXAxisView.get('isNumeric') && tYAxisView.get('isNumeric')),
        tMarquee,
        tStartPt,
        tBaseSelection = [],
        //tHaveShowZoomTip = false,
        tToolTip;

    function createRulerLines() {

      function vLine( iX, iColor, iWidth) {
        tGridLayer.push(
          this_._paper.line( iX, tFrame.height, iX, 0)
                .attr( { stroke: iColor, 'stroke-width': iWidth }));
      }

      function hLine( iY, iColor, iWidth) {
        tGridLayer.push(
          this_._paper.line( 0, iY, tFrame.width, iY)
                  .attr( { stroke: iColor, 'stroke-width': iWidth }));
      }

      function drawVRule( iValue, iX) {
        vLine( iX, DG.PlotUtilities.kRuleColor, DG.PlotUtilities.kRuleWidth);
      }

      function drawHRule( iValue, iY) {
        hLine( iY, DG.PlotUtilities.kRuleColor, DG.PlotUtilities.kRuleWidth);
      }

      function drawZeroLines() {

        function drawLine( iAxisView, iDrawingFunc) {
          var tZeroCoord = iAxisView.get('zeroPixel');
          if( tZeroCoord)
            iDrawingFunc( tZeroCoord, DG.PlotUtilities.kZeroLineColor, DG.PlotUtilities.kZeroLineWidth);
        }

        drawLine( tXAxisView, vLine);
        drawLine( tYAxisView, hLine);
      }

      if( tBothWaysNumeric ) {
        tXAxisView.forEachTickDo( drawVRule);
        tYAxisView.forEachTickDo( drawHRule);
        drawZeroLines();
      } // else suppress numeric grid lines for dot plots (numeric only on one axis), because it interferes with mean/median lines, etc.
    } // createRulerLines

    function startMarquee( iWindowX, iWindowY, iEvent) {
      // It's a little weird to put this altKey handling here because it makes the assumption
      //  that all subclasses have a different meaning for altKey dragging.
      if( iEvent.altKey)
        return; // Alt key has a different meaning

      if( iEvent.shiftKey)
        tBaseSelection = this_.getPath( 'graphModel.selection').toArray();
      else
        this_.get('graphModel').selectAll( false);
      tStartPt = DG.ViewUtilities.windowToViewCoordinates(
                    { x: iWindowX, y: iWindowY }, this_);
      tMarquee = this_._paper.rect( tStartPt.x, tStartPt.y, 0, 0)
              .attr( { fill: DG.PlotUtilities.kMarqueeColor,
                    stroke: DG.RenderingUtilities.kTransparent });
      this_.getPath('layerManager.' + DG.LayerNames.kAdornments ).push( tMarquee);
    }

    function continueMarquee( idX, idY) {
      if( SC.none( tMarquee))
        return; // Alt key was down when we started

      var tX = (idX > 0) ? tStartPt.x : tStartPt.x + idX,
        tY = (idY > 0) ? tStartPt.y : tStartPt.y + idY,
        tWidth = Math.abs( idX),
        tHeight = Math.abs( idY),
        tRect = { x: tX, y: tY, width: tWidth, height: tHeight };
      tMarquee.attr( tRect);
      this_.get('parentView' ).selectPointsInRect( tRect, tBaseSelection);
    }

    function endMarquee( idX, idY) {
      if( SC.none( tMarquee))
        return; // Alt key was down when we started

      this_.getPath('layerManager').removeElement( tMarquee);
      tMarquee = null;
      tBaseSelection = [];

      var tNumCases = this_.getPath( 'graphModel.casesController.selection.length');
      if( tNumCases > 0)  // We must have something > 0
        DG.logUser("marqueeSelection: %@", tNumCases);
    }

    function showCursor( iEvent) {
      if( iEvent.altKey) {
        var magnifyPlusCursorUrl = static_url('cursors/MagnifyPlus.cur'),
            magnifyMinusCursorUrl = static_url('cursors/MagnifyMinus.cur'),
            cursorUrl = iEvent.shiftKey ? magnifyMinusCursorUrl : magnifyPlusCursorUrl;
        this.attr( { cursor: DG.Browser.customCursorStr( cursorUrl, 8, 8) });
      }
      else
        this.attr( { cursor: 'auto' });
    }

/*
    function destroyZoomTip() {
      if( tToolTip) {
        tToolTip.hide();
        tToolTip.destroy();
        tToolTip = null;
      }
    }
*/

/*
    function mouseOver( iEvent) {
      if( !tHaveShowZoomTip) {
        var tZoomTipText = 'DG.GraphView.zoomTip'.loc();
        tToolTip = DG.ToolTip.create( { paperSource: this_,
                                            text: tZoomTipText,
                                            tipOrigin: {x: iEvent.layerX, y: iEvent.layerY},
            layerName: 'dataTip' });
        tToolTip.show();
        tHaveShowZoomTip = true;
        this_.invokeLater( destroyZoomTip, 5000);
      }
    }
*/

    var drawCellBands = function() {
      var tPaper = this.get('paper' ),
          tXView = this.get('xAxisView'),
          tYView = this.get('yAxisView'),
          tNumSecCells = tXView.getPath('model.numberOfCells'),
          tNumPrimaryCells = tYView.getPath('model.numberOfCells'),
          tSecCellWidth = tXView.get('fullCellWidth'),
          tPrimaryCellWidth = tYView.get('fullCellWidth'),
          tIsVertical = this.getPath('model.orientation') === 'vertical',
          tHeight = tIsVertical ? tSecCellWidth : tPrimaryCellWidth,
          tWidth = tIsVertical ? tPrimaryCellWidth : tSecCellWidth,
          tSecIndex, tPrimaryIndex,
          tXCoord, tYCoord, tLeft, tTop;
      if(SC.none( tPaper))
        return;

      for( tPrimaryIndex = 0; tPrimaryIndex < tNumPrimaryCells; tPrimaryIndex++) {
        if( tIsVertical){
          tXCoord = tYView.cellToCoordinate( tPrimaryIndex);
          tLeft = tXCoord - tPrimaryCellWidth / 2;
        }
        else {
          tYCoord = tYView.cellToCoordinate( tPrimaryIndex);
          tTop = tYCoord - tPrimaryCellWidth / 2;
        }
        for( tSecIndex = 0; tSecIndex < tNumSecCells; tSecIndex++) {
          if( tIsVertical) {
            tYCoord = tXView.cellToCoordinate( tSecIndex);
            tTop = tYCoord - tSecCellWidth / 2;
          }
          else {
            tXCoord = tXView.cellToCoordinate( tSecIndex);
            tLeft = tXCoord - tSecCellWidth / 2;
          }
          if( (tPrimaryIndex + tSecIndex) / 2 !== Math.floor((tPrimaryIndex + tSecIndex) / 2))
            tBackgroundLayer.push(
              tPaper.rect( tLeft, tTop, tWidth, tHeight)
                .attr( { fill: DG.PlotUtilities.kPlotCellFill, opacity: 0.8,
                  stroke:DG.RenderingUtilities.kTransparent} ));
        }
      }
    }.bind( this); // drawCellBands

    tGridLayer.clear();
    tBackgroundLayer.clear();

    createRulerLines();

    drawCellBands();

    if( SC.none( this._backgroundForClick)) {
      this._backgroundForClick = this.getPath('layerManager.' + DG.LayerNames.kClick).push(
        this._paper.rect( 0, 0, 0, 0 )
                .attr( { fill: DG.RenderingUtilities.kSeeThrough,
                         stroke: DG.RenderingUtilities.kTransparent })
                .click( function( iEvent) {
                          this_.get('parentView').handleBackgroundClick( iEvent);
                        })
                .dblclick( function( iEvent) {
                          this_.get('parentView').handleBackgroundDblClick( iEvent);
                        })
                .drag( continueMarquee, startMarquee, endMarquee)
                .mousemove( showCursor)
                // The mouseover hint is annoying, and probably not useful.
                /*.mouseover( mouseOver)*/);
    }

    this._backgroundForClick.attr( { width: this.get('drawWidth'),
                                    height: this.get('drawHeight') } );

  }

});

<|endoftext|>


<commit_before>/*** MQTT Z-Way odule *******************************************
 Version: 1.0.0
 -----------------------------------------------------------------------------
 Author: David Uebelacker <david@uebelacker.ch>
 ******************************************************************************/

function ZWayMqttBridge(id, controller) {
    ZWayMqttBridge.super_.call(this, id, controller);
}

inherits(ZWayMqttBridge, AutomationModule);

_module = ZWayMqttBridge;

ZWayMqttBridge.prototype.init = function (config) {
    ZWayMqttBridge.super_.prototype.init.call(this, config);

    var self = this;

    this.deviceUpdate = function (device) {
        if (self.mqttBridge) {
            self.mqttBridge.send(JSON.stringify(device, null, 4));
        }
    };

    this.connect();
    this.controller.devices.on('change:metrics:level', self.deviceUpdate);
};

ZWayMqttBridge.prototype.connect = function () {
    console.log('Connecting to Mqtt Brdige ....');
    var self = this;

    this.mqttBridge = new sockets.websocket('ws://192.168.0.62:8080');

    setTimeout(function() {
        if (self.mqttBridge && !self.connected) {
            console.log('Could not connect to Mqtt Bridge after 5 seconds!');
            self.connected = false;
            self.mqttBridge = null;
            setTimeout(self.connect, 10000);
        }
    }, 5000);

    this.mqttBridge.onopen = function () {
        console.log('Mqtt Bridge websocket connected!');
        self.connected = true;
    };

    this.mqttBridge.onmessage = function (ev) {
        console.log('got data:' + ev.data);
    };

    this.mqttBridge.onclose = function () {
        console.log('Mqtt Bridge websocket was closed!');
        setTimeout(self.connect, 10000);
        self.connected = false;
        self.mqttBridge.close();
        self.mqttBridge = null;
    };

    this.mqttBridge.onerror = function (ev) {
        console.log('Mqtt Bridge websocket error: ' + ev.data);
        setTimeout(self.connect, 10000);
        self.connected = false;
        self.mqttBridge.close();
        self.mqttBridge = null;
    };
};

ZWayMqttBridge.prototype.stop = function () {
    var self = this;
    if (self.mqttBridge) {
        self.mqttBridge.close();
        self.mqttBridge = null;
    }
};<commit_msg>devel<commit_after>/*** MQTT Z-Way odule *******************************************
 Version: 1.0.0
 -----------------------------------------------------------------------------
 Author: David Uebelacker <david@uebelacker.ch>
 ******************************************************************************/

function ZWayMqttBridge(id, controller) {
    ZWayMqttBridge.super_.call(this, id, controller);
}

inherits(ZWayMqttBridge, AutomationModule);

_module = ZWayMqttBridge;

ZWayMqttBridge.prototype.init = function (config) {
    ZWayMqttBridge.super_.prototype.init.call(this, config);

    var self = this;

    this.deviceUpdate = function (device) {
        if (self.mqttBridge) {
            self.mqttBridge.send(JSON.stringify(device, null, 4));
        }
    };

    this.connect();
    this.controller.devices.on('change:metrics:level', self.deviceUpdate);
};

ZWayMqttBridge.prototype.connect = function () {
    console.log('Connecting to Mqtt Brdige ....');
    var self = this;

    this.mqttBridge = new sockets.websocket('ws://192.168.0.62:8080');

    setTimeout(function() {
        if (self.mqttBridge && !self.connected) {
            console.log('Could not connect to Mqtt Bridge after 5 seconds!');
            self.connected = false;
            self.mqttBridge = null;
            setTimeout(self.connect, 10000);
        }
    }, 5000);

    this.mqttBridge.onopen = function () {
        console.log('Mqtt Bridge websocket connected!');
        self.connected = true;
    };

    this.mqttBridge.onmessage = function (ev) {
        console.log('got data:' + ev.data);
    };

    this.mqttBridge.onclose = function () {
        console.log('Mqtt Bridge websocket was closed!');
        setTimeout(self.connect, 10000);
        self.connected = false;
        self.mqttBridge = null;
    };

    this.mqttBridge.onerror = function (ev) {
        console.log('Mqtt Bridge websocket error: ' + ev.data);
        setTimeout(self.connect, 10000);
        self.connected = false;
        self.mqttBridge = null;
    };
};

ZWayMqttBridge.prototype.stop = function () {
    var self = this;
    if (self.mqttBridge) {
        self.mqttBridge.close();
        self.mqttBridge = null;
    }
};<|endoftext|>