<commit_before>window.requestAnimFrame = (function (callback) {
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.oRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  function (callback) {
    window.setTimeout(callback, 1000 / 60);
  }
})();

var dx = 0;
var dy = 0;

var screenWidth = 1600;
var screenHeight = 900;

var linearSpeed = 50;

var field = {
  grid: 10, width: 160, height: 90, parts: []
};

var fieldPartsCount = field.width * field.height;
var fieldPartsLeft = fieldPartsCount;

var id = getRandomInt(1000, 9999);
var connectedCombines = {};

var combine = {
  id: id,
  grain: 0,
  maxGrain: 5000,
  fuel: 300,
  maxFuel: 300,
  x: 100, y: 100, angle: 0, width: 80, height: 80,
  header: { x1: 0, y1: 0, x2: 10, y2: 10},
  back: { x1: 0, y1: 0, x2: 10, y2: 10},
  diagonal: 0,
  diagonalAngleRad: 0,
  diagonalAngleDeg: 0,
  diagonal2: 0,
  diagonal2AngleRad: 0,
  diagonal2AngleDeg: 0,
  sprite: null
};

combine.diagonal = combine.height / 2;
combine.diagonal2 = Math.sqrt(Math.pow(combine.height / 10, 2) + Math.pow(combine.width - 30, 2));
combine.diagonal2AngleRad = Math.atan2(combine.height / 10, combine.width - 30);
combine.diagonal2AngleDeg = combine.diagonal2AngleRad * 180 / Math.PI;

var canvas = document.getElementById("canvas");
canvas.width = screenWidth;
canvas.height = screenHeight;
var context = canvas.getContext("2d");

var bufferCanvas = document.createElement('canvas');
bufferCanvas.width = screenWidth;
bufferCanvas.height = screenHeight;
var bufferContext = bufferCanvas.getContext("2d");

var serverCanvas = document.createElement('canvas');
serverCanvas.width = screenWidth;
serverCanvas.height = screenHeight;
var serverContext = serverCanvas.getContext("2d");

var fieldCanvas = document.createElement('canvas');
fieldCanvas.width = screenWidth;
fieldCanvas.height = screenHeight;
var fieldContext = fieldCanvas.getContext("2d");

var spritesImage = new Image();
spritesImage.src = 'atlas.png';
spritesImage.onload = function() {
  generateField();
  renderField(fieldContext);
  var date = new Date();
  var time = date.getTime();
  animate(time);
}

/*
var socket = io();
socket.on('combine', function(combineMsg){
connectedCombines[combineMsg.id] = combineMsg;
});

socket.on('empty', function(msg){
fieldContext.drawImage(spritesImage, 20, 60, 20, 20, msg.i * field.grid, msg.j * field.grid, field.grid, field.grid);
});

socket.on('straw', function(msg){
fieldContext.drawImage(spritesImage, 40, 60, 20, 20, msg.i * field.grid, msg.j * field.grid, field.grid, field.grid);
});
*/

document.onkeydown = function (e) {
  var key = e.keyCode;
  if (key == 37) dx = -1;
  else if (key == 38) dy = -1;
  else if (key == 39) dx = 1;
  else if (key == 40) dy = 1;
  else return true;
  return false;
};

document.onkeyup = function (e) {
  var key = e.keyCode;
  if (key == 37 || key == 39) dx = 0;
  else if (key == 38 || key == 40) dy = 0;
  else return true;
  return false;
};

function generateField() {
  for (var i = 0; i < field.width; i++) {
    if (!field.parts[i]) {
      field.parts[i] = [];
    }
    for (var j = 0; j < field.height; j++) {
      field.parts[i][j] = {
        type: 0
      };
    }
  }
}

function renderField(ctx) {
  for (var i = 0; i < field.width; i++) {
    for (var j = 0; j < field.height; j++) {
      // var partOfField = field.parts[i][j];
      ctx.drawImage(spritesImage, 0, 60, 20, 20, i * field.grid, j * field.grid, field.grid, field.grid);
    }
  }
}

function updateFieldView(ctx, i, j, type) {
  if (field.parts[i] === undefined || field.parts[i][j] === undefined) {
    return false;
  }
  var partOfField = field.parts[i][j];
  if (partOfField.type === 0 && type === 1) {
    partOfField.type = type;
    if (combine.grain < combine.maxGrain) {
      combine.grain += 1;
    }
    fieldPartsLeft--;
    // socket.emit('empty', {i:i, j:j});
    ctx.drawImage(spritesImage, 20, 60, 20, 20, i * field.grid, j * field.grid, field.grid, field.grid);
    return true;
  } else if (partOfField.type === 1 && type === 2) {
    partOfField.type = type;
    // socket.emit('straw', {i:i, j:j});
    ctx.drawImage(spritesImage, 40, 60, 20, 20, i * field.grid, j * field.grid, field.grid, field.grid);
    return false;
  }
}

function animate(lastTime) {

  // update
  var date = new Date();
  var time = date.getTime();
  var timeDiff = time - lastTime;
  var linearDistEachFrame = linearSpeed * timeDiff / 1000;

  if (dy !== 0) {
    if (combine.fuel > 0) {
      combine.fuel -= timeDiff * 0.001;
    } else {
      combine.fuel = 0;
    }
    if (dy == 1) {
      combine.angle += linearDistEachFrame * -dx;
    } else {
      combine.angle += linearDistEachFrame * dx;
    }
  }

  combine.x -= dy * Math.cos(combine.angle * Math.PI / 180) * linearDistEachFrame;
  combine.y -= dy * Math.sin(combine.angle * Math.PI / 180) * linearDistEachFrame;

  var diagonalAngle1 = combine.angle + 60;//combine.diagonalAngleDeg;
  var diagonalAngle2 = combine.angle - 60;//combine.diagonalAngleDeg;
  var diagonalAngleRad1 = diagonalAngle1 * Math.PI / 180;
  var diagonalAngleRad2 = diagonalAngle2 * Math.PI / 180;
  combine.header.x1 = Math.cos(diagonalAngleRad1) * combine.diagonal + combine.x;
  combine.header.y1 = Math.sin(diagonalAngleRad1) * combine.diagonal + combine.y;
  combine.header.x2 = Math.cos(diagonalAngleRad2) * combine.diagonal + combine.x;
  combine.header.y2 = Math.sin(diagonalAngleRad2) * combine.diagonal + combine.y;

  var diagonalAngleBack1 = combine.angle + combine.diagonal2AngleDeg - 180;
  var diagonalAngleBack2 = combine.angle - combine.diagonal2AngleDeg - 180;
  var diagonalAngleBackRad1 = diagonalAngleBack1 * Math.PI / 180;
  var diagonalAngleBackRad2 = diagonalAngleBack2 * Math.PI / 180;
  combine.back.x1 = Math.cos(diagonalAngleBackRad1) * combine.diagonal2 + combine.x;
  combine.back.y1 = Math.sin(diagonalAngleBackRad1) * combine.diagonal2 + combine.y;
  combine.back.x2 = Math.cos(diagonalAngleBackRad2) * combine.diagonal2 + combine.x;
  combine.back.y2 = Math.sin(diagonalAngleBackRad2) * combine.diagonal2 + combine.y;

  // socket.emit('combine', {id:combine.id, x:combine.x, y:combine.y, angle:combine.angle});

  bufferContext.clearRect(0, 0, bufferCanvas.width, bufferCanvas.height);
  renderCombine(bufferContext, combine);
  // for (var prop in connectedCombines) {
  //   if (connectedCombines.hasOwnProperty(prop)) {
  //     renderCombine(bufferContext, connectedCombines[prop]);
  //   }
  // }

  if (dy < 0) {
    if (bline(combine.header.x1, combine.header.y1, combine.header.x2, combine.header.y2, 1)) {
      bline(combine.back.x1, combine.back.y1, combine.back.x2, combine.back.y2, 2);
    }
  }

  var grainLevel = combine.grain * 100/combine.maxGrain;
  var fuelLevel = combine.fuel * 100/combine.maxFuel;
  renderBar(bufferContext, grainLevel, 10, 10);
  renderBar(bufferContext, fuelLevel, 40, 10);

  bufferContext.fillText(Math.floor((fieldPartsCount-fieldPartsLeft)/fieldPartsCount * 100) + "% done", 80, 20);
  bufferContext.fillText("grain", 9, 122);
  bufferContext.fillText("fuel", 42, 122);

  context.clearRect(0, 0, canvas.width, canvas.height);
  context.drawImage(fieldCanvas, 0, 0);
  context.drawImage(bufferCanvas, 0, 0);
  // context.drawImage(serverCanvas, 0, 0);

  lastTime = time;
  requestAnimFrame(function () {
    animate(lastTime);
  });
}

function renderBar(ctx, level, x, y) {
  ctx.save();
  ctx.fillStyle="#FFFFFF";
  ctx.fillRect(x, y, 20, 100);
  ctx.fillStyle="#68c1e7";
  ctx.fillRect(x,100 + y - level, 20, level);
  ctx.strokeStyle="#000000";
  ctx.strokeRect(x, y, 20, 100);
  ctx.restore();
}

function renderCombine(ctx, combineObj) {
  ctx.save();
  ctx.translate(combineObj.x, combineObj.y);
  ctx.rotate(combineObj.angle * Math.PI / 180);
  ctx.translate(-combine.width, -combine.height / 2);
  ctx.translate(30, 0);
  ctx.drawImage(spritesImage, 0, 0, 20, 20, 0, 0, combine.width, combine.height);
  ctx.restore();
}

function bline(x0, y0, x1, y1, type) {
  x0 = Math.floor(x0/field.grid);
  y0 = Math.floor(y0/field.grid);
  x1 = Math.floor(x1/field.grid);
  y1 = Math.floor(y1/field.grid);
  var dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
  var dy = Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
  var err = (dx>dy ? dx : -dy)/2;
  var notEmptyField = false;
  while (true) {
    if (updateFieldView(fieldContext, x0, y0, type)) {
      notEmptyField = true;
    }
    if (x0 === x1 && y0 === y1) break;
    var e2 = err;
    if (e2 > -dx) { err -= dy; x0 += sx; }
    if (e2 < dy) { err += dx; y0 += sy; }
  }
  return notEmptyField;
}

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
<commit_msg>warning levels added<commit_after>window.requestAnimFrame = (function (callback) {
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.oRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  function (callback) {
    window.setTimeout(callback, 1000 / 60);
  }
})();

var dx = 0;
var dy = 0;

var screenWidth = 1600;
var screenHeight = 900;

var linearSpeed = 50;

var field = {
  grid: 10, width: 160, height: 90, parts: []
};

var fieldPartsCount = field.width * field.height;
var fieldPartsLeft = fieldPartsCount;

var id = getRandomInt(1000, 9999);
var connectedCombines = {};

var combine = {
  id: id,
  grain: 0,
  maxGrain: 5000,
  fuel: 300,
  maxFuel: 300,
  x: 100, y: 100, angle: 0, width: 80, height: 80,
  header: { x1: 0, y1: 0, x2: 10, y2: 10},
  back: { x1: 0, y1: 0, x2: 10, y2: 10},
  diagonal: 0,
  diagonalAngleRad: 0,
  diagonalAngleDeg: 0,
  diagonal2: 0,
  diagonal2AngleRad: 0,
  diagonal2AngleDeg: 0,
  sprite: null
};

