<commit_before>/**
 * @license
 * Copyright 2013 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview A single avatar.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Pond.Avatar');

goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.math');
goog.require('BlocklyGames');

/**
 * Class for a avatar.
 * @param {string} name Avatar's name.
 * @param {!Blockly.utils.Coordinate} startLoc Start location.
 * @param {?number} startDamage Initial damage to avatar (0-100, default 0).
 * @param {boolean} editable Allow user to edit code.
 * @param {!Pond.Battle} battle The battle featuring the avatar.
 * @constructor
 */
Pond.Avatar = function(name, startLoc, startDamage, editable, battle) {
  this.name = name;
  this.startLoc_ = startLoc;
  this.startDamage_ = startDamage || 0;
  this.editable = editable;
  this.battle_ = battle;
  this.loc = new Blockly.utils.Coordinate();
  this.reset();
  this.visualizationIndex = battle.AVATARS.length;
  battle.AVATARS.push(this);
  console.log(this + ' loaded.');
};

/**
 * Has this avatar fully loaded and started playing?
 */
Pond.Avatar.prototype.started = false;

/**
 * Has the avatar been killed?
 */
Pond.Avatar.prototype.dead = false;

/**
 * Damage of this avatar (0 = perfect, 100 = dead).
 */
Pond.Avatar.prototype.damage = 0;

/**
 * Heading the avatar is moving in (0 - 360).
 */
Pond.Avatar.prototype.degree = 0;

/**
 * Direction the avatar's head is facing (0 - 360).
 */
Pond.Avatar.prototype.facing = 0;

/**
 * Speed the avatar is actually moving (0 - 100).
 */
Pond.Avatar.prototype.speed = 0;

/**
 * Speed the avatar is aiming to move at (0 - 100).
 */
Pond.Avatar.prototype.desiredSpeed = 0;

/**
 * X/Y location of the avatar (0 - 100).
 * @type Blockly.utils.Coordinate
 */
Pond.Avatar.prototype.loc = null;

/**
 * Date of last missile.
 */
Pond.Avatar.prototype.lastMissile = 0;

/**
 * A text representation of this avatar for debugging purposes.
 * @return {string} String representation.
 */
Pond.Avatar.prototype.toString = function() {
  return '[' + this.name + ']';
};

/**
 * Sets the code for this avatar.
 * @param {string|undefined} blockly Blockly XML, or undefined if no Blockly.
 * @param {string|undefined} js JavaScript source, or undefined if no JS.
 * @param {string} compiled Executable ES5 code (generated by Blockly or Babel).
 */
Pond.Avatar.prototype.setCode = function(blockly, js, compiled) {
  this.blockly = blockly;
  this.js = js;
  this.compiled = compiled;
};

/**
 * Reset this avatar to a starting state.
 */
Pond.Avatar.prototype.reset = function() {
  delete this.started;
  delete this.dead;
  delete this.speed;
  delete this.desiredSpeed;
  delete this.lastMissile;

  this.damage = this.startDamage_;
  this.loc.x = this.startLoc_.x;
  this.loc.y = this.startLoc_.y;
  // Face the centre.
  this.degree = Pond.Avatar.pointsToAngle(this.loc.x, this.loc.y, 50, 50);
  this.facing = this.degree;
  this.interpreter = null;
};

/**
 * Create an interpreter for this avatar.
 */
Pond.Avatar.prototype.initInterpreter = function() {
  this.interpreter = new Interpreter(this.compiled, this.battle_.initInterpreter);
};

/**
 * Damage the avatar.
 * @param {number} add Amount of damage to add.
 */
Pond.Avatar.prototype.addDamage = function(add) {
  this.damage += add;
  if (this.damage >= 100) {
    this.die();
  }
};

/**
 * Kill this avatar.
 */
Pond.Avatar.prototype.die = function() {
  this.speed = 0;
  this.dead = true;
  this.damage = 100;
  this.battle_.RANK.unshift(this);
  this.battle_.EVENTS.push({'type': 'DIE', 'avatar': this});
  console.log(this + ' sinks.');
};

// API functions exposed to the user.

/**
 * Scan in a direction for the nearest avatar.
 * @param {number} degree Scan in this direction (wrapped to 0-360).
 * @param {number} opt_resolution Sensing resolution, 1 to 20 degrees.
 *   Defaults to 5.
 * @return {number} Distance (0 - ~141), or Infinity if no avatar detected.
 */
Pond.Avatar.prototype.scan = function(degree, opt_resolution) {
  var resolution;
  if (opt_resolution === undefined || opt_resolution === null) {
    resolution = 5;
  } else {
    resolution = opt_resolution;
  }
  if ((typeof degree != 'number') || isNaN(degree) ||
      (typeof resolution != 'number') || isNaN(resolution)) {
    throw TypeError();
  }
  degree = BlocklyGames.normalizeAngle(degree);
  resolution = Blockly.utils.math.clamp(resolution, 0, 20);

  this.battle_.EVENTS.push({'type': 'SCAN', 'avatar': this,
                            'degree': degree, 'resolution': resolution});

  // Compute both edges of the scan.
  var scan1 = BlocklyGames.normalizeAngle(degree - resolution / 2);
  var scan2 = BlocklyGames.normalizeAngle(degree + resolution / 2);
  if (scan1 > scan2) {
    scan2 += 360;
  }
  var locX = this.loc.x;
  var locY = this.loc.y;
  // Check every enemy for existence in the scan beam.
  var closest = Infinity;
  for (var i = 0, enemy; (enemy = this.battle_.AVATARS[i]); i++) {
    if (enemy == this || enemy.dead) {
      continue;
    }
    var ex = enemy.loc.x;
    var ey = enemy.loc.y;
    // Pythagorean theorem to find range to enemy's centre.
    var range = Math.sqrt((ey - locY) * (ey - locY) +
                          (ex - locX) * (ex - locX));
    if (range >= closest) {
      continue;
    }
    // Compute angle between avatar and enemy's centre.
    var angle = Math.atan2(ey - locY, ex - locX);
    angle = BlocklyGames.normalizeAngle(Blockly.utils.math.toDegrees(angle));
    // Raise angle by 360 if needed (handles wrapping).
    if (angle < scan1) {
      angle += 360;
    }
    // Check if enemy is within scan edges.
    if (scan1 <= angle && angle <= scan2) {
      closest = range;
    }
  }
  return closest;
};

/**
 * Commands the avatar to move in the specified heading at the specified speed.
 * @param {number} degree Heading (0-360).
 * @param {number} opt_speed Desired speed (0-100).  Defaults to 50.
 */
Pond.Avatar.prototype.drive = function(degree, opt_speed) {
  var speed;
  if (opt_speed === undefined || opt_speed === null) {
    speed = 50;
  } else {
    speed = opt_speed;
  }
  if ((typeof degree != 'number') || isNaN(degree) ||
      (typeof speed != 'number') || isNaN(speed)) {
    throw TypeError;
  }
  var desiredDegree = BlocklyGames.normalizeAngle(degree);
  if (this.degree != desiredDegree) {
    if (this.speed <= 50) {
      // Changes in direction can be negotiated at speeds of less than 50%.
      this.degree = BlocklyGames.normalizeAngle(degree);
      this.facing = this.degree;
    } else {
      // Stop the avatar if an over-speed turn was commanded.
      speed = 0;
    }
  }
  if (this.speed == 0 && speed > 0) {
    // If starting, bump the speed immediately so that avatars can see a change.
    this.speed = 0.1;
  }
  this.desiredSpeed = Blockly.utils.math.clamp(speed, 0, 100);
};

/**
 * Commands the avatar to stop.
 */
Pond.Avatar.prototype.stop = function() {
  this.desiredSpeed = 0;
};

/**
 * Commands the avatar to shoot in the specified heading at the specified range.
 * @param {number} degree Heading (0-360).
 * @param {number} range Distance to impact (0-70).
 * @return {boolean} True if cannon fired, false if still reloading from a
 *     previous shot.
 */
Pond.Avatar.prototype.cannon = function(degree, range) {
  if ((typeof degree != 'number') || isNaN(degree) ||
      (typeof range != 'number') || isNaN(range)) {
    throw TypeError;
  }
  var now = Date.now();
  if (this.lastMissile + this.battle_.RELOAD_TIME * 1000 > now) {
    return false;
  }
  this.lastMissile = now;
  var startLoc = new Blockly.utils.Coordinate(this.loc.x, this.loc.y);
  degree = BlocklyGames.normalizeAngle(degree);
  this.facing = degree;
  range = Blockly.utils.math.clamp(range, 0, 70);
  var endLoc = new Blockly.utils.Coordinate(
      startLoc.x + Pond.Avatar.angleDx(degree, range),
      startLoc.y + Pond.Avatar.angleDy(degree, range));
  var missile = {
    avatar: this,
    startLoc: startLoc,
    degree: degree,
    range: range,
    endLoc: endLoc,
    progress: 0
  };
  this.battle_.MISSILES.push(missile);
  this.battle_.EVENTS.push({'type': 'BANG', 'avatar': this,
      'degree': missile.degree});
  return true;
};

/**
 * For a given angle and radius, finds the X portion of the offset.
 * Copied from Closure's goog.math.angleDx.
 * @param {number} degrees Angle in degrees (zero points in +X direction).
 * @param {number} radius Radius.
 * @return {number} The x-distance for the angle and radius.
 */
Pond.Avatar.angleDx = function(degrees, radius) {
  return radius * Math.cos(Blockly.utils.math.toRadians(degrees));
};

/**
 * For a given angle and radius, finds the Y portion of the offset.
 * Copied from Closure's goog.math.angleDy.
 * @param {number} degrees Angle in degrees (zero points in +X direction).
 * @param {number} radius Radius.
 * @return {number} The y-distance for the angle and radius.
 */
Pond.Avatar.angleDy = function(degrees, radius) {
  return radius * Math.sin(Blockly.utils.math.toRadians(degrees));
};

/**
 * Computes the angle between two points (x1,y1) and (x2,y2).
 * Angle zero points in the +X direction, 90 degrees points in the +Y
 * direction (down) and from there we grow clockwise towards 360 degrees.
 * Copied from Closure's goog.math.angle.
 * @param {number} x1 x of first point.
 * @param {number} y1 y of first point.
 * @param {number} x2 x of second point.
 * @param {number} y2 y of second point.
 * @return {number} Standardized angle in degrees of the vector from
 *     x1,y1 to x2,y2.
 */
Pond.Avatar.pointsToAngle = function(x1, y1, x2, y2) {
  var angle = Blockly.utils.math.toDegrees(Math.atan2(y2 - y1, x2 - x1));
  return BlocklyGames.normalizeAngle(angle);
};
<commit_msg>Remove duplicate normalizeAngle call.<commit_after>/**
 * @license
 * Copyright 2013 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview A single avatar.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Pond.Avatar');

goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.math');
goog.require('BlocklyGames');

/**
 * Class for a avatar.
 * @param {string} name Avatar's name.
 * @param {!Blockly.utils.Coordinate} startLoc Start location.
 * @param {?number} startDamage Initial damage to avatar (0-100, default 0).
 * @param {boolean} editable Allow user to edit code.
 * @param {!Pond.Battle} battle The battle featuring the avatar.
 * @constructor
 */
