<commit_before>/* jshint node:true */

'use strict';

var spawn = require('child_process').spawn;
var temp = require('temp');
var fs = require('fs');
var Q = require('q');

temp.track();

var tempOpen = function (name) {
  var defer = Q.defer();

  temp.open('exec_out', function (err, tmp) {
    if (err) {
      defer.reject();
    } else {
      defer.resolve(tmp);
    }
  });

  return defer.promise;
};

var tempClose = function (tmp) {
  var defer = Q.defer();

  fs.close(tmp.fd, function (err) {
    if (err) {
      defer.reject();
    } else {
      defer.resolve(tmp);
    }
  });

  return defer.promise;
};

var tempRead = function (tmp) {
  var defer = Q.defer();

  fs.readFile(tmp.path, { encoding: 'utf-8' }, function (err, out) {
    if (err) {
      defer.reject();
    } else {
      defer.resolve(out);
    }
  });

  return defer.promise;
};

// workaround to get full stdout output in Windows
var exec = function (command, args, options, callback) {

  Q.all([
    tempOpen('exec_out'),
    tempOpen('exec_err')

  ]).spread(function (tempOut, tempErr) {
    var defer = Q.defer();

    options.stdio = ['ignore', tempOut.fd, tempErr.fd];
    spawn(command, args, options).on('close', function (code) {
      defer.resolve({
        tempOut: tempOut,
        tempErr: tempErr,
        code: code
      });
    });

    return defer.promise;

  }).then(function (result) {
    var tempOut = result.tempOut;
    var tempErr = result.tempErr;
    var code = result.code;

    return Q.all([
      tempClose(tempOut),
      tempClose(tempErr),
      code
    ]);

  }).spread(function (tempOut, tempErr, code) {
    return Q.all([
      tempRead(tempOut),
      tempRead(tempErr),
      code
    ]);

  }).spread(function (out, err, code) {
    callback(code, out, err);
  });
};

module.exports = exec;
<commit_msg>Add error handler in exec.<commit_after>/* jshint node:true */

'use strict';

var spawn = require('child_process').spawn;
var temp = require('temp');
var fs = require('fs');
var Q = require('q');

temp.track();

var tempOpen = function (name) {
  var defer = Q.defer();

  temp.open('exec_out', function (err, tmp) {
    if (err) {
      defer.reject();
    } else {
      defer.resolve(tmp);
    }
  });

  return defer.promise;
};

var tempClose = function (tmp) {
  var defer = Q.defer();

  fs.close(tmp.fd, function (err) {
    if (err) {
      defer.reject();
    } else {
      defer.resolve(tmp);
    }
  });

  return defer.promise;
};

var tempRead = function (tmp) {
  var defer = Q.defer();

  fs.readFile(tmp.path, { encoding: 'utf-8' }, function (err, out) {
    if (err) {
      defer.reject();
    } else {
      defer.resolve(out);
    }
  });

  return defer.promise;
};

// workaround to get full stdout output in Windows
var exec = function (command, args, options, callback) {

  Q.all([
    tempOpen('exec_out'),
    tempOpen('exec_err')

  ]).spread(function (tempOut, tempErr) {
    var defer = Q.defer();

    options.stdio = ['ignore', tempOut.fd, tempErr.fd];
    spawn(command, args, options).on('close', function (code) {
      defer.resolve({
        tempOut: tempOut,
        tempErr: tempErr,
        code: code
      });
    });

    return defer.promise;

  }).then(function (result) {
    var tempOut = result.tempOut;
    var tempErr = result.tempErr;
    var code = result.code;

    return Q.all([
      tempClose(tempOut),
      tempClose(tempErr),
      code
    ]);

  }).spread(function (tempOut, tempErr, code) {
    return Q.all([
      tempRead(tempOut),
      tempRead(tempErr),
      code
    ]);

  }).spread(function (out, err, code) {
    callback(code, out, err);

  }).catch(function () {
    console.log(arguments);
    callback(0, '', ''); // when error, just tell nothing

  });
};

module.exports = exec;
<|endoftext|>


<commit_before>var board = require('./board');
var util = require('./util');
var hold = require('./hold');

function renderSquareTarget(data, cur) {
  var pos = util.key2pos(cur.over),
    width = cur.bounds.width,
    targetWidth = width / 4,
    squareWidth = width / 8,
    asWhite = data.orientation === 'white';
  var sq = document.createElement('div');
  var style = sq.style;
  var vector = [
    (asWhite ? pos[0] - 1 : 8 - pos[0]) * squareWidth,
    (asWhite ? 8 - pos[1] : pos[1] - 1) * squareWidth
  ];
  style.width = targetWidth + 'px';
  style.height = targetWidth + 'px';
  style.left = (-0.5 * squareWidth) + 'px';
  style.top = (-0.5 * squareWidth) + 'px';
  style[util.transformProp()] = util.translate(vector);
  sq.className = 'cg-square-target';
  data.element.appendChild(sq);
  return sq;
}

function fixDomAfterDrag(data) {
  if (data.element) {
    var dp = data.element.querySelector('.cg-piece.dragging');
    if (dp) {
      dp.classList.remove('dragging');
      dp.removeAttribute('style');
    }
    var sqs = data.element.getElementsByClassName('cg-square-target');
    while (sqs[0]) sqs[0].parentNode.removeChild(sqs[0]);
  }
}

function start(data, e) {
  if (e.button !== undefined && e.button !== 0) return; // only touch or left click
  if (e.touches && e.touches.length > 1) return; // support one finger touch only
  e.stopPropagation();
  e.preventDefault();
  var previouslySelected = data.selected;
  var position = util.eventPosition(e);
  var bounds = data.bounds;
  var orig = board.getKeyAtDomPos(data, position, bounds);
  var hadPremove = !!data.premovable.current;
  board.selectSquare(data, orig);
  var stillSelected = data.selected === orig;
  if (data.pieces[orig] && stillSelected && board.isDraggable(data, orig)) {
    var bpos = util.boardpos(util.key2pos(orig), data.orientation === 'white');
    data.draggable.current = {
      previouslySelected: previouslySelected,
      orig: orig,
      piece: data.pieces[orig],
      rel: position,
      epos: position,
      pos: [0, 0],
      dec: [
        position[0] - (bounds.left + (bounds.width * bpos.left / 100) + (bounds.width * 0.25) / 2),
        position[1] - (bounds.top + bounds.height - (bounds.height * bpos.bottom / 100) + 10)
      ],
      bounds: bounds,
      started: false,
      squareTarget: null,
      draggingPiece: e.target,
      originTarget: e.target,
      scheduledAnimationFrame: false
    };
    if (data.draggable.centerPiece) {
      data.draggable.current.dec[1] = position[1] - (bounds.top + bounds.height - (bounds.height * bpos.bottom / 100) - (bounds.height * 0.25) / 2);
    }
    hold.start();
  } else if (hadPremove) board.unsetPremove(data);
  data.renderRAF();
  processDrag(data);
}

function processDrag(data) {
  if (data.draggable.current.scheduledAnimationFrame) return;
  data.draggable.current.scheduledAnimationFrame = true;
  requestAnimationFrame(function() {
    var cur = data.draggable.current;
    cur.scheduledAnimationFrame = false;
    if (cur.orig) {
      // cancel animations while dragging
      if (data.animation.current.start &&
        Object.keys(data.animation.current.anims).indexOf(cur.orig) !== -1)
        data.animation.current.start = false;

      // if moving piece is gone, cancel
      if (data.pieces[cur.orig] !== cur.piece) cancel(data);
      else {
        if (!cur.started && util.distance(cur.epos, cur.rel) >= data.draggable.distance) {
          cur.started = true;
          cur.draggingPiece.classList.add('dragging');
        }
        if (cur.started) {
          cur.pos = [
            cur.epos[0] - cur.rel[0],
            cur.epos[1] - cur.rel[1]
          ];

          cur.over = board.getKeyAtDomPos(data, cur.epos, cur.bounds);
          if (cur.over && !cur.squareTarget) {
            cur.squareTarget = renderSquareTarget(data, cur);
          } else if (!cur.over && cur.squareTarget) {
            if (cur.squareTarget.parentNode) cur.squareTarget.parentNode.removeChild(cur.squareTarget);
            cur.squareTarget = null;
          }

          // move piece
          cur.draggingPiece.style[util.transformProp()] = util.translate([
            cur.pos[0] + cur.dec[0],
            cur.pos[1] + cur.dec[1]
          ]);

          // move square target
          if (cur.over && cur.squareTarget && cur.over !== cur.prevTarget) {
            var squareWidth = cur.bounds.width / 8,
            asWhite = data.orientation === 'white',
            stPos = util.key2pos(cur.over),
            vector = [
              (asWhite ? stPos[0] - 1 : 8 - stPos[0]) * squareWidth,
              (asWhite ? 8 - stPos[1] : stPos[1] - 1) * squareWidth
            ];
            cur.squareTarget.style[util.transformProp()] = util.translate(vector);
            cur.prevTarget = cur.over;
          }
        }
      }
      processDrag(data);
    }
  });
}

function move(data, e) {
  if (e.touches && e.touches.length > 1) return; // support one finger touch only

  if (data.draggable.current.orig) {
    data.draggable.current.epos = util.eventPosition(e);
  }
}

function end(data, e) {
  var draggable = data.draggable;
  var orig = draggable.current ? draggable.current.orig : null;
  var dest;
  fixDomAfterDrag(data);
  if (!orig) return;
  // comparing with the origin target is an easy way to test that the end event
  // has the same touch origin
  if (e && e.type === 'touchend' && draggable.current.originTarget !== e.target) return;
  board.unsetPremove(data);
  if (draggable.current.started) {
    dest = draggable.current.over;
    if (orig !== dest) data.movable.dropped = [orig, dest];
    board.userMove(data, orig, dest);
  } else if (draggable.current.previouslySelected === orig) {
    board.setSelected(data, null);
  }
  draggable.current = {};
  data.renderRAF();
}

function cancel(data) {
  fixDomAfterDrag(data);
  if (data.draggable.current.orig) {
    data.draggable.current = {};
    board.selectSquare(data, null);
  }
}

module.exports = {
  start: start,
  move: move,
  end: end,
  cancel: cancel,
  processDrag: processDrag // must be exposed for board editors
};
<commit_msg>Improve drag; fix cancelling when piece gone<commit_after>var board = require('./board');
var util = require('./util');
var hold = require('./hold');

function renderSquareTarget(data, cur) {
  var pos = util.key2pos(cur.over),
    width = cur.bounds.width,
    targetWidth = width / 4,
    squareWidth = width / 8,
    asWhite = data.orientation === 'white';
  var sq = document.createElement('div');
  var style = sq.style;
  var vector = [
    (asWhite ? pos[0] - 1 : 8 - pos[0]) * squareWidth,
    (asWhite ? 8 - pos[1] : pos[1] - 1) * squareWidth
  ];
  style.width = targetWidth + 'px';
  style.height = targetWidth + 'px';
  style.left = (-0.5 * squareWidth) + 'px';
  style.top = (-0.5 * squareWidth) + 'px';
  style[util.transformProp()] = util.translate(vector);
  sq.className = 'cg-square-target';
  data.element.appendChild(sq);
  return sq;
}

function fixDomAfterDrag(data) {
  if (data.element) {
    var dp = data.element.querySelector('.cg-piece.dragging');
    if (dp) {
      dp.classList.remove('dragging');
      dp.removeAttribute('style');
    }
    var sqs = data.element.getElementsByClassName('cg-square-target');
    while (sqs[0]) sqs[0].parentNode.removeChild(sqs[0]);
  }
}