combine.diagonal = combine.height / 2;
combine.diagonal2 = Math.sqrt(Math.pow(combine.height / 10, 2) + Math.pow(combine.width - 30, 2));
combine.diagonal2AngleRad = Math.atan2(combine.height / 10, combine.width - 30);
combine.diagonal2AngleDeg = combine.diagonal2AngleRad * 180 / Math.PI;

var canvas = document.getElementById("canvas");
canvas.width = screenWidth;
canvas.height = screenHeight;
var context = canvas.getContext("2d");

var bufferCanvas = document.createElement('canvas');
bufferCanvas.width = screenWidth;
bufferCanvas.height = screenHeight;
var bufferContext = bufferCanvas.getContext("2d");

var serverCanvas = document.createElement('canvas');
serverCanvas.width = screenWidth;
serverCanvas.height = screenHeight;
var serverContext = serverCanvas.getContext("2d");

var fieldCanvas = document.createElement('canvas');
fieldCanvas.width = screenWidth;
fieldCanvas.height = screenHeight;
var fieldContext = fieldCanvas.getContext("2d");

var spritesImage = new Image();
spritesImage.src = 'atlas.png';
spritesImage.onload = function() {
  generateField();
  renderField(fieldContext);
  var date = new Date();
  var time = date.getTime();
  animate(time);
}

/*
var socket = io();
socket.on('combine', function(combineMsg){
connectedCombines[combineMsg.id] = combineMsg;
});

socket.on('empty', function(msg){
fieldContext.drawImage(spritesImage, 20, 60, 20, 20, msg.i * field.grid, msg.j * field.grid, field.grid, field.grid);
});

socket.on('straw', function(msg){
fieldContext.drawImage(spritesImage, 40, 60, 20, 20, msg.i * field.grid, msg.j * field.grid, field.grid, field.grid);
});
*/

document.onkeydown = function (e) {
  var key = e.keyCode;
  if (key == 37) dx = -1;
  else if (key == 38) dy = -1;
  else if (key == 39) dx = 1;
  else if (key == 40) dy = 1;
  else return true;
  return false;
};

document.onkeyup = function (e) {
  var key = e.keyCode;
  if (key == 37 || key == 39) dx = 0;
  else if (key == 38 || key == 40) dy = 0;
  else return true;
  return false;
};

function generateField() {
  for (var i = 0; i < field.width; i++) {
    if (!field.parts[i]) {
      field.parts[i] = [];
    }
    for (var j = 0; j < field.height; j++) {
      field.parts[i][j] = {
        type: 0
      };
    }
  }
}

function renderField(ctx) {
  for (var i = 0; i < field.width; i++) {
    for (var j = 0; j < field.height; j++) {
      // var partOfField = field.parts[i][j];
      ctx.drawImage(spritesImage, 0, 60, 20, 20, i * field.grid, j * field.grid, field.grid, field.grid);
    }
  }
}

function updateFieldView(ctx, i, j, type) {
  if (field.parts[i] === undefined || field.parts[i][j] === undefined) {
    return false;
  }
  var partOfField = field.parts[i][j];
  if (partOfField.type === 0 && type === 1) {
    partOfField.type = type;
    if (combine.grain < combine.maxGrain) {
      combine.grain += 1;
    }
    fieldPartsLeft--;
    // socket.emit('empty', {i:i, j:j});
    ctx.drawImage(spritesImage, 20, 60, 20, 20, i * field.grid, j * field.grid, field.grid, field.grid);
    return true;
  } else if (partOfField.type === 1 && type === 2) {
    partOfField.type = type;
    // socket.emit('straw', {i:i, j:j});
    ctx.drawImage(spritesImage, 40, 60, 20, 20, i * field.grid, j * field.grid, field.grid, field.grid);
    return false;
  }
}

function animate(lastTime) {

  // update
  var date = new Date();
  var time = date.getTime();
  var timeDiff = time - lastTime;
  var linearDistEachFrame = linearSpeed * timeDiff / 1000;

  if (dy !== 0) {
    if (combine.fuel > 0) {
      combine.fuel -= timeDiff * 0.001;
    } else {
      combine.fuel = 0;
    }
    if (dy == 1) {
      combine.angle += linearDistEachFrame * -dx;
    } else {
      combine.angle += linearDistEachFrame * dx;
    }
  }

  combine.x -= dy * Math.cos(combine.angle * Math.PI / 180) * linearDistEachFrame;
  combine.y -= dy * Math.sin(combine.angle * Math.PI / 180) * linearDistEachFrame;

  var diagonalAngle1 = combine.angle + 60;//combine.diagonalAngleDeg;
  var diagonalAngle2 = combine.angle - 60;//combine.diagonalAngleDeg;
  var diagonalAngleRad1 = diagonalAngle1 * Math.PI / 180;
  var diagonalAngleRad2 = diagonalAngle2 * Math.PI / 180;
  combine.header.x1 = Math.cos(diagonalAngleRad1) * combine.diagonal + combine.x;
  combine.header.y1 = Math.sin(diagonalAngleRad1) * combine.diagonal + combine.y;
  combine.header.x2 = Math.cos(diagonalAngleRad2) * combine.diagonal + combine.x;
  combine.header.y2 = Math.sin(diagonalAngleRad2) * combine.diagonal + combine.y;

  var diagonalAngleBack1 = combine.angle + combine.diagonal2AngleDeg - 180;
  var diagonalAngleBack2 = combine.angle - combine.diagonal2AngleDeg - 180;
  var diagonalAngleBackRad1 = diagonalAngleBack1 * Math.PI / 180;
  var diagonalAngleBackRad2 = diagonalAngleBack2 * Math.PI / 180;
  combine.back.x1 = Math.cos(diagonalAngleBackRad1) * combine.diagonal2 + combine.x;
  combine.back.y1 = Math.sin(diagonalAngleBackRad1) * combine.diagonal2 + combine.y;
  combine.back.x2 = Math.cos(diagonalAngleBackRad2) * combine.diagonal2 + combine.x;
  combine.back.y2 = Math.sin(diagonalAngleBackRad2) * combine.diagonal2 + combine.y;

  // socket.emit('combine', {id:combine.id, x:combine.x, y:combine.y, angle:combine.angle});

  bufferContext.clearRect(0, 0, bufferCanvas.width, bufferCanvas.height);
  renderCombine(bufferContext, combine);
  // for (var prop in connectedCombines) {
  //   if (connectedCombines.hasOwnProperty(prop)) {
  //     renderCombine(bufferContext, connectedCombines[prop]);
  //   }
  // }

  if (dy < 0) {
    if (bline(combine.header.x1, combine.header.y1, combine.header.x2, combine.header.y2, 1)) {
      bline(combine.back.x1, combine.back.y1, combine.back.x2, combine.back.y2, 2);
    }
  }

  var grainLevel = combine.grain * 100/combine.maxGrain;
  var fuelLevel = combine.fuel * 100/combine.maxFuel;
  renderBar(bufferContext, grainLevel, 10, 10, 80, false);
  renderBar(bufferContext, fuelLevel, 40, 10, 20, true);

  bufferContext.fillText(Math.floor((fieldPartsCount-fieldPartsLeft)/fieldPartsCount * 100) + "% done", 80, 20);
  bufferContext.fillText("grain", 9, 122);
  bufferContext.fillText("fuel", 42, 122);

  context.clearRect(0, 0, canvas.width, canvas.height);
  context.drawImage(fieldCanvas, 0, 0);
  context.drawImage(bufferCanvas, 0, 0);
  // context.drawImage(serverCanvas, 0, 0);

  lastTime = time;
  requestAnimFrame(function () {
    animate(lastTime);
  });
}

function renderBar(ctx, level, x, y, warningLevel, below) {
  ctx.save();
  ctx.fillStyle="#FFFFFF";
  ctx.fillRect(x, y, 20, 100);
  if (below && level < warningLevel) {
    ctx.fillStyle="#ff0000";
  } else if (!below && level > warningLevel) {
    ctx.fillStyle="#ff0000";
  } else {
    ctx.fillStyle="#68c1e7";
  }
  ctx.fillRect(x,100 + y - level, 20, level);
  ctx.strokeStyle="#000000";
  ctx.strokeRect(x, y, 20, 100);
  ctx.restore();
}

function renderCombine(ctx, combineObj) {
  ctx.save();
  ctx.translate(combineObj.x, combineObj.y);
  ctx.rotate(combineObj.angle * Math.PI / 180);
  ctx.translate(-combine.width, -combine.height / 2);
  ctx.translate(30, 0);
  ctx.drawImage(spritesImage, 0, 0, 20, 20, 0, 0, combine.width, combine.height);
  ctx.restore();
}

function bline(x0, y0, x1, y1, type) {
  x0 = Math.floor(x0/field.grid);
  y0 = Math.floor(y0/field.grid);
  x1 = Math.floor(x1/field.grid);
  y1 = Math.floor(y1/field.grid);
  var dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
  var dy = Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
  var err = (dx>dy ? dx : -dy)/2;
  var notEmptyField = false;
  while (true) {
    if (updateFieldView(fieldContext, x0, y0, type)) {
      notEmptyField = true;
    }
    if (x0 === x1 && y0 === y1) break;
    var e2 = err;
    if (e2 > -dx) { err -= dy; x0 += sx; }
    if (e2 < dy) { err += dx; y0 += sy; }
  }
  return notEmptyField;
}

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
<|endoftext|>


<commit_before>module.exports = {
    entry: './web/src/index.js',
    output: {
        filename: './web/dist/bundle.js'
    },

    module: {
        loaders: [
            {
                test: /\.(js|jsx)$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader'
            },
            // {
            //     test: /\.scss$/,
            //     loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")
            // },
            {
<<<<<<< HEAD
                /*test: /\.scss/,
                loaders: ['sass-loader', 'css-loader', 'autoprefixer'],*/
                test: /\.scss$/,
                loaders: ['style-loader', 'css-loader', 'sass-loader']
=======
                test: /\.scss/,
                loaders: ['style-loader', 'css-loader', 'sass-loader'],
>>>>>>> master
            }
        ]
    }
}
<commit_msg>fix bug<commit_after>module.exports = {
    entry: './web/src/index.js',
    output: {
        filename: './web/dist/bundle.js'
    },

    module: {
        loaders: [
            {
                test: /\.(js|jsx)$/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel-loader'
            },
            // {
            //     test: /\.scss$/,
            //     loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")
            // },
            {
                test: /\.scss/,
                loaders: ['style-loader', 'css-loader', 'sass-loader'],
            }
        ]
    }
}
<|endoftext|>


<commit_before>'use strict';

var async = require('async'),
  events = require('events'),
  util = require('util'),
  Config = require('./Config'),
  DataStore = require('./ds/DataStore'),
  Tenant = require('./resource/Tenant');

/**
 * Creates a new Client.
 *
 * @class
 */
function Client(config) {
  var self = this;

  // Call the constructor of the EventEmitter class -- this, allows us to
  // initialize our Client object as an EventEmitter, and allows us to fire off
  // events later on.
  events.EventEmitter.call(self);

  // Bind the user-supplied config property to our class so it can be accessed
  // like an object.
  self.config = new Config(config);

  // For backwards compatibility reasons, if no API key is specified we'll try
  // to grab the API credentials out of our new format and shove it into the old
  // format.  This can go away once we cut a release and decide to no longer
  // support the old configuration formatting.
  if (!self.config.apiKey) {
    self.config.apiKey = self.config.client.apiKey;
  }

  self._dataStore = new DataStore(self.config);

  // We'll maintain this class variable as an in-memory singleton for caching
  // purposes.  We do this because Tenants never ever change once a Client has
  // been initialized, so it makes sense to cache the Tenant object so we don't
  // make unnecessary API requests if this object is looked up more than once.
  self._currentTenant = null;

  self.mergeRemoteConfig(function(err) {
    return err ? self.emit('error', err): self.emit('ready');
  });
}