Pond.Avatar = function(name, startLoc, startDamage, editable, battle) {
  this.name = name;
  this.startLoc_ = startLoc;
  this.startDamage_ = startDamage || 0;
  this.editable = editable;
  this.battle_ = battle;
  this.loc = new Blockly.utils.Coordinate();
  this.reset();
  this.visualizationIndex = battle.AVATARS.length;
  battle.AVATARS.push(this);
  console.log(this + ' loaded.');
};

/**
 * Has this avatar fully loaded and started playing?
 */
Pond.Avatar.prototype.started = false;

/**
 * Has the avatar been killed?
 */
Pond.Avatar.prototype.dead = false;

/**
 * Damage of this avatar (0 = perfect, 100 = dead).
 */
Pond.Avatar.prototype.damage = 0;

/**
 * Heading the avatar is moving in (0 - 360).
 */
Pond.Avatar.prototype.degree = 0;

/**
 * Direction the avatar's head is facing (0 - 360).
 */
Pond.Avatar.prototype.facing = 0;

/**
 * Speed the avatar is actually moving (0 - 100).
 */
Pond.Avatar.prototype.speed = 0;

/**
 * Speed the avatar is aiming to move at (0 - 100).
 */
Pond.Avatar.prototype.desiredSpeed = 0;

/**
 * X/Y location of the avatar (0 - 100).
 * @type Blockly.utils.Coordinate
 */
Pond.Avatar.prototype.loc = null;

/**
 * Date of last missile.
 */
Pond.Avatar.prototype.lastMissile = 0;

/**
 * A text representation of this avatar for debugging purposes.
 * @return {string} String representation.
 */
Pond.Avatar.prototype.toString = function() {
  return '[' + this.name + ']';
};

/**
 * Sets the code for this avatar.
 * @param {string|undefined} blockly Blockly XML, or undefined if no Blockly.
 * @param {string|undefined} js JavaScript source, or undefined if no JS.
 * @param {string} compiled Executable ES5 code (generated by Blockly or Babel).
 */
Pond.Avatar.prototype.setCode = function(blockly, js, compiled) {
  this.blockly = blockly;
  this.js = js;
  this.compiled = compiled;
};

/**
 * Reset this avatar to a starting state.
 */
Pond.Avatar.prototype.reset = function() {
  delete this.started;
  delete this.dead;
  delete this.speed;
  delete this.desiredSpeed;
  delete this.lastMissile;

  this.damage = this.startDamage_;
  this.loc.x = this.startLoc_.x;
  this.loc.y = this.startLoc_.y;
  // Face the centre.
  this.degree = Pond.Avatar.pointsToAngle(this.loc.x, this.loc.y, 50, 50);
  this.facing = this.degree;
  this.interpreter = null;
};

/**
 * Create an interpreter for this avatar.
 */
Pond.Avatar.prototype.initInterpreter = function() {
  this.interpreter = new Interpreter(this.compiled, this.battle_.initInterpreter);
};

/**
 * Damage the avatar.
 * @param {number} add Amount of damage to add.
 */
Pond.Avatar.prototype.addDamage = function(add) {
  this.damage += add;
  if (this.damage >= 100) {
    this.die();
  }
};

/**
 * Kill this avatar.
 */
Pond.Avatar.prototype.die = function() {
  this.speed = 0;
  this.dead = true;
  this.damage = 100;
  this.battle_.RANK.unshift(this);
  this.battle_.EVENTS.push({'type': 'DIE', 'avatar': this});
  console.log(this + ' sinks.');
};

// API functions exposed to the user.

/**
 * Scan in a direction for the nearest avatar.
 * @param {number} degree Scan in this direction (wrapped to 0-360).
 * @param {number} opt_resolution Sensing resolution, 1 to 20 degrees.
 *   Defaults to 5.
 * @return {number} Distance (0 - ~141), or Infinity if no avatar detected.
 */
Pond.Avatar.prototype.scan = function(degree, opt_resolution) {
  var resolution;
  if (opt_resolution === undefined || opt_resolution === null) {
    resolution = 5;
  } else {
    resolution = opt_resolution;
  }
  if ((typeof degree != 'number') || isNaN(degree) ||
      (typeof resolution != 'number') || isNaN(resolution)) {
    throw TypeError();
  }
  degree = BlocklyGames.normalizeAngle(degree);
  resolution = Blockly.utils.math.clamp(resolution, 0, 20);

  this.battle_.EVENTS.push({'type': 'SCAN', 'avatar': this,
                            'degree': degree, 'resolution': resolution});

  // Compute both edges of the scan.
  var scan1 = BlocklyGames.normalizeAngle(degree - resolution / 2);
  var scan2 = BlocklyGames.normalizeAngle(degree + resolution / 2);
  if (scan1 > scan2) {
    scan2 += 360;
  }
  var locX = this.loc.x;
  var locY = this.loc.y;
  // Check every enemy for existence in the scan beam.
  var closest = Infinity;
  for (var i = 0, enemy; (enemy = this.battle_.AVATARS[i]); i++) {
    if (enemy == this || enemy.dead) {
      continue;
    }
    var ex = enemy.loc.x;
    var ey = enemy.loc.y;
    // Pythagorean theorem to find range to enemy's centre.
    var range = Math.sqrt((ey - locY) * (ey - locY) +
                          (ex - locX) * (ex - locX));
    if (range >= closest) {
      continue;
    }
    // Compute angle between avatar and enemy's centre.
    var angle = Math.atan2(ey - locY, ex - locX);
    angle = BlocklyGames.normalizeAngle(Blockly.utils.math.toDegrees(angle));
    // Raise angle by 360 if needed (handles wrapping).
    if (angle < scan1) {
      angle += 360;
    }
    // Check if enemy is within scan edges.
    if (scan1 <= angle && angle <= scan2) {
      closest = range;
    }
  }
  return closest;
};

/**
 * Commands the avatar to move in the specified heading at the specified speed.
 * @param {number} degree Heading (0-360).
 * @param {number} opt_speed Desired speed (0-100).  Defaults to 50.
 */
Pond.Avatar.prototype.drive = function(degree, opt_speed) {
  var speed;
  if (opt_speed === undefined || opt_speed === null) {
    speed = 50;
  } else {
    speed = opt_speed;
  }
  if ((typeof degree != 'number') || isNaN(degree) ||
      (typeof speed != 'number') || isNaN(speed)) {
    throw TypeError;
  }
  var desiredDegree = BlocklyGames.normalizeAngle(degree);
  if (this.degree != desiredDegree) {
    if (this.speed <= 50) {
      // Changes in direction can be negotiated at speeds of less than 50%.
      this.degree = desiredDegree;
      this.facing = this.degree;
    } else {
      // Stop the avatar if an over-speed turn was commanded.
      speed = 0;
    }
  }
  if (this.speed == 0 && speed > 0) {
    // If starting, bump the speed immediately so that avatars can see a change.
    this.speed = 0.1;
  }
  this.desiredSpeed = Blockly.utils.math.clamp(speed, 0, 100);
};

/**
 * Commands the avatar to stop.
 */
Pond.Avatar.prototype.stop = function() {
  this.desiredSpeed = 0;
};

/**
 * Commands the avatar to shoot in the specified heading at the specified range.
 * @param {number} degree Heading (0-360).
 * @param {number} range Distance to impact (0-70).
 * @return {boolean} True if cannon fired, false if still reloading from a
 *     previous shot.
 */
Pond.Avatar.prototype.cannon = function(degree, range) {
  if ((typeof degree != 'number') || isNaN(degree) ||
      (typeof range != 'number') || isNaN(range)) {
    throw TypeError;
  }
  var now = Date.now();
  if (this.lastMissile + this.battle_.RELOAD_TIME * 1000 > now) {
    return false;
  }
  this.lastMissile = now;
  var startLoc = new Blockly.utils.Coordinate(this.loc.x, this.loc.y);
  degree = BlocklyGames.normalizeAngle(degree);
  this.facing = degree;
  range = Blockly.utils.math.clamp(range, 0, 70);
  var endLoc = new Blockly.utils.Coordinate(
      startLoc.x + Pond.Avatar.angleDx(degree, range),
      startLoc.y + Pond.Avatar.angleDy(degree, range));
  var missile = {
    avatar: this,
    startLoc: startLoc,
    degree: degree,
    range: range,
    endLoc: endLoc,
    progress: 0
  };
  this.battle_.MISSILES.push(missile);
  this.battle_.EVENTS.push({'type': 'BANG', 'avatar': this,
      'degree': missile.degree});
  return true;
};

/**
 * For a given angle and radius, finds the X portion of the offset.
 * Copied from Closure's goog.math.angleDx.
 * @param {number} degrees Angle in degrees (zero points in +X direction).
 * @param {number} radius Radius.
 * @return {number} The x-distance for the angle and radius.
 */
Pond.Avatar.angleDx = function(degrees, radius) {
  return radius * Math.cos(Blockly.utils.math.toRadians(degrees));
};

/**
 * For a given angle and radius, finds the Y portion of the offset.
 * Copied from Closure's goog.math.angleDy.
 * @param {number} degrees Angle in degrees (zero points in +X direction).
 * @param {number} radius Radius.
 * @return {number} The y-distance for the angle and radius.
 */
Pond.Avatar.angleDy = function(degrees, radius) {
  return radius * Math.sin(Blockly.utils.math.toRadians(degrees));
};

/**
 * Computes the angle between two points (x1,y1) and (x2,y2).
 * Angle zero points in the +X direction, 90 degrees points in the +Y
 * direction (down) and from there we grow clockwise towards 360 degrees.
 * Copied from Closure's goog.math.angle.
 * @param {number} x1 x of first point.
 * @param {number} y1 y of first point.
 * @param {number} x2 x of second point.
 * @param {number} y2 y of second point.
 * @return {number} Standardized angle in degrees of the vector from
 *     x1,y1 to x2,y2.
 */
Pond.Avatar.pointsToAngle = function(x1, y1, x2, y2) {
  var angle = Blockly.utils.math.toDegrees(Math.atan2(y2 - y1, x2 - x1));
  return BlocklyGames.normalizeAngle(angle);
};
<|endoftext|>


<commit_before>const glob = require('glob').sync;
const {name} = require('./package.json');

module.exports = {
  entry: glob('./src/**/*.vue'),
  filename: {
    js: name + '.min.js',
  },
  sourceMap: false,
  html: false
};
<commit_msg>add poi preset karma<commit_after>const presetKarma = require('poi-preset-karma');
const glob = require('glob').sync;
const {name} = require('./package.json');