function start(data, e) {
  if (e.button !== undefined && e.button !== 0) return; // only touch or left click
  if (e.touches && e.touches.length > 1) return; // support one finger touch only
  e.stopPropagation();
  e.preventDefault();
  var previouslySelected = data.selected;
  var position = util.eventPosition(e);
  var bounds = data.bounds;
  var orig = board.getKeyAtDomPos(data, position, bounds);
  var hadPremove = !!data.premovable.current;
  board.selectSquare(data, orig);
  var stillSelected = data.selected === orig;
  if (data.pieces[orig] && stillSelected && board.isDraggable(data, orig)) {
    var bpos = util.boardpos(util.key2pos(orig), data.orientation === 'white');
    data.draggable.current = {
      previouslySelected: previouslySelected,
      orig: orig,
      piece: data.pieces[orig],
      rel: position,
      epos: position,
      pos: [0, 0],
      dec: [
        position[0] - (bounds.left + (bounds.width * bpos.left / 100) + (bounds.width * 0.25) / 2),
        position[1] - (bounds.top + bounds.height - (bounds.height * bpos.bottom / 100) + 10)
      ],
      bounds: bounds,
      started: false,
      squareTarget: null,
      draggingPiece: e.target,
      originTarget: e.target,
      scheduledAnimationFrame: false
    };
    if (data.draggable.centerPiece) {
      data.draggable.current.dec[1] = position[1] - (bounds.top + bounds.height - (bounds.height * bpos.bottom / 100) - (bounds.height * 0.25) / 2);
    }
    hold.start();
  } else if (hadPremove) board.unsetPremove(data);
  data.renderRAF();
}

function processDrag(data) {
  if (data.draggable.current.scheduledAnimationFrame) return;
  data.draggable.current.scheduledAnimationFrame = true;
  requestAnimationFrame(function() {
    var cur = data.draggable.current;
    cur.scheduledAnimationFrame = false;
    if (cur.orig) {
      // if moving piece is gone, cancel
      if (data.pieces[cur.orig] !== cur.piece) {
        cancel(data);
        return;
      }

      // cancel animations while dragging
      if (data.animation.current.start &&
        Object.keys(data.animation.current.anims).indexOf(cur.orig) !== -1)
        data.animation.current.start = false;

      else if (cur.started) {
        cur.pos = [
          cur.epos[0] - cur.rel[0],
          cur.epos[1] - cur.rel[1]
        ];

        cur.over = board.getKeyAtDomPos(data, cur.epos, cur.bounds);
        if (cur.over && !cur.squareTarget) {
          cur.squareTarget = renderSquareTarget(data, cur);
        } else if (!cur.over && cur.squareTarget) {
          if (cur.squareTarget.parentNode) cur.squareTarget.parentNode.removeChild(cur.squareTarget);
          cur.squareTarget = null;
        }

        // move piece
        cur.draggingPiece.style[util.transformProp()] = util.translate([
          cur.pos[0] + cur.dec[0],
          cur.pos[1] + cur.dec[1]
        ]);

        // move square target
        if (cur.over && cur.squareTarget && cur.over !== cur.prevTarget) {
          var squareWidth = cur.bounds.width / 8,
          asWhite = data.orientation === 'white',
          stPos = util.key2pos(cur.over),
          vector = [
            (asWhite ? stPos[0] - 1 : 8 - stPos[0]) * squareWidth,
            (asWhite ? 8 - stPos[1] : stPos[1] - 1) * squareWidth
          ];
          cur.squareTarget.style[util.transformProp()] = util.translate(vector);
          cur.prevTarget = cur.over;
        }
      }
      processDrag(data);
    }
  });
}

function move(data, e) {
  if (e.touches && e.touches.length > 1) return; // support one finger touch only

  var cur = data.draggable.current;
  if (cur.orig) {
    data.draggable.current.epos = util.eventPosition(e);
    if (!cur.started && util.distance(cur.epos, cur.rel) >= data.draggable.distance) {
      cur.started = true;
      cur.draggingPiece.classList.add('dragging');
      processDrag(data);
    }
  }
}

function end(data, e) {
  var draggable = data.draggable;
  var orig = draggable.current ? draggable.current.orig : null;
  var dest;
  fixDomAfterDrag(data);
  if (!orig) return;
  // comparing with the origin target is an easy way to test that the end event
  // has the same touch origin
  if (e && e.type === 'touchend' && draggable.current.originTarget !== e.target) return;
  board.unsetPremove(data);
  if (draggable.current.started) {
    dest = draggable.current.over;
    if (orig !== dest) data.movable.dropped = [orig, dest];
    board.userMove(data, orig, dest);
    data.renderRAF();
  } else if (draggable.current.previouslySelected === orig) {
    board.setSelected(data, null);
    data.renderRAF();
  }
  draggable.current = {};
}

function cancel(data) {
  fixDomAfterDrag(data);
  if (data.draggable.current.orig) {
    data.draggable.current = {};
    board.selectSquare(data, null);
  }
}

module.exports = {
  start: start,
  move: move,
  end: end,
  cancel: cancel,
  processDrag: processDrag // must be exposed for board editors
};
<|endoftext|>


<commit_before>/**
 * Created by AlexanderC on 6/10/15.
 */

'use strict';

import {SuperagentResponse} from './SuperagentResponse';
import {LambdaResponse} from './LambdaResponse';
import {Response} from './Response';
import {Exception} from '../Exception/Exception';
import {Action} from './Action';
import Http from 'superagent';
import AWS from 'aws-sdk';
import {MissingCacheImplementationException} from './Exception/MissingCacheImplementationException';
import {CachedRequestException} from './Exception/CachedRequestException';
import {NotAuthenticatedException} from './Exception/NotAuthenticatedException';
import aws4 from 'aws4';
import urlParse from 'url-parse';
import qs from 'qs';
import Core from 'deep-core';
import {MissingSecurityServiceException} from './Exception/MissingSecurityServiceException';
import {AsyncCallNotAvailableException} from './Exception/AsyncCallNotAvailableException';
import {LoadCredentialsException} from './Exception/LoadCredentialsException';
import Security from 'deep-security';
import crypto from 'crypto';

/**
 * Action request instance
 */
export class Request {
  /**
   * @param {Action} action
   * @param {Object} payload
   * @param {String} method
   */
  constructor(action, payload, method) {
    this._action = action;
    this._payload = payload;
    this._method = method;
    this._lambda = null;

    this._cacheImpl = null;
    this._cacheTtl = Request.TTL_FOREVER;
    this._cached = false;

    this._async = false;
    this._native = false;
  }

  /**
   * @returns {Boolean}
   */
  get async() {
    return this._async;
  }

  /**
   * @returns {Request}
   */
  invokeAsync() {
    if (!this.isLambda) {
      throw new AsyncCallNotAvailableException(this._action.type);
    }

    this._native = true;
    this._async = true;

    return this;
  }

  /**
   * @returns {Boolean}
   */
  get native() {
    return this._native;
  }

  /**
   * @returns {Request}
   */
  useDirectCall() {
    this._native = true;

    return this;
  }

  /**
   * @returns {Boolean}
   */
  get isCached() {
    return this._cacheImpl && this._cached;
  }

  /**
   * @returns {Request}
   */
  enableCache() {
    this._cached = true;
    return this;
  }

  /**
   * @returns {Request}
   */
  disableCache() {
    this._cached = false;
    return this;
  }

  /**
   * @param {Number} ttl
   * @returns {Request}
   */
  cache(ttl = Request.TTL_FOREVER) {
    if (!this._cacheImpl) {
      throw new MissingCacheImplementationException();
    }

    this._cacheTtl = ttl;
    this.enableCache();

    return this;
  }

  /**
   * @returns {Number}
   */
  get cacheTtl() {
    return this._cacheTtl;
  }

  /**
   * @param {Number} ttl
   */
  set cacheTtl(ttl) {
    this._cacheTtl = ttl;
  }

  /**
   * @returns {Object}
   */
  get cacheImpl() {
    return this._cacheImpl;
  }

  /**
   * @param {Object} cache
   */
  set cacheImpl(cache) {
    this._cacheImpl = cache;

    // @todo: do we really have to force it?
    this.cache(Request.TTL_DEFAULT);
  }

  /**
   * @returns {String}
   * @private
   */
  _buildCacheKey() {
    let payload = Request._md5(JSON.stringify(this._payload));
    let endpoint = this.native ? this._action.source.original : this._action.source.api;

    return `${this._method}:${this._action.type}:${endpoint}#${payload}`;
  }

  /**
   * @param {String} str
   * @returns {String}
   */
  static _md5(str) {
    var md5sum = crypto.createHash('md5');

    md5sum.update(str);

    return md5sum.digest('hex');
  }

  /**
   * @param {Response} response
   * @returns {String}
   * @private
   */
  static _stringifyResponse(response) {
    return JSON.stringify({
      _class: response.constructor.name,
      data: response.rawData,
      error: response.rawError,
    });
  }

  /**
   * @param {String} rawData
   * @returns {Response}
   * @private
   */
  _rebuildResponse(rawData) {
    let response = JSON.parse(rawData);

    if (!response) {
      throw new CachedRequestException(`Unable to unpack cached JSON object from ${rawData}`);
    }

    let ResponseImpl = Request._chooseResponseImpl(response._class);

    if (!ResponseImpl) {
      throw new Exception(`Unknown Response implementation ${response._class}`);
    }

    return new ResponseImpl(this, response.data, response.error);
  }

  /**
   * @param {String} className
   * @returns {*}
   * @private
   */
  static _chooseResponseImpl(className) {
    let implMap = {};

    implMap[Response.name] = Response;
    implMap[LambdaResponse.name] = LambdaResponse;
    implMap[SuperagentResponse.name] = SuperagentResponse;

    return implMap[className];
  }

  /**
   * @param {Function} callback
   */
  invalidateCache(callback = () => {}) {
    if (!this.isCached) {
      callback(true);

      return this;
    }

    let cache = this._cacheImpl;
    let cacheKey = this._buildCacheKey();

    cache.has(cacheKey, (error, result) => {
      if (error) {
        throw new CachedRequestException(error);
      }

      if (result) {
        cache.invalidate(cacheKey, 0, (error, result) => {
          if (error) {
            throw new CachedRequestException(error);
          }

          callback(result);
        });

        return;
      }

      callback(true);
    });

    return this;
  }

  /**
   * @param {Function} callback
   */
  send(callback = () => {}) {
    if (!this.isCached || this._async) {
      return this._send(callback);
    }

    let cache = this._cacheImpl;
    let invalidateCache = this._cacheTtl === Request.TTL_INVALIDATE;
    let cacheKey = this._buildCacheKey();

    cache.has(cacheKey, (error, result) => {
      if (error) {
        throw new CachedRequestException(error);
      }

      if (result && !invalidateCache) {
        cache.get(cacheKey, (error, result) => {
          if (error) {
            throw new CachedRequestException(error);
          }

          callback(this._rebuildResponse(result));
        });

        return;
      }

      this._send((response) => {
        cache.set(cacheKey, Request._stringifyResponse(response), this._cacheTtl, (error, result) => {
          if (!result) {
            error = `Unable to persist request cache under key ${cacheKey}`;
          }

          if (error) {
            throw new CachedRequestException(error);
          }
        });

        // @todo: do it synchronous?
        callback(response);
      });
    });

    return this;
  }