// By inheriting from `events.EventEmitter`, we're making our Client object a
// true EventEmitter -- allowing us to fire off events.
util.inherits(Client, Object);
util.inherits(Client, events.EventEmitter);

Client.prototype.mergeRemoteConfig = function(callback) {
  var self = this;
  var config = self.config;
  var application = config.application;

  function findApplication(name, cb) {
    self.getApplications({ name: application.name }, function(err, applications) {
      if (err) {
        return cb(err);
      }

      applications.detect(function(app, cb) {
        cb(application.name === app.name);
      }, function(app) {
        if (app) {
          self.config.application.href = app.href;
          return cb(null, app);
        }

        return cb(new Error('Application not found: "' + application.name + '"'));
      });
    });
  }

  function findDefaultDirectoryHref(application, cb) {
    application.getAccountStoreMappings(function(err, mappings) {
      if (err) {
        return cb(err);
      }
      mappings.detect(function(mapping,cb){
        cb(mapping.isDefaultAccountStore);
      },function(defaultMapping){
        if(defaultMapping){
          var href = defaultMapping.accountStore.href;
          if(href.match(/group/)){
            self.getGroup(href,function(err,group){
              cb(err,group &&group.directory.href);
            });
          }else{
            cb(null,href);
          }
        }else{
          cb(null,null);
        }
      });
    });
  }

  function applyConfig(directoryHref, cb) {
    if(!directoryHref){
      callback(null);
    }else{
      self.getDirectory(
        directoryHref,
        {expand:'passwordPolicy,accountCreationPolicy'},
        function(err,directory){
          if(err){
            cb(err);
          }else{
            self.config.web.verifyEmail.enabled =
              directory.accountCreationPolicy.verificationEmailStatus === 'ENABLED';
            self.config.web.changePassword.enabled = self.config.web.forgotPassword.enabled =
              directory.passwordPolicy.resetEmailStatus === 'ENABLED';
            cb(null);
          }
        }
      );
    }
  }

  if (application && application.href) {
    async.waterfall([
      self.getApplication.bind(self, application.href),
      findDefaultDirectoryHref,
      applyConfig
    ], callback);
  } else if (application && application.name) {
    async.waterfall([
      findApplication(application.name),
      findDefaultDirectoryHref,
      applyConfig
    ], callback);
  } else {
    process.nextTick(callback);
  }

};

/**
 * @callback getCurrentTenantCallback
 * @param {Error} err - The error (if there is one).
 * @param {Object} tenant - The retrieved Tenant object.
 */

/**
 * Retrieves the current Tenant object.
 *
 * @method getCurrentTenant
 * @param {Object} [options] - Options.
 * @param {getCurrentTenantCallback} callback - The callback that handles the
 *  response.
 */
Client.prototype.getCurrentTenant = function() {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  // First, we'll check to see if we've already cached the current tenant (since
  // a Tenant never changes once a Client has been initialized).  This prevents
  // us from making unnecessary repeat API requests if this method is called
  // multiple times.
  if (self._currentTenant) {
    return callback(null, self._currentTenant);
  }

  self._dataStore.getResource('/tenants/current', options, Tenant, function(err, tenant) {
    if (err) {
      return callback(err);
    }

    self._currentTenant = tenant;
    return callback(null, tenant);
  });
};

/**
 * @callback getResourceCallback
 * @param {Error} err - The error (if there is one).
 * @param {Object} resource - The retrieved resource object.
 */

/**
 * Retrieves a resource object by href.
 *
 * @method getResource
 * @param {String} href - The URI of the resource.
 * @param {Object} [query] - Name / value pairs to use as query parameters.
 * @param {Function} [constructor] - The constructor function that will be
 *  invoked when the given resource is retrieved.  EG: Account, Directory,
 *  Group, etc.  Defaults to `InstanceResource`.  If a resource returned from
 *  the API is a collection (not a single resource object), then each returned
 *  object in the `items` array will be passed into this constructor function
 *  and initialized.
 * @param {getResourceCallback} callback - The callback that handles the
 *  resposne.
 */
Client.prototype.getResource = function() {
  return this._dataStore.getResource.apply(this._dataStore, arguments);
};

/**
 * Creates a new resource on the server as a child of the specified `parentHref` location.  `parentHref` must be a collection resource endpoint.
 *
 * @param {String} parentHref the URI of the parent collection under which the new resource will be created as a child - must always be the first argument.
 * @param {Object} query (optional, defaults to `undefined`) name/value pairs to use as query parameters to `parentHref`
 * @param {Object} data the resource (name/value pairs) to send to the server.
 * @param {Function} instanceCtor (optional, defaults to `InstanceResource`)  The Constructor function to invoke for any instance resource returned by the server.  If the request result is a single resource, this function is used to construct the resource.  If the request result is a collection, the `instanceCtor` is used to construct each resource in the collection's `items` field.
 * @param {Function} callback the callback function to invoke with the constructed Resource. The callback's first argument is an `Error` object, the second is the constructed resource. Must always be the last argument.
 * @return {void} result is provided to `callback`.
 * @method createResource
 * @version 0.1
 */
Client.prototype.createResource = function createResource(/* parentHref, [query,] data, [InstanceConstructor,] callback */) {
  this._dataStore.createResource.apply(this._dataStore, arguments);
};

/**
 * @callback getApplicationsCallback
 * @param {Error} err - The error (if there is one).
 * @param {Object} applications - The retrieved Application objects.
 */

/**
 * Retrieves all Application objects.
 *
 * @method
 * @param {Object} [options] - Options.
 * @param {getApplicationsCallback} callback - The callback that handles the
 *  response.
 */
Client.prototype.getApplications = function() {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  self.getCurrentTenant(function(err, tenant) {
    if (err) {
      return callback(err);
    }

    return tenant.getApplications(options, callback);
  });
};