module.exports = {
  entry: glob('./src/**/*.vue'),
  filename: {
    js: name + '.min.js',
  },
  sourceMap: false,
  html: false,
  presets: [
    presetKarma({
      files: ['test/specs/**/*.spec.js'],
      browsers: ['PhantomJS'],
      frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
      coverage: true
    })
  ]
};
<|endoftext|>


<commit_before>import { arr } from "lively.lang";
import { pt, Color, Point } from "lively.graphics";
import { Morph, World, List, Polygon, MorphicEnv } from "lively.morphic";
import { Window, Button} from "lively.morphic/widgets.js";
import { ObjectDrawer, Workspace } from "lively.morphic/tools.js";

var world = new World({
  name: "world",
  extent: pt(window.innerWidth, window.innerHeight),
  submorphs: [
    new ObjectDrawer(),

    new List({items: arr.range(0,2000).map(n => "item " + n), position: pt(20, 300), extent: pt(140, 200), borderWidth: 1, borderColor: Color.gray}),

    new Window({
      name: "Alice", extent: pt(300, 300), position: pt(200,200),
      submorphs: [
        new Button({label: "Click me!", bottomLeft: pt(10,290)}),
        new Button({label: "Click me!", bottomRight: pt(220,290), active: false}),
        new Polygon({
          name: "poly", vertices: [pt(0,0), pt(100,50), pt(50, 100)],
          extent: pt(102,102), fill: Color.orange})
      ]}),

    new Workspace({extent: pt(200, 300), position: pt(800,200)})
  ]
});

MorphicEnv.default().setWorld(world);

window.$$world = world;

window.addEventListener('beforeunload', function(evt) {
  var msg = "Really?";
  evt.returnValue = msg;
  return msg;
}, true);
<commit_msg>test world: save contents of workspace<commit_after>import { arr } from "lively.lang";
import { pt, Color, Point } from "lively.graphics";
import { Morph, World, List, Polygon, MorphicEnv, show } from "lively.morphic";
import { Window, Button} from "lively.morphic/widgets.js";
import { ObjectDrawer, Workspace } from "lively.morphic/tools.js";

var world = new World({
  name: "world",
  extent: pt(window.innerWidth, window.innerHeight),
  submorphs: [
    new ObjectDrawer(),

    new List({items: arr.range(0,2000).map(n => "item " + n), position: pt(20, 300), extent: pt(140, 200), borderWidth: 1, borderColor: Color.gray}),

    new Window({
      name: "Alice", extent: pt(300, 300), position: pt(200,200),
      submorphs: [
        new Button({label: "Click me!", bottomLeft: pt(10,290)}),
        new Button({label: "Click me!", bottomRight: pt(220,290), active: false}),
        new Polygon({
          name: "poly", vertices: [pt(0,0), pt(100,50), pt(50, 100)],
          extent: pt(102,102), fill: Color.orange})
      ]}),

    new Workspace({extent: pt(200, 300), position: pt(800,200)})
  ]

});

world.submorphs[3].targetMorph.doSave = function() {
  show("saved!");
  localStorage.setItem('lively workspace', this.textString)
}

var code = localStorage.getItem('lively workspace');
if (code) world.submorphs[3].targetMorph.textString = code;

MorphicEnv.default().setWorld(world);

window.$$world = world;

window.addEventListener('beforeunload', function(evt) {
  var msg = "Really?";
  evt.returnValue = msg;
  return msg;
}, true);
<|endoftext|>