  /**
   * @returns {Boolean}
   *
   * @todo: remove this?
   */
  get isLambda() {
    return this._action.type === Action.LAMBDA;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   */
  _send(callback = () => {}) {
    if (!this._native) {
      return this._sendThroughApi(callback);
    }

    switch (this._action.type) {
      case Action.LAMBDA:
        this._sendLambda(callback);
        break;
      case Action.EXTERNAL:
        this._sendExternal(callback);
        break;
      default: throw new Exception(`Request of type ${this._action.type} is not implemented`);
    }

    return this;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   * @private
   */
  _sendThroughApi(callback = () => {}) {
    let endpoint = this._action.source.api;

    this._createAws4SignedRequest(endpoint, this.method, this.payload, (signedRequest) => {
      signedRequest.end((error, response) => {
        callback(new SuperagentResponse(this, response, error));
      });
    });

    return this;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   * @private
   */
  _sendLambda(callback = () => {}) {
    // @todo: set retries in a smarter way...
    AWS.config.maxRetries = 3;

    this._lambda = new AWS.Lambda({
      region: this._action.region,
    });

    let payloadKey = this._async ? 'InvokeArgs' : 'Payload';
    let invokeMethod = this._async ? 'invokeAsync' : 'invoke';

    let invocationParameters = {
      FunctionName: this._action.source.original,
    };

    invocationParameters[payloadKey] = JSON.stringify(this.payload);

    this._lambda[invokeMethod](invocationParameters, (error, data) => {
      callback(new LambdaResponse(this, data, error));
    });

    return this;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   * @private
   */
  _sendExternal(callback = () => {}) {
    Http[this._method.toLowerCase()](this._action.source.original)
      .send(this.payload)
      .end((error, response) => {
        callback(new SuperagentResponse(this, response, error));
      });

    return this;
  }

  /**
   * @param {String} url
   * @param {String} httpMethod
   * @param {Object} payload
   * @param {Function} callback
   * @private
   */
  _createAws4SignedRequest(url, httpMethod, payload, callback) {
    let parsedUrl = urlParse(url, qs);
    let apiHost = parsedUrl.hostname;
    let apiPath = parsedUrl.pathname ? parsedUrl.pathname : '/';

    let opsToSign = {
      service: Core.AWS.Service.API_GATEWAY_EXECUTE,
      region: this.getEndpointHostRegion(apiHost),
      host: apiHost,
      method: httpMethod,
      path: apiPath,
      headers: {
        'Content-Type': 'application/json; charset=UTF-8',
      },
    };

    httpMethod = httpMethod.toLowerCase();

    switch (httpMethod) {
      case 'get':
      case 'delete':
        if (parsedUrl.query || payload) {
          let mergedPayload = Object.assign(parsedUrl.query, payload);

          opsToSign.path += `?${qs.stringify(mergedPayload)}`;

          // pass payload as query string
          parsedUrl.set('query', mergedPayload, qs.parse);
          url = parsedUrl.toString(qs.stringify);
          payload = null; // reset it coz superagent overrides url query string
        }
        break;
      case 'post':
      case 'put':
      case 'patch':
        opsToSign.body = JSON.stringify(payload);
        break;
    }

    this._loadSecurityCredentials((credentials) => {
      let signature = aws4.sign(opsToSign, credentials);

      let request = Http[httpMethod](url, payload)
        .set('Content-Type', 'application/json; charset=UTF-8')
        .set('X-Amz-Date', signature.headers['X-Amz-Date'])
        .set('X-Amz-Security-Token', signature.headers['X-Amz-Security-Token'])
        .set('Authorization', signature.headers.Authorization);

      if (signature.headers.hasOwnProperty('Content-Length')) {
        request.set('Content-Length', signature.headers['Content-Length']);
      }

      callback(request);
    });
  }

  /**
   * @returns {Object}
   * @private
   */
  _loadSecurityCredentials(callback) {
    let securityService = this._action.resource.security;

    if (!(securityService instanceof Security)) {
      throw new MissingSecurityServiceException();
    }

    if (!securityService.token) {
      throw new NotAuthenticatedException();
    }

    return securityService.token.loadCredentials((error, credentials) => {
      if (error) {
        throw new LoadCredentialsException(error);
      }

      callback(credentials);
    });
  }

  /**
   * @param {String} endpointHost
   * @returns {String}
   */
  getEndpointHostRegion(endpointHost) {
    let regionParts = endpointHost.match(/\.([^\.]+)\.amazonaws\.com$/i);

    // @todo - expose API region into config provision section
    return regionParts ? regionParts[1] : this._action.region; // use action region as fallback
  }

  /**
   * @returns {Action}
   */
  get action() {
    return this._action;
  }

  /**
   * @returns {Object}
   */
  get payload() {
    return this._payload;
  }

  /**
   * @returns {String}
   */
  get method() {
    return this._method;
  }

  /**
   * @returns {Number}
   * @constructor
   */
  static get TTL_DEFAULT() {
    return 10;
  }

  /**
   * @returns {Number}
   */
  static get TTL_INVALIDATE() {
    return -1;
  }

  /**
   * @returns {Number}
   */
  static get TTL_FOREVER() {
    return 0;
  }
}
<commit_msg>Use cognito identity credentials as primary creds when calling a lambda func<commit_after>/**
 * Created by AlexanderC on 6/10/15.
 */

'use strict';

import {SuperagentResponse} from './SuperagentResponse';
import {LambdaResponse} from './LambdaResponse';
import {Response} from './Response';
import {Exception} from '../Exception/Exception';
import {Action} from './Action';
import Http from 'superagent';
import AWS from 'aws-sdk';
import {MissingCacheImplementationException} from './Exception/MissingCacheImplementationException';
import {CachedRequestException} from './Exception/CachedRequestException';
import {NotAuthenticatedException} from './Exception/NotAuthenticatedException';
import aws4 from 'aws4';
import urlParse from 'url-parse';
import qs from 'qs';
import Core from 'deep-core';
import {MissingSecurityServiceException} from './Exception/MissingSecurityServiceException';
import {AsyncCallNotAvailableException} from './Exception/AsyncCallNotAvailableException';
import {LoadCredentialsException} from './Exception/LoadCredentialsException';
import Security from 'deep-security';
import crypto from 'crypto';

/**
 * Action request instance
 */
export class Request {
  /**
   * @param {Action} action
   * @param {Object} payload
   * @param {String} method
   */
  constructor(action, payload, method) {
    this._action = action;
    this._payload = payload;
    this._method = method;
    this._lambda = null;

    this._cacheImpl = null;
    this._cacheTtl = Request.TTL_FOREVER;
    this._cached = false;

    this._async = false;
    this._native = false;
  }

  /**
   * @returns {Boolean}
   */
  get async() {
    return this._async;
  }

  /**
   * @returns {Request}
   */
  invokeAsync() {
    if (!this.isLambda) {
      throw new AsyncCallNotAvailableException(this._action.type);
    }

    this._native = true;
    this._async = true;

    return this;
  }

  /**
   * @returns {Boolean}
   */
  get native() {
    return this._native;
  }

  /**
   * @returns {Request}
   */
  useDirectCall() {
    this._native = true;

    return this;
  }

  /**
   * @returns {Boolean}
   */
  get isCached() {
    return this._cacheImpl && this._cached;
  }

  /**
   * @returns {Request}
   */
  enableCache() {
    this._cached = true;
    return this;
  }

  /**
   * @returns {Request}
   */
  disableCache() {
    this._cached = false;
    return this;
  }

  /**
   * @param {Number} ttl
   * @returns {Request}
   */
  cache(ttl = Request.TTL_FOREVER) {
    if (!this._cacheImpl) {
      throw new MissingCacheImplementationException();
    }

    this._cacheTtl = ttl;
    this.enableCache();

    return this;
  }

  /**
   * @returns {Number}
   */
  get cacheTtl() {
    return this._cacheTtl;
  }

  /**
   * @param {Number} ttl
   */
  set cacheTtl(ttl) {
    this._cacheTtl = ttl;
  }

  /**
   * @returns {Object}
   */
  get cacheImpl() {
    return this._cacheImpl;
  }

  /**
   * @param {Object} cache
   */
  set cacheImpl(cache) {
    this._cacheImpl = cache;

    // @todo: do we really have to force it?
    this.cache(Request.TTL_DEFAULT);
  }

  /**
   * @returns {String}
   * @private
   */
  _buildCacheKey() {
    let payload = Request._md5(JSON.stringify(this._payload));
    let endpoint = this.native ? this._action.source.original : this._action.source.api;

    return `${this._method}:${this._action.type}:${endpoint}#${payload}`;
  }

  /**
   * @param {String} str
   * @returns {String}
   */
  static _md5(str) {
    var md5sum = crypto.createHash('md5');

    md5sum.update(str);

    return md5sum.digest('hex');
  }

  /**
   * @param {Response} response
   * @returns {String}
   * @private
   */
  static _stringifyResponse(response) {
    return JSON.stringify({
      _class: response.constructor.name,
      data: response.rawData,
      error: response.rawError,
    });
  }

  /**
   * @param {String} rawData
   * @returns {Response}
   * @private
   */
  _rebuildResponse(rawData) {
    let response = JSON.parse(rawData);

    if (!response) {
      throw new CachedRequestException(`Unable to unpack cached JSON object from ${rawData}`);
    }

    let ResponseImpl = Request._chooseResponseImpl(response._class);

    if (!ResponseImpl) {
      throw new Exception(`Unknown Response implementation ${response._class}`);
    }

    return new ResponseImpl(this, response.data, response.error);
  }

  /**
   * @param {String} className
   * @returns {*}
   * @private
   */
  static _chooseResponseImpl(className) {
    let implMap = {};

    implMap[Response.name] = Response;
    implMap[LambdaResponse.name] = LambdaResponse;
    implMap[SuperagentResponse.name] = SuperagentResponse;

    return implMap[className];
  }

  /**
   * @param {Function} callback
   */
  invalidateCache(callback = () => {}) {
    if (!this.isCached) {
      callback(true);

      return this;
    }

    let cache = this._cacheImpl;
    let cacheKey = this._buildCacheKey();

    cache.has(cacheKey, (error, result) => {
      if (error) {
        throw new CachedRequestException(error);
      }

      if (result) {
        cache.invalidate(cacheKey, 0, (error, result) => {
          if (error) {
            throw new CachedRequestException(error);
          }

          callback(result);
        });

        return;
      }

      callback(true);
    });

    return this;
  }

  /**
   * @param {Function} callback
   */
  send(callback = () => {}) {
    if (!this.isCached || this._async) {
      return this._send(callback);
    }

    let cache = this._cacheImpl;
    let invalidateCache = this._cacheTtl === Request.TTL_INVALIDATE;
    let cacheKey = this._buildCacheKey();

    cache.has(cacheKey, (error, result) => {
      if (error) {
        throw new CachedRequestException(error);
      }

      if (result && !invalidateCache) {
        cache.get(cacheKey, (error, result) => {
          if (error) {
            throw new CachedRequestException(error);
          }

          callback(this._rebuildResponse(result));
        });

        return;
      }

      this._send((response) => {
        cache.set(cacheKey, Request._stringifyResponse(response), this._cacheTtl, (error, result) => {
          if (!result) {
            error = `Unable to persist request cache under key ${cacheKey}`;
          }

          if (error) {
            throw new CachedRequestException(error);
          }
        });

        // @todo: do it synchronous?
        callback(response);
      });
    });

    return this;
  }

  /**
   * @returns {Boolean}
   *
   * @todo: remove this?
   */
  get isLambda() {
    return this._action.type === Action.LAMBDA;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   */
  _send(callback = () => {}) {
    if (!this._native) {
      return this._sendThroughApi(callback);
    }

    switch (this._action.type) {
      case Action.LAMBDA:
        this._sendLambda(callback);
        break;
      case Action.EXTERNAL:
        this._sendExternal(callback);
        break;
      default: throw new Exception(`Request of type ${this._action.type} is not implemented`);
    }

    return this;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   * @private
   */
  _sendThroughApi(callback = () => {}) {
    let endpoint = this._action.source.api;

    this._createAws4SignedRequest(endpoint, this.method, this.payload, (signedRequest) => {
      signedRequest.end((error, response) => {
        callback(new SuperagentResponse(this, response, error));
      });
    });

    return this;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   * @private
   */
  _sendLambda(callback = () => {}) {
    // @todo: set retries in a smarter way...
    AWS.config.maxRetries = 3;

    let options = {
      region: this._action.region,
    };

    let payloadKey = this._async ? 'InvokeArgs' : 'Payload';
    let invokeMethod = this._async ? 'invokeAsync' : 'invoke';

    let invocationParameters = {
      FunctionName: this._action.source.original,
    };

    invocationParameters[payloadKey] = JSON.stringify(this.payload);

    this._loadSecurityCredentials((credentials) => {
      // use cognito identity credentials if present
      // if not, fallback to lambda execution role permissions
      if (credentials) {
        options.credentials = credentials;
      }

      this._lambda = new AWS.Lambda(options);

      this._lambda[invokeMethod](invocationParameters, (error, data) => {
        callback(new LambdaResponse(this, data, error));
      });
    });

    return this;
  }

  /**
   * @param {Function} callback
   * @returns {Request}
   * @private
   */
  _sendExternal(callback = () => {}) {
    Http[this._method.toLowerCase()](this._action.source.original)
      .send(this.payload)
      .end((error, response) => {
        callback(new SuperagentResponse(this, response, error));
      });

    return this;
  }

  /**
   * @param {String} url
   * @param {String} httpMethod
   * @param {Object} payload
   * @param {Function} callback
   * @private
   */
  _createAws4SignedRequest(url, httpMethod, payload, callback) {
    let parsedUrl = urlParse(url, qs);
    let apiHost = parsedUrl.hostname;
    let apiPath = parsedUrl.pathname ? parsedUrl.pathname : '/';

    let opsToSign = {
      service: Core.AWS.Service.API_GATEWAY_EXECUTE,
      region: this.getEndpointHostRegion(apiHost),
      host: apiHost,
      method: httpMethod,
      path: apiPath,
      headers: {
        'Content-Type': 'application/json; charset=UTF-8',
      },
    };

    httpMethod = httpMethod.toLowerCase();

    switch (httpMethod) {
      case 'get':
      case 'delete':
        if (parsedUrl.query || payload) {
          let mergedPayload = Object.assign(parsedUrl.query, payload);

          opsToSign.path += `?${qs.stringify(mergedPayload)}`;

          // pass payload as query string
          parsedUrl.set('query', mergedPayload, qs.parse);
          url = parsedUrl.toString(qs.stringify);
          payload = null; // reset it coz superagent overrides url query string
        }
        break;
      case 'post':
      case 'put':
      case 'patch':
        opsToSign.body = JSON.stringify(payload);
        break;
    }

    this._loadSecurityCredentials((credentials) => {
      let signature = aws4.sign(opsToSign, credentials);

      let request = Http[httpMethod](url, payload)
        .set('Content-Type', 'application/json; charset=UTF-8')
        .set('X-Amz-Date', signature.headers['X-Amz-Date'])
        .set('X-Amz-Security-Token', signature.headers['X-Amz-Security-Token'])
        .set('Authorization', signature.headers.Authorization);

      if (signature.headers.hasOwnProperty('Content-Length')) {
        request.set('Content-Length', signature.headers['Content-Length']);
      }

      callback(request);
    });
  }

  /**
   * @returns {Object}
   * @private
   */
  _loadSecurityCredentials(callback) {
    let securityService = this._action.resource.security;

    if (!(securityService instanceof Security)) {
      throw new MissingSecurityServiceException();
    }

    if (!securityService.token) {
      throw new NotAuthenticatedException();
    }

    return securityService.token.loadCredentials((error, credentials) => {
      if (error) {
        throw new LoadCredentialsException(error);
      }

      callback(credentials);
    });
  }

  /**
   * @param {String} endpointHost
   * @returns {String}
   */
  getEndpointHostRegion(endpointHost) {
    let regionParts = endpointHost.match(/\.([^\.]+)\.amazonaws\.com$/i);

    // @todo - expose API region into config provision section
    return regionParts ? regionParts[1] : this._action.region; // use action region as fallback
  }

  /**
   * @returns {Action}
   */
  get action() {
    return this._action;
  }

  /**
   * @returns {Object}
   */
  get payload() {
    return this._payload;
  }

  /**
   * @returns {String}
   */
  get method() {
    return this._method;
  }

  /**
   * @returns {Number}
   * @constructor
   */
  static get TTL_DEFAULT() {
    return 10;
  }

  /**
   * @returns {Number}
   */
  static get TTL_INVALIDATE() {
    return -1;
  }

  /**
   * @returns {Number}
   */
  static get TTL_FOREVER() {
    return 0;
  }
}
<|endoftext|>


<commit_before>//toolbar-test-cases.js
const jsdom = require('jsdom');
const assert = require('assert');
const { JSDOM } = jsdom;

// jsdom instance
let dom;

describe('Toolbar Component', function () {

	/* --  prepare test START -- */
	// loading the test page and wait til the scripts on the test pages are executed.
	before(function (done) {

		JSDOM.fromURL(
			`${global.origin}${global.testFolder}/ui/toolbar-test-cases.html`,
			{
				runScripts: "dangerously",
				resources: "usable"
			}
		).then(jsdom => {
			dom = jsdom;
			// check the loading flag
			let checkLoaded = setInterval(function () {
				if (jsdom.window.document.getElementById('isLoad').checked) {
					clearInterval(checkLoaded);
					done();
				}
			}, 100);
		}).catch(function (error) {
			// error
			done(error);
		});

	});
	/* --  prepare test END -- */

	/* -- test cases START -- */
	describe('constructor:options[default]', function () {
		// menu is close

			it('style', function () {
				//const tools = ;
				let list = dom.window.tools.elt.querySelectorAll('li[class]');
				//console.log(list[0].classList)
				//const menu = dom.window.document.getElementById('menu1');
				assert.equal(list[0].classList.contains('separator'), true);
				assert.equal(list[1].classList.contains('handler'), true);
				list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				assert.equal(list.length, 6);
			});

			it('li > states', function () {
				// status of check/btn
				dom.window.tools.elt.querySelectorAll(' .tools > li:not([class]) > input[type=checkbox]').forEach(chk=>{
					assert.equal(chk.checked, false);
				});
			});

			it('handler events', function() {
				const handler = dom.window.tools.elt.querySelector('.handler > label');
				// click first then all `li`s hide
				eventFire(handler,'click', dom);
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				assert.equal(list[0].style.display,'');
				assert.equal(list[1].style.display,'');
				assert.equal(list[2].style.display,'none');
				assert.equal(list[3].style.display,'none');
				assert.equal(list[4].style.display,'none');
				assert.equal(list[5].style.display,'none');

				// click first then a;; `li`s diplay
				eventFire(handler,'click', dom);
				dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])').forEach(li=>{
					assert.equal('','');
				});

			});

	});

	describe('click events for each tool', function () {
			it('main tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[0].querySelector('label');
				eventFire(label,'click', dom);
				assert.equal(list[0].querySelector('input[type=checkbox]').checked,true);
				assert.equal(list[1].querySelector('input[type=checkbox]').checked,false);
				assert.equal(dom.window.changedData.apps, true);
				assert.equal(dom.window.changedData.layers, false);

				label = list[1].querySelector('label');
				eventFire(label,'click', dom);
				assert.equal(list[0].querySelector('input[type=checkbox]').checked,false);
				assert.equal(list[1].querySelector('input[type=checkbox]').checked,true);
				assert.equal(dom.window.changedData.apps, false);
				assert.equal(dom.window.changedData.layers, true);
			});

			it('btn tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let i = list[2].querySelector('i');
				eventFire(i,'click', dom);
				assert.equal(dom.window.changedData.value, 'btn');
			});
			it('check tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[3].querySelector('label');
				eventFire(label,'click', dom);
				assert.equal(list[3].querySelector('input[type=checkbox]').checked,true);
				assert.equal(dom.window.changedData.checked, true);

				eventFire(label,'click', dom);
				assert.equal(list[3].querySelector('input[type=checkbox]').checked,false);
				assert.equal(dom.window.changedData.checked, false);
			});
			it('multistates tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[4].querySelector('label');
				eventFire(label,'click', dom);
				assert.equal(dom.window.changedData.state, 1);

				eventFire(label,'click', dom);
				assert.equal(dom.window.changedData.state, 2);

				eventFire(label,'click', dom);
				assert.equal(dom.window.changedData.state, 0);
			});

			it('dropdown tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[5].querySelector('label');
				const li = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])')[5].querySelectorAll('ul li');
				const checkList = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])')[5].querySelectorAll('ul li input[type=radio]');

				assert.equal(checkList[0].checked,true);
				assert.equal(checkList[1].checked,false);
				assert.equal(checkList[2].checked,false);

				eventFire(label,'click', dom);
				console.log(dom.window.changedData);
				assert.equal(dom.window.changedData.value, 'dropdown');
				assert.equal(dom.window.changedData.checked, true);
				assert.equal(dom.window.changedData.status, 'a');
			});

	});

});<commit_msg>update click handler<commit_after>//toolbar-test-cases.js
const jsdom = require('jsdom');
const assert = require('assert');
const { JSDOM } = jsdom;