Client.prototype.createApplication = function createClientApplication(/* app, [options,] callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var app = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;
  return self.getCurrentTenant(function onGetCurrentTenantToCreateApplication(err, tenant) {
    if (err) {
      return callback(err, null);
    }
    return tenant.createApplication(app, options, callback);
  });
};

Client.prototype.getDirectories = function getClientDirectories(/* [options,] callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;
  return self.getCurrentTenant(function onGetCurrentTenantForDirectories(err, tenant) {
    if (err) {
      return callback(err, null);
    }
    return tenant.getDirectories(options, callback);
  });
};

Client.prototype.createDirectory = function createClientDirectory(/* dir, [options,] callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var dir = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;
  return self.getCurrentTenant(function onGetCurrentTenantToCreateDirectory(err, tenant) {
    if (err) {
      return callback(err, null);
    }
    return tenant.createDirectory(dir, options, callback);
  });
};

// Individual resource type convenience methods:
Client.prototype.getAccount = function getClientAccount(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Account'), callback);
};
Client.prototype.getApplication = function getClientApplication(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Application'), callback);
};
Client.prototype.getDirectory = function getClientDirectory(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Directory'), callback);
};
Client.prototype.getGroup = function getClientGroup(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Group'), callback);
};
Client.prototype.getGroupMembership = function getClientGroupMembership(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/GroupMembership'), callback);
};

module.exports = Client;
<commit_msg>Removing unnecessary variable.<commit_after>'use strict';

var async = require('async'),
  events = require('events'),
  util = require('util'),
  Config = require('./Config'),
  DataStore = require('./ds/DataStore'),
  Tenant = require('./resource/Tenant');

/**
 * Creates a new Client.
 *
 * @class
 */
function Client(config) {
  var self = this;

  // Call the constructor of the EventEmitter class -- this, allows us to
  // initialize our Client object as an EventEmitter, and allows us to fire off
  // events later on.
  events.EventEmitter.call(self);

  // Bind the user-supplied config property to our class so it can be accessed
  // like an object.
  self.config = new Config(config);

  // For backwards compatibility reasons, if no API key is specified we'll try
  // to grab the API credentials out of our new format and shove it into the old
  // format.  This can go away once we cut a release and decide to no longer
  // support the old configuration formatting.
  if (!self.config.apiKey) {
    self.config.apiKey = self.config.client.apiKey;
  }

  self._dataStore = new DataStore(self.config);

  // We'll maintain this class variable as an in-memory singleton for caching
  // purposes.  We do this because Tenants never ever change once a Client has
  // been initialized, so it makes sense to cache the Tenant object so we don't
  // make unnecessary API requests if this object is looked up more than once.
  self._currentTenant = null;

  self.mergeRemoteConfig(function(err) {
    return err ? self.emit('error', err): self.emit('ready');
  });
}

// By inheriting from `events.EventEmitter`, we're making our Client object a
// true EventEmitter -- allowing us to fire off events.
util.inherits(Client, Object);
util.inherits(Client, events.EventEmitter);

Client.prototype.mergeRemoteConfig = function(callback) {
  var self = this;
  var config = self.config;
  var application = config.application;

  function findApplication(name, cb) {
    self.getApplications({ name: application.name }, function(err, applications) {
      if (err) {
        return cb(err);
      }

      applications.detect(function(app, cb) {
        cb(application.name === app.name);
      }, function(app) {
        if (app) {
          self.config.application.href = app.href;
          return cb(null, app);
        }

        return cb(new Error('Application not found: "' + application.name + '"'));
      });
    });
  }

  function findDefaultDirectoryHref(application, cb) {
    application.getAccountStoreMappings(function(err, mappings) {
      if (err) {
        return cb(err);
      }
      mappings.detect(function(mapping,cb){
        cb(mapping.isDefaultAccountStore);
      },function(defaultMapping){
        if(defaultMapping){
          var href = defaultMapping.accountStore.href;
          if(href.match(/group/)){
            self.getGroup(href,function(err,group){
              cb(err,group &&group.directory.href);
            });
          }else{
            cb(null,href);
          }
        }else{
          cb(null,null);
        }
      });
    });
  }

  function applyConfig(directoryHref, cb) {
    if(!directoryHref){
      callback(null);
    }else{
      self.getDirectory(
        directoryHref,
        {expand:'passwordPolicy,accountCreationPolicy'},
        function(err,directory){
          if(err){
            cb(err);
          }else{
            self.config.web.verifyEmail.enabled =
              directory.accountCreationPolicy.verificationEmailStatus === 'ENABLED';
            self.config.web.changePassword.enabled = self.config.web.forgotPassword.enabled =
              directory.passwordPolicy.resetEmailStatus === 'ENABLED';
            cb(null);
          }
        }
      );
    }
  }

  if (application && application.href) {
    async.waterfall([
      self.getApplication.bind(self, application.href),
      findDefaultDirectoryHref,
      applyConfig
    ], callback);
  } else if (application && application.name) {
    async.waterfall([
      findApplication(application.name),
      findDefaultDirectoryHref,
      applyConfig
    ], callback);
  } else {
    process.nextTick(callback);
  }

};

/**
 * @callback getCurrentTenantCallback
 * @param {Error} err - The error (if there is one).
 * @param {Object} tenant - The retrieved Tenant object.
 */

/**
 * Retrieves the current Tenant object.
 *
 * @method getCurrentTenant
 * @param {Object} [options] - Options.
 * @param {getCurrentTenantCallback} callback - The callback that handles the
 *  response.
 */
Client.prototype.getCurrentTenant = function() {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  // First, we'll check to see if we've already cached the current tenant (since
  // a Tenant never changes once a Client has been initialized).  This prevents
  // us from making unnecessary repeat API requests if this method is called
  // multiple times.
  if (self._currentTenant) {
    return callback(null, self._currentTenant);
  }

  self._dataStore.getResource('/tenants/current', options, Tenant, function(err, tenant) {
    if (err) {
      return callback(err);
    }

    self._currentTenant = tenant;
    return callback(null, tenant);
  });
};

/**
 * @callback getResourceCallback
 * @param {Error} err - The error (if there is one).
 * @param {Object} resource - The retrieved resource object.
 */

/**
 * Retrieves a resource object by href.
 *
 * @method getResource
 * @param {String} href - The URI of the resource.
 * @param {Object} [query] - Name / value pairs to use as query parameters.
 * @param {Function} [constructor] - The constructor function that will be
 *  invoked when the given resource is retrieved.  EG: Account, Directory,
 *  Group, etc.  Defaults to `InstanceResource`.  If a resource returned from
 *  the API is a collection (not a single resource object), then each returned
 *  object in the `items` array will be passed into this constructor function
 *  and initialized.
 * @param {getResourceCallback} callback - The callback that handles the
 *  resposne.
 */
Client.prototype.getResource = function() {
  return this._dataStore.getResource.apply(this._dataStore, arguments);
};

/**
 * Creates a new resource on the server as a child of the specified `parentHref` location.  `parentHref` must be a collection resource endpoint.
 *
 * @param {String} parentHref the URI of the parent collection under which the new resource will be created as a child - must always be the first argument.
 * @param {Object} query (optional, defaults to `undefined`) name/value pairs to use as query parameters to `parentHref`
 * @param {Object} data the resource (name/value pairs) to send to the server.
 * @param {Function} instanceCtor (optional, defaults to `InstanceResource`)  The Constructor function to invoke for any instance resource returned by the server.  If the request result is a single resource, this function is used to construct the resource.  If the request result is a collection, the `instanceCtor` is used to construct each resource in the collection's `items` field.
 * @param {Function} callback the callback function to invoke with the constructed Resource. The callback's first argument is an `Error` object, the second is the constructed resource. Must always be the last argument.
 * @return {void} result is provided to `callback`.
 * @method createResource
 * @version 0.1
 */
Client.prototype.createResource = function createResource(/* parentHref, [query,] data, [InstanceConstructor,] callback */) {
  this._dataStore.createResource.apply(this._dataStore, arguments);
};

/**
 * @callback getApplicationsCallback
 * @param {Error} err - The error (if there is one).
 * @param {Object} applications - The retrieved Application objects.
 */

/**
 * Retrieves all Application objects.
 *
 * @method
 * @param {Object} [options] - Options.
 * @param {getApplicationsCallback} callback - The callback that handles the
 *  response.
 */
Client.prototype.getApplications = function() {
  var args = Array.prototype.slice.call(arguments);
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  this.getCurrentTenant(function(err, tenant) {
    if (err) {
      return callback(err);
    }

    return tenant.getApplications(options, callback);
  });
};

Client.prototype.createApplication = function createClientApplication(/* app, [options,] callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var app = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;
  return self.getCurrentTenant(function onGetCurrentTenantToCreateApplication(err, tenant) {
    if (err) {
      return callback(err, null);
    }
    return tenant.createApplication(app, options, callback);
  });
};

Client.prototype.getDirectories = function getClientDirectories(/* [options,] callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;
  return self.getCurrentTenant(function onGetCurrentTenantForDirectories(err, tenant) {
    if (err) {
      return callback(err, null);
    }
    return tenant.getDirectories(options, callback);
  });
};

Client.prototype.createDirectory = function createClientDirectory(/* dir, [options,] callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var dir = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;
  return self.getCurrentTenant(function onGetCurrentTenantToCreateDirectory(err, tenant) {
    if (err) {
      return callback(err, null);
    }
    return tenant.createDirectory(dir, options, callback);
  });
};

// Individual resource type convenience methods:
Client.prototype.getAccount = function getClientAccount(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Account'), callback);
};
Client.prototype.getApplication = function getClientApplication(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Application'), callback);
};
Client.prototype.getDirectory = function getClientDirectory(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Directory'), callback);
};
Client.prototype.getGroup = function getClientGroup(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/Group'), callback);
};
Client.prototype.getGroupMembership = function getClientGroupMembership(/* href, [options,], callback */) {
  var self = this;
  var args = Array.prototype.slice.call(arguments);
  var href = args.shift();
  var callback = args.pop();
  var options = (args.length > 0) ? args.shift() : null;

  return self.getResource(href, options, require('./resource/GroupMembership'), callback);
};

module.exports = Client;
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Jiří Janoušek <janousek.jiri@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(Nuvola)
{

Nuvola.Player.init();

var ADDRESS = "app.address";
var HOST = "app.host";
var PORT = "app.port";
var COUNTRY_VARIANT = "app.country_variant";

var Initialization = function()
{
	Nuvola.Config.setDefault(ADDRESS, "default");
	Nuvola.Config.setDefault(HOST, "");
	Nuvola.Config.setDefault(PORT, "");
	Nuvola.Config.setDefault(COUNTRY_VARIANT, "com");
	Nuvola.connect("home-page", this, "onHomePage");
	Nuvola.connect("append-preferences", this, "onAppendPreferences");
	Nuvola.connect("init-request", this, "onInitRequest");
}

Initialization.prototype.onHomePage = function(object, result)
{
	result.url = Nuvola.meta.home_url;
}

Initialization.prototype.onAppendPreferences = function(emitter, values, entries)
{
	this.appendPreferences(values, entries);
}

Initialization.prototype.onInitRequest = function(emitter, values, entries)
{
	if (!Nuvola.Config.hasKey(ADDRESS))
		this.appendPreferences(values, entries);
}

Initialization.prototype.appendPreferences = function(values, entries)
{
	values[ADDRESS] = Nuvola.Config.get(ADDRESS);
	values[HOST] = Nuvola.Config.get(HOST);
	values[PORT] = Nuvola.Config.get(PORT);
	entries.push(["header", "Logitech Media Server"]);
	entries.push(["label", "Address of your Logitech Media Server"]);
	entries.push(["option", ADDRESS + ":default", "use default address ('localhost:9000')", null, [HOST, PORT]]);
	entries.push(["option", ADDRESS + ":custom", "use custom address", [HOST, PORT], null]);
	entries.push(["string", HOST, "Host"]);
	entries.push(["string", PORT, "Port"]);

	values[COUNTRY_VARIANT] = Nuvola.Config.get(COUNTRY_VARIANT);
	entries.push(["header", "Amazon Cloud Player"]);
	entries.push(["label", "Preferred national variant"]);
	entries.push(["option", COUNTRY_VARIANT + ":de", "Germany"]);
	entries.push(["option", COUNTRY_VARIANT + ":fr", "France"]);
	entries.push(["option", COUNTRY_VARIANT + ":co.uk", "United Kingdom"]);
	entries.push(["option", COUNTRY_VARIANT + ":com", "United States"]);
}

Nuvola.initialization = new Initialization();

})(this);  // function(Nuvola)
<commit_msg>Port test web app to the new API<commit_after>/*
 * Copyright 2014 Jiří Janoušek <janousek.jiri@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(Nuvola)
{

Nuvola.Player.init();

var ADDRESS = "app.address";
var HOST = "app.host";
var PORT = "app.port";
var COUNTRY_VARIANT = "app.country_variant";

var Initialization = function()
{
	Nuvola.Config.setDefault(ADDRESS, "default");
	Nuvola.Config.setDefault(HOST, "");
	Nuvola.Config.setDefault(PORT, "");
	Nuvola.Config.setDefault(COUNTRY_VARIANT, "com");
	Nuvola.Core.connect("home-page", this, "onHomePage");
	Nuvola.Core.connect("append-preferences", this, "onAppendPreferences");
	Nuvola.Core.connect("init-request", this, "onInitRequest");
}

Initialization.prototype.onHomePage = function(object, result)
{
	result.url = Nuvola.meta.home_url;
}

Initialization.prototype.onAppendPreferences = function(emitter, values, entries)
{
	this.appendPreferences(values, entries);
}

Initialization.prototype.onInitRequest = function(emitter, values, entries)
{
	if (!Nuvola.Config.hasKey(ADDRESS))
		this.appendPreferences(values, entries);
}

Initialization.prototype.appendPreferences = function(values, entries)
{
	values[ADDRESS] = Nuvola.Config.get(ADDRESS);
	values[HOST] = Nuvola.Config.get(HOST);
	values[PORT] = Nuvola.Config.get(PORT);
	entries.push(["header", "Logitech Media Server"]);
	entries.push(["label", "Address of your Logitech Media Server"]);
	entries.push(["option", ADDRESS + ":default", "use default address ('localhost:9000')", null, [HOST, PORT]]);
	entries.push(["option", ADDRESS + ":custom", "use custom address", [HOST, PORT], null]);
	entries.push(["string", HOST, "Host"]);
	entries.push(["string", PORT, "Port"]);

	values[COUNTRY_VARIANT] = Nuvola.Config.get(COUNTRY_VARIANT);
	entries.push(["header", "Amazon Cloud Player"]);
	entries.push(["label", "Preferred national variant"]);
	entries.push(["option", COUNTRY_VARIANT + ":de", "Germany"]);
	entries.push(["option", COUNTRY_VARIANT + ":fr", "France"]);
	entries.push(["option", COUNTRY_VARIANT + ":co.uk", "United Kingdom"]);
	entries.push(["option", COUNTRY_VARIANT + ":com", "United States"]);
}

Nuvola.initialization = new Initialization();

})(this);  // function(Nuvola)
<|endoftext|>


<commit_before>'use strict'

var co = require('co')
// var Promise = require('bluebird')

var Delete = function (ctx, file_id) {
  return co(function *() {
    var result = yield ctx.r.table(ctx.conf.fileTable).get(file_id).delete()
    return result.deleted === 1
  }).catch(function (err) {
    console.log(err.stack)
    throw err
  })
}

module.exports = Delete
<commit_msg>cleanup<commit_after>'use strict'

var co = require('co')

var Delete = function (ctx, file_id) {
  return co(function *() {
    var result = yield ctx.r.table(ctx.conf.fileTable).get(file_id).delete().run()
    return result.deleted === 1
  }).catch(function (err) {
    console.log(err.stack)
    throw err
  })
}

module.exports = Delete
<|endoftext|>


<commit_before>import _ from 'lodash';
import * as utils from './utils';
import ts, { groupBy_perf as groupBy } from './timeseries';

let downsampleSeries = ts.downsample;
let groupBy_exported = (interval, groupFunc, datapoints) => groupBy(datapoints, interval, groupFunc);
let sumSeries = ts.sumSeries;
let delta = ts.delta;
let rate = ts.rate;
let scale = (factor, datapoints) => ts.scale_perf(datapoints, factor);
let offset = (delta, datapoints) => ts.offset(datapoints, delta);
let simpleMovingAverage = (n, datapoints) => ts.simpleMovingAverage(datapoints, n);
let expMovingAverage = (a, datapoints) => ts.expMovingAverage(datapoints, a);

let SUM = ts.SUM;
let COUNT = ts.COUNT;
let AVERAGE = ts.AVERAGE;
let MIN = ts.MIN;
let MAX = ts.MAX;
let MEDIAN = ts.MEDIAN;
let PERCENTILE = ts.PERCENTILE;

function limit(order, n, orderByFunc, timeseries) {
  let orderByCallback = aggregationFunctions[orderByFunc];
  let sortByIteratee = (ts) => {
    let values = _.map(ts.datapoints, (point) => {
      return point[0];
    });
    return orderByCallback(values);
  };
  let sortedTimeseries = _.sortBy(timeseries, sortByIteratee);
  if (order === 'bottom') {
    return sortedTimeseries.slice(0, n);
  } else {
    return sortedTimeseries.slice(-n);
  }
}

function removeAboveValue(n, datapoints) {
  return _.map(datapoints, point => {
    return [
      (point[0] > n) ? null : point[0],
      point[1]
    ];
  });
}

function removeBelowValue(n, datapoints) {
  return _.map(datapoints, point => {
    return [
      (point[0] < n) ? null : point[0],
      point[1]
    ];
  });
}

function transformNull(n, datapoints) {
  return _.map(datapoints, point => {
    return [
      (point[0] !== null) ? point[0] : n,
      point[1]
    ];
  });
}

function sortSeries(direction, timeseries) {
  return _.orderBy(timeseries, [function (ts) {
    return ts.target.toLowerCase();
  }], direction);
}

function setAlias(alias, timeseries) {
  timeseries.target = alias;
  return timeseries;
}

function replaceAlias(regexp, newAlias, timeseries) {
  let pattern;
  if (utils.isRegex(regexp)) {
    pattern = utils.buildRegex(regexp);
  } else {
    pattern = regexp;
  }

  let alias = timeseries.target.replace(pattern, newAlias);
  timeseries.target = alias;
  return timeseries;
}

function setAliasByRegex(alias, timeseries) {
  timeseries.target = extractText(timeseries.target, alias);
  return timeseries;
}

function extractText(str, pattern) {
  var extractPattern = new RegExp(pattern);
  var extractedValue = extractPattern.exec(str);
  extractedValue = extractedValue[0];
  return extractedValue;
}

function groupByWrapper(interval, groupFunc, datapoints) {
  var groupByCallback = aggregationFunctions[groupFunc];
  return groupBy(datapoints, interval, groupByCallback);
}

function aggregateByWrapper(interval, aggregateFunc, datapoints) {
  // Flatten all points in frame and then just use groupBy()
  const flattenedPoints = ts.flattenDatapoints(datapoints);
  // groupBy_perf works with sorted series only
  const sortedPoints = ts.sortByTime(flattenedPoints);
  let groupByCallback = aggregationFunctions[aggregateFunc];
  return groupBy(sortedPoints, interval, groupByCallback);
}

function aggregateWrapper(groupByCallback, interval, datapoints) {
  var flattenedPoints = ts.flattenDatapoints(datapoints);
  // groupBy_perf works with sorted series only
  const sortedPoints = ts.sortByTime(flattenedPoints);
  return groupBy(sortedPoints, interval, groupByCallback);
}

function percentile(interval, n, datapoints) {
  var flattenedPoints = ts.flattenDatapoints(datapoints);
  var groupByCallback = _.partial(PERCENTILE, n);
  return groupBy(flattenedPoints, interval, groupByCallback);
}

function timeShift(interval, range) {
  let shift = utils.parseTimeShiftInterval(interval) / 1000;
  return _.map(range, time => {
    return time - shift;
  });
}

function unShiftTimeSeries(interval, datapoints) {
  let unshift = utils.parseTimeShiftInterval(interval);
  return _.map(datapoints, dp => {
    return [
      dp[0],
      dp[1] + unshift
    ];
  });
}

let metricFunctions = {
  groupBy: groupByWrapper,
  scale: scale,
  offset: offset,
  delta: delta,
  rate: rate,
  movingAverage: simpleMovingAverage,
  exponentialMovingAverage: expMovingAverage,
  transformNull: transformNull,
  aggregateBy: aggregateByWrapper,
  // Predefined aggs
  percentile: percentile,
  average: _.partial(aggregateWrapper, AVERAGE),
  min: _.partial(aggregateWrapper, MIN),
  max: _.partial(aggregateWrapper, MAX),
  median: _.partial(aggregateWrapper, MEDIAN),
  sum: _.partial(aggregateWrapper, SUM),
  count: _.partial(aggregateWrapper, COUNT),
  sumSeries: sumSeries,
  removeAboveValue: removeAboveValue,
  removeBelowValue: removeBelowValue,
  top: _.partial(limit, 'top'),
  bottom: _.partial(limit, 'bottom'),
  sortSeries: sortSeries,
  timeShift: timeShift,
  setAlias: setAlias,
  setAliasByRegex: setAliasByRegex,
  replaceAlias: replaceAlias
};

let aggregationFunctions = {
  avg: AVERAGE,
  min: MIN,
  max: MAX,
  median: MEDIAN,
  sum: SUM,
  count: COUNT
};

export default {
  downsampleSeries: downsampleSeries,
  groupBy: groupBy_exported,
  AVERAGE: AVERAGE,
  MIN: MIN,
  MAX: MAX,
  MEDIAN: MEDIAN,
  SUM: SUM,
  COUNT: COUNT,
  unShiftTimeSeries: unShiftTimeSeries,

  get aggregationFunctions() {
    return aggregationFunctions;
  },

  get metricFunctions() {
    return metricFunctions;
  }
};
<commit_msg>Fix percentile() function, closes #862 (#863)<commit_after>import _ from 'lodash';
import * as utils from './utils';
import ts, { groupBy_perf as groupBy } from './timeseries';

let downsampleSeries = ts.downsample;
let groupBy_exported = (interval, groupFunc, datapoints) => groupBy(datapoints, interval, groupFunc);
let sumSeries = ts.sumSeries;
let delta = ts.delta;
let rate = ts.rate;
let scale = (factor, datapoints) => ts.scale_perf(datapoints, factor);
let offset = (delta, datapoints) => ts.offset(datapoints, delta);
let simpleMovingAverage = (n, datapoints) => ts.simpleMovingAverage(datapoints, n);
let expMovingAverage = (a, datapoints) => ts.expMovingAverage(datapoints, a);

let SUM = ts.SUM;
let COUNT = ts.COUNT;
let AVERAGE = ts.AVERAGE;
let MIN = ts.MIN;
let MAX = ts.MAX;
let MEDIAN = ts.MEDIAN;
let PERCENTILE = ts.PERCENTILE;

function limit(order, n, orderByFunc, timeseries) {
  let orderByCallback = aggregationFunctions[orderByFunc];
  let sortByIteratee = (ts) => {
    let values = _.map(ts.datapoints, (point) => {
      return point[0];
    });
    return orderByCallback(values);
  };
  let sortedTimeseries = _.sortBy(timeseries, sortByIteratee);
  if (order === 'bottom') {
    return sortedTimeseries.slice(0, n);
  } else {
    return sortedTimeseries.slice(-n);
  }
}

function removeAboveValue(n, datapoints) {
  return _.map(datapoints, point => {
    return [
      (point[0] > n) ? null : point[0],
      point[1]
    ];
  });
}

function removeBelowValue(n, datapoints) {
  return _.map(datapoints, point => {
    return [
      (point[0] < n) ? null : point[0],
      point[1]
    ];
  });
}

function transformNull(n, datapoints) {
  return _.map(datapoints, point => {
    return [
      (point[0] !== null) ? point[0] : n,
      point[1]
    ];
  });
}

function sortSeries(direction, timeseries) {
  return _.orderBy(timeseries, [function (ts) {
    return ts.target.toLowerCase();
  }], direction);
}

function setAlias(alias, timeseries) {
  timeseries.target = alias;
  return timeseries;
}

function replaceAlias(regexp, newAlias, timeseries) {
  let pattern;
  if (utils.isRegex(regexp)) {
    pattern = utils.buildRegex(regexp);
  } else {
    pattern = regexp;
  }

  let alias = timeseries.target.replace(pattern, newAlias);
  timeseries.target = alias;
  return timeseries;
}

function setAliasByRegex(alias, timeseries) {
  timeseries.target = extractText(timeseries.target, alias);
  return timeseries;
}

function extractText(str, pattern) {
  var extractPattern = new RegExp(pattern);
  var extractedValue = extractPattern.exec(str);
  extractedValue = extractedValue[0];
  return extractedValue;
}

function groupByWrapper(interval, groupFunc, datapoints) {
  var groupByCallback = aggregationFunctions[groupFunc];
  return groupBy(datapoints, interval, groupByCallback);
}

function aggregateByWrapper(interval, aggregateFunc, datapoints) {
  // Flatten all points in frame and then just use groupBy()
  const flattenedPoints = ts.flattenDatapoints(datapoints);
  // groupBy_perf works with sorted series only
  const sortedPoints = ts.sortByTime(flattenedPoints);
  let groupByCallback = aggregationFunctions[aggregateFunc];
  return groupBy(sortedPoints, interval, groupByCallback);
}

function aggregateWrapper(groupByCallback, interval, datapoints) {
  var flattenedPoints = ts.flattenDatapoints(datapoints);
  // groupBy_perf works with sorted series only
  const sortedPoints = ts.sortByTime(flattenedPoints);
  return groupBy(sortedPoints, interval, groupByCallback);
}

function percentile(interval, n, datapoints) {
  const flattenedPoints = ts.flattenDatapoints(datapoints);
  // groupBy_perf works with sorted series only
  const sortedPoints = ts.sortByTime(flattenedPoints);
  let groupByCallback = _.partial(PERCENTILE, n);
  return groupBy(sortedPoints, interval, groupByCallback);
}

function timeShift(interval, range) {
  let shift = utils.parseTimeShiftInterval(interval) / 1000;
  return _.map(range, time => {
    return time - shift;
  });
}

function unShiftTimeSeries(interval, datapoints) {
  let unshift = utils.parseTimeShiftInterval(interval);
  return _.map(datapoints, dp => {
    return [
      dp[0],
      dp[1] + unshift
    ];
  });
}

let metricFunctions = {
  groupBy: groupByWrapper,
  scale: scale,
  offset: offset,
  delta: delta,
  rate: rate,
  movingAverage: simpleMovingAverage,
  exponentialMovingAverage: expMovingAverage,
  transformNull: transformNull,
  aggregateBy: aggregateByWrapper,
  // Predefined aggs
  percentile: percentile,
  average: _.partial(aggregateWrapper, AVERAGE),
  min: _.partial(aggregateWrapper, MIN),
  max: _.partial(aggregateWrapper, MAX),
  median: _.partial(aggregateWrapper, MEDIAN),
  sum: _.partial(aggregateWrapper, SUM),
  count: _.partial(aggregateWrapper, COUNT),
  sumSeries: sumSeries,
  removeAboveValue: removeAboveValue,
  removeBelowValue: removeBelowValue,
  top: _.partial(limit, 'top'),
  bottom: _.partial(limit, 'bottom'),
  sortSeries: sortSeries,
  timeShift: timeShift,
  setAlias: setAlias,
  setAliasByRegex: setAliasByRegex,
  replaceAlias: replaceAlias
};

let aggregationFunctions = {
  avg: AVERAGE,
  min: MIN,
  max: MAX,
  median: MEDIAN,
  sum: SUM,
  count: COUNT
};

export default {
  downsampleSeries: downsampleSeries,
  groupBy: groupBy_exported,
  AVERAGE: AVERAGE,
  MIN: MIN,
  MAX: MAX,
  MEDIAN: MEDIAN,
  SUM: SUM,
  COUNT: COUNT,
  unShiftTimeSeries: unShiftTimeSeries,

  get aggregationFunctions() {
    return aggregationFunctions;
  },

  get metricFunctions() {
    return metricFunctions;
  }
};
<|endoftext|>


<commit_before>/**
 * GSS-API wrapper for Kerberos implementation. For now it's very
 * kerberos-specific. We can add machinery to make it generic if the
 * need ever arises.
 */