<commit_before>function extract (arr, type, prefix) {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brett-zamir.me)
    // %        note 1: Only works by extracting into global context (whether called in the global scope or
    // %        note 1: within a function); also, the EXTR_REFS flag I believe can't be made to work
    // *     example 1: size = 'large';
    // *     example 1: var_array = {'color' : 'blue', 'size' : 'medium', 'shape' : 'sphere'};
    // *     example 1: extract(var_array, 'EXTR_PREFIX_SAME', 'wddx');
    // *     example 1: color+'-'+size+'-'+shape+'-'+wddx_size;
    // *     returns 1: 'blue-large-sphere-medium'

    if (arr instanceof Array && (type !== 'EXTR_PREFIX_ALL' && type !== 'EXTR_PREFIX_INVALID')) {
        return 0;
    }
    var chng = 0;

    for (var i in arr) {
        var validIdent = /^[_a-zA-Z$][\w|$]*$/; // TODO: Refine regexp to allow JS 1.5+ Unicode identifiers
        var prefixed = prefix+'_'+i;
        try {
            switch (type) {
                case 'EXTR_PREFIX_SAME' || 2:
                    if (this[i] !== undefined) {
                        if (prefixed.match(validIdent) !== null) {
                            this[prefixed] = arr[i];
                            ++chng;
                        }
                    }
                    else {
                        this[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_SKIP' || 1:
                    if (this[i] === undefined) {
                        this[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_PREFIX_ALL' || 3:
                    if (prefixed.match(validIdent) !== null) {
                        this[prefixed] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_PREFIX_INVALID' || 4:
                    if(i.match(validIdent) !== null) {
                        if (prefixed.match(validIdent) !== null) {
                            this[prefixed] = arr[i];
                            ++chng;
                        }
                    }
                    else {
                        this[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_IF_EXISTS' || 6:
                    if (this[i] !== undefined) {
                        this[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_PREFIX_IF_EXISTS' || 5:
                    if (this[i] !== undefined && prefixed.match(validIdent) !== null) {
                        this[prefixed] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_REFS' || 256:
                    throw 'The EXTR_REFS type will not work in JavaScript';
                case 'EXTR_OVERWRITE' || 0:
                // Fall-through
                default:
                    this[i] = arr[i];
                    ++chng;
                    break;
            }
        }
        catch (e) { // Just won't increment for problem assignments

        }
    }
    return chng;
}<commit_msg>Allow alternative for extract() target<commit_after>function extract (arr, type, prefix) {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brett-zamir.me)
    // %        note 1: Only works by extracting into global context (whether called in the global scope or
    // %        note 1: within a function); also, the EXTR_REFS flag I believe can't be made to work
    // *     example 1: size = 'large';
    // *     example 1: var_array = {'color' : 'blue', 'size' : 'medium', 'shape' : 'sphere'};
    // *     example 1: extract(var_array, 'EXTR_PREFIX_SAME', 'wddx');
    // *     example 1: color+'-'+size+'-'+shape+'-'+wddx_size;
    // *     returns 1: 'blue-large-sphere-medium'

    if (arr instanceof Array && (type !== 'EXTR_PREFIX_ALL' && type !== 'EXTR_PREFIX_INVALID')) {
        return 0;
    }
    var targetObj = this.window;
    if (this.php_js && this.php_js.ini && this.php_js.ini['phpjs.extractTargetObj'] &&
        this.php_js.ini['phpjs.extractTargetObj'].local_value) { // Allow designated object to be used instead of window
        targetObj = this.php_js.ini['phpjs.extractTargetObj'].local_value;
    }
    var chng = 0;

    for (var i in arr) {
        var validIdent = /^[_a-zA-Z$][\w|$]*$/; // TODO: Refine regexp to allow JS 1.5+ Unicode identifiers
        var prefixed = prefix+'_'+i;
        try {
            switch (type) {
                case 'EXTR_PREFIX_SAME' || 2:
                    if (targetObj[i] !== undefined) {
                        if (prefixed.match(validIdent) !== null) {
                            targetObj[prefixed] = arr[i];
                            ++chng;
                        }
                    }
                    else {
                        targetObj[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_SKIP' || 1:
                    if (targetObj[i] === undefined) {
                        targetObj[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_PREFIX_ALL' || 3:
                    if (prefixed.match(validIdent) !== null) {
                        targetObj[prefixed] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_PREFIX_INVALID' || 4:
                    if(i.match(validIdent) !== null) {
                        if (prefixed.match(validIdent) !== null) {
                            targetObj[prefixed] = arr[i];
                            ++chng;
                        }
                    }
                    else {
                        targetObj[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_IF_EXISTS' || 6:
                    if (targetObj[i] !== undefined) {
                        targetObj[i] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_PREFIX_IF_EXISTS' || 5:
                    if (targetObj[i] !== undefined && prefixed.match(validIdent) !== null) {
                        targetObj[prefixed] = arr[i];
                        ++chng;
                    }
                    break;
                case 'EXTR_REFS' || 256:
                    throw 'The EXTR_REFS type will not work in JavaScript';
                case 'EXTR_OVERWRITE' || 0:
                // Fall-through
                default:
                    targetObj[i] = arr[i];
                    ++chng;
                    break;
            }
        }
        catch (e) { // Just won't increment for problem assignments

        }
    }
    return chng;
}<|endoftext|>


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

    function ConcreteInlineStyleCustomizer($element, options) {
        var my = this;
        options = $.extend({
        }, options);

        my.options = options;
        my.$element = $element;
        my.$toolbar = my.$element.find('>ul');
        my.$toolbar.find('div.dropdown-menu').on('click', function(e) {
            if ($(e.target).is('button')) {
                return true;
            } else {
                e.stopPropagation(); // stop the menu from closing
            }
        });

        my.setupForm();
        my.setupButtons();
        my.setupSliders();
    }

    ConcreteInlineStyleCustomizer.prototype = {

        refreshStyles: function(resp) {
            if (resp.oldIssID) {
                $('head').find('style[data-style-set=' + resp.oldIssID +']').remove();
            }
            if (resp.issID) {
                $('head').append($('<style />', {'data-style-set': resp.issID, 'text': resp.css}));
            }
        },

        setupForm: function() {
            var my = this;
            my.$element.concreteAjaxForm({
                success: function(resp) {
                    my.handleResponse(resp);
                },
                error: function(r) {
                    my.$toolbar.prependTo('#ccm-inline-toolbar-container').show();
                }
            });
        },

        setupButtons: function() {
            var my = this;
            my.$toolbar.on('click.inlineStyleCustomizer', 'button[data-action=cancel-design]', function() {
                my.$element.hide();
                ConcreteEvent.fire('EditModeExitInline');
                return false;
            });

            my.$toolbar.on('click.inlineStyleCustomizer', 'button[data-action=reset-design]', function() {
                $.concreteAjax({
                    url: $(this).attr('data-reset-action'),
                    success: function(resp) {
                        my.handleResponse(resp);
                    }
                });
                return false;
            });

            my.$toolbar.on('click.inlineStyleCustomizer', 'button[data-action=save-design]', function() {
                // move the toolbar back into the form so it submits. so great.
                my.$toolbar.hide().prependTo(my.$element);
                my.$element.submit();
                ConcreteEvent.unsubscribe('EditModeExitInlineComplete');
                return false;
            });
        },

        setupSliders: function(){
            var my = this;
            my.$toolbar.find('.ccm-inline-style-sliders').each(function(){
                var targetInput = $(this).next().children('.ccm-inline-style-slider-value');
                var targetInputFormat = targetInput.attr('data-value-format');
                var sliderElement = $(this);
                var min = parseInt($(this).attr('data-style-slider-min'));
                var max = parseInt($(this).attr('data-style-slider-max'));
                var defaultValue = $(this).attr('data-style-slider-default-setting');
                var currentValue = function () {
                    return parseInt(targetInput.val().replace(/\D\-/g,''));
                };
                var disableCheck = function () {
                    if (parseInt(defaultValue) === currentValue() || isNaN(currentValue())) {
                        targetInput.prop('disabled', true).val(defaultValue + targetInputFormat);
                    }
                };

                sliderElement.slider({
                    min: min,
                    max: max,
                    value: currentValue(),
                    slide: function( event, ui ) {
                        targetInput.prop('disabled', false);
                        targetInput.val( ui.value + targetInputFormat );
                        disableCheck();
                    }
                });

                targetInput.change(function () {
                    var value = currentValue();

                    if (value > max) {
                        value = max;
                    } else if (value < min) {
                        value = min;
                    } else if (isNaN(value)) {
                        value = defaultValue;
                    }

                    $(this).val(value + targetInputFormat);
                    sliderElement.slider("value", value);
                    disableCheck();

                }).parent().click(function () {
                    if (targetInput.prop('disabled')) {
                        targetInput.prop('disabled', false).select();
                    }
                });

                disableCheck();
            });
        }

    };

    function ConcreteBlockInlineStyleCustomizer($element, options) {
        var my = this;
        ConcreteInlineStyleCustomizer.call(my, $element, options);
    }

    ConcreteBlockInlineStyleCustomizer.prototype = Object.create(ConcreteInlineStyleCustomizer.prototype);

    ConcreteBlockInlineStyleCustomizer.prototype.handleResponse = function(resp) {
        var my = this;
        var editor = new Concrete.getEditMode(),
            area = editor.getAreaByID(resp.aID),
            block = area.getBlockByID(parseInt(resp.originalBlockID)),
            arEnableGridContainer = area.getEnableGridContainer() ? 1 : 0,
            action = CCM_DISPATCHER_FILENAME + '/ccm/system/block/render';

        $.get(action, {
            arHandle: area.getHandle(),
            cID: resp.cID,
            bID: resp.bID,
            arEnableGridContainer: arEnableGridContainer
        }, function (r) {
            ConcreteToolbar.disableDirectExit();
            var newBlock = block.replace(r);
            ConcreteAlert.notify({
                'message': resp.message
            });

            my.refreshStyles(resp);
            ConcreteEvent.fire('EditModeExitInline', {
                action: 'save_inline',
                block: newBlock
            });
            ConcreteEvent.fire('EditModeExitInlineComplete', {
                block: newBlock
            });
            $.fn.dialog.hideLoader();
            editor.destroyInlineEditModeToolbars();
            editor.scanBlocks();

        });
    }

    function ConcreteAreaInlineStyleCustomizer($element, options) {
        var my = this;
        ConcreteInlineStyleCustomizer.call(my, $element, options);
    }

    ConcreteAreaInlineStyleCustomizer.prototype = Object.create(ConcreteInlineStyleCustomizer.prototype);

    ConcreteAreaInlineStyleCustomizer.prototype.handleResponse = function(resp) {
        var my = this,
            editor = new Concrete.getEditMode(),
            area = editor.getAreaByID(resp.aID);
        my.refreshStyles(resp);
        area.getElem().removeClassExcept('ccm-area ccm-global-area');
        if (resp.containerClass) {
            area.getElem().addClass(resp.containerClass);
        }
        editor.destroyInlineEditModeToolbars();
    }

    // jQuery Plugin
    $.fn.concreteBlockInlineStyleCustomizer = function (options) {
        return $.each($(this), function (i, obj) {
            new ConcreteBlockInlineStyleCustomizer($(this), options);
        });
    }

    $.fn.concreteAreaInlineStyleCustomizer = function (options) {
        return $.each($(this), function (i, obj) {
            new ConcreteAreaInlineStyleCustomizer($(this), options);
        });
    }

    $.fn.removeClassExcept = function (val) {
        return this.each(function (index, el) {
            var keep = val.split(" "),  // list we'd like to keep
                reAdd = [],          // ones that should be re-added if found
                $el = $(el);       // element we're working on

            // look for which we re-add (based on them already existing)
            for (var i = 0; i < keep.length; i++){
                if ($el.hasClass(keep[i])) reAdd.push(keep[i]);
            }

            // drop all, and only add those confirmed as existing
            $el
                .removeClass()               // remove existing classes
                .addClass(reAdd.join(' '));  // re-add the confirmed ones
        });
    };

    global.ConcreteBlockInlineStyleCustomizer = ConcreteBlockInlineStyleCustomizer;
    global.ConcreteAreaInlineStyleCustomizer = ConcreteAreaInlineStyleCustomizer;

})(this, $);
<commit_msg>Added check to disable control on blur.<commit_after>(function(global, $) {
    'use strict';

    function ConcreteInlineStyleCustomizer($element, options) {
        var my = this;
        options = $.extend({
        }, options);

        my.options = options;
        my.$element = $element;
        my.$toolbar = my.$element.find('>ul');
        my.$toolbar.find('div.dropdown-menu').on('click', function(e) {
            if ($(e.target).is('button')) {
                return true;
            } else {
                e.stopPropagation(); // stop the menu from closing
            }
        });

        my.setupForm();
        my.setupButtons();
        my.setupSliders();
    }

    ConcreteInlineStyleCustomizer.prototype = {

        refreshStyles: function(resp) {
            if (resp.oldIssID) {
                $('head').find('style[data-style-set=' + resp.oldIssID +']').remove();
            }
            if (resp.issID) {
                $('head').append($('<style />', {'data-style-set': resp.issID, 'text': resp.css}));
            }
        },

        setupForm: function() {
            var my = this;
            my.$element.concreteAjaxForm({
                success: function(resp) {
                    my.handleResponse(resp);
                },
                error: function(r) {
                    my.$toolbar.prependTo('#ccm-inline-toolbar-container').show();
                }
            });
        },

        setupButtons: function() {
            var my = this;
            my.$toolbar.on('click.inlineStyleCustomizer', 'button[data-action=cancel-design]', function() {
                my.$element.hide();
                ConcreteEvent.fire('EditModeExitInline');
                return false;
            });

            my.$toolbar.on('click.inlineStyleCustomizer', 'button[data-action=reset-design]', function() {
                $.concreteAjax({
                    url: $(this).attr('data-reset-action'),
                    success: function(resp) {
                        my.handleResponse(resp);
                    }
                });
                return false;
            });

            my.$toolbar.on('click.inlineStyleCustomizer', 'button[data-action=save-design]', function() {
                // move the toolbar back into the form so it submits. so great.
                my.$toolbar.hide().prependTo(my.$element);
                my.$element.submit();
                ConcreteEvent.unsubscribe('EditModeExitInlineComplete');
                return false;
            });
        },

        setupSliders: function(){
            var my = this;
            my.$toolbar.find('.ccm-inline-style-sliders').each(function(){
                var targetInput = $(this).next().children('.ccm-inline-style-slider-value');
                var targetInputFormat = targetInput.attr('data-value-format');
                var sliderElement = $(this);
                var min = parseInt($(this).attr('data-style-slider-min'));
                var max = parseInt($(this).attr('data-style-slider-max'));
                var defaultValue = $(this).attr('data-style-slider-default-setting');
                var currentValue = function () {
                    return parseInt(targetInput.val().replace(/\D\-/g,''));
                };
                var disableCheck = function () {
                    if (parseInt(defaultValue) === currentValue() || isNaN(currentValue())) {
                        targetInput.prop('disabled', true).val(defaultValue + targetInputFormat);
                    }
                };

                sliderElement.slider({
                    min: min,
                    max: max,
                    value: currentValue(),
                    slide: function( event, ui ) {
                        targetInput.prop('disabled', false);
                        targetInput.val(ui.value + targetInputFormat);
                        disableCheck();
                    }
                });

                targetInput.change(function () {
                    var value = currentValue();

                    if (value > max) {
                        value = max;
                    } else if (value < min) {
                        value = min;
                    } else if (isNaN(value)) {
                        value = defaultValue;
                    }

                    $(this).val(value + targetInputFormat);
                    sliderElement.slider("value", value);
                    disableCheck();
                }).blur(function () {
                    disableCheck();
                }).parent().click(function () {
                    if (targetInput.prop('disabled')) {
                        targetInput.prop('disabled', false).select();
                    }
                });

                disableCheck();
            });
        }

    };

    function ConcreteBlockInlineStyleCustomizer($element, options) {
        var my = this;
        ConcreteInlineStyleCustomizer.call(my, $element, options);
    }

    ConcreteBlockInlineStyleCustomizer.prototype = Object.create(ConcreteInlineStyleCustomizer.prototype);

    ConcreteBlockInlineStyleCustomizer.prototype.handleResponse = function(resp) {
        var my = this;
        var editor = new Concrete.getEditMode(),
            area = editor.getAreaByID(resp.aID),
            block = area.getBlockByID(parseInt(resp.originalBlockID)),
            arEnableGridContainer = area.getEnableGridContainer() ? 1 : 0,
            action = CCM_DISPATCHER_FILENAME + '/ccm/system/block/render';

        $.get(action, {
            arHandle: area.getHandle(),
            cID: resp.cID,
            bID: resp.bID,
            arEnableGridContainer: arEnableGridContainer
        }, function (r) {
            ConcreteToolbar.disableDirectExit();
            var newBlock = block.replace(r);
            ConcreteAlert.notify({
                'message': resp.message
            });

            my.refreshStyles(resp);
            ConcreteEvent.fire('EditModeExitInline', {
                action: 'save_inline',
                block: newBlock
            });
            ConcreteEvent.fire('EditModeExitInlineComplete', {
                block: newBlock
            });
            $.fn.dialog.hideLoader();
            editor.destroyInlineEditModeToolbars();
            editor.scanBlocks();

        });
    }

    function ConcreteAreaInlineStyleCustomizer($element, options) {
        var my = this;
        ConcreteInlineStyleCustomizer.call(my, $element, options);
    }

    ConcreteAreaInlineStyleCustomizer.prototype = Object.create(ConcreteInlineStyleCustomizer.prototype);

    ConcreteAreaInlineStyleCustomizer.prototype.handleResponse = function(resp) {
        var my = this,
            editor = new Concrete.getEditMode(),
            area = editor.getAreaByID(resp.aID);
        my.refreshStyles(resp);
        area.getElem().removeClassExcept('ccm-area ccm-global-area');
        if (resp.containerClass) {
            area.getElem().addClass(resp.containerClass);
        }
        editor.destroyInlineEditModeToolbars();
    }

    // jQuery Plugin
    $.fn.concreteBlockInlineStyleCustomizer = function (options) {
        return $.each($(this), function (i, obj) {
            new ConcreteBlockInlineStyleCustomizer($(this), options);
        });
    }

    $.fn.concreteAreaInlineStyleCustomizer = function (options) {
        return $.each($(this), function (i, obj) {
            new ConcreteAreaInlineStyleCustomizer($(this), options);
        });
    }

    $.fn.removeClassExcept = function (val) {
        return this.each(function (index, el) {
            var keep = val.split(" "),  // list we'd like to keep
                reAdd = [],          // ones that should be re-added if found
                $el = $(el);       // element we're working on

            // look for which we re-add (based on them already existing)
            for (var i = 0; i < keep.length; i++){
                if ($el.hasClass(keep[i])) reAdd.push(keep[i]);
            }

            // drop all, and only add those confirmed as existing
            $el
                .removeClass()               // remove existing classes
                .addClass(reAdd.join(' '));  // re-add the confirmed ones
        });
    };

    global.ConcreteBlockInlineStyleCustomizer = ConcreteBlockInlineStyleCustomizer;
    global.ConcreteAreaInlineStyleCustomizer = ConcreteAreaInlineStyleCustomizer;

})(this, $);
<|endoftext|>


<commit_before>const async = require('async');
const AWS = require('aws-sdk');
const http = require('http');

// configurable params
const BUCKET = 'foo';
const LISTING_LIMIT = 10000;
const ACCESSKEY = '';
const SECRETKEY = '';
const ENDPOINT = 'http://127.0.0.1:8000';
const QUIET_MODE = false;

AWS.config.update({
    accessKeyId: ACCESSKEY,
    secretAccessKey: SECRETKEY,
    // region: "us-east-1",
    sslEnabled: false,
    endpoint: ENDPOINT,
    s3ForcePathStyle: true,
    apiVersions: { s3: '2006-03-01' },
    signatureVersion: 'v4',
    signatureCache: false,
});

const s3 = new AWS.S3({
    httpOptions: {
        maxRetries: 0,
        timeout: 0,
        agent: new http.Agent({ keepAlive: true }),
    },
});

// list object versions
function _listObjectVersions(VersionIdMarker, KeyMarker, cb) {
    s3.listObjectVersions({ Bucket: BUCKET, MaxKeys: LISTING_LIMIT, VersionIdMarker, KeyMarker }, cb);
}

// return object with key and version_id
function _getKeys(keys) {
    return keys.map((v) => ({
        Key: v.Key,
        VersionId: v.VersionId,
    }));
}

function logger (msg, val) {
    if (!QUIET_MODE) {
        console.log(msg, val);
    }
}

function rabbitHole(cb) {
    let VersionIdMarker = null;
    let KeyMarker = null;
    async.doWhilst(
        done => _listObjectVersions(VersionIdMarker, KeyMarker, (err, data) => {
            if (err) {
                console.log('error');
                return done(err);
            }
            // data.Versions.forEach(d => {
            //     // logger('Key', d.Key, 'VersionId', d.VersionId);
            // });
            VersionIdMarker = data.NextVersionIdMarker;
            KeyMarker = data.NextKeyMarker;
            logger('VersionIdMarker', VersionIdMarker);
            logger('KeyMarker', KeyMarker);
            return done();
        }),
        () => {
            if (!VersionIdMarker ||  !KeyMarker) {
                return false;
            }
            return true;
        },
        (err, res) => {
            console.log('err', err, 'res', res);
            return cb(err, res);
        }
    );
}

rabbitHole((err, res) => {
    console.log('err', err, 'res', res);
    if (err) {
        return console.log('error occured listing objects', err);
    }
    return console.log('completed listing');
});
<commit_msg>count current, non-current versions in a bucket<commit_after>const async = require('async');
const AWS = require('aws-sdk');
const http = require('http');

// configurable params
const BUCKET = '';
const LISTING_LIMIT = 10000;
const ACCESSKEY = '';
const SECRETKEY = '';
const ENDPOINT = 'http://127.0.0.1:8000';
const QUIET_MODE = false;

AWS.config.update({
    accessKeyId: ACCESSKEY,
    secretAccessKey: SECRETKEY,
    region: "us-east-1",
    sslEnabled: false,
    endpoint: ENDPOINT,
    s3ForcePathStyle: true,
    apiVersions: { s3: '2006-03-01' },
    signatureVersion: 'v4',
    signatureCache: false,
});

const s3 = new AWS.S3({
    httpOptions: {
        maxRetries: 0,
        timeout: 0,
        agent: new http.Agent({ keepAlive: true }),
    },
});

// list object versions
function _listObjectVersions(VersionIdMarker, KeyMarker, cb) {
    s3.listObjectVersions({ Bucket: BUCKET, MaxKeys: LISTING_LIMIT, VersionIdMarker, KeyMarker }, cb);
}

// return object with key and version_id
function _getKeys(keys) {
    return keys.map((v) => ({
        Key: v.Key,
        VersionId: v.VersionId,
    }));
}

function logger (msg, val) {
    if (!QUIET_MODE) {
        console.log(msg, val);
    }
}

function rabbitHole(cb) {
    let VersionIdMarker = null;
    let KeyMarker = null;
    let currentVersions = 0;
    let nonCurrentVersions = 0;
    async.doWhilst(
        done => _listObjectVersions(VersionIdMarker, KeyMarker, (err, data) => {
            if (err) {
                console.log('error');
                return done(err);
            }
            // console.log(data)
            data.Versions.forEach(d => {
                if (d.IsLatest) {
                    currentVersions++;
                } else {
                    nonCurrentVersions++;
                }
                // logger('Key', d.Key, 'VersionId', d.VersionId);
            });
            VersionIdMarker = data.NextVersionIdMarker;
            KeyMarker = data.NextKeyMarker;
            logger('VersionIdMarker', VersionIdMarker);
            logger('KeyMarker', KeyMarker);
            return done();
        }),
        () => {
            if (!VersionIdMarker ||  !KeyMarker) {
                return false;
            }
            return true;
        },
        (err, res) => {
            // console.log('err', err, 'res', res);
            console.log('CURRENT: ', currentVersions);
            console.log('NON-CURRENT: ', nonCurrentVersions);
            return cb(err, res);
        }
    );
}

rabbitHole((err, res) => {
    // console.log('err', err, 'res', res);
    if (err) {
        return console.log('error occured listing objects', err);
    }
    return console.log('completed listing');
});
<|endoftext|>


<commit_before>describe('Dialog', function () {
  'use strict';

  beforeEach(function(done) {
    var self = this;

    requirejs([
      'phantom-shims',
      'jquery',
      'Dialog',
      'eventsWithPromises'
    ],
    function (
      phantomShims,
      $,
      Dialog,
      eventsWithPromises
    ) {
      self.$html = $(window.__html__['spec/javascripts/fixtures/Dialog.html']).appendTo('body');
      self.$fixture = self.$html.find('[data-dough-component="Dialog"]');
      self.Dialog = Dialog;
      self.showSpy = sinon.spy(self.Dialog.prototype, 'show');
      self.closeSpy = sinon.spy(self.Dialog.prototype, 'close');
      self.handleCancelSpy = sinon.spy(self.Dialog.prototype, '_handleCancel');
      self.eventsWithPromises = eventsWithPromises;
      done();
    }, done);
  });

  afterEach(function() {
    this.$html.remove();
    this.showSpy.restore();
    this.closeSpy.restore();
    this.handleCancelSpy.restore();
    $('[data-dough-dialog]').remove();
  });

  describe('Initialisation', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should create the dialog element, child elements and append it to the body', function() {
      var $body = $('body');
      expect($body.find(this.component.config.selectors.dialog).length).to.equal(1);
      expect(this.component.$dialog.find(this.component.config.selectors.container).length).to.equal(1);
      expect(this.component.$dialog.find(this.component.config.selectors.content).length).to.equal(1);
      expect(this.component.$dialog.find(this.component.config.selectors.close).length).to.equal(1);
    });

  });

  describe('Events', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      // this.component.dialog.show();
      done();
    });

    // it('should trigger the cancel handler when ESC is hit', function () {
    //   var e = $.Event('keyup');
    //   e.keyCode = 27;
    //   $('body').trigger(e);
    //   expect(this.handleCancelSpy.called).to.be.true;
    // });

    it('should show the dialog when clicking the trigger ', function() {
      this.component.$trigger.click();
      expect(this.showSpy.called).to.be.true;
    });

    it('should hide the dialog when clicking the close button ', function() {
      this.component.$dialog.find(this.component.config.selectors.close).click();
      expect(this.hideSpy.called).to.be.true;
    });
  });

  describe('Show dialog', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should detach the target content and append this to the dialog box', function() {
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.false;
      this.component.show();
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.true;
    });

    it('should trigger a shown event', function () {
      var spy = sinon.spy();
      this.eventsWithPromises.subscribe('dialog:shown', spy);
      this.component.show();
      expect(spy.called).to.be.true;
    });

    it('should add the active class to the dialog element', function() {
      this.component.show();
      expect(this.component.$dialog.hasClass(this.component.config.selectors.activeClass)).to.be.true;
    });

    it('should show the dialog', function() {

    });
  });

  describe('Hide dialog', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should detach the target content from the dialog and reattach it in its original position', function() {
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.false;
      this.component.show();
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.true;
    });

    it('should trigger a hidden event', function () {
      var spy = sinon.spy();
      this.eventsWithPromises.subscribe('dialog:closed', spy);
      this.component.show();
      this.component.close();
      expect(spy.called).to.be.true;
    });

    it('should remove the active class from the dialog element', function() {
      this.component.show();
      this.component.close();
      expect(this.component.$dialog.hasClass(this.component.config.selectors.activeClass)).to.be.false;
    });

    it('should hide the dialog', function() {

    });
  });

  describe('Set Content', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should trigger a ready event', function () {
      var spy = sinon.spy();
      this.eventsWithPromises.subscribe('dialog:ready', spy);
      this.component.show();
      expect(spy.called).to.be.true;
    });

  });
});