// jsdom instance
let dom;

describe('Toolbar Component', function () {

	/* --  prepare test START -- */
	// loading the test page and wait til the scripts on the test pages are executed.
	before(function (done) {

		JSDOM.fromURL(
			`${global.origin}${global.testFolder}/ui/toolbar-test-cases.html`,
			{
				runScripts: "dangerously",
				resources: "usable"
			}
		).then(jsdom => {
			dom = jsdom;
			// check the loading flag
			let checkLoaded = setInterval(function () {
				if (jsdom.window.document.getElementById('isLoad').checked) {
					clearInterval(checkLoaded);
					done();
				}
			}, 100);
		}).catch(function (error) {
			// error
			done(error);
		});

	});
	/* --  prepare test END -- */

	/* -- test cases START -- */
	describe('constructor:options[default]', function () {
		// menu is close

			it('style', function () {
				//const tools = ;
				let list = dom.window.tools.elt.querySelectorAll('li[class]');
				//console.log(list[0].classList)
				//const menu = dom.window.document.getElementById('menu1');
				assert.equal(list[0].classList.contains('separator'), true);
				assert.equal(list[1].classList.contains('handler'), true);
				list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				assert.equal(list.length, 6);
			});

			it('li > states', function () {
				// status of check/btn
				dom.window.tools.elt.querySelectorAll(' .tools > li:not([class]) > input[type=checkbox]').forEach(chk=>{
					assert.equal(chk.checked, false);
				});
			});

			it('handler events', function() {
				const handler = dom.window.tools.elt.querySelector('.handler > label');
				// click first then all `li`s hide
				handler.click();
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				assert.equal(list[0].style.display,'');
				assert.equal(list[1].style.display,'');
				assert.equal(list[2].style.display,'none');
				assert.equal(list[3].style.display,'none');
				assert.equal(list[4].style.display,'none');
				assert.equal(list[5].style.display,'none');

				// click first then a;; `li`s diplay
				handler.click()
				dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])').forEach(li=>{
					assert.equal('','');
				});

			});

	});

	describe('click events for each tool', function () {
			it('main tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[0].querySelector('label');
				label.click()
				assert.equal(list[0].querySelector('input[type=checkbox]').checked,true);
				assert.equal(list[1].querySelector('input[type=checkbox]').checked,false);
				assert.equal(dom.window.changedData.apps, true);
				assert.equal(dom.window.changedData.layers, false);

				label = list[1].querySelector('label');
				label.click()
				assert.equal(list[0].querySelector('input[type=checkbox]').checked,false);
				assert.equal(list[1].querySelector('input[type=checkbox]').checked,true);
				assert.equal(dom.window.changedData.apps, false);
				assert.equal(dom.window.changedData.layers, true);
			});

			it('btn tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let i = list[2].querySelector('i');
				i.click()
				assert.equal(dom.window.changedData.value, 'btn');
			});
			it('check tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[3].querySelector('label');
				label.click()
				assert.equal(list[3].querySelector('input[type=checkbox]').checked,true);
				assert.equal(dom.window.changedData.checked, true);

				label.click()
				assert.equal(list[3].querySelector('input[type=checkbox]').checked,false);
				assert.equal(dom.window.changedData.checked, false);
			});
			it('multistates tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[4].querySelector('label');
				label.click()
				assert.equal(dom.window.changedData.state, 1);

				label.click()
				assert.equal(dom.window.changedData.state, 2);

				label.click()
				assert.equal(dom.window.changedData.state, 0);
			});

			it('dropdown tool click events', function () {
				const list = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])');
				let label = list[5].querySelector('label');
				const li = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])')[5].querySelectorAll('ul li');
				const checkList = dom.window.tools.elt.querySelectorAll(' .tools > li:not([class])')[5].querySelectorAll('ul li input[type=radio]');

				assert.equal(checkList[0].checked,true);
				assert.equal(checkList[1].checked,false);
				assert.equal(checkList[2].checked,false);

				label.click()
				console.log(dom.window.changedData);
				assert.equal(dom.window.changedData.value, 'dropdown');
				assert.equal(dom.window.changedData.checked, true);
				assert.equal(dom.window.changedData.status, 'a');
			});

	});

});
<|endoftext|>