var gss = (function() {
    "use strict";

    var gss = { };

    /** @const */ gss.NT_USER_NAME         = "1.2.840.113554.1.2.1.1";
    /** @const */ gss.NT_MACHINE_UID_NAME  = "1.2.840.113554.1.2.1.2";
    /** @const */ gss.NT_STRING_UID_NAME   = "1.2.840.113554.1.2.1.3";
    /** @const */ gss.NT_HOSTBASED_SERVICE = "1.3.6.1.5.6.2";
    /** @const */ gss.NT_ANONYMOUS         = "1.3.6.1.5.6.3";
    /** @const */ gss.NT_EXPORT_NAME       = "1.3.6.1.5.6.4";

    /** @const */ gss.S_BAD_BINDINGS = 1;
    /** @const */ gss.S_BAD_MECH = 2;
    /** @const */ gss.S_BAD_NAME = 3;
    /** @const */ gss.S_BAD_NAMETYPE = 4;
    /** @const */ gss.S_BAD_STATUS = 5;
    /** @const */ gss.S_BAD_SIG = 6;
    /** @const */ gss.S_CONTEXT_EXPIRED = 7;
    /** @const */ gss.S_CREDENTIALS_EXPIRED = 8;
    /** @const */ gss.S_DEFECTIVE_CREDENTIAL = 9;
    /** @const */ gss.S_DEFECTIVE_TOKEN = 10;
    /** @const */ gss.S_FAILURE = 11;
    /** @const */ gss.S_NO_CONTEXT = 12;
    /** @const */ gss.S_NO_CRED = 13;
    /** @const */ gss.S_BAD_QOP = 14;
    /** @const */ gss.S_UNAUTHORIZED = 15;
    /** @const */ gss.S_UNAVAILABLE = 16;
    /** @const */ gss.S_DUPLICATE_ELEMENT = 17;
    /** @const */ gss.S_NAME_NOT_MN = 18;

    /** @const */ gss.S_DUPLICATE_TOKEN = 19;
    /** @const */ gss.S_OLD_TOKEN = 20;
    /** @const */ gss.S_UNSEQ_TOKEN = 21;
    /** @const */ gss.S_GAP_TOKEN = 22;

    /** @const */ gss.KRB5_MECHANISM = "1.2.840.113554.1.2.2";

    /** @const */ gss.KRB5_NT_PRINCIPAL_NAME         = "1.2.840.113554.1.2.2.1";
    /** @const */ gss.KRB5_NT_HOSTBASED_SERVICE_NAME = "1.2.840.113554.1.2.1.4";

    /** @const */ gss.KRB5_S_G_BAD_SERVICE_NAME = 1;
    /** @const */ gss.KRB5_S_G_BAD_STRING_UID = 2;
    /** @const */ gss.KRB5_S_G_NOUSER = 3;
    /** @const */ gss.KRB5_S_G_VALIDATE_FAILED = 4;
    /** @const */ gss.KRB5_S_G_BUFFER_ALLOC = 5;
    /** @const */ gss.KRB5_S_G_BAD_MSG_CTX = 6;
    /** @const */ gss.KRB5_S_G_WRONG_SIZE = 7;
    /** @const */ gss.KRB5_S_G_BAD_USAGE = 8;
    /** @const */ gss.KRB5_S_G_UNKNOWN_QOP = 9;

    /** @const */ gss.KRB5_S_KG_CCACHE_NOMATCH = 10;
    /** @const */ gss.KRB5_S_KG_KEYTAB_NOMATCH = 11;
    /** @const */ gss.KRB5_S_KG_TGT_MISSING = 12;
    /** @const */ gss.KRB5_S_KG_NO_SUBKEY = 13;
    /** @const */ gss.KRB5_S_KG_CONTEXT_ESTABLISHED = 14;
    /** @const */ gss.KRB5_S_KG_BAD_SIGN_TYPE = 15;
    /** @const */ gss.KRB5_S_KG_BAD_LENGTH = 16;
    /** @const */ gss.KRB5_S_KG_CTX_INCOMPLETE = 17;

    var TOK_ID_AP_REQ = 0x0100;
    var TOK_ID_AP_REP = 0x0200;
    var TOK_ID_ERROR  = 0x0300;
    var TOK_ID_EXPORT_NAME = 0x0401;

    /**
     * @constructor
     * @param {number} major
     * @param {number} minor
     * @param {string} message
     */
    gss.Error = function(major, minor, message) {
        this.major = major;
        this.minor = minor;
        this.message = message;
    };
    /** @return {string} */
    gss.Error.prototype.toString = function() {
        return this.message;
    };

    /**
     * Creates a gss.Name that wraps a krb.Principal.
     * @constructor
     * @param {krb.Principal} principal
     */
    gss.Name = function(principal) {
        this.principal = principal;
    };
    /**
     * GSS_Import_name. For now just returns a gss.Name. If we want to
     * do some sort of host canonicalization, that may want a promise
     * object from Q.
     *
     * @param {ArrayBufferView|string} data The input bytes.
     * @param {string} nameType An OID for the name type.
     * @return {gss.Name} The resulting name.
     */
    gss.Name.importName = function(data, nameType) {
        if (nameType === gss.NT_EXPORT_NAME) {
            // TODO: For sanity, importName should take a string for
            // all the sane name types. Should we avoid type confusion
            // and just force everything into a string?
            data = arrayutils.asUint8Array(data);
            var dataview = new DataView(data.buffer,
                                        data.byteOffset,
                                        data.byteLength);
            // Strip off the header.
            if (data.length < 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            if (dataview.getUint16(0) != TOK_ID_EXPORT_NAME)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad TOK_ID");
            var mechOidLen = dataview.getUint16(2);
            if (data.length < 4 + mechOidLen + 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            try {
                var mechOid = asn1.OBJECT_IDENTIFIER.decodeDER(
                    data.subarray(4, 4 + mechOidLen));
            } catch (e) {
                if (e instanceof asn1.Error)
                    throw new gss.Error(gss.S_BAD_NAME, 0, e.toString());
                throw e;
            }
            // We only support KRB5.
            if (mechOid !== gss.KRB5_MECHANISM)
                throw new gss.Error(gss.S_BAD_MECH, 0,
                                    "Only krb5 names supported");
            var nameLen = dataview.getUint32(4 + mechOidLen);
            if (data.length != (4 + mechOidLen + 4 + nameLen))
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad length");
            try {
                return new gss.Name(krb.Principal.fromString(
                    arrayutils.toUTF16(data.subarray(4 + mechOidLen + 4))));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_HOSTBASED_SERVICE ||
                   nameType === gss.KRB5_NT_HOSTBASED_SERVICE_NAME) {
            // Format is service@hostname. Hostname is optional, but
            // for now require it. Probably the most reasonable
            // interpretation of "the canonicalized name of the local
            // host" is location.host, but meh.
            var at = data.indexOf("@");
            if (at < 0)
                throw new gss.Error(
                    gss.S_BAD_NAME, gss.KRB5_S_G_BAD_SERVICE_NAME,
                    "Default host not supported");
            var service = data.substring(0, at);
            var host = data.substring(at + 1);
            // FIXME: Hostname canonicalization??
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_SRV_HST,
                nameString: [service, host]
            }, krb.realm));
        } else if (nameType === gss.KRB5_NT_PRINCIPAL_NAME) {
            try {
                return new gss.Name(krb.Principal.fromString(data));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_USER_NAME) {
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_PRINCIPAL,
                nameString: [data]
            }, krb.realm));
        } else {
            throw new gss.Error(gss.S_BAD_NAMETYPE, 0, "Bad nametype");
        }
    };
    gss.Name.prototype.canonicalize = function() {
        // TODO
    };
    /** @return {Uint8Array} */
    gss.Name.prototype.exportName = function() {
        // Build it backwards.
        var b = new asn1.Buffer();
        var nameLen =
            b.prependBytes(arrayutils.fromUTF16(this.principal.toString()));
        b.prependUint32(name.length);
        var mechOidLen =
            asn1.OBJECT_IDENTIFIER.encodeDERTriple(gss.KRB5_MECHANISM, b);
        b.prependUint16(mechOidLen);
        // tokId is 0x04 0x01
        b.prependUint16(TOK_ID_EXPORT_NAME);
        return b.contents();
    };

    var GSSAPI_TOKEN_TAG = 0x60;  // [APPLICATION 0]

    /** @param {ArrayBufferView}
     *  @returns {{thisMech:string, innerToken:Uint8Array}}
     */
    function decodeGSSToken(token) {
        try {
            // This is weirdo pseudo-ASN.1 with a hole in it. We could
            // hack it into our parser, but it's easy to parse manually.
            var tvr = asn1.decodeTagLengthValueDER(token);
            var tag = tvr[0], value = tvr[1], rest = tvr[2];
            if (tag !== GSSAPI_TOKEN_TAG)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");
            if (rest)  // Bad length.
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");

            // Pull out the mechanism.
            var mr = asn1.OBJECT_IDENTIFIER.decodeDERPrefix(value);
            var mech = mr[0], rest = mr[1];

            return {
                thisMech: mech,
                innerToken: rest
            };
        } catch (e) {
            if (e instanceof asn1.Error)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, e.toString());
            throw e;
        }
    }

    var DELEG_FLAG    = 1;
    var MUTUAL_FLAG   = 2;
    var REPLAY_FLAG   = 4;
    var SEQUENCE_FLAG = 8;
    var CONF_FLAG     = 16;
    var INTEG_FLAG    = 32;

    // Context states.
    var INITIAL_STATE = 1;
    var PENDING_AP_REP = 2;
    var ESTABLISHED_STATE = 3;

    /**
     * Creates an initiator GSS context. If the need ever arises, we
     * can arrange for acceptor contexts to be supported, but it's
     * unlikely this'll ever run outside a client.
     *
     * The constructor takes an options dictionary with various
     * optional keys. The keys are:
     *   delegation : boolean
     *   mutualAuthentication : boolean
     *   replayDetection : boolean
     *   sequence : boolean
     *   anonymous : boolean
     *   confidentiality : boolean
     *   integrity : boolean
     *   lifetime : number (default: 0)
     *   bindings : ?ArrayBufferView (default: null)
     *
     * Not all flags can be provided, so the corresponding attributes
     * should be checked on the returned gss.Context object.
     *
     * @constructor
     */
    gss.Context = function(peer, mechanism, credential, opts) {
        if (mechanism !== gss.KRB5_MECHANISM)
            throw new gss.Error(gss.S_BAD_MECH, 0, "Only krb5 is supported");
        this.state = INITIAL_STATE;
        this.credential = credential;
        this.peer = peer;

        // this.delegation = opts.delegation || false;
        this.delegation = false;
        this.mutualAuthentication = opts.mutualAuthentication || false;
        this.replayDetection = opts.replayDetection || false;
        this.sequence = opts.sequence || false;
        // this.anonymous = opts.anonymous || false;
        this.confidentiality = opts.confidentiality || false;
        this.integrity = opts.integrity || false;

        // TODO: This is actually the MD5 sum of something...
        this.bindings = opts.bindings || new Uint8Array(16);

        // TODO...
    };
    gss.Context.prototype.initSecContext = function(token) {
        if (this.state === INITIAL_STATE) {
            var cksumBuf = new asn1.Buffer();
            //  Octet      Name      Description
            // ---------------------------------------------------------------
            //  n..last    Exts    Extensions [optional].
            if (this.delegation) {
                //  28..(n-1)  Deleg   A KRB_CRED message (n = Dlgth + 28)
                //                     [optional].
                //  26..27     Dlgth   The length of the Deleg field in
                //                     little-endian order [optional].
                //  24..25     DlgOpt  The delegation option identifier (=1) in
                //                     little-endian order [optional].  This
                //                     field and the next two fields are present
                //                     if and only if GSS_C_DELEG_FLAG is set as
                //                     described in section 4.1.1.1.
                throw "Delegation not implemented.";
            }
            //  20..23     Flags   Four-octet context-establishment flags in
            //                     little-endian order as described in section
            //                     4.1.1.1.
            var flags = 0;
            if (this.delegation)
                flags |= DELEG_FLAG;
            if (this.mutualAuthentication)
                flags |= MUTUAL_FLAG;
            if (this.replayDetection)
                flags |= REPLAY_FLAG;
            if (this.sequence)
                flags |= SEQUENCE_FLAG;
            if (this.confidentiality)
                flags |= CONF_FLAG;
            if (this.integrity)
                flags |= INTEG_FLAG;
            cksumBuf.prependUint32(flags, true);
            //  4..19      Bnd     Channel binding information, as described in
            //                     section 4.1.1.2.
            var bndLen = cksumBuf.prependBytes(this.bindings);
            //  0..3       Lgth    Number of octets in Bnd field;  Represented
            //                     in little-endian order;  Currently contains
            //                     hex value 10 00 00 00 (16).
            cksumBuf.prependUint32(bndLen, true);
            var apReq = this.credential.makeAPReq(
                ???,
                { cksumtype: 0x8003,
                  checksum: cksumBuf.contents() },
                ???,
                ???);
        }
        // TODO
    };
    gss.Context.prototype.isEstablished = function() {
        // TODO
    };

    return gss;
}());
<commit_msg>Pick a key usage<commit_after>/**
 * GSS-API wrapper for Kerberos implementation. For now it's very
 * kerberos-specific. We can add machinery to make it generic if the
 * need ever arises.
 */