<commit_msg>Add test for content setting and fix broken hide test<commit_after>describe('Dialog', function () {
  'use strict';

  beforeEach(function(done) {
    var self = this;

    requirejs([
      'phantom-shims',
      'jquery',
      'Dialog',
      'eventsWithPromises'
    ],
    function (
      phantomShims,
      $,
      Dialog,
      eventsWithPromises
    ) {
      self.$html = $(window.__html__['spec/javascripts/fixtures/Dialog.html']).appendTo('body');
      self.$fixture = self.$html.find('[data-dough-component="Dialog"]');
      self.Dialog = Dialog;
      self.showSpy = sinon.spy(self.Dialog.prototype, 'show');
      self.closeSpy = sinon.spy(self.Dialog.prototype, 'close');
      self.handleCancelSpy = sinon.spy(self.Dialog.prototype, '_handleCancel');
      self.eventsWithPromises = eventsWithPromises;
      done();
    }, done);
  });

  afterEach(function() {
    this.$html.remove();
    this.showSpy.restore();
    this.closeSpy.restore();
    this.handleCancelSpy.restore();
    $('[data-dough-dialog]').remove();
  });

  describe('Initialisation', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should create the dialog element, child elements and append it to the body', function() {
      var $body = $('body');
      expect($body.find(this.component.config.selectors.dialog).length).to.equal(1);
      expect(this.component.$dialog.find(this.component.config.selectors.container).length).to.equal(1);
      expect(this.component.$dialog.find(this.component.config.selectors.content).length).to.equal(1);
      expect(this.component.$dialog.find(this.component.config.selectors.close).length).to.equal(1);
    });

  });

  describe('Events', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    // Dialog 'cancel' event not being triggered from within Karma env
    // it('should trigger the cancel handler when ESC is hit', function () {
    //   var e = $.Event('keyup');
    //   e.keyCode = 27;
    //   $('body').trigger(e);
    //   expect(this.handleCancelSpy.called).to.be.true;
    // });

    it('should show the dialog when clicking the trigger ', function() {
      this.component.$trigger.click();
      expect(this.showSpy.called).to.be.true;
    });

    it('should hide the dialog when clicking the close button ', function() {
      this.component.$trigger.click();
      this.component.$dialog.find(this.component.config.selectors.close).click();
      expect(this.closeSpy.called).to.be.true;
    });
  });

  describe('Show dialog', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should detach the target content and append this to the dialog box', function() {
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.false;
      this.component.show();
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.true;
    });

    it('should trigger a shown event', function () {
      var spy = sinon.spy();
      this.eventsWithPromises.subscribe('dialog:shown', spy);
      this.component.show();
      expect(spy.called).to.be.true;
    });

    it('should add the active class to the dialog element', function() {
      this.component.show();
      expect(this.component.$dialog.hasClass(this.component.config.selectors.activeClass)).to.be.true;
    });
  });

  describe('Hide dialog', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should detach the target content from the dialog and reattach it in its original position', function() {
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.false;
      this.component.show();
      expect($.contains(this.component.dialog, this.component.$target[0])).to.be.true;
    });

    it('should trigger a hidden event', function () {
      var spy = sinon.spy();
      this.eventsWithPromises.subscribe('dialog:closed', spy);
      this.component.show();
      this.component.close();
      expect(spy.called).to.be.true;
    });

    it('should remove the active class from the dialog element', function() {
      this.component.show();
      this.component.close();
      expect(this.component.$dialog.hasClass(this.component.config.selectors.activeClass)).to.be.false;
    });
  });

  describe('Set Content', function () {
    beforeEach(function (done) {
      this.component = new this.Dialog(this.$fixture);
      this.component.init();
      done();
    });

    it('should set the content of the dialog with that of the target\'s', function () {
      this.component.$dialogContent.empty();
      this.component.show();
      expect(this.component.$dialogContent.get(0).innerHTML).to.be.equal(this.component.$target[0].outerHTML);
    });

    it('should trigger a ready event', function () {
      var spy = sinon.spy();
      this.eventsWithPromises.subscribe('dialog:ready', spy);
      this.component.show();
      expect(spy.called).to.be.true;
    });

  });
});