<commit_before>// Extend the jQuery FN so that new methods can be called.
jQuery.fn.extend({

  // Enable the tab contents for a given tab element.
  EnableTabContents: function() {

    // Start by deactiving every tab element on the page.
    $("li[role=tab]").each(function(index) {
      $(this).removeClass("active");
      $(".contents", this).removeClass("active");
    });

    // Activate the tab which is requested.
    $(this).addClass("active");
    $(".contents", this).addClass("active");

    // Return the "tab" element.
    return $(this);
  },

  // Enable the menu for a given icon.
  //  Parameters:
  //    Timekey: The duration it takes to slide down the element.,
  //    Elementkey: The element on which the "active" class should be set.
  EnableMenu: function(time, element) {
    // Check if the menu is closed. If that's the case, we should show it.
    if(!$(this).data("state") || $(this).data("state") == 0) {
      $(this).show("slide", { direction: "up" }, time);
      $(element).addClass("active");

      // Update the current state.
      $(this).data("state", 1);

    // Menu is visible, so let's close it.
    } else if ($(this).data("state") == 1) {
      $(this).DisableMenu($(element));
    }

    $(".menu").not(this).each(function() {
      $(this).DisableMenu($(this).parent());
    });
  },

  DisableMenu: function(element) {
      $(this).hide();
      $(element).removeClass("active");

      // Update the state.
      $(this).data("state", 0);
  }

});

var OfficeUICoreInternal = {
	AddHandlers: function() {

	  // Events handlers are placed here.

	    // When you click anywhere on the document, execute the following code.
	    $(document).click(function() {
	      // Make sure that all dropdowns are closed.
	       $(".menu").each(function() {
	         $(this).hide().parent().removeClass("active");
	         $(this).data("state", 0);
	       });
	    });

	    // When you click on a tab element (not the first element, since that's the application), make sure the contents are coming available.
	    $("li[role=tab]:not(.application)").click(function() {
	      $(this).EnableTabContents();
	    });

	    // When you click on an icon execute the code below.
	    $(".icon").click(function(e) {
	      // When the icon holds a menu, show the menu.
	      if ($(this).children(".menu").length > 0) {

	        e.stopPropagation();

	        $(".menu", this).EnableMenu(50, $(this));

	      }
	    });
	}
}

var OfficeUICore = {

  // Initialize the OfficeUI controls which are on the page.
  // The initialization is done by placeing classes automatticly on the necessary elements.
  // That way the HTML is cleaner.
  Init: function() {
    $(".ribbon, .tabs").addClass("brd_btm_grey");
    $(".tabs UL, .menucontents UL").addClass("nopadding nomargin");
    $(".menucontents UL LI").addClass("nowrap");
    $("li[role='tab']").addClass("inline");

    // Enable the first tab.
    $("li[role='tab']:not(.application)").first().EnableTabContents();

    $("li span:first-child").addClass("uppercase");
    $("li[role='tab'] .contents").addClass("absolute");
    $(".group, .seperator").addClass("relative inline");
    $(".icongroup, .smallicon .iconlegend, .imageHolder, .menuItem").addClass("inline");
    $(".bigicon").addClass("icon relative inline center");
    $(".smallicon").addClass("icon relative");
    $(".legend, .menu").addClass("absolute");
    $(".arrow").addClass("relative");

    OfficeUICoreInternal.AddHandlers();
  }

}<commit_msg>Inizializzazioni degli elementi a runtime<commit_after>// Extend the jQuery FN so that new methods can be called.
jQuery.fn.extend({

  // Enable the tab contents for a given tab element.
  EnableTabContents: function() {

    // Start by deactiving every tab element on the page.
    $("li[role=tab]").each(function(index) {
      $(this).removeClass("active");
      $(".contents", this).removeClass("active");
    });

    // Activate the tab which is requested.
    $(this).addClass("active");
    $(".contents", this).addClass("active");

    // Return the "tab" element.
    return $(this);
  },

  // Enable the menu for a given icon.
  //  Parameters:
  //    Timekey: The duration it takes to slide down the element.,
  //    Elementkey: The element on which the "active" class should be set.
  EnableMenu: function(time, element) {
    // Check if the menu is closed. If that's the case, we should show it.
    if(!$(this).data("state") || $(this).data("state") == 0) {
      $(this).show("slide", { direction: "up" }, time);
      $(element).addClass("active");

      // Update the current state.
      $(this).data("state", 1);

    // Menu is visible, so let's close it.
    } else if ($(this).data("state") == 1) {
      $(this).DisableMenu($(element));
    }

    $(".menu").not(this).each(function() {
      $(this).DisableMenu($(this).parent());
    });
  },

  DisableMenu: function(element) {
      $(this).hide();
      $(element).removeClass("active");

      // Update the state.
      $(this).data("state", 0);
  }

});

var OfficeUICoreInternal = {
	AddGlobalHandlers: function() {

	  // Events handlers are placed here.

	    // When you click anywhere on the document, execute the following code.
	    $(document).click(function() {
	      // Make sure that all dropdowns are closed.
	       $(".menu").each(function() {
	         $(this).hide().parent().removeClass("active");
	         $(this).data("state", 0);
	       });
	    });

	}

}

var OfficeUICore = {

	/** Initialize an element and its descendants.
	 * The initialization is done by placeing classes automatticly on the necessary elements.
	 * That way the HTML is cleaner.
	 */
	InitElement: function(element) {
		var el = $(element);

		for (var i = 0; i < 2; i++) {
			var fun;

			if(i == 0)
				fun = function(s) { return el.filter(s); };
			else
				fun = function(s) { return el.find(s); };

			fun(".ribbon, .tabs").addClass("brd_btm_grey");
			fun(".tabs UL, .menucontents UL").addClass("nopadding nomargin");
			fun(".menucontents UL LI").addClass("nowrap");
			fun("li[role='tab']").addClass("inline");

			// Enable the first tab.
			fun("li[role='tab']:not(.application)").first().EnableTabContents();

			fun("li span:first-child").addClass("uppercase");
			fun("li[role='tab'] .contents").addClass("absolute");
			fun(".group, .seperator").addClass("relative inline");
			fun(".icongroup, .smallicon .iconlegend, .imageHolder, .menuItem").addClass("inline");
			fun(".bigicon").addClass("icon relative inline center");
			fun(".smallicon").addClass("icon relative");
			fun(".legend, .menu").addClass("absolute");
			fun(".arrow").addClass("relative");

			// Attach handlers

		    // When you click on a tab element (not the first element, since that's the application), make sure the contents are coming available.
		    $("li[role=tab]:not(.application)").click(function() {
		      $(this).EnableTabContents();
		    });

		    // When you click on an icon execute the code below.
		    $(".icon").click(function(e) {
		      // When the icon holds a menu, show the menu.
		      if ($(this).children(".menu").length > 0) {

		        e.stopPropagation();

		        $(".menu", this).EnableMenu(50, $(this));

		      }
		    });
		}

	},

  /** Initialize the OfficeUI controls which are on the page. */
  Init: function() {
	OfficeUICore.InitElement(document);
    OfficeUICoreInternal.AddGlobalHandlers();
  }

}<|endoftext|>


<commit_before>/**
 * We will expose all methods and properties of CookieMaster
 * through the parent object, for easy extendability
 *
 * @type {Object}
 */
CM = {};

/**
 * Configuration settings for CookieMaster, the loaded version of
 * Cookie Clicker and user-specific settings.
 *
 * @type {Object}
 */
CM.config = {

	cmVersion: '0.1',
	cmIsLoaded: false,
	cmDecimalSeparator: '.',
	cmStyleID: 'cmStyles',

	ccURL: 'http://orteil.dashnet.org/cookieclicker/',
	ccVersion: '',
	ccCompatibleVersions: ['1.0402', '1.0403'],

	ccGame: $('#game'),

	// TO DO: Make these actually do something :)
	settings: {
		cleanUI: {
			label: 'Clean UI',
			desc: 'Hide the top bar, and make other small graphical enhancements to the game interface',
			options: true
		},
		numFormat: {
			label: 'Decimal Separator',
			desc: 'Display numbers in US or European format',
			options: ['us', 'eu']
		},
		shortNums: {
			label: 'Short Numbers',
			desc: 'Shorten large numbers with suffixes',
			options: true
		}
	},

};

/**
 * Initialization method. This is the first thing that gets called
 * when the script runs, and all methods that need to be invoked on
 * startup should get called from here in the order needed.
 */
CM.init = function() {

	var self = this;

	/**
	 * Perform a quick check to make sure CM can run correctly
	 */
	if(this.integrityCheck()) {

		this.attachSettingsPanel();
		this.cleanUI();

		this.attachStyleElement(this.config.cmStyleID);
		this.addStyles({
			'#CMSettingsPanel': {
				'position': 'absolute',
				'z-index': '9001',
				'bottom': '0',
				'left': '0',
				'width': '300px',
				'height': '300px',
				'background-color': 'rgba(0,0,0,0.95)',
				'padding': '20px',
				'color': '#FFF',
				'border': '2px solid #555'
			},
			'#CMSettingsTitle': {
				'margin': '0 0 20px',
				'font-size': '22px',
				'font-family': '"Kavoon", Georgia, serif'
			}
		}, document.getElementById('CMStyles').sheet);

		// All done :)
		this.config.cmIsLoaded = true;
		Game.Popup('CookieMaster version ' + this.config.cmVersion + ' loaded successfully!');

	} else {

		this.suicide();
		return false;

	}

};

/**
 * Checks that CookieMaster can run correctly and informs the
 * user if anything is wrong
 *
 * @return {boolean}
 */