var gss = (function() {
    "use strict";

    var gss = { };

    /** @const */ gss.NT_USER_NAME         = "1.2.840.113554.1.2.1.1";
    /** @const */ gss.NT_MACHINE_UID_NAME  = "1.2.840.113554.1.2.1.2";
    /** @const */ gss.NT_STRING_UID_NAME   = "1.2.840.113554.1.2.1.3";
    /** @const */ gss.NT_HOSTBASED_SERVICE = "1.3.6.1.5.6.2";
    /** @const */ gss.NT_ANONYMOUS         = "1.3.6.1.5.6.3";
    /** @const */ gss.NT_EXPORT_NAME       = "1.3.6.1.5.6.4";

    /** @const */ gss.S_BAD_BINDINGS = 1;
    /** @const */ gss.S_BAD_MECH = 2;
    /** @const */ gss.S_BAD_NAME = 3;
    /** @const */ gss.S_BAD_NAMETYPE = 4;
    /** @const */ gss.S_BAD_STATUS = 5;
    /** @const */ gss.S_BAD_SIG = 6;
    /** @const */ gss.S_CONTEXT_EXPIRED = 7;
    /** @const */ gss.S_CREDENTIALS_EXPIRED = 8;
    /** @const */ gss.S_DEFECTIVE_CREDENTIAL = 9;
    /** @const */ gss.S_DEFECTIVE_TOKEN = 10;
    /** @const */ gss.S_FAILURE = 11;
    /** @const */ gss.S_NO_CONTEXT = 12;
    /** @const */ gss.S_NO_CRED = 13;
    /** @const */ gss.S_BAD_QOP = 14;
    /** @const */ gss.S_UNAUTHORIZED = 15;
    /** @const */ gss.S_UNAVAILABLE = 16;
    /** @const */ gss.S_DUPLICATE_ELEMENT = 17;
    /** @const */ gss.S_NAME_NOT_MN = 18;

    /** @const */ gss.S_DUPLICATE_TOKEN = 19;
    /** @const */ gss.S_OLD_TOKEN = 20;
    /** @const */ gss.S_UNSEQ_TOKEN = 21;
    /** @const */ gss.S_GAP_TOKEN = 22;

    /** @const */ gss.KRB5_MECHANISM = "1.2.840.113554.1.2.2";

    /** @const */ gss.KRB5_NT_PRINCIPAL_NAME         = "1.2.840.113554.1.2.2.1";
    /** @const */ gss.KRB5_NT_HOSTBASED_SERVICE_NAME = "1.2.840.113554.1.2.1.4";

    /** @const */ gss.KRB5_S_G_BAD_SERVICE_NAME = 1;
    /** @const */ gss.KRB5_S_G_BAD_STRING_UID = 2;
    /** @const */ gss.KRB5_S_G_NOUSER = 3;
    /** @const */ gss.KRB5_S_G_VALIDATE_FAILED = 4;
    /** @const */ gss.KRB5_S_G_BUFFER_ALLOC = 5;
    /** @const */ gss.KRB5_S_G_BAD_MSG_CTX = 6;
    /** @const */ gss.KRB5_S_G_WRONG_SIZE = 7;
    /** @const */ gss.KRB5_S_G_BAD_USAGE = 8;
    /** @const */ gss.KRB5_S_G_UNKNOWN_QOP = 9;

    /** @const */ gss.KRB5_S_KG_CCACHE_NOMATCH = 10;
    /** @const */ gss.KRB5_S_KG_KEYTAB_NOMATCH = 11;
    /** @const */ gss.KRB5_S_KG_TGT_MISSING = 12;
    /** @const */ gss.KRB5_S_KG_NO_SUBKEY = 13;
    /** @const */ gss.KRB5_S_KG_CONTEXT_ESTABLISHED = 14;
    /** @const */ gss.KRB5_S_KG_BAD_SIGN_TYPE = 15;
    /** @const */ gss.KRB5_S_KG_BAD_LENGTH = 16;
    /** @const */ gss.KRB5_S_KG_CTX_INCOMPLETE = 17;

    var TOK_ID_AP_REQ = 0x0100;
    var TOK_ID_AP_REP = 0x0200;
    var TOK_ID_ERROR  = 0x0300;
    var TOK_ID_EXPORT_NAME = 0x0401;

    /**
     * @constructor
     * @param {number} major
     * @param {number} minor
     * @param {string} message
     */
    gss.Error = function(major, minor, message) {
        this.major = major;
        this.minor = minor;
        this.message = message;
    };
    /** @return {string} */
    gss.Error.prototype.toString = function() {
        return this.message;
    };

    /**
     * Creates a gss.Name that wraps a krb.Principal.
     * @constructor
     * @param {krb.Principal} principal
     */
    gss.Name = function(principal) {
        this.principal = principal;
    };
    /**
     * GSS_Import_name. For now just returns a gss.Name. If we want to
     * do some sort of host canonicalization, that may want a promise
     * object from Q.
     *
     * @param {ArrayBufferView|string} data The input bytes.
     * @param {string} nameType An OID for the name type.
     * @return {gss.Name} The resulting name.
     */
    gss.Name.importName = function(data, nameType) {
        if (nameType === gss.NT_EXPORT_NAME) {
            // TODO: For sanity, importName should take a string for
            // all the sane name types. Should we avoid type confusion
            // and just force everything into a string?
            data = arrayutils.asUint8Array(data);
            var dataview = new DataView(data.buffer,
                                        data.byteOffset,
                                        data.byteLength);
            // Strip off the header.
            if (data.length < 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            if (dataview.getUint16(0) != TOK_ID_EXPORT_NAME)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad TOK_ID");
            var mechOidLen = dataview.getUint16(2);
            if (data.length < 4 + mechOidLen + 4)
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad format");
            try {
                var mechOid = asn1.OBJECT_IDENTIFIER.decodeDER(
                    data.subarray(4, 4 + mechOidLen));
            } catch (e) {
                if (e instanceof asn1.Error)
                    throw new gss.Error(gss.S_BAD_NAME, 0, e.toString());
                throw e;
            }
            // We only support KRB5.
            if (mechOid !== gss.KRB5_MECHANISM)
                throw new gss.Error(gss.S_BAD_MECH, 0,
                                    "Only krb5 names supported");
            var nameLen = dataview.getUint32(4 + mechOidLen);
            if (data.length != (4 + mechOidLen + 4 + nameLen))
                throw new gss.Error(gss.S_BAD_NAME, 0, "Bad length");
            try {
                return new gss.Name(krb.Principal.fromString(
                    arrayutils.toUTF16(data.subarray(4 + mechOidLen + 4))));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_HOSTBASED_SERVICE ||
                   nameType === gss.KRB5_NT_HOSTBASED_SERVICE_NAME) {
            // Format is service@hostname. Hostname is optional, but
            // for now require it. Probably the most reasonable
            // interpretation of "the canonicalized name of the local
            // host" is location.host, but meh.
            var at = data.indexOf("@");
            if (at < 0)
                throw new gss.Error(
                    gss.S_BAD_NAME, gss.KRB5_S_G_BAD_SERVICE_NAME,
                    "Default host not supported");
            var service = data.substring(0, at);
            var host = data.substring(at + 1);
            // FIXME: Hostname canonicalization??
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_SRV_HST,
                nameString: [service, host]
            }, krb.realm));
        } else if (nameType === gss.KRB5_NT_PRINCIPAL_NAME) {
            try {
                return new gss.Name(krb.Principal.fromString(data));
            } catch (e) {
                throw new gss.Error(gss.S_BAD_NAME, 0, e);
            }
        } else if (nameType === gss.NT_USER_NAME) {
            return new gss.Name(new krb.Principal({
                nameType: krb.KRB_NT_PRINCIPAL,
                nameString: [data]
            }, krb.realm));
        } else {
            throw new gss.Error(gss.S_BAD_NAMETYPE, 0, "Bad nametype");
        }
    };
    gss.Name.prototype.canonicalize = function() {
        // TODO
    };
    /** @return {Uint8Array} */
    gss.Name.prototype.exportName = function() {
        // Build it backwards.
        var b = new asn1.Buffer();
        var nameLen =
            b.prependBytes(arrayutils.fromUTF16(this.principal.toString()));
        b.prependUint32(name.length);
        var mechOidLen =
            asn1.OBJECT_IDENTIFIER.encodeDERTriple(gss.KRB5_MECHANISM, b);
        b.prependUint16(mechOidLen);
        // tokId is 0x04 0x01
        b.prependUint16(TOK_ID_EXPORT_NAME);
        return b.contents();
    };

    var GSSAPI_TOKEN_TAG = 0x60;  // [APPLICATION 0]

    /** @param {ArrayBufferView}
     *  @returns {{thisMech:string, innerToken:Uint8Array}}
     */
    function decodeGSSToken(token) {
        try {
            // This is weirdo pseudo-ASN.1 with a hole in it. We could
            // hack it into our parser, but it's easy to parse manually.
            var tvr = asn1.decodeTagLengthValueDER(token);
            var tag = tvr[0], value = tvr[1], rest = tvr[2];
            if (tag !== GSSAPI_TOKEN_TAG)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");
            if (rest)  // Bad length.
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, "Bad token");

            // Pull out the mechanism.
            var mr = asn1.OBJECT_IDENTIFIER.decodeDERPrefix(value);
            var mech = mr[0], rest = mr[1];

            return {
                thisMech: mech,
                innerToken: rest
            };
        } catch (e) {
            if (e instanceof asn1.Error)
                throw new gss.Error(gss.S_DEFECTIVE_TOKEN, 0, e.toString());
            throw e;
        }
    }

    var DELEG_FLAG    = 1;
    var MUTUAL_FLAG   = 2;
    var REPLAY_FLAG   = 4;
    var SEQUENCE_FLAG = 8;
    var CONF_FLAG     = 16;
    var INTEG_FLAG    = 32;

    // Context states.
    var INITIAL_STATE = 1;
    var PENDING_AP_REP = 2;
    var ESTABLISHED_STATE = 3;

    /**
     * Creates an initiator GSS context. If the need ever arises, we
     * can arrange for acceptor contexts to be supported, but it's
     * unlikely this'll ever run outside a client.
     *
     * The constructor takes an options dictionary with various
     * optional keys. The keys are:
     *   delegation : boolean
     *   mutualAuthentication : boolean
     *   replayDetection : boolean
     *   sequence : boolean
     *   anonymous : boolean
     *   confidentiality : boolean
     *   integrity : boolean
     *   lifetime : number (default: 0)
     *   bindings : ?ArrayBufferView (default: null)
     *
     * Not all flags can be provided, so the corresponding attributes
     * should be checked on the returned gss.Context object.
     *
     * @constructor
     */
    gss.Context = function(peer, mechanism, credential, opts) {
        if (mechanism !== gss.KRB5_MECHANISM)
            throw new gss.Error(gss.S_BAD_MECH, 0, "Only krb5 is supported");
        this.state = INITIAL_STATE;
        this.credential = credential;
        this.peer = peer;

        // this.delegation = opts.delegation || false;
        this.delegation = false;
        this.mutualAuthentication = opts.mutualAuthentication || false;
        this.replayDetection = opts.replayDetection || false;
        this.sequence = opts.sequence || false;
        // this.anonymous = opts.anonymous || false;
        this.confidentiality = opts.confidentiality || false;
        this.integrity = opts.integrity || false;

        // TODO: This is actually the MD5 sum of something...
        this.bindings = opts.bindings || new Uint8Array(16);

        // TODO...
    };
    gss.Context.prototype.initSecContext = function(token) {
        if (this.state === INITIAL_STATE) {
            var cksumBuf = new asn1.Buffer();
            //  Octet      Name      Description
            // ---------------------------------------------------------------
            //  n..last    Exts    Extensions [optional].
            if (this.delegation) {
                //  28..(n-1)  Deleg   A KRB_CRED message (n = Dlgth + 28)
                //                     [optional].
                //  26..27     Dlgth   The length of the Deleg field in
                //                     little-endian order [optional].
                //  24..25     DlgOpt  The delegation option identifier (=1) in
                //                     little-endian order [optional].  This
                //                     field and the next two fields are present
                //                     if and only if GSS_C_DELEG_FLAG is set as
                //                     described in section 4.1.1.1.
                throw "Delegation not implemented.";
            }
            //  20..23     Flags   Four-octet context-establishment flags in
            //                     little-endian order as described in section
            //                     4.1.1.1.
            var flags = 0;
            if (this.delegation)
                flags |= DELEG_FLAG;
            if (this.mutualAuthentication)
                flags |= MUTUAL_FLAG;
            if (this.replayDetection)
                flags |= REPLAY_FLAG;
            if (this.sequence)
                flags |= SEQUENCE_FLAG;
            if (this.confidentiality)
                flags |= CONF_FLAG;
            if (this.integrity)
                flags |= INTEG_FLAG;
            cksumBuf.prependUint32(flags, true);
            //  4..19      Bnd     Channel binding information, as described in
            //                     section 4.1.1.2.
            var bndLen = cksumBuf.prependBytes(this.bindings);
            //  0..3       Lgth    Number of octets in Bnd field;  Represented
            //                     in little-endian order;  Currently contains
            //                     hex value 10 00 00 00 (16).
            cksumBuf.prependUint32(bndLen, true);
            var apReq = this.credential.makeAPReq(
                krb.KU_AP_REQ_AUTHENTICATOR,
                { cksumtype: 0x8003,
                  checksum: cksumBuf.contents() },
                ???,
                ???);
        }
        // TODO
    };
    gss.Context.prototype.isEstablished = function() {
        // TODO
    };

    return gss;
}());
<|endoftext|>