<|endoftext|>


<commit_before>var proxyquire  =  require('proxyquire').noPreserveCache();

describe('when importing a space, but the space definition has not been specified', function() {
  var output;

  beforeEach(function() {
    var mockProgram = {
        parse: function() { },
        args: [ ]
      };

    console.log = function(msg) { output = msg; };
    console.error = function(msg) { output = msg; };

    proxyquire('../librato-cli-space-import', { 'commander': mockProgram, './modules/librato-cli-flow': { error: function(msg) { output = msg; } } });
  });

  it('should stop and tell the user to provide a space definition', function() {
    expect(output).toEqual('You must specify a space definition to import a space');
  });
});

describe('when importing a space', function() {
  var output;
  var calledEndPoints = [ ];
  var calledPayloads = [ ];
  var testPayload;

  beforeEach(function() {
    testSpaceDefinition = { name: 'foo', charts: [ { name: 'bar' } ] };
    var mockClient = {
        post: function(endPoint, data, handler) {
          calledEndPoints.push(endPoint);
          calledPayloads.push(data);
          handler({ }, data, { });
        }
      };
    var mockProgram = {
        parse: function() { },
        args: [ JSON.stringify(testSpaceDefinition) ]
      };

    console.log = function(msg) { output = msg; };

    proxyquire('../librato-cli-space-import',
            { './modules/librato-cli-client': mockClient, './modules/librato-cli-config': { baseUrl: '' },
              'commander': mockProgram });
  });

  it('should create a new space', function() {
    expect(calledEndPoints[0]).toEqual('spaces');
    expect(calledPayloads[0].data).toEqual('{"name":"foo"}');
  });

  it('should create a chart within the new space for each chart defined', function() {
    expect(calledEndPoints[1]).toEqual('spaces/undefined/charts');
    expect(calledPayloads[1].data).toEqual(testSpaceDefinition.charts[0]);
  });

  it('should set the content type to JSON for librato api', function() {
    expect(calledPayloads[0].headers['Content-Type']).toEqual('application/json');
    expect(calledPayloads[1].headers['Content-Type']).toEqual('application/json');
  });
});
<commit_msg>Fixed up broken import tests.<commit_after>var proxyquire  =  require('proxyquire').noPreserveCache();

describe('when importing a space, but the space definition has not been specified', function() {
  var output;

  beforeEach(function() {
    var mockProgram = {
        parse: function() { },
        option: function() { return { parse: function() { } } },
        args: [ ]
      };

    console.log = function(msg) { output = msg; };
    console.error = function(msg) { output = msg; };

    proxyquire('../librato-cli-space-import', { 'commander': mockProgram, './modules/librato-cli-flow': { error: function(msg) { output = msg; } } });
  });

  it('should stop and tell the user to provide a space definition', function() {
    expect(output).toEqual('You must specify a space definition to import a space');
  });
});

describe('when importing a space', function() {
  var output;
  var calledEndPoints = [ ];
  var calledPayloads = [ ];
  var testPayload;

  beforeEach(function() {
    testSpaceDefinition = { name: 'foo', charts: [ { name: 'bar' } ] };
    var mockClient = {
        post: function(endPoint, data, handler) {
          calledEndPoints.push(endPoint);
          calledPayloads.push(data);
          handler({ }, data, { });
        }
      };
    var mockProgram = {
        parse: function() { },
        option: function() { return { parse: function() { } } },
        args: [ JSON.stringify(testSpaceDefinition) ]
      };

    console.log = function(msg) { output = msg; };

    proxyquire('../librato-cli-space-import',
            { './modules/librato-cli-client': mockClient, './modules/librato-cli-config': { baseUrl: '' },
              'commander': mockProgram });
  });

  it('should create a new space', function() {
    expect(calledEndPoints[0]).toEqual('spaces');
    expect(calledPayloads[0].data).toEqual('{"name":"foo"}');
  });

  it('should create a chart within the new space for each chart defined', function() {
    expect(calledEndPoints[1]).toEqual('spaces/undefined/charts');
    expect(calledPayloads[1].data).toEqual(testSpaceDefinition.charts[0]);
  });

  it('should set the content type to JSON for librato api', function() {
    expect(calledPayloads[0].headers['Content-Type']).toEqual('application/json');
    expect(calledPayloads[1].headers['Content-Type']).toEqual('application/json');
  });
});
<|endoftext|>


<commit_before>'use strict';

var fs        = require('fs-extra');
var yeoman    = require('yeoman-generator');
var Gruntfile = require('gruntfile-editor');
var utils     = require('../app/utils');
var banner    = require('../app/banner');
var prompt    = require('../app/prompts').webapp;
var tasks     = require('../app/gruntTaskConfigs');
var footer    = require('./doneMessage');

var commandLineOptions = {
    defaults: {
        type: Boolean,
        desc: 'Scaffold app with no user input using default settings',
        defaults: false
    },
    scriptBundler: {
        type: String,
        desc: 'Choose script bundler',
        defaults: ''
    },
    cssPreprocessor: {
        type: String,
        desc: 'Choose CSS pre-processor',
        defaults: 'less'
    },
    templateTechnology: {
        desc: 'Choose technology to use when pre-compiling templates',
        defaults: 'handlebars'
    },
    skipImagemin: {
        type: Boolean,
        desc: 'DO NOT add image minification to project deploy pipeline',
        defaults: false
    },
    skipAria: {
        type: Boolean,
        desc: 'DO NOT add ARIA auditing tasks and dependencies to project',
        defaults: false
    }
};