CM.integrityCheck = function() {

	var ccVersion = Game.version.toString() || '',
		message = false,
		error = false,
		i;

	if(this.config.cmIsLoaded) {
		// Already loaded
		message = 'Error: CookieMaster is already running!';
		error = true;
	} else if(document.location.href.indexOf(this.config.ccURL) === -1) {
		// Wrong URL
		message = 'Error: This isn\'t the Cookie Clicker URL';
		error = true;
	} else if(!window.jQuery) {
		// jQuery isn't loaded
		message = 'Error: jQuery is not loaded';
		error = true;
	} else if(!Game) {
		// Game class doesn't exist
		message = 'Error: Cookie Clicker does not appear to be initialized';
		error = true;
	}

	// Warn against potential incompatibility
	if(this.compatibilityCheck(ccVersion) === -1) {
		message = 'Warning: This version of Cookie Clicker may not be fully supported!';
	}

	// Alert user to any issues
	if(message) {
		this.alertMessage(message);
	}

	if(error) {

		return false;

	} else {

		// Set some useful config options for later use
		this.config.ccVersion = ccVersion;
		this.config.ccGame = $('#game');

		return true;
	}

};

/**
 * Checks the loaded version of CC against a list of
 * known compatible versions
 *
 * @param  {string} version The version of CC we are running on
 *
 * @return {integer}         Return index of matched version
 */
CM.compatibilityCheck = function(version) {

	var compVersions = this.config.ccCompatibleVersions,
		ccVersion = version || '',
		i;

	for(i = 0; i < compVersions.length; i++) {
		if(compVersions[i].match(ccVersion)) {
			return i;
		}
	}

	return -1;

}

/**
 * Clean up the game interface a little. Most of these are borrowed
 * from Cookie Monster :)
 */
CM.cleanUI = function() {

	var $game = this.config.ccGame,
		gameFixes =
		'-webkit-touch-callout: none;' +
		'-webkit-user-select: none;' +
		'-khtml-user-select: none;' +
		'-moz-user-select: none;' +
		'-ms-user-select: none;' +
		'-o-user-select: none;' +
		'user-select: none;' +
		'top: 0;';

	$('#topBar').css('display', 'none');
	$game.css('cssText', gameFixes);
	$game.find('#cookies').css({
		'background': 'rgba(0,0,0,0.75)',
		'border-top': '1px solid black',
		'border-bottom': '1px solid black'
	});
	$game.find('#tooltip').css({
		'margin-top': '32px',
		'pointer-events': 'none'
	});

};

/**
 * Formats very large numbers with their appropriate suffix, also adds
 * thousands and decimal separators and performs correct rounding for
 * smaller numbers
 *
 * @param  {integer} num The number to be formatted
 * @param  {integer} floats Amount of decimal places required
 *
 * @return {string}     Formatted number (as string) with suffix
 */
CM.largeNumFormat = function(num, floats, decSep) {

	var decSep = decSep || this.config.cmDecimalSeparator,
		decimal = decSep === '.' ? '.' : ',',
		comma = decSep === '.' ? ',' : '.',
		floats = floats || 0,
		parts,
		ranges = [
			{divider: 1e33, suffix: 'Dc'},
			{divider: 1e30, suffix: 'No'},
			{divider: 1e27, suffix: 'Oc'},
			{divider: 1e24, suffix: 'Sp'},
			{divider: 1e21, suffix: 'Sx'},
			{divider: 1e18, suffix: 'Qi'},
			{divider: 1e15, suffix: 'Qa'},
			{divider: 1e12, suffix: 'T'},
			{divider: 1e9, suffix: 'B'},
			{divider: 1e6, suffix: 'M'}
		];

	for(var i = 0; i < ranges.length; i++) {

		if(num >= ranges[i].divider) {
			num = (num / ranges[i].divider).toFixed(3) + ' ' + ranges[i].suffix;
			// Apply localization if necessary
			if(decSep === ',') {
				return num.replace('.', ',');
			} else {
				return num;
			}
		}

	}

	// Apply rounding, if any
	num = Math.round(num * Math.pow(10, floats)) / Math.pow(10, floats);

	// Prettify and localize the remaining "smaller" numbers
	parts = num.toString().split('.');
	parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, comma);
	return parts.join(decimal);

};

/**
 * Build and attach the settings panel to the DOM
 */