<commit_before>var vm = require('vm'),
  util = require('util'),
  esprima = require('esprima'),
  ScriptTargetBuilderApi = require('./intern/ScriptTargetBuilderApi'),
  MessageType = require('./MessageHandler').MessageType;
  PreparedTemplateBuilder = require('./PreparedTemplateBuilder');

module.exports = Engine;

function generateExceptionCallerStack(backtrace, sourceMap) {
  var callerStack = [];
  var re = /:(\d+):(\d+)\)?$/;
  backtrace = backtrace.split('\n').slice(1);
  for (var i = 0, l = backtrace.length; i < l; i++) {
    var traceLine = backtrace[i];
    if (-1 != traceLine.indexOf("[as runInNewContext]")) break;
    var m = traceLine.match(re);
    if (!m) continue;
    var line = parseInt(m[1]) - 1; // remove the first "try{" line
    var column = parseInt(m[2]);
    var position = sourceMap.findPosition(line, column);
    callerStack.push(position);
  }
  return callerStack;
}

function Engine(msgHandler, loader)
{
  function showSyntaxError(prepared) {
    try {
      esprima.parse(prepared.javascript);
    }
    catch (err) {
      var line = err.lineNumber;
      var column = err.column;
      var position = [ prepared.sourceMap.findPosition(line, column) ];
      var text = err.message.replace(/^Line \d+: /, '');
      msgHandler.javascriptMessage(MessageType.Error, position, text);
    }
  }
  function showException(exception, prepared) {
    if (!('stack' in exception)) {
      msgHandler.message(MessageType.Error, "Unknown exception: " + exception);
      return;
    }
    var positionStack = generateExceptionCallerStack(exception.stack, prepared.sourceMap);
    var text = "Uncaught Exception: " + exception.message;
    msgHandler.javascriptMessage(MessageType.Error, positionStack, text);
  }

  function exec(prepared, inputs) {
    var templateApi = ScriptTargetBuilderApi(prepared.originPositions);
    var sandbox =  util._extend({}, inputs);
    util._extend(sandbox, {_template: templateApi});
    if (prepared.script) {
      var result = prepared.script.runInNewContext(sandbox);
      if (result) {
        showException(result, prepared);
      }
    }
    return templateApi.build();
  }
  function prepare(name) {
    var prepared = PreparedTemplateBuilder(msgHandler, loader).build(name);
    try {
      prepared.script = vm.createScript("try{\n"+prepared.javascript+"\n}catch(e){e}", name + ".js");
    }
    catch(e) {
      showSyntaxError(prepared);
    }
    return prepared;
  }

  return {
    exec: exec,
    prepare: prepare,
    execTemplateName: function(name, inputs) {
      var prepared = prepare(name);
      return exec(prepared, inputs);
    }
  };
}
<commit_msg>improved Engine behavior.<commit_after>var vm = require('vm'),
  util = require('util'),
  esprima = require('esprima'),
  ScriptTargetBuilderApi = require('./intern/ScriptTargetBuilderApi'),
  MessageType = require('./MessageHandler').MessageType;
  PreparedTemplateBuilder = require('./PreparedTemplateBuilder');