module.exports = yeoman.Base.extend({
    constructor: function() {
        var generator = this;
        yeoman.Base.apply(generator, arguments);
        Object.keys(commandLineOptions).forEach(function(option) {
            generator.option(option, commandLineOptions[option]);
        });
    },
    prompting: function() {
        var generator = this;
        if (generator.options.defaults) {
            var done = this.async();
            generator.use = prompt.defaults;
            Object.keys(prompt.defaults).forEach(function(option) {
                generator[option] = prompt.defaults[option];
            });
            var bundler = generator.options.scriptBundler;
            var preprocessor = generator.options.cssPreprocessor;
            var templateTechnology = generator.options.templateTechnology;
            var options = {
                useBrowserify: (bundler === 'browserify') || prompt.defaults.useBrowserify,
                useLess:       (preprocessor === 'less'),
                useSass:       (preprocessor === 'sass'),
                useHandlebars: (templateTechnology === 'handlebars')
            };
            Object.keys(options).forEach(function(option) {
                generator[option] = options[option];
            });
            done();
        } else {
            function isUnAnswered(option) {
                return !!!generator.options[option.name] || (generator.options[option.name] === commandLineOptions[option.name].defaults);
            }
            return generator.prompt(prompt.questions.filter(isUnAnswered)).then(function (answers) {
                generator.use = answers;
                var bundler = (generator.options.scriptBundler || generator.use.scriptBundler).toLowerCase();
                var preprocessor;
                if (generator.options.cssPreprocessor === commandLineOptions.cssPreprocessor.defaults) {
                    preprocessor = generator.use.cssPreprocessor.toLowerCase();
                } else {
                    preprocessor = generator.options.cssPreprocessor;
                }
                var templateTechnology;
                if (generator.options.templateTechnology === commandLineOptions.templateTechnology.defaults) {
                    templateTechnology = generator.use.templateTechnology.toLowerCase();
                } else {
                    templateTechnology = generator.options.templateTechnology;
                }
                var options = {
                    useBrowserify: (bundler === 'browserify'),
                    useLess:       (preprocessor === 'less'),
                    useSass:       (preprocessor === 'sass'),
                    useHandlebars: (templateTechnology === 'handlebars')
                };
                Object.keys(options).forEach(function(option) {
                    generator[option] = options[option];
                });
            }.bind(generator));
        }
    },
    writing: {
        configFiles: function() {
            var generator = this;
            generator.projectName = generator.config.get('projectName');
            generator.userName = generator.config.get('userName') || generator.user.git.name();
            generator.sourceDirectory = generator.config.get('sourceDirectory');
            generator.useAria = generator.use.aria && !generator.options.skipAria;
            generator.useImagemin = generator.use.imagemin && !generator.options.skipImagemin;
            generator.config.set('useAria', generator.useAria);
            generator.config.set('useImagemin', generator.useImagemin);
            generator.config.set('pluginDirectory', generator.sourceDirectory);
            generator.template('_README.md', 'README.md');
            generator.template('config/_csslintrc', 'config/.csslintrc');
            generator.template('tasks/webapp.js', 'tasks/webapp.js');
            generator.template('_config.js', generator.sourceDirectory + 'app/config.js');
        },
        appFiles: function() {
            if (this.useHandlebars) {
                this.fs.copy(
                    this.templatePath('helpers/handlebars.helpers.js'),
                    this.destinationPath(this.sourceDirectory + 'app/helpers/handlebars.helpers.js')
                );
            }
            this.fs.copy(
                this.templatePath('helpers/jquery.extensions.js'),
                this.destinationPath(this.sourceDirectory + 'app/helpers/jquery.extensions.js')
            );
            this.fs.copy(
                this.templatePath('helpers/underscore.mixins.js'),
                this.destinationPath(this.sourceDirectory + 'app/helpers/underscore.mixins.js')
            );
            this.fs.copy(
                this.templatePath('plugins/*.js'),
                this.destinationPath(this.sourceDirectory + 'app/plugins')
            );
            this.fs.copy(
                this.templatePath('shims/*.js'),
                this.destinationPath(this.sourceDirectory + 'app/shims')
            );
        },
        assets: function() {
            if (this.useLess) {
                fs.mkdirp(this.sourceDirectory + 'assets/less');
            }
            if (this.useSass) {
                fs.mkdirp(this.sourceDirectory + 'assets/sass');
            }
            fs.mkdirp(this.sourceDirectory + 'assets/fonts');
            fs.mkdirp(this.sourceDirectory + 'assets/images');
            fs.mkdirp(this.sourceDirectory + 'assets/templates');
            fs.mkdirp(this.sourceDirectory + 'assets/library');
            this.fs.copy(
                this.templatePath('library/require.min.js'),
                this.destinationPath(this.sourceDirectory + 'assets/library/require.min.js')
            );
            this.fs.copy(
                this.templatePath('techtonic.png'),
                this.destinationPath(this.sourceDirectory + 'assets/images/logo.png')
            );
        },
        boilerplate: function() {
            this.template('_index.html', this.sourceDirectory + 'app/index.html');
            this.template('_app.js', this.sourceDirectory + 'app/app.js');
            this.template('_main.js', this.sourceDirectory + 'app/main.js');
            this.template('_router.js', this.sourceDirectory + 'app/router.js');
            this.template('example.model.js', this.sourceDirectory + 'app/models/example.js');
            this.template('example.view.js', this.sourceDirectory + 'app/views/example.js');
            this.template('example.controller.js', this.sourceDirectory + 'app/controllers/example.js');
            this.template('example.webworker.js', this.sourceDirectory + 'app/controllers/example.webworker.js');
            this.template('example.template.hbs', this.sourceDirectory + 'assets/templates/example.hbs');
            if (this.useLess) {
                this.template('_reset.css', this.sourceDirectory + 'assets/less/reset.less');
                this.template('_style.less', this.sourceDirectory + 'assets/less/style.less');
            }
            else if (this.useSass) {
                this.template('_reset.css', this.sourceDirectory + 'assets/sass/reset.scss');
                this.template('_style.scss', this.sourceDirectory + 'assets/sass/style.scss');
            } else{
                this.template('_style.css', this.sourceDirectory + 'assets/css/style.css');
            }
        }
    },
    install: function() {
        var generator = this;
        var dependencies = [
            'jquery',
            'underscore',
            'backbone',
            'backbone.marionette',
            'backbone.radio'
        ];
        var htmlDevDependencies = [
            'grunt-contrib-htmlmin',
            'grunt-htmlhint-plus'
        ];
        var cssDevDependencies = [
            'grunt-contrib-csslint',
            'grunt-postcss',
            'autoprefixer',
            'cssnano',
            'postcss-safe-parser',
            'mdcss',
            'mdcss-theme-github'
        ];
        var requirejsDevDependencies = [
            'grunt-contrib-requirejs',
            'karma-requirejs'
        ];
        var devDependencies = [].concat(
            htmlDevDependencies,
            cssDevDependencies,
            requirejsDevDependencies,
            generator.useBrowserify ? ['browserify', 'browserify-shim', 'aliasify', 'deamdify', 'grunt-browserify', 'grunt-replace'] : [],
            generator.useAria ? ['grunt-a11y', 'grunt-accessibility'] : [],
            generator.useImagemin ? ['grunt-contrib-imagemin'] :[],
            generator.useLess ? ['grunt-contrib-less'] : [],
            generator.useSass ? ['grunt-contrib-sass'] : [],
            generator.useHandlebars ? ['grunt-contrib-handlebars'] : ['grunt-contrib-jst']
        );
        generator.useHandlebars && dependencies.push('handlebars');

        generator.npmInstall(dependencies, {save: true});
        generator.npmInstall(devDependencies, {saveDev: true});
    },
    end: function() {
        var generator = this;
        var sourceDirectory = generator.sourceDirectory;
        var gruntfile = new Gruntfile(fs.readFileSync(generator.destinationPath('Gruntfile.js')).toString());
        utils.json.extend(generator.destinationPath('package.json'), {
            main: sourceDirectory + 'app/main.js',
            scripts: {
                build:     'grunt build',
                test:      'grunt test',
                predemo:   'npm run build',
                demo:      'grunt open:demo express:demo',
                start:     'grunt serve',
                predeploy: 'npm run build'
            }
        });
        if (/^linux/.test(process.platform)) {
            utils.json.extend(generator.destinationPath('package.json'), {
                scripts: {
                    prestart: 'nohup npm run rest-api &'
                }
            });
        }
        utils.json.extend(generator.destinationPath('config/default.json'), {
            grunt: {
                folders: {
                    app:    sourceDirectory + 'app',
                    assets: sourceDirectory + 'assets'
                }
            }
        });
        if (generator.useAria) {
            gruntfile.insertConfig('a11y', tasks.a11y);
            gruntfile.insertConfig('accessibility', tasks.accessibility);
            gruntfile.registerTask('aria-audit', ['accessibility', 'a11y']);
        }
        if (generator.useBrowserify) {
            gruntfile.insertConfig('browserify', tasks.browserify);
            gruntfile.insertConfig('replace', tasks.replace);
            gruntfile.insertConfig('uglify', tasks.uglify);
            utils.json.extend(generator.destinationPath('package.json'), {
                browser: {
                    underscore: './node_modules/underscore/underscore-min.js'
                },
                browserify: {
                    transform: ['deamdify', 'browserify-shim', 'aliasify']
                },
                'browserify-shim': {
                    underscore: '_'
                },
                aliasify: {
                    aliases: {
                        app:       './' + sourceDirectory + 'app/app',
                        router:    './' + sourceDirectory + 'app/router',
                        templates: './' + sourceDirectory + 'app/templates'
                    },
                    replacements: {
                        'models/(\\w+)':      './' + sourceDirectory + 'app/models/$1',
                        'views/(\\w+)':       './' + sourceDirectory + 'app/views/$1',
                        'controllers/(\\w+)': './' + sourceDirectory + 'app/controllers/$1',
                        'plugins/(\\w+)':     './' + sourceDirectory + 'app/plugins/$1'
                    }
                }
            });
        }
        if (generator.useHandlebars) {
            gruntfile.insertConfig('handlebars', tasks.handlebars);
        } else {
            gruntfile.insertConfig('jst', tasks.jst);
        }
        if (generator.useImagemin) {
            gruntfile.insertConfig('imagemin', tasks.imagemin);
            gruntfile.insertConfig('copy', tasks.copy);
        }
        if (generator.useLess) {
            gruntfile.insertConfig('less', tasks.less);
            utils.json.extend(generator.destinationPath('config/default.json'), {
                grunt: {
                    files: {
                        styles: "less/**/*.less"
                    }
                }
            });
        }
        if (generator.useSass) {
            gruntfile.insertConfig('sass', tasks.sass);
            utils.json.extend(generator.destinationPath('config/default.json'), {
                grunt: {
                    files: {
                        styles: "sass/**/*.scss"
                    }
                }
            });
        }
        gruntfile.insertConfig('htmlhintplus', tasks.htmlhintplus);
        gruntfile.insertConfig('htmlmin', tasks.htmlmin);
        gruntfile.insertConfig('postcss', tasks.postcss(sourceDirectory));
        fs.writeFileSync(generator.destinationPath('Gruntfile.js'), gruntfile.toString());
        generator.log(footer(generator));
    }
});
<commit_msg>Hard-coded Marionette version to 2.4.7, since Marionette v3 was released<commit_after>'use strict';

var fs        = require('fs-extra');
var yeoman    = require('yeoman-generator');
var Gruntfile = require('gruntfile-editor');
var utils     = require('../app/utils');
var banner    = require('../app/banner');
var prompt    = require('../app/prompts').webapp;
var tasks     = require('../app/gruntTaskConfigs');
var footer    = require('./doneMessage');

var commandLineOptions = {
    defaults: {
        type: Boolean,
        desc: 'Scaffold app with no user input using default settings',
        defaults: false
    },
    scriptBundler: {
        type: String,
        desc: 'Choose script bundler',
        defaults: ''
    },
    cssPreprocessor: {
        type: String,
        desc: 'Choose CSS pre-processor',
        defaults: 'less'
    },
    templateTechnology: {
        desc: 'Choose technology to use when pre-compiling templates',
        defaults: 'handlebars'
    },
    skipImagemin: {
        type: Boolean,
        desc: 'DO NOT add image minification to project deploy pipeline',
        defaults: false
    },
    skipAria: {
        type: Boolean,
        desc: 'DO NOT add ARIA auditing tasks and dependencies to project',
        defaults: false
    }
};