CM.attachSettingsPanel = function() {

	var settings = this.config.settings,
		items = [],
		$wrapper = $('#wrapper'),
		$cmSettingsPanel = $('
').attr('id', 'CMSettingsPanel'),
		$cmSettingsTitle = $('
').attr('id', 'CMSettingsTitle').text('CookieMaster Settings'),
		$cmSettingsList = $('
').attr('id', 'CMSettingsList');

		// Build each setting item
		$.each(settings, function() {
			items.push('
' + this.label + '
');

		});

		// Glue it together
		$cmSettingsList.append(items.join(''));
		$cmSettingsPanel.append($cmSettingsTitle);
		$cmSettingsPanel.append($cmSettingsList);

		// Attach to DOM
		$wrapper.append($cmSettingsPanel);

};

/**
 * Append a style element to document head for adding CSS styles
 *
 * @param  {string} Desired element ID
 *
 * @return {object}    The inserted style element
 */
CM.attachStyleElement = function(id) {

	var styleEl = document.createElement('style'),
		id = id || '';

	styleEl.setAttribute('id', id);
	styleEl.appendChild(document.createTextNode(''));
	document.head.appendChild(styleEl);

	return styleEl;

};

/**
 * Adds CSS rules to the specified style element
 *
 * @param {object} rules List of rules in JSON format
 * @param {object} sheet The style element to apply the rules to
 *
 * @return {object}    The style element
 */
CM.addStyles = function(rules, sheet) {

	for(var selector in rules) {
		var props = rules[selector],
			propStr = '';
		for(var propName in props) {
			var propVal = props[propName],
				propImportant = '';
			if(propVal[1] === true) {
				// propVal is an array of value/important, rather than a string.
				propVal = propVal[0];
				propImportant = ' !important';
			}
			propStr += propName + ':' + propVal + propImportant + ';\n';
		}
		sheet.insertRule(selector + '{' + propStr + '}', sheet.cssRules.length);
	}

	return sheet;

};

/**
 * Remove all traces of CookieMaster
 */
CM.suicide = function() {
	// TO DO: Implement this functionality
	alert('This kills the CookieMaster.');
};

/**
 * Alert user to messages (expand later)
 *
 * @param  {string} msg The message
 */
CM.alertMessage = function(msg) {
	alert(msg);
};

// Start it up!
CM.init();

/* ===========================================
	COOKIE CLICKER FUNCTION OVERRIDES
=========================================== */

/**
 * Hijacks the original Beautify method to use our own formatting function
 *
 * @param {integer} what   The number to beautify
 * @param {integer} floats Number of decimal places desired :/
 *
 * @return {string}    Nicely formatted number as a string
 */
function Beautify(what, floats) {

	var floats = floats || 0;

	return CM.largeNumFormat(what, floats, CM.config.cmDecimalSeparator);

}
/* ===========================================
	END COOKIE CLICKER FUNCTION OVERRIDES
=========================================== */
<commit_msg>Fixed method name typo<commit_after>/**
 * We will expose all methods and properties of CookieMaster
 * through the parent object, for easy extendability
 *
 * @type {Object}
 */
CM = {};

/**
 * Configuration settings for CookieMaster, the loaded version of
 * Cookie Clicker and user-specific settings.
 *
 * @type {Object}
 */
CM.config = {

	cmVersion: '0.1',
	cmIsLoaded: false,
	cmDecimalSeparator: '.',
	cmStyleID: 'cmStyles',

	ccURL: 'http://orteil.dashnet.org/cookieclicker/',
	ccVersion: '',
	ccCompatibleVersions: ['1.0402', '1.0403'],

	ccGame: $('#game'),

	// TO DO: Make these actually do something :)
	settings: {
		cleanUI: {
			label: 'Clean UI',
			desc: 'Hide the top bar, and make other small graphical enhancements to the game interface',
			options: true
		},
		numFormat: {
			label: 'Decimal Separator',
			desc: 'Display numbers in US or European format',
			options: ['us', 'eu']
		},
		shortNums: {
			label: 'Short Numbers',
			desc: 'Shorten large numbers with suffixes',
			options: true
		}
	},

};

/**
 * Initialization method. This is the first thing that gets called
 * when the script runs, and all methods that need to be invoked on
 * startup should get called from here in the order needed.
 */
CM.init = function() {

	var self = this;

	/**
	 * Perform a quick check to make sure CM can run correctly
	 */
	if(this.integrityCheck()) {

		this.attachSettingsPanel();
		this.cleanUI();

		this.attachStyleElement(this.config.cmStyleID);
		this.addStyles({
			'#CMSettingsPanel': {
				'position': 'absolute',
				'z-index': '9001',
				'bottom': '0',
				'left': '0',
				'width': '300px',
				'height': '300px',
				'background-color': 'rgba(0,0,0,0.95)',
				'padding': '20px',
				'color': '#FFF',
				'border': '2px solid #555'
			},
			'#CMSettingsTitle': {
				'margin': '0 0 20px',
				'font-size': '22px',
				'font-family': '"Kavoon", Georgia, serif'
			}
		}, document.getElementById('CMStyles'));

		// All done :)
		this.config.cmIsLoaded = true;
		Game.Popup('CookieMaster version ' + this.config.cmVersion + ' loaded successfully!');

	} else {

		this.suicide();
		return false;

	}

};

/**
 * Checks that CookieMaster can run correctly and informs the
 * user if anything is wrong
 *
 * @return {boolean}
 */
CM.integrityCheck = function() {

	var ccVersion = Game.version.toString() || '',
		message = false,
		error = false,
		i;

	if(this.config.cmIsLoaded) {
		// Already loaded
		message = 'Error: CookieMaster is already running!';
		error = true;
	} else if(document.location.href.indexOf(this.config.ccURL) === -1) {
		// Wrong URL
		message = 'Error: This isn\'t the Cookie Clicker URL';
		error = true;
	} else if(!window.jQuery) {
		// jQuery isn't loaded
		message = 'Error: jQuery is not loaded';
		error = true;
	} else if(!Game) {
		// Game class doesn't exist
		message = 'Error: Cookie Clicker does not appear to be initialized';
		error = true;
	}

	// Warn against potential incompatibility
	if(this.compatibilityCheck(ccVersion) === -1) {
		message = 'Warning: This version of Cookie Clicker may not be fully supported!';
	}

	// Alert user to any issues
	if(message) {
		this.alertMessage(message);
	}

	if(error) {

		return false;

	} else {

		// Set some useful config options for later use
		this.config.ccVersion = ccVersion;
		this.config.ccGame = $('#game');

		return true;
	}

};

/**
 * Checks the loaded version of CC against a list of
 * known compatible versions
 *
 * @param  {string} version The version of CC we are running on
 *
 * @return {integer}         Return index of matched version
 */
CM.compatibilityCheck = function(version) {

	var compVersions = this.config.ccCompatibleVersions,
		ccVersion = version || '',
		i;

	for(i = 0; i < compVersions.length; i++) {
		if(compVersions[i].match(ccVersion)) {
			return i;
		}
	}

	return -1;

}

/**
 * Clean up the game interface a little. Most of these are borrowed
 * from Cookie Monster :)
 */
CM.cleanUI = function() {

	var $game = this.config.ccGame,
		gameFixes =
		'-webkit-touch-callout: none;' +
		'-webkit-user-select: none;' +
		'-khtml-user-select: none;' +
		'-moz-user-select: none;' +
		'-ms-user-select: none;' +
		'-o-user-select: none;' +
		'user-select: none;' +
		'top: 0;';

	$('#topBar').css('display', 'none');
	$game.css('cssText', gameFixes);
	$game.find('#cookies').css({
		'background': 'rgba(0,0,0,0.75)',
		'border-top': '1px solid black',
		'border-bottom': '1px solid black'
	});
	$game.find('#tooltip').css({
		'margin-top': '32px',
		'pointer-events': 'none'
	});

};

/**
 * Formats very large numbers with their appropriate suffix, also adds
 * thousands and decimal separators and performs correct rounding for
 * smaller numbers
 *
 * @param  {integer} num The number to be formatted
 * @param  {integer} floats Amount of decimal places required
 *
 * @return {string}     Formatted number (as string) with suffix
 */
CM.largeNumFormat = function(num, floats, decSep) {

	var decSep = decSep || this.config.cmDecimalSeparator,
		decimal = decSep === '.' ? '.' : ',',
		comma = decSep === '.' ? ',' : '.',
		floats = floats || 0,
		parts,
		ranges = [
			{divider: 1e33, suffix: 'Dc'},
			{divider: 1e30, suffix: 'No'},
			{divider: 1e27, suffix: 'Oc'},
			{divider: 1e24, suffix: 'Sp'},
			{divider: 1e21, suffix: 'Sx'},
			{divider: 1e18, suffix: 'Qi'},
			{divider: 1e15, suffix: 'Qa'},
			{divider: 1e12, suffix: 'T'},
			{divider: 1e9, suffix: 'B'},
			{divider: 1e6, suffix: 'M'}
		];

	for(var i = 0; i < ranges.length; i++) {

		if(num >= ranges[i].divider) {
			num = (num / ranges[i].divider).toFixed(3) + ' ' + ranges[i].suffix;
			// Apply localization if necessary
			if(decSep === ',') {
				return num.replace('.', ',');
			} else {
				return num;
			}
		}

	}

	// Apply rounding, if any
	num = Math.round(num * Math.pow(10, floats)) / Math.pow(10, floats);

	// Prettify and localize the remaining "smaller" numbers
	parts = num.toString().split('.');
	parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, comma);
	return parts.join(decimal);

};

/**
 * Build and attach the settings panel to the DOM
 */
CM.attachSettingsPanel = function() {

	var settings = this.config.settings,
		items = [],
		$wrapper = $('#wrapper'),
		$cmSettingsPanel = $('
').attr('id', 'CMSettingsPanel'),
		$cmSettingsTitle = $('
').attr('id', 'CMSettingsTitle').text('CookieMaster Settings'),
		$cmSettingsList = $('
').attr('id', 'CMSettingsList');

		// Build each setting item
		$.each(settings, function() {
			items.push('
' + this.label + '
');

		});

		// Glue it together
		$cmSettingsList.append(items.join(''));
		$cmSettingsPanel.append($cmSettingsTitle);
		$cmSettingsPanel.append($cmSettingsList);

		// Attach to DOM
		$wrapper.append($cmSettingsPanel);

};

/**
 * Append a style element to document head for adding CSS styles
 *
 * @param  {string} Desired element ID
 *
 * @return {object}    The inserted style element
 */
CM.attachStyleElement = function(id) {

	var styleEl = document.createElement('style'),
		id = id || '';

	styleEl.setAttribute('id', id);
	styleEl.appendChild(document.createTextNode(''));
	document.head.appendChild(styleEl);

	return styleEl;

};

/**
 * Adds CSS rules to the specified style element
 *
 * @param {object} rules List of rules in JSON format
 * @param {object} sheet The style element to apply the rules to
 *
 * @return {object}    The style element
 */
CM.addStyles = function(rules, el) {

	var sheet = el.sheet;

	for(var selector in rules) {
		var props = rules[selector],
			propStr = '';
		for(var propName in props) {
			var propVal = props[propName],
				propImportant = '';
			if(propVal[1] === true) {
				// propVal is an array of value/important, rather than a string.
				propVal = propVal[0];
				propImportant = ' !important';
			}
			propStr += propName + ':' + propVal + propImportant + ';\n';
		}
		sheet.insertRule(selector + '{' + propStr + '}', sheet.cssRules.length);
	}

	return el;

};

/**
 * Remove all traces of CookieMaster
 */
CM.suicide = function() {
	// TO DO: Implement this functionality
	alert('This kills the CookieMaster.');
};

/**
 * Alert user to messages (expand later)
 *
 * @param  {string} msg The message
 */
CM.alertMessage = function(msg) {
	alert(msg);
};

// Start it up!
CM.init();

/* ===========================================
	COOKIE CLICKER FUNCTION OVERRIDES
=========================================== */

/**
 * Hijacks the original Beautify method to use our own formatting function
 *
 * @param {integer} what   The number to beautify
 * @param {integer} floats Number of decimal places desired :/
 *
 * @return {string}    Nicely formatted number as a string
 */
function Beautify(what, floats) {

	var floats = floats || 0;

	return CM.largeNumFormat(what, floats, CM.config.cmDecimalSeparator);

}
/* ===========================================
	END COOKIE CLICKER FUNCTION OVERRIDES
=========================================== */
<|endoftext|>


<commit_before>import { useQuery, gql } from '@apollo/client'
import { Feed } from 'feed'
import { fs } from 'fs'

async function generateRssFeed() {
  if (process.env.NODE_ENV === 'development') {
    return
  }

  const baseUrl = process.env.BASE_URL
  const date = new Date()
  const author = {
    name: 'Matthias Jordan',
    email: 'hey@iammatthias.com',
    link: 'https://twitter.com/iammatthias',
  }

  const feed = new Feed({
    title: `I AM MATTHIAS`,
    description: 'Photographer & Growth Marketer',
    id: baseUrl,
    link: baseUrl,
    language: 'en',
    image: `${baseUrl}/images/logo.svg`,
    favicon: `${baseUrl}/favicon.ico`,
    copyright: `All rights reserved ${date.getFullYear()}, Matthias Jordan`,
    updated: date,
    generator: 'Next.js using Feed for Node.js',
    feedLinks: {
      rss2: `${baseUrl}/rss/feed.xml`,
      json: `${baseUrl}/rss/feed.json`,
      atom: `${baseUrl}/rss/atom.xml`,
    },
    author,
  })

  const QUERY = gql`
   query {
     pageCollection(
       order: publishDate_DESC
       where: { pageType: 'Blog' OR pageType: 'Gallery' }
     ) {
       items {
         slug
         title
         publishDate
       }
     }
   }
 `

  const { data, loading, error } = useQuery(QUERY)

  if (loading) {
    return 'Loading...'
  }

  if (error) {
    console.error(error)
    return null
  }

  const posts = data.pageCollection.items

  posts.forEach(post => {
    const url = `${baseUrl}/${post.slug}`
    feed.addItem({
      title: post.title,
      id: url,
      link: url,
      author: [author],
      contributor: [author],
      date: new Date(post.publishDate),
    })
  })

  fs.mkdirSync('./public/rss', { recursive: true })
  fs.writeFileSync('./public/rss/feed.xml', feed.rss2())
  fs.writeFileSync('./public/rss/atom.xml', feed.atom1())
  fs.writeFileSync('./public/rss/feed.json', feed.json1())
}

export default generateRssFeed
<commit_msg>' to "<commit_after>import { useQuery, gql } from '@apollo/client'
import { Feed } from 'feed'
import { fs } from 'fs'

async function generateRssFeed() {
  if (process.env.NODE_ENV === 'development') {
    return
  }

  const baseUrl = process.env.BASE_URL
  const date = new Date()
  const author = {
    name: 'Matthias Jordan',
    email: 'hey@iammatthias.com',
    link: 'https://twitter.com/iammatthias',
  }

  const feed = new Feed({
    title: `I AM MATTHIAS`,
    description: 'Photographer & Growth Marketer',
    id: baseUrl,
    link: baseUrl,
    language: 'en',
    image: `${baseUrl}/images/logo.svg`,
    favicon: `${baseUrl}/favicon.ico`,
    copyright: `All rights reserved ${date.getFullYear()}, Matthias Jordan`,
    updated: date,
    generator: 'Next.js using Feed for Node.js',
    feedLinks: {
      rss2: `${baseUrl}/rss/feed.xml`,
      json: `${baseUrl}/rss/feed.json`,
      atom: `${baseUrl}/rss/atom.xml`,
    },
    author,
  })

  const QUERY = gql`
   query {
     pageCollection(
       order: publishDate_DESC
       where: { pageType: "Blog" OR pageType: "Gallery" }
     ) {
       items {
         slug
         title
         publishDate
       }
     }
   }
 `

  const { data, loading, error } = useQuery(QUERY)

  if (loading) {
    return 'Loading...'
  }

  if (error) {
    console.error(error)
    return null
  }

  const posts = data.pageCollection.items

  posts.forEach(post => {
    const url = `${baseUrl}/${post.slug}`
    feed.addItem({
      title: post.title,
      id: url,
      link: url,
      author: [author],
      contributor: [author],
      date: new Date(post.publishDate),
    })
  })

  fs.mkdirSync('./public/rss', { recursive: true })
  fs.writeFileSync('./public/rss/feed.xml', feed.rss2())
  fs.writeFileSync('./public/rss/atom.xml', feed.atom1())
  fs.writeFileSync('./public/rss/feed.json', feed.json1())
}

export default generateRssFeed
<|endoftext|>


<commit_before>// Based on jsDump by Ariel Flesler
// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
QUnit.dump = (function() {
	function quote( str ) {
		return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
	}
	function literal( o ) {
		return o + "";
	}
	function join( pre, arr, post ) {
		var s = dump.separator(),
			base = dump.indent(),
			inner = dump.indent( 1 );
		if ( arr.join ) {
			arr = arr.join( "," + s + inner );
		}
		if ( !arr ) {
			return pre + post;
		}
		return [ pre, inner + arr, base + post ].join( s );
	}
	function array( arr, stack ) {
		var i = arr.length,
			ret = new Array( i );

		if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
			return "[object Array]";
		}

		this.up();
		while ( i-- ) {
			ret[ i ] = this.parse( arr[ i ], undefined, stack );
		}
		this.down();
		return join( "[", ret, "]" );
	}

	var reName = /^function (\w+)/,
		dump = {

			// objType is used mostly internally, you can fix a (custom) type in advance
			parse: function( obj, objType, stack ) {
				stack = stack || [];
				var res, parser, parserType,
					inStack = inArray( obj, stack );

				if ( inStack !== -1 ) {
					return "recursion(" + ( inStack - stack.length ) + ")";
				}

				objType = objType || this.typeOf( obj  );
				parser = this.parsers[ objType ];
				parserType = typeof parser;

				if ( parserType === "function" ) {
					stack.push( obj );
					res = parser.call( this, obj, stack );
					stack.pop();
					return res;
				}
				return ( parserType === "string" ) ? parser : this.parsers.error;
			},
			typeOf: function( obj ) {
				var type;
				if ( obj === null ) {
					type = "null";
				} else if ( typeof obj === "undefined" ) {
					type = "undefined";
				} else if ( QUnit.is( "regexp", obj ) ) {
					type = "regexp";
				} else if ( QUnit.is( "date", obj ) ) {
					type = "date";
				} else if ( QUnit.is( "function", obj ) ) {
					type = "function";
				} else if ( obj.setInterval !== undefined &&
						obj.document !== undefined &&
						obj.nodeType === undefined ) {
					type = "window";
				} else if ( obj.nodeType === 9 ) {
					type = "document";
				} else if ( obj.nodeType ) {
					type = "node";
				} else if (

					// native arrays
					toString.call( obj ) === "[object Array]" ||

					// NodeList objects
					( typeof obj.length === "number" && obj.item !== undefined &&
					( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null &&
					obj[ 0 ] === undefined ) ) )
				) {
					type = "array";
				} else if ( obj.constructor === Error.prototype.constructor ) {
					type = "error";
				} else {
					type = typeof obj;
				}
				return type;
			},
			separator: function() {
				return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
			},
			// extra can be a number, shortcut for increasing-calling-decreasing
			indent: function( extra ) {
				if ( !this.multiline ) {
					return "";
				}
				var chr = this.indentChar;
				if ( this.HTML ) {
					chr = chr.replace( /\t/g, "   " ).replace( / /g, " " );
				}
				return new Array( this.depth + ( extra || 0 ) ).join( chr );
			},
			up: function( a ) {
				this.depth += a || 1;
			},
			down: function( a ) {
				this.depth -= a || 1;
			},
			setParser: function( name, parser ) {
				this.parsers[ name ] = parser;
			},
			// The next 3 are exposed so you can use them
			quote: quote,
			literal: literal,
			join: join,
			//
			depth: 1,
			maxDepth: 5,

			// This is the list of parsers, to modify them, use dump.setParser
			parsers: {
				window: "[Window]",
				document: "[Document]",
				error: function( error ) {
					return "Error(\"" + error.message + "\")";
				},
				unknown: "[Unknown]",
				"null": "null",
				"undefined": "undefined",
				"function": function( fn ) {
					var ret = "function",

						// functions never have name in IE
						name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];

					if ( name ) {
						ret += " " + name;
					}
					ret += "( ";

					ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
					return join( ret, dump.parse( fn, "functionCode" ), "}" );
				},
				array: array,
				nodelist: array,
				"arguments": array,
				object: function( map, stack ) {
					var keys, key, val, i, nonEnumerableProperties,
						ret = [];

					if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
						return "[object Object]";
					}

					dump.up();
					keys = [];
					for ( key in map ) {
						keys.push( key );
					}

					// Some properties are not always enumerable on Error objects.
					nonEnumerableProperties = [ "message", "name" ];
					for ( i in nonEnumerableProperties ) {
						key = nonEnumerableProperties[ i ];
						if ( key in map && !( key in keys ) ) {
							keys.push( key );
						}
					}
					keys.sort();
					for ( i = 0; i < keys.length; i++ ) {
						key = keys[ i ];
						val = map[ key ];
						ret.push( dump.parse( key, "key" ) + ": " +
							dump.parse( val, undefined, stack ) );
					}
					dump.down();
					return join( "{", ret, "}" );
				},
				node: function( node ) {
					var len, i, val,
						open = dump.HTML ? "<" : "<",
						close = dump.HTML ? ">" : ">",
						tag = node.nodeName.toLowerCase(),
						ret = open + tag,
						attrs = node.attributes;

					if ( attrs ) {
						for ( i = 0, len = attrs.length; i < len; i++ ) {
							val = attrs[ i ].nodeValue;

							// IE6 includes all attributes in .attributes, even ones not explicitly
							// set. Those have values like undefined, null, 0, false, "" or
							// "inherit".
							if ( val && val !== "inherit" ) {
								ret += " " + attrs[ i ].nodeName + "=" +
									dump.parse( val, "attribute" );
							}
						}
					}
					ret += close;

					// Show content of TextNode or CDATASection
					if ( node.nodeType === 3 || node.nodeType === 4 ) {
						ret += node.nodeValue;
					}

					return ret + open + "/" + tag + close;
				},

				// function calls it internally, it's the arguments part of the function
				functionArgs: function( fn ) {
					var args,
						l = fn.length;

					if ( !l ) {
						return "";
					}

					args = new Array( l );
					while ( l-- ) {

						// 97 is 'a'
						args[ l ] = String.fromCharCode( 97 + l );
					}
					return " " + args.join( ", " ) + " ";
				},
				// object calls it internally, the key part of an item in a map
				key: quote,
				// function calls it internally, it's the content of the function
				functionCode: "[code]",
				// node calls it internally, it's an html attribute value
				attribute: quote,
				string: quote,
				date: quote,
				regexp: literal,
				number: literal,
				"boolean": literal
			},
			// if true, entities are escaped ( <, >, \t, space and \n )
			HTML: false,
			// indentation unit
			indentChar: "  ",
			// if true, items in a collection, are separated by a \n, else just a space.
			multiline: true
		};

	return dump;
}());

// back compat
QUnit.jsDump = QUnit.dump;
<commit_msg>Dump: Fix .name/.property doublettes<commit_after>// Based on jsDump by Ariel Flesler
// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
QUnit.dump = (function() {
	function quote( str ) {
		return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
	}
	function literal( o ) {
		return o + "";
	}
	function join( pre, arr, post ) {
		var s = dump.separator(),
			base = dump.indent(),
			inner = dump.indent( 1 );
		if ( arr.join ) {
			arr = arr.join( "," + s + inner );
		}
		if ( !arr ) {
			return pre + post;
		}
		return [ pre, inner + arr, base + post ].join( s );
	}
	function array( arr, stack ) {
		var i = arr.length,
			ret = new Array( i );

		if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
			return "[object Array]";
		}

		this.up();
		while ( i-- ) {
			ret[ i ] = this.parse( arr[ i ], undefined, stack );
		}
		this.down();
		return join( "[", ret, "]" );
	}

	var reName = /^function (\w+)/,
		dump = {

			// objType is used mostly internally, you can fix a (custom) type in advance
			parse: function( obj, objType, stack ) {
				stack = stack || [];
				var res, parser, parserType,
					inStack = inArray( obj, stack );

				if ( inStack !== -1 ) {
					return "recursion(" + ( inStack - stack.length ) + ")";
				}

				objType = objType || this.typeOf( obj  );
				parser = this.parsers[ objType ];
				parserType = typeof parser;

				if ( parserType === "function" ) {
					stack.push( obj );
					res = parser.call( this, obj, stack );
					stack.pop();
					return res;
				}
				return ( parserType === "string" ) ? parser : this.parsers.error;
			},
			typeOf: function( obj ) {
				var type;
				if ( obj === null ) {
					type = "null";
				} else if ( typeof obj === "undefined" ) {
					type = "undefined";
				} else if ( QUnit.is( "regexp", obj ) ) {
					type = "regexp";
				} else if ( QUnit.is( "date", obj ) ) {
					type = "date";
				} else if ( QUnit.is( "function", obj ) ) {
					type = "function";
				} else if ( obj.setInterval !== undefined &&
						obj.document !== undefined &&
						obj.nodeType === undefined ) {
					type = "window";
				} else if ( obj.nodeType === 9 ) {
					type = "document";
				} else if ( obj.nodeType ) {
					type = "node";
				} else if (

					// native arrays
					toString.call( obj ) === "[object Array]" ||

					// NodeList objects
					( typeof obj.length === "number" && obj.item !== undefined &&
					( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null &&
					obj[ 0 ] === undefined ) ) )
				) {
					type = "array";
				} else if ( obj.constructor === Error.prototype.constructor ) {
					type = "error";
				} else {
					type = typeof obj;
				}
				return type;
			},
			separator: function() {
				return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
			},
			// extra can be a number, shortcut for increasing-calling-decreasing
			indent: function( extra ) {
				if ( !this.multiline ) {
					return "";
				}
				var chr = this.indentChar;
				if ( this.HTML ) {
					chr = chr.replace( /\t/g, "   " ).replace( / /g, " " );
				}
				return new Array( this.depth + ( extra || 0 ) ).join( chr );
			},
			up: function( a ) {
				this.depth += a || 1;
			},
			down: function( a ) {
				this.depth -= a || 1;
			},
			setParser: function( name, parser ) {
				this.parsers[ name ] = parser;
			},
			// The next 3 are exposed so you can use them
			quote: quote,
			literal: literal,
			join: join,
			//
			depth: 1,
			maxDepth: 5,

			// This is the list of parsers, to modify them, use dump.setParser
			parsers: {
				window: "[Window]",
				document: "[Document]",
				error: function( error ) {
					return "Error(\"" + error.message + "\")";
				},
				unknown: "[Unknown]",
				"null": "null",
				"undefined": "undefined",
				"function": function( fn ) {
					var ret = "function",

						// functions never have name in IE
						name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];

					if ( name ) {
						ret += " " + name;
					}
					ret += "( ";

					ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
					return join( ret, dump.parse( fn, "functionCode" ), "}" );
				},
				array: array,
				nodelist: array,
				"arguments": array,
				object: function( map, stack ) {
					var keys, key, val, i, nonEnumerableProperties,
						ret = [];

					if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
						return "[object Object]";
					}

					dump.up();
					keys = [];
					for ( key in map ) {
						keys.push( key );
					}

					// Some properties are not always enumerable on Error objects.
					nonEnumerableProperties = [ "message", "name" ];
					for ( i in nonEnumerableProperties ) {
						key = nonEnumerableProperties[ i ];
						if ( key in map && !inArray( key, keys ) ) {
							keys.push( key );
						}
					}
					keys.sort();
					for ( i = 0; i < keys.length; i++ ) {
						key = keys[ i ];
						val = map[ key ];
						ret.push( dump.parse( key, "key" ) + ": " +
							dump.parse( val, undefined, stack ) );
					}
					dump.down();
					return join( "{", ret, "}" );
				},
				node: function( node ) {
					var len, i, val,
						open = dump.HTML ? "<" : "<",
						close = dump.HTML ? ">" : ">",
						tag = node.nodeName.toLowerCase(),
						ret = open + tag,
						attrs = node.attributes;

					if ( attrs ) {
						for ( i = 0, len = attrs.length; i < len; i++ ) {
							val = attrs[ i ].nodeValue;

							// IE6 includes all attributes in .attributes, even ones not explicitly
							// set. Those have values like undefined, null, 0, false, "" or
							// "inherit".
							if ( val && val !== "inherit" ) {
								ret += " " + attrs[ i ].nodeName + "=" +
									dump.parse( val, "attribute" );
							}
						}
					}
					ret += close;

					// Show content of TextNode or CDATASection
					if ( node.nodeType === 3 || node.nodeType === 4 ) {
						ret += node.nodeValue;
					}

					return ret + open + "/" + tag + close;
				},

				// function calls it internally, it's the arguments part of the function
				functionArgs: function( fn ) {
					var args,
						l = fn.length;

					if ( !l ) {
						return "";
					}

					args = new Array( l );
					while ( l-- ) {

						// 97 is 'a'
						args[ l ] = String.fromCharCode( 97 + l );
					}
					return " " + args.join( ", " ) + " ";
				},
				// object calls it internally, the key part of an item in a map
				key: quote,
				// function calls it internally, it's the content of the function
				functionCode: "[code]",
				// node calls it internally, it's an html attribute value
				attribute: quote,
				string: quote,
				date: quote,
				regexp: literal,
				number: literal,
				"boolean": literal
			},
			// if true, entities are escaped ( <, >, \t, space and \n )
			HTML: false,
			// indentation unit
			indentChar: "  ",
			// if true, items in a collection, are separated by a \n, else just a space.
			multiline: true
		};

	return dump;
}());

// back compat
QUnit.jsDump = QUnit.dump;
<|endoftext|>


<commit_before>import { endpoint } from 'src/app/api';
import asyncActionCreator from './asyncActionCreator';
import { queryEndpoint } from './util';

export const queryNotifications = asyncActionCreator(query => async () => queryEndpoint(query), { name: 'QUERY_NOTIFCATIONS' });
<commit_msg>Linty<commit_after>import asyncActionCreator from './asyncActionCreator';
import { queryEndpoint } from './util';

export const queryNotifications = asyncActionCreator(query => async () => queryEndpoint(query), { name: 'QUERY_NOTIFCATIONS' });
<|endoftext|>