module.exports = Engine;

function generateExceptionCallerStack(backtrace, sourceMap) {
  var callerStack = [];
  var re = /:(\d+):(\d+)\)?$/;
  backtrace = backtrace.split('\n').slice(1);
  for (var i = 0, l = backtrace.length; i < l; i++) {
    var traceLine = backtrace[i];
    if (-1 != traceLine.indexOf("[as runInNewContext]")) break;
    var m = traceLine.match(re);
    if (!m) continue;
    var line = parseInt(m[1]) - 1; // remove the first "try{" line
    var column = parseInt(m[2]);
    var position = sourceMap.findPosition(line, column);
    callerStack.push(position);
  }
  return callerStack;
}

function Engine(msgHandler, loader)
{
  function showSyntaxError(prepared) {
    try {
      esprima.parse(prepared.javascript);
    }
    catch (err) {
      var line = err.lineNumber;
      var column = err.column;
      var position = [ prepared.sourceMap.findPosition(line, column) ];
      var text = err.message.replace(/^Line \d+: /, '');
      msgHandler.javascriptMessage(MessageType.Error, position, text);
    }
  }
  function showException(exception, prepared) {
    if (!('stack' in exception)) {
      msgHandler.message(MessageType.Error, "Unknown exception: " + exception);
      return;
    }
    var positionStack = generateExceptionCallerStack(exception.stack, prepared.sourceMap);
    var text = "Uncaught Exception: " + exception.message;
    msgHandler.javascriptMessage(MessageType.Error, positionStack, text);
  }
  function prepareScript(prepared) {
    if ('script' in prepared) return;
    prepared.script = false;
    try {
      prepared.script = vm.createScript("try{\n"+prepared.javascript+"\n}catch(e){e}", "[TemplateEngine]");
    }
    catch(e) {
      showSyntaxError(prepared);
    }
  }
  function exec(prepared, inputs) {
    prepareScript(prepared);
    var templateApi = ScriptTargetBuilderApi(prepared.originPositions);
    var sandbox =  util._extend({}, inputs);
    util._extend(sandbox, {_template: templateApi});
    if (prepared.script) {
      var result = prepared.script.runInNewContext(sandbox);
      if (result) {
        showException(result, prepared);
      }
    }
    return templateApi.build();
  }
  function prepare(name) {
    var prepared = PreparedTemplateBuilder(msgHandler, loader).build(name);
    prepareScript(prepared);
    return prepared;
  }

  return {
    exec: exec,
    prepare: prepare,
    execTemplateName: function(name, inputs) {
      var prepared = prepare(name);
      return exec(prepared, inputs);
    }
  };
}
<|endoftext|>


<commit_before>const packager = require('electron-packager')
const path = require('path')

const options = {
  dir: '.',
  name: 'todu',
  out: 'dist/',
  overwrite: true,
  icon: path.resolve(__dirname, 'src/resource/img/icon.ico'),
  ignore: [
    '^/(?!src|package\\.json|window\\.js)',
    '^/src/(storage|component|plugin)($|/)',
  ],
  win32metadata: {
    CompanyName: 'Driver',
    FileDescription: 'TODU',
    OriginalFilename: 'todu.exe',
    ProductName: 'TODU',
    InternalName: 'TODU',
  }
}

packager(options, appPaths => {
  console.log('Build finished.')
})
<commit_msg>Reduce makefile declaration<commit_after>const packager = require('electron-packager')
const path = require('path')

const options = {
  dir: '.',
  name: 'todu',
  out: 'dist/',
  overwrite: true,
  icon: path.resolve(__dirname, 'src/resource/img/icon.ico'),
  ignore: [
    '^/(?!src|package\\.json|window\\.js)',
    '^/src/(storage|component|plugin)($|/)',
  ],
  win32metadata: {
    OriginalFilename: 'todu.exe',
  }
}

packager(options, appPaths => {
  console.log('Build finished.')
})
<|endoftext|>