module.exports = yeoman.Base.extend({
    constructor: function() {
        var generator = this;
        yeoman.Base.apply(generator, arguments);
        Object.keys(commandLineOptions).forEach(function(option) {
            generator.option(option, commandLineOptions[option]);
        });
    },
    prompting: function() {
        var generator = this;
        if (generator.options.defaults) {
            var done = this.async();
            generator.use = prompt.defaults;
            Object.keys(prompt.defaults).forEach(function(option) {
                generator[option] = prompt.defaults[option];
            });
            var bundler = generator.options.scriptBundler;
            var preprocessor = generator.options.cssPreprocessor;
            var templateTechnology = generator.options.templateTechnology;
            var options = {
                useBrowserify: (bundler === 'browserify') || prompt.defaults.useBrowserify,
                useLess:       (preprocessor === 'less'),
                useSass:       (preprocessor === 'sass'),
                useHandlebars: (templateTechnology === 'handlebars')
            };
            Object.keys(options).forEach(function(option) {
                generator[option] = options[option];
            });
            done();
        } else {
            function isUnAnswered(option) {
                return !!!generator.options[option.name] || (generator.options[option.name] === commandLineOptions[option.name].defaults);
            }
            return generator.prompt(prompt.questions.filter(isUnAnswered)).then(function (answers) {
                generator.use = answers;
                var bundler = (generator.options.scriptBundler || generator.use.scriptBundler).toLowerCase();
                var preprocessor;
                if (generator.options.cssPreprocessor === commandLineOptions.cssPreprocessor.defaults) {
                    preprocessor = generator.use.cssPreprocessor.toLowerCase();
                } else {
                    preprocessor = generator.options.cssPreprocessor;
                }
                var templateTechnology;
                if (generator.options.templateTechnology === commandLineOptions.templateTechnology.defaults) {
                    templateTechnology = generator.use.templateTechnology.toLowerCase();
                } else {
                    templateTechnology = generator.options.templateTechnology;
                }
                var options = {
                    useBrowserify: (bundler === 'browserify'),
                    useLess:       (preprocessor === 'less'),
                    useSass:       (preprocessor === 'sass'),
                    useHandlebars: (templateTechnology === 'handlebars')
                };
                Object.keys(options).forEach(function(option) {
                    generator[option] = options[option];
                });
            }.bind(generator));
        }
    },
    writing: {
        configFiles: function() {
            var generator = this;
            generator.projectName = generator.config.get('projectName');
            generator.userName = generator.config.get('userName') || generator.user.git.name();
            generator.sourceDirectory = generator.config.get('sourceDirectory');
            generator.useAria = generator.use.aria && !generator.options.skipAria;
            generator.useImagemin = generator.use.imagemin && !generator.options.skipImagemin;
            generator.config.set('useAria', generator.useAria);
            generator.config.set('useImagemin', generator.useImagemin);
            generator.config.set('pluginDirectory', generator.sourceDirectory);
            generator.template('_README.md', 'README.md');
            generator.template('config/_csslintrc', 'config/.csslintrc');
            generator.template('tasks/webapp.js', 'tasks/webapp.js');
            generator.template('_config.js', generator.sourceDirectory + 'app/config.js');
        },
        appFiles: function() {
            if (this.useHandlebars) {
                this.fs.copy(
                    this.templatePath('helpers/handlebars.helpers.js'),
                    this.destinationPath(this.sourceDirectory + 'app/helpers/handlebars.helpers.js')
                );
            }
            this.fs.copy(
                this.templatePath('helpers/jquery.extensions.js'),
                this.destinationPath(this.sourceDirectory + 'app/helpers/jquery.extensions.js')
            );
            this.fs.copy(
                this.templatePath('helpers/underscore.mixins.js'),
                this.destinationPath(this.sourceDirectory + 'app/helpers/underscore.mixins.js')
            );
            this.fs.copy(
                this.templatePath('plugins/*.js'),
                this.destinationPath(this.sourceDirectory + 'app/plugins')
            );
            this.fs.copy(
                this.templatePath('shims/*.js'),
                this.destinationPath(this.sourceDirectory + 'app/shims')
            );
        },
        assets: function() {
            if (this.useLess) {
                fs.mkdirp(this.sourceDirectory + 'assets/less');
            }
            if (this.useSass) {
                fs.mkdirp(this.sourceDirectory + 'assets/sass');
            }
            fs.mkdirp(this.sourceDirectory + 'assets/fonts');
            fs.mkdirp(this.sourceDirectory + 'assets/images');
            fs.mkdirp(this.sourceDirectory + 'assets/templates');
            fs.mkdirp(this.sourceDirectory + 'assets/library');
            this.fs.copy(
                this.templatePath('library/require.min.js'),
                this.destinationPath(this.sourceDirectory + 'assets/library/require.min.js')
            );
            this.fs.copy(
                this.templatePath('techtonic.png'),
                this.destinationPath(this.sourceDirectory + 'assets/images/logo.png')
            );
        },
        boilerplate: function() {
            this.template('_index.html', this.sourceDirectory + 'app/index.html');
            this.template('_app.js', this.sourceDirectory + 'app/app.js');
            this.template('_main.js', this.sourceDirectory + 'app/main.js');
            this.template('_router.js', this.sourceDirectory + 'app/router.js');
            this.template('example.model.js', this.sourceDirectory + 'app/models/example.js');
            this.template('example.view.js', this.sourceDirectory + 'app/views/example.js');
            this.template('example.controller.js', this.sourceDirectory + 'app/controllers/example.js');
            this.template('example.webworker.js', this.sourceDirectory + 'app/controllers/example.webworker.js');
            this.template('example.template.hbs', this.sourceDirectory + 'assets/templates/example.hbs');
            if (this.useLess) {
                this.template('_reset.css', this.sourceDirectory + 'assets/less/reset.less');
                this.template('_style.less', this.sourceDirectory + 'assets/less/style.less');
            }
            else if (this.useSass) {
                this.template('_reset.css', this.sourceDirectory + 'assets/sass/reset.scss');
                this.template('_style.scss', this.sourceDirectory + 'assets/sass/style.scss');
            } else{
                this.template('_style.css', this.sourceDirectory + 'assets/css/style.css');
            }
        }
    },
    install: function() {
        var generator = this;
        var dependencies = [
            'jquery',
            'underscore',
            'backbone',
            'backbone.marionette@^2.4.7',
            'backbone.radio'
        ];
        var htmlDevDependencies = [
            'grunt-contrib-htmlmin',
            'grunt-htmlhint-plus'
        ];
        var cssDevDependencies = [
            'grunt-contrib-csslint',
            'grunt-postcss',
            'autoprefixer',
            'cssnano',
            'postcss-safe-parser',
            'mdcss',
            'mdcss-theme-github'
        ];
        var requirejsDevDependencies = [
            'grunt-contrib-requirejs',
            'karma-requirejs'
        ];
        var devDependencies = [].concat(
            htmlDevDependencies,
            cssDevDependencies,
            requirejsDevDependencies,
            generator.useBrowserify ? ['browserify', 'browserify-shim', 'aliasify', 'deamdify', 'grunt-browserify', 'grunt-replace'] : [],
            generator.useAria ? ['grunt-a11y', 'grunt-accessibility'] : [],
            generator.useImagemin ? ['grunt-contrib-imagemin'] :[],
            generator.useLess ? ['grunt-contrib-less'] : [],
            generator.useSass ? ['grunt-contrib-sass'] : [],
            generator.useHandlebars ? ['grunt-contrib-handlebars'] : ['grunt-contrib-jst']
        );
        generator.useHandlebars && dependencies.push('handlebars');

        generator.npmInstall(dependencies, {save: true});
        generator.npmInstall(devDependencies, {saveDev: true});
    },
    end: function() {
        var generator = this;
        var sourceDirectory = generator.sourceDirectory;
        var gruntfile = new Gruntfile(fs.readFileSync(generator.destinationPath('Gruntfile.js')).toString());
        utils.json.extend(generator.destinationPath('package.json'), {
            main: sourceDirectory + 'app/main.js',
            scripts: {
                build:     'grunt build',
                test:      'grunt test',
                predemo:   'npm run build',
                demo:      'grunt open:demo express:demo',
                start:     'grunt serve',
                predeploy: 'npm run build'
            }
        });
        if (/^linux/.test(process.platform)) {
            utils.json.extend(generator.destinationPath('package.json'), {
                scripts: {
                    prestart: 'nohup npm run rest-api &'
                }
            });
        }
        utils.json.extend(generator.destinationPath('config/default.json'), {
            grunt: {
                folders: {
                    app:    sourceDirectory + 'app',
                    assets: sourceDirectory + 'assets'
                }
            }
        });
        if (generator.useAria) {
            gruntfile.insertConfig('a11y', tasks.a11y);
            gruntfile.insertConfig('accessibility', tasks.accessibility);
            gruntfile.registerTask('aria-audit', ['accessibility', 'a11y']);
        }
        if (generator.useBrowserify) {
            gruntfile.insertConfig('browserify', tasks.browserify);
            gruntfile.insertConfig('replace', tasks.replace);
            gruntfile.insertConfig('uglify', tasks.uglify);
            utils.json.extend(generator.destinationPath('package.json'), {
                browser: {
                    underscore: './node_modules/underscore/underscore-min.js'
                },
                browserify: {
                    transform: ['deamdify', 'browserify-shim', 'aliasify']
                },
                'browserify-shim': {
                    underscore: '_'
                },
                aliasify: {
                    aliases: {
                        app:       './' + sourceDirectory + 'app/app',
                        router:    './' + sourceDirectory + 'app/router',
                        templates: './' + sourceDirectory + 'app/templates'
                    },
                    replacements: {
                        'models/(\\w+)':      './' + sourceDirectory + 'app/models/$1',
                        'views/(\\w+)':       './' + sourceDirectory + 'app/views/$1',
                        'controllers/(\\w+)': './' + sourceDirectory + 'app/controllers/$1',
                        'plugins/(\\w+)':     './' + sourceDirectory + 'app/plugins/$1'
                    }
                }
            });
        }
        if (generator.useHandlebars) {
            gruntfile.insertConfig('handlebars', tasks.handlebars);
        } else {
            gruntfile.insertConfig('jst', tasks.jst);
        }
        if (generator.useImagemin) {
            gruntfile.insertConfig('imagemin', tasks.imagemin);
            gruntfile.insertConfig('copy', tasks.copy);
        }
        if (generator.useLess) {
            gruntfile.insertConfig('less', tasks.less);
            utils.json.extend(generator.destinationPath('config/default.json'), {
                grunt: {
                    files: {
                        styles: "less/**/*.less"
                    }
                }
            });
        }
        if (generator.useSass) {
            gruntfile.insertConfig('sass', tasks.sass);
            utils.json.extend(generator.destinationPath('config/default.json'), {
                grunt: {
                    files: {
                        styles: "sass/**/*.scss"
                    }
                }
            });
        }
        gruntfile.insertConfig('htmlhintplus', tasks.htmlhintplus);
        gruntfile.insertConfig('htmlmin', tasks.htmlmin);
        gruntfile.insertConfig('postcss', tasks.postcss(sourceDirectory));
        fs.writeFileSync(generator.destinationPath('Gruntfile.js'), gruntfile.toString());
        generator.log(footer(generator));
    }
});
<|endoftext|>