<commit_before>'use strict';

var throttle = require('lodash').throttle;
var moment = require('moment');

function roundUp(v, x) {
  var stepWidth = Math.ceil(v / x);
  var stepWidthStr = '' + stepWidth;
  stepWidth = (parseInt(stepWidthStr[0], 10) + 1) * Math.pow(10, stepWidthStr.length - 1);
  return stepWidth * x;
}

function Sparkline(options) {
  this.resize(options.width, options.height);

  this.lineColors = options.lineColors;

  this.rulersColor = options.rulersColor || '#666';

  this.fontSize = options.fontSize || 12;

  this.lineWidth = options.lineWidth || 1;

  this.valueLabelsCount = 8;

  this.timespan = options.timespan || 'day';

  this.timestampFormat = 'YYYY-MM-DDTHH:mm:ss';

  this.timeLabelFormats = {
    day: 'HH:mm',
    week: 'dd DD',
    month: 'DD MMM'
  };
}

var proto = Sparkline.prototype;

proto.resize = function(width, height) {
  this.canvas = this.canvas || document.createElement('canvas');
  this.canvas.width = width;
  this.canvas.height = height;

  this.ctx = this.canvas.getContext('2d');

  return this;
};

proto.max = function(index) {
  var self = this;

  var val = 0;
  if (!arguments.length) {
    (self.data || []).forEach(function(set, i) {
      val = Math.max(val, self.max(i));
    });
    return val;
  }

  (self.data[index] || []).forEach(function(d) {
    val = Math.max(d.value, val);
  });

  return val;
};

proto.min = function(index) {
  var self = this;

  var val = self.max();
  if (!arguments.length) {
    (self.data || []).forEach(function(set, i) {
      val = Math.min(val, self.min(i));
    });
    return val;
  }

  val = self.max(index);
  (self.data[index] || []).forEach(function(d) {
    val = Math.min(d.value, val);
  });

  return val;
};

proto.setData = function(data, newTimespan) {
  if (newTimespan) {
    this.timespan = newTimespan;
  }
  var emptyDate = moment();
  var defaultData = [[
    {
      value: 0,
      timestamp: emptyDate.format(this.dateformat)
    }
  ]];
  if (!data || !data.length || !data[0]) {
    data = defaultData;
  }
  this.data = data;

  var timespan = this.timespan;
  var labelsStart;
  var timestampFormat = this.timestampFormat;
  var max = this.max();
  var rounded = roundUp(max, this.valueLabelsCount);
  var timeLabelFormats = this.timeLabelFormats;

  this.valueLabels = [];
  for (var l = this.valueLabelsCount; l >= 0; l--) {
    this.valueLabels.push((l * rounded) / this.valueLabelsCount);
  }

  this.timeLabels = [];
  if (data.length && data[0] && data[0].length && data[0][0].timestamp) {
    var to = moment();

    var labelTo = this.labelTo = to.clone();
    if (timespan === 'day') {
      labelTo.startOf('hour').add(1, 'hour');
    }
    else if (timespan === 'week') {
      labelTo.startOf('day').add(1, 'day');
    }
    else if (timespan === 'month') {
      labelTo.startOf('week').add(1, 'week');
    }
    var labelFrom = this.labelFrom = labelTo.clone().subtract(1, timespan);

    var count;
    var unit;
    var unitCount = 1;
    if (timespan === 'day') {
      count = 12;
      unit = 'hour';
      unitCount = 2;
    }
    else if (timespan === 'week') {
      count = 7;
      unit = 'day';
    }
    else if (timespan === 'month') {
      count = 4;
      unit = 'week';
    }

    for (var c = 0; c <= count; c++) {
      this.timeLabels.push(labelFrom.clone().add(c * unitCount, unit).format(timeLabelFormats[timespan]));
    }
  }

  this.data = data.map(function(set) {
    if (!set || !set.length) {
      set = [{value: 0}];
    }

    if (set.length === 1) {
      set = [set[0], set[0]];
    }

    var to = moment(set[set.length - 1].timestamp, timestampFormat);
    var milliDiff = to - labelsStart;

    return set.map(function(item) {
      var millis = moment(item.timestamp, timestampFormat);
      item.positionPercent = (to - millis) / milliDiff;
      return item;
    });
  });

  return this.draw();
};

proto.draw = function() {
  var self = this;
  var lineWidth = self.lineWidth;
  var ctx = self.ctx;
  var padding = Math.max(2 * lineWidth, 10);

  var timeLabels = this.timeLabels;
  var valueLabels = this.valueLabels;
  var fontSize = this.fontSize;

  var textPadding = 3;
  var verticalScaleX = 0;
  var horizontalScaleY = 0;
  var tickSize = 10;

  var step;
  var c;

  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

  ctx.strokeStyle = this.rulersColor;
  ctx.fillStyle = this.rulersColor;
  ctx.lineWidth = 1;
  ctx.font = fontSize + 'px Arial';

  valueLabels.forEach(function(l) {
    verticalScaleX = Math.max(verticalScaleX, ctx.measureText(l).width + (textPadding * 2) + tickSize);
  });
  verticalScaleX = Math.round(Math.max(verticalScaleX, tickSize + textPadding)) + 0.5;

  var innerW = ctx.canvas.width - (padding + verticalScaleX);
  var innerH = ctx.canvas.height - padding;

  var tt = 0;
  var tm = 0;
  timeLabels.forEach(function(l) {
    tt += ctx.measureText(l).width + (textPadding * 2);
    tm = Math.max(tm, ctx.measureText(l).width + (textPadding * 2));
  });

  var vertLabel = tt > innerW;
  if (vertLabel) {
    timeLabels.forEach(function(l) {
      horizontalScaleY = Math.max(horizontalScaleY, ctx.measureText(l).width + (textPadding * 2) + tickSize);
    });
    horizontalScaleY = Math.round(Math.max(horizontalScaleY, tickSize + textPadding)) + 0.5;
  }
  else {
    horizontalScaleY = fontSize + (textPadding * 2) + tickSize;
    innerW -= tm / 2;
  }
  innerH -= horizontalScaleY;

  // draw horizontal (time) scale
  var t = ctx.canvas.height - horizontalScaleY;
  ctx.beginPath();
  ctx.moveTo(verticalScaleX - tickSize, t);
  ctx.lineTo(verticalScaleX + innerW, t);
  ctx.stroke();

  // draw vertical (value) scale
  ctx.beginPath();
  ctx.moveTo(verticalScaleX, padding);
  ctx.lineTo(verticalScaleX, t + tickSize);
  ctx.stroke();

  if (vertLabel) {
    ctx.textAlign = 'right';
    ctx.textBaseline = 'bottom';
  }
  else {
    ctx.textAlign = 'center';
    ctx.textBaseline = 'top';
  }

  timeLabels.forEach(function(label, l) {
    var tx = verticalScaleX + (l * (innerW / (timeLabels.length - 1)));

    ctx.beginPath();
    ctx.moveTo(tx, t);
    ctx.lineTo(tx, t + tickSize);
    ctx.stroke();

    if (vertLabel) {
      ctx.save();
      ctx.translate(tx, ctx.canvas.height - (horizontalScaleY - (tickSize + textPadding)));
      ctx.rotate(-Math.PI / 2);
      ctx.fillText(timeLabels[l], 0, fontSize / 2);
      ctx.restore();
    }
    else {
      ctx.fillText(timeLabels[l], tx, ctx.canvas.height - (horizontalScaleY - (tickSize + textPadding)));
    }
  });

  step = innerH / (valueLabels.length - 1);
  ctx.textAlign = 'right';
  ctx.textBaseline = 'middle';
  for (c = 0; c < valueLabels.length; c++) {
    var ty = Math.round(padding + (step * c)) - 0.5;
    ctx.fillText(valueLabels[c], verticalScaleX - (tickSize + textPadding), ty);

    if (c < valueLabels.length - 1) {
      ctx.beginPath();
      ctx.moveTo(verticalScaleX - tickSize, ty);
      ctx.lineTo(verticalScaleX, ty);
      ctx.stroke();
    }
  }

  var rounded = this.valueLabels[0];
  function toPx(val) {
    return (innerH - ((innerH / rounded) * val)) + padding;
  }

  var labelFrom = this.labelFrom;
  var labelTo = this.labelTo;
  var labelDiff = labelTo - labelFrom;

  // draw the data
  this.data.forEach(function(set, index) {
    var right;
    var top;
    var skipped;
    var color = self.lineColors[index];

    ctx.lineWidth = lineWidth;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.strokeStyle = color;

    ctx.beginPath();
    set.forEach(function(d) {
      var mom = moment(d.timestamp);
      if (mom <= labelFrom) {
        skipped = d;
        return;
      }

      if (skipped) {
        right = verticalScaleX;
        top = toPx(skipped.value);
        ctx.lineTo(right, top);
        skipped = null;
      }

      right = verticalScaleX + ((mom - labelFrom) / (labelDiff)) * innerW;
      top = toPx(d.value);
      ctx.lineTo(right, top);
    });
    ctx.stroke();

    // draw the starting point
    if (set.length >= 3) {
      ctx.beginPath();
      ctx.fillStyle = color;
      ctx.arc(right, top, lineWidth * 2, 0, 2 * Math.PI);
      ctx.fill();
      ctx.closePath();
    }
  });

  return self;
};

module.exports = function() {
  return {
    restrict: 'A',

    scope: {
      values: '=',
      colors: '=?',
      timespan: '=?'
    },

    link: function($scope, $element) {
      $scope.timespan = $scope.timespan || 'day';

      var container = $element[0];
      var win = container.ownerDocument.defaultView;

      var sparkline = $scope.sparkline = new Sparkline({
        width: container.clientWidth,
        height: container.clientHeight,
        lineColors: $scope.colors
      });

      $scope.$watch('values', function() {
        var cn = container.className.replace('no-data', '');
        if (!$scope.values.length || !$scope.values[0] || !$scope.values[0].length) {
          cn += ' no-data';
        }
        container.className = cn;
        sparkline.setData($scope.values, $scope.timespan);
      });

      container.appendChild(sparkline.canvas);

      var resize = throttle(function() {
        sparkline.resize(container.clientWidth, container.clientHeight).draw();
      }, 100);

      win.addEventListener('resize', resize);

      $scope.$on('$destroy', function() {
        win.removeEventListener('resize', resize);
      });
    },

    template: '<!-- keule!! pech jehabt! -->'
  };
};<commit_msg>improve(sparkline): draw a line at 0 when no data is available<commit_after>'use strict';

var throttle = require('lodash').throttle;
var moment = require('moment');

function roundUp(v, x) {
  var stepWidth = Math.ceil(v / x);
  var stepWidthStr = '' + stepWidth;
  stepWidth = (parseInt(stepWidthStr[0], 10) + 1) * Math.pow(10, stepWidthStr.length - 1);
  return stepWidth * x;
}

function Sparkline(options) {
  this.resize(options.width, options.height);

  this.lineColors = options.lineColors;

  this.rulersColor = options.rulersColor || '#666';

  this.fontSize = options.fontSize || 12;

  this.lineWidth = options.lineWidth || 1;

  this.valueLabelsCount = 8;

  this.timespan = options.timespan || 'day';

  this.interval = options.interval || 900;

  this.timestampFormat = 'YYYY-MM-DDTHH:mm:ss';

  this.timeLabelFormats = {
    day: 'HH:mm',
    week: 'dd DD',
    month: 'DD MMM'
  };
}

var proto = Sparkline.prototype;

proto.resize = function(width, height) {
  this.canvas = this.canvas || document.createElement('canvas');
  this.canvas.width = width;
  this.canvas.height = height;

  this.ctx = this.canvas.getContext('2d');

  return this;
};

proto.max = function(index) {
  var self = this;

  var val = 0;
  if (!arguments.length) {
    (self.data || []).forEach(function(set, i) {
      val = Math.max(val, self.max(i));
    });
    return val;
  }

  (self.data[index] || []).forEach(function(d) {
    val = Math.max(d.value, val);
  });

  return val;
};

proto.min = function(index) {
  var self = this;

  var val = self.max();
  if (!arguments.length) {
    (self.data || []).forEach(function(set, i) {
      val = Math.min(val, self.min(i));
    });
    return val;
  }

  val = self.max(index);
  (self.data[index] || []).forEach(function(d) {
    val = Math.min(d.value, val);
  });

  return val;
};

proto.setData = function(data, newTimespan, newInterval) {
  if (newTimespan) {
    this.timespan = newTimespan;
  }
  if (newInterval) {
    this.interval = newInterval;
  }
  var emptyDate = moment();
  var defaultData = [[
    {
      value: 0,
      timestamp: emptyDate.format(this.dateformat)
    }
  ]];
  if (!data || !data.length || !data[0]) {
    data = defaultData;
  }
  this.data = data;

  var timespan = this.timespan;
  var labelsStart;
  var timestampFormat = this.timestampFormat;
  var max = this.max();
  var rounded = roundUp(max, this.valueLabelsCount);
  var timeLabelFormats = this.timeLabelFormats;

  this.valueLabels = [];
  for (var l = this.valueLabelsCount; l >= 0; l--) {
    this.valueLabels.push((l * rounded) / this.valueLabelsCount);
  }

  this.timeLabels = [];
  if (data.length && data[0] && data[0].length && data[0][0].timestamp) {
    var to = moment();

    var labelTo = this.labelTo = to.clone();
    if (timespan === 'day') {
      labelTo.startOf('hour').add(1, 'hour');
    }
    else if (timespan === 'week') {
      labelTo.startOf('day').add(1, 'day');
    }
    else if (timespan === 'month') {
      labelTo.startOf('week').add(1, 'week');
    }
    var labelFrom = this.labelFrom = labelTo.clone().subtract(1, timespan);

    var count;
    var unit;
    var unitCount = 1;
    if (timespan === 'day') {
      count = 12;
      unit = 'hour';
      unitCount = 2;
    }
    else if (timespan === 'week') {
      count = 7;
      unit = 'day';
    }
    else if (timespan === 'month') {
      count = 4;
      unit = 'week';
    }

    for (var c = 0; c <= count; c++) {
      this.timeLabels.push(labelFrom.clone().add(c * unitCount, unit).format(timeLabelFormats[timespan]));
    }
  }

  this.data = data.map(function(set) {
    if (!set || !set.length) {
      set = [{value: 0}];
    }

    if (set.length === 1) {
      set = [set[0], set[0]];
    }

    var to = moment(set[set.length - 1].timestamp, timestampFormat);
    var milliDiff = to - labelsStart;

    return set.map(function(item) {
      var millis = moment(item.timestamp, timestampFormat);
      item.positionPercent = (to - millis) / milliDiff;
      return item;
    });
  });

  return this.draw();
};

proto.draw = function() {
  var self = this;
  var lineWidth = self.lineWidth;
  var ctx = self.ctx;
  var padding = Math.max(2 * lineWidth, 10);

  var timeLabels = this.timeLabels;
  var valueLabels = this.valueLabels;
  var fontSize = this.fontSize;

  var textPadding = 3;
  var verticalScaleX = 0;
  var horizontalScaleY = 0;
  var tickSize = 10;

  var step;
  var c;

  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

  ctx.strokeStyle = this.rulersColor;
  ctx.fillStyle = this.rulersColor;
  ctx.lineWidth = 1;
  ctx.font = fontSize + 'px Arial';

  valueLabels.forEach(function(l) {
    verticalScaleX = Math.max(verticalScaleX, ctx.measureText(l).width + (textPadding * 2) + tickSize);
  });
  verticalScaleX = Math.round(Math.max(verticalScaleX, tickSize + textPadding)) + 0.5;

  var innerW = ctx.canvas.width - (padding + verticalScaleX);
  var innerH = ctx.canvas.height - padding;

  var tt = 0;
  var tm = 0;
  timeLabels.forEach(function(l) {
    tt += ctx.measureText(l).width + (textPadding * 2);
    tm = Math.max(tm, ctx.measureText(l).width + (textPadding * 2));
  });

  var vertLabel = tt > innerW;
  if (vertLabel) {
    timeLabels.forEach(function(l) {
      horizontalScaleY = Math.max(horizontalScaleY, ctx.measureText(l).width + (textPadding * 2) + tickSize);
    });
    horizontalScaleY = Math.round(Math.max(horizontalScaleY, tickSize + textPadding)) + 0.5;
  }
  else {
    horizontalScaleY = fontSize + (textPadding * 2) + tickSize;
    innerW -= tm / 2;
  }
  innerH -= horizontalScaleY;

  // draw horizontal (time) scale
  var t = ctx.canvas.height - horizontalScaleY;
  ctx.beginPath();
  ctx.moveTo(verticalScaleX - tickSize, t);
  ctx.lineTo(verticalScaleX + innerW, t);
  ctx.stroke();

  // draw vertical (value) scale
  ctx.beginPath();
  ctx.moveTo(verticalScaleX, padding);
  ctx.lineTo(verticalScaleX, t + tickSize);
  ctx.stroke();

  if (vertLabel) {
    ctx.textAlign = 'right';
    ctx.textBaseline = 'bottom';
  }
  else {
    ctx.textAlign = 'center';
    ctx.textBaseline = 'top';
  }

  timeLabels.forEach(function(label, l) {
    var tx = verticalScaleX + (l * (innerW / (timeLabels.length - 1)));

    ctx.beginPath();
    ctx.moveTo(tx, t);
    ctx.lineTo(tx, t + tickSize);
    ctx.stroke();

    if (vertLabel) {
      ctx.save();
      ctx.translate(tx, ctx.canvas.height - (horizontalScaleY - (tickSize + textPadding)));
      ctx.rotate(-Math.PI / 2);
      ctx.fillText(timeLabels[l], 0, fontSize / 2);
      ctx.restore();
    }
    else {
      ctx.fillText(timeLabels[l], tx, ctx.canvas.height - (horizontalScaleY - (tickSize + textPadding)));
    }
  });

  step = innerH / (valueLabels.length - 1);
  ctx.textAlign = 'right';
  ctx.textBaseline = 'middle';
  for (c = 0; c < valueLabels.length; c++) {
    var ty = Math.round(padding + (step * c)) - 0.5;
    ctx.fillText(valueLabels[c], verticalScaleX - (tickSize + textPadding), ty);

    if (c < valueLabels.length - 1) {
      ctx.beginPath();
      ctx.moveTo(verticalScaleX - tickSize, ty);
      ctx.lineTo(verticalScaleX, ty);
      ctx.stroke();
    }
  }

  var labelFrom = this.labelFrom;
  var labelTo = this.labelTo;
  var labelDiff = labelTo - labelFrom;
  var interval = this.interval;

  var rounded = this.valueLabels[0];
  function pxFromTop(val) {
    return (innerH - ((innerH / rounded) * val)) + padding;
  }
  function pxFromLeft(mom) {
    return verticalScaleX + ((mom - labelFrom) / labelDiff) * innerW;
  }

  // draw the data
  this.data.forEach(function(set, index) {
    var right;
    var top;
    var skipped;
    var color = self.lineColors[index];

    ctx.lineWidth = lineWidth;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.strokeStyle = color;

    ctx.beginPath();
    set.forEach(function(item, i) {
      var mom = moment(item.timestamp);
      // record is older than the from label
      if (mom <= labelFrom) {
        skipped = item;
        return;
      }
      // first record is after label from, draw a line at 0 until (mom - interval)
      else if (i === 0 && mom > labelFrom) {
        ctx.moveTo(verticalScaleX, ctx.canvas.height - horizontalScaleY);
        ctx.lineTo(pxFromLeft(mom.clone().subtract(interval, 'seconds')), ctx.canvas.height - horizontalScaleY);
      }

      if (skipped) {
        right = verticalScaleX;
        top = pxFromTop(skipped.value);
        ctx.lineTo(right, top);
        skipped = null;
      }

      right = pxFromLeft(mom);
      top = pxFromTop(item.value);
      ctx.lineTo(right, top);
    });
    ctx.stroke();
    ctx.closePath();

    // draw the starting point
    if (set.length >= 1) {
      ctx.beginPath();
      ctx.fillStyle = color;
      ctx.arc(right, top, lineWidth * 2, 0, 2 * Math.PI);
      ctx.fill();
      ctx.closePath();
    }
  });

  return self;
};

module.exports = function() {
  return {
    restrict: 'A',

    scope: {
      values: '=',
      colors: '=?',
      timespan: '=?',
      interval: '=?'
    },

    link: function($scope, $element) {
      $scope.timespan = $scope.timespan || 'day';
      $scope.interval = $scope.interval || 900;

      var container = $element[0];
      var win = container.ownerDocument.defaultView;

      var sparkline = $scope.sparkline = new Sparkline({
        width: container.clientWidth,
        height: container.clientHeight,
        lineColors: $scope.colors
      });

      $scope.$watch('values', function() {
        var cn = container.className.replace('no-data', '');
        if (!$scope.values.length || !$scope.values[0] || !$scope.values[0].length) {
          cn += ' no-data';
        }
        container.className = cn;
        sparkline.setData($scope.values, $scope.timespan, $scope.interval);
      });

      container.appendChild(sparkline.canvas);

      var resize = throttle(function() {
        sparkline.resize(container.clientWidth, container.clientHeight).draw();
      }, 100);

      win.addEventListener('resize', resize);

      $scope.$on('$destroy', function() {
        win.removeEventListener('resize', resize);
      });
    },

    template: '<!-- keule!! pech jehabt! -->'
  };
};<|endoftext|>


<commit_before>/*
Compile fest .xml template to output file.
*/
var
	fs	 = require('fs'),
	path = require('path'),
	fest  = require('./fest'),
	po    = require('./po'),
	utils = require('./utils'),
	cmd   = require('./cmd');
var existsSync = fs.existsSync || path.existsSync;

function help(exit_code) {
	/* Print help and exit. */
	if (exit_code === undefined) {
		exit_code = 0;
	}
	console.info([
		'Usage:',
		'  fest-compile [--out=...] [--wrapper=...] [--translate=...] template.xml',
		'',
		'Options:',
		'  --out         output directory for compiled files (use "-" for STDOUT, default)',
		'  --wrapper     type of postcompile wrappers, fest|loader|source|variable (default is fest)',
		'  --translate   input PO file',
		'  template.xml  path to .xml template file',
		'',
		'  --version     current version',
		'  --help        display these usage instructions',
		''
	].join('\n'));
	process.exit(exit_code);
}

function version(exit_code) {
	/* Print version and exit. */
	if (exit_code === undefined) {
		exit_code = 0;
	}
	console.info(JSON.parse(fs.readFileSync(__dirname + '/../package.json')).version);
	process.exit(exit_code);
}

function abs_path(f) {
	/* Resolve absolute pathname. */
	if (f[0] === '~' && f[1] === path.sep) {
		// don't forget about HOME: '~'
		var homedir = process.env.HOME || process.env.USERPROFILE;
		f = homedir + path.sep + f.slice(2);
	}
	return path.resolve(f);  // convert any path to absolute (relative to current work dir)
}

function mkdir(filename, mode) {
	/* Make directory if not exists. */
	if (existsSync(filename)) {
		return;
	}
	mode = mode || 0755;  // Achtung! Do not use '777' permission! Never.
	var parts = filename.split(path.sep);
	for (var i = 1; i < parts.length; i++) {
		var dir = parts.slice(0, i + 1).join(path.sep);
		if (!existsSync(dir)) {
			fs.mkdirSync(dir, mode);
		}
	}
}

if (cmd.help) {
	help();  // show help screen and exit
}
if (cmd.version) {
	version();  // show fest version and exit
}

// check if we have one and only one template file defined
if (cmd.length !== 1) {
	if (cmd.length === 0) {
		console.error('ERROR: you need to define template file (filename)\n');
	} else {
		console.error('ERROR: You may define only one template file (filename)\n');
	}
	help(1);
}

var template_file = cmd[0];  // input template file
var output_file = cmd.out || '-'  // output js file
var wrapper = cmd.wrapper || 'fest';  // postcompile wrapper

template_file_abs = abs_path(template_file);
if (!existsSync(template_file_abs)) {
	console.error('ERROR: file "' + template_file_abs + '" does not exists');
	process.exit(1);
}

cmd.compile = cmd.compile || {};
var messages;
var language;
if (cmd.translate) {
	translate_file = abs_path(cmd.translate);
	if (!existsSync(translate_file)) {
		console.error('ERROR: translate file "' + translate_file + '" does not exists')
		process.exit(1);
	}
	var pof = po.load(translate_file);
	cmd.compile.plural = pof.plural;
	language = pof.headers['Language'];
	messages = pof.toJSON();
	var errors = [], str, err;
	for (var k in messages) {
		str = messages[k];
		err = utils.validate('<template>' + str + '</template>');
		if (true !== err) {
			errors.push({
				id: k,
				str: str,
				errors: err
			});
		}
	}
	if (errors.length) {
		console.error('ERROR: translation failed:');
		errors.forEach(function (msg) {
			console.error('>>>\nmsg_id: ' + msg.id);
			console.error('msg_str: ' + msg.str);
			console.error('errors: ' + msg.errors.join('; ') + '\n<<<');
		});
		process.exit(1);
	}
}
cmd.compile.messages = messages;

// compile template
var source = fest.compile(template_file_abs, cmd.compile, '');
var template_file_lang = template_file.replace(/\.xml$/, language ? '.' + language : '');
var compiled = fest.compile_tmpl(template_file_lang, source, wrapper);

// output compiled template
if (output_file === '-') {
	console.log(compiled);  // to STDOUT
} else {
	output_file = abs_path(output_file)
	mkdir(path.dirname(output_file));
	fs.writeFileSync(output_file, compiled, 'utf8');  // to output file
}
<commit_msg>Small improvement of 'abs_path' in fest-compile<commit_after>/*
Compile fest .xml template to output file.
*/
var
	fs	 = require('fs'),
	path = require('path'),
	fest  = require('./fest'),
	po    = require('./po'),
	utils = require('./utils'),
	cmd   = require('./cmd');
var existsSync = fs.existsSync || path.existsSync;

function help(exit_code) {
	/* Print help and exit. */
	if (exit_code === undefined) {
		exit_code = 0;
	}
	console.info([
		'Usage:',
		'  fest-compile [--out=...] [--wrapper=...] [--translate=...] template.xml',
		'',
		'Options:',
		'  --out         output directory for compiled files (use "-" for STDOUT, default)',
		'  --wrapper     type of postcompile wrappers, fest|loader|source|variable (default is fest)',
		'  --translate   input PO file',
		'  template.xml  path to .xml template file',
		'',
		'  --version     current version',
		'  --help        display these usage instructions',
		''
	].join('\n'));
	process.exit(exit_code);
}

function version(exit_code) {
	/* Print version and exit. */
	if (exit_code === undefined) {
		exit_code = 0;
	}
	console.info(JSON.parse(fs.readFileSync(__dirname + '/../package.json')).version);
	process.exit(exit_code);
}

function abs_path(f) {
	/* Resolve absolute pathname. */
	if (f[0] === '~' && f[1] === path.sep) {
		// don't forget about HOME: '~'
		var homedir = process.env.HOME || process.env.USERPROFILE;
		f = homedir + f.slice(1);
	}
	return path.resolve(f);  // convert any path to absolute (relative to current work dir)
}

function mkdir(filename, mode) {
	/* Make directory if not exists. */
	if (existsSync(filename)) {
		return;
	}
	mode = mode || 0755;  // Achtung! Do not use '777' permission! Never.
	var parts = filename.split(path.sep);
	for (var i = 1; i < parts.length; i++) {
		var dir = parts.slice(0, i + 1).join(path.sep);
		if (!existsSync(dir)) {
			fs.mkdirSync(dir, mode);
		}
	}
}

if (cmd.help) {
	help();  // show help screen and exit
}
if (cmd.version) {
	version();  // show fest version and exit
}

// check if we have one and only one template file defined
if (cmd.length !== 1) {
	if (cmd.length === 0) {
		console.error('ERROR: you need to define template file (filename)\n');
	} else {
		console.error('ERROR: You may define only one template file (filename)\n');
	}
	help(1);
}

var template_file = cmd[0];  // input template file
var output_file = cmd.out || '-'  // output js file
var wrapper = cmd.wrapper || 'fest';  // postcompile wrapper

template_file_abs = abs_path(template_file);
if (!existsSync(template_file_abs)) {
	console.error('ERROR: file "' + template_file_abs + '" does not exists');
	process.exit(1);
}

cmd.compile = cmd.compile || {};
var messages;
var language;
if (cmd.translate) {
	translate_file = abs_path(cmd.translate);
	if (!existsSync(translate_file)) {
		console.error('ERROR: translate file "' + translate_file + '" does not exists')
		process.exit(1);
	}
	var pof = po.load(translate_file);
	cmd.compile.plural = pof.plural;
	language = pof.headers['Language'];
	messages = pof.toJSON();
	var errors = [], str, err;
	for (var k in messages) {
		str = messages[k];
		err = utils.validate('<template>' + str + '</template>');
		if (true !== err) {
			errors.push({
				id: k,
				str: str,
				errors: err
			});
		}
	}
	if (errors.length) {
		console.error('ERROR: translation failed:');
		errors.forEach(function (msg) {
			console.error('>>>\nmsg_id: ' + msg.id);
			console.error('msg_str: ' + msg.str);
			console.error('errors: ' + msg.errors.join('; ') + '\n<<<');
		});
		process.exit(1);
	}
}
cmd.compile.messages = messages;

// compile template
var source = fest.compile(template_file_abs, cmd.compile, '');
var template_file_lang = template_file.replace(/\.xml$/, language ? '.' + language : '');
var compiled = fest.compile_tmpl(template_file_lang, source, wrapper);

// output compiled template
if (output_file === '-') {
	console.log(compiled);  // to STDOUT
} else {
	output_file = abs_path(output_file)
	mkdir(path.dirname(output_file));
	fs.writeFileSync(output_file, compiled, 'utf8');  // to output file
}
<|endoftext|>


<commit_before>const { BadRequest, Forbidden } = require('@feathersjs/errors');
const { resolveScope } = require('./util/resolveScope');

const getScope = async (context) => {
	const { scopeName, scopeId } = await resolveScope(context);
	if (scopeName === undefined || scopeId === undefined) {
		throw new BadRequest('Cannot find scope name or scopeId.');
	}
	return { scopeName, scopeId };
};

const getPermissionService = (app, scopeName) => {
	const permissionServicePath = `/${scopeName}/:scopeId/userPermissions`;
	const permissionService = app.service(permissionServicePath);
	if (permissionService === undefined) {
		throw new BadRequest(`There is no userPermission service for the scope '${scopeName}'.`);
	}
	return permissionService;
};

/**
 * Retrieve permissions of a user in a given scope
 * @param {FeathersApp} app Feathers app object
 * @param {ObjectId|String} userId A userId as ObjectId or String
 * @param {Object} scope A scope in the format {id, name}
 * @example
 * await getScopePermissions(app, new ObjectId(), {name: 'teams', id: new ObjectId()}) ==> []
 * await getScopePermissions(app, aRealUserId, {name: 'teams', id: aTeamId}) ==> [
 * 	'FILE_CREATE',
 * 	'TEAM_EDIT',
 * ]
 */
const getScopePermissions = async (app, userId, scope) => {
	const permissionService = getPermissionService(app, scope.name);
	return permissionService.get(userId, {
		route: {
			scopeId: scope.id,
		},
	});
};

/**
 * Resolves the context if the (authenticated) user has the required permissions inside the scope.
 * @param {Array<Permission>} requiredPermissions an array of strings identifying permissions in the scope
 * @requires auth.hooks.authenticate('jwt')
 */
const checkScopePermissions = (requiredPermissions) => async (context) => {
	const { scopeName, scopeId } = await getScope(context);
	const { userId } = context.params.account;
	const userPermissions = await getScopePermissions(context.app, userId, { id: scopeId, name: scopeName });

	if (requiredPermissions.every((permission) => userPermissions.includes(permission))) {
		return context;
	}
	throw new Forbidden(`Missing one of the required permissions ${requiredPermissions}.`, {
		userId, scopeName, scopeId, requiredPermissions,
	});
};

module.exports = {
	getScopePermissions,
	checkScopePermissions,
};
<commit_msg>Update inline docs<commit_after>const { BadRequest, Forbidden } = require('@feathersjs/errors');
const { resolveScope } = require('./util/resolveScope');

/**
 * Returns the name and id for the scope of the requested resource
 * @param {Context} context Feathers hook context
 * @returns {Object} { scopeName, scopeId }
 * @throws {BadRequest} if the scope cannot be found
 */
const getScope = async (context) => {
	const { scopeName, scopeId } = await resolveScope(context);
	if (scopeName === undefined || scopeId === undefined) {
		throw new BadRequest('Cannot find scope name or scopeId.');
	}
	return { scopeName, scopeId };
};

/**
 * Returns the service instance of the user permission service for the given scope
 * @param {FeathersApp} app Feathers app object
 * @param {String} scopeName scope name
 * @returns {Service} permissionService
 * @throws {BadRequest} if no user permission service exists for the scope
 */
const getPermissionService = (app, scopeName) => {
	const permissionServicePath = `/${scopeName}/:scopeId/userPermissions`;
	const permissionService = app.service(permissionServicePath);
	if (permissionService === undefined) {
		throw new BadRequest(`There is no userPermission service for the scope '${scopeName}'.`);
	}
	return permissionService;
};

/**
 * Retrieve permissions of a user in a given scope
 * @param {FeathersApp} app Feathers app object
 * @param {ObjectId|String} userId A userId as ObjectId or String
 * @param {Object} scope A scope in the format {id, name}
 * @example
 * await getScopePermissions(app, new ObjectId(), {name: 'teams', id: new ObjectId()}) ==> []
 * await getScopePermissions(app, aRealUserId, {name: 'teams', id: aTeamId}) ==> [
 * 	'FILE_CREATE',
 * 	'TEAM_EDIT',
 * ]
 */
const getScopePermissions = async (app, userId, scope) => {
	const permissionService = getPermissionService(app, scope.name);
	return permissionService.get(userId, {
		route: {
			scopeId: scope.id,
		},
	});
};

/**
 * Returns a hook that resolves the context if the (authenticated) user has the required permissions inside the scope.
 * @param {Array<Permission>} requiredPermissions an array of strings identifying permissions in the scope
 * @requires auth.hooks.authenticate('jwt')
 * @returns {Function} Hook function: (context) => context
 * @throws {BadRequest} if the scope cannot be found or has no user permission service
 * @throws {Forbidden} if the user does not have the required permissions
 */
const checkScopePermissions = (requiredPermissions) => async (context) => {
	const { scopeName, scopeId } = await getScope(context);
	const { userId } = context.params.account;
	const userPermissions = await getScopePermissions(context.app, userId, { id: scopeId, name: scopeName });

	if (requiredPermissions.every((permission) => userPermissions.includes(permission))) {
		return context;
	}
	throw new Forbidden(`Missing one of the required permissions ${requiredPermissions}.`, {
		userId, scopeName, scopeId, requiredPermissions,
	});
};

module.exports = {
	getScopePermissions,
	checkScopePermissions,
};
<|endoftext|>


<commit_before>module.exports = {
  'data:create': ['write:add', 'publish:add'],
  'data:createOrReplace': ['write:add', 'publish:add'],
  'data:replace': ['write:add', 'publish:add'],
  'data:update': ['write:add'],
  'data:delete': ['write:add', 'publish:add'],
  'data:deleteByQuery': ['write:add'],
  'data:bulkImport': ['write:add'],
  'data:updateMapping': ['write:add'],
  'data:createCollection': ['write:add'],
  'data:deleteCollection': ['write:add'],
  'data:truncateCollection': ['write:add'],
  'data:publish': [],
  'data:listIndexes': [],
  'data:createIndex': ['write:add'],
  'data:deleteIndex': ['write:add'],
  'data:deleteIndexes': ['write:add'],
  'data:createOrReplaceRole': [],
  'data:createOrReplaceProfile': []
};

<commit_msg>updated hooks to match the new security events<commit_after>module.exports = {
  'data:create': ['write:add', 'publish:add'],
  'data:createOrReplace': ['write:add', 'publish:add'],
  'data:replace': ['write:add', 'publish:add'],
  'data:update': ['write:add'],
  'data:delete': ['write:add', 'publish:add'],
  'data:deleteByQuery': ['write:add'],
  'data:bulkImport': ['write:add'],
  'data:updateMapping': ['write:add'],
  'data:createCollection': ['write:add'],
  'data:deleteCollection': ['write:add'],
  'data:truncateCollection': ['write:add'],
  'data:publish': [],
  'data:listIndexes': [],
  'data:createIndex': ['write:add'],
  'data:deleteIndex': ['write:add'],
  'data:deleteIndexes': ['write:add'],
  'security:createOrReplaceRole': [],
  'security:createOrReplaceProfile': [],
  'security:getRole': [],
  'security:mGetRole': [],
  'security:searchRole': [],
  'security:deleteRole': [],
  'security:getProfile': [],
  'security:mGetProfile': [],
  'security:deleteProfile': [],
  'security:searchProfiles': [],
  'security:getUser': [],
  'security:searchUsers': [],
  'security:deleteUser': [],
  'security:createUser': [],
  'security:updateUser': [],
  'security:createOrReplaceUser': []
};

<|endoftext|>


<commit_before>'use strict';

module.exports = {
  '0-8-recommended': require('./0-8-recommended'),
  recommended: require('./recommended'),
};
<commit_msg>Add 'octane' config to export list so it can be found (#803)<commit_after>'use strict';

module.exports = {
  '0-8-recommended': require('./0-8-recommended'),
  octane: require('./octane'),
  recommended: require('./recommended'),
};
<|endoftext|>


<commit_before>'use strict';

var Promise = require('bluebird');
var pathFn = require('path');
var chalk = require('chalk');
var fs = require('hexo-fs');
var tildify = require('tildify');
var spawn = require('hexo-util/lib/spawn');
var assign = require('object-assign');
var commandExistsSync = require('command-exists').sync;

var ASSET_DIR = pathFn.join(__dirname, '../../assets');
var GIT_REPO_URL = 'https://github.com/hexojs/hexo-starter.git';

function initConsole(args) {
  args = assign({
    install: true,
    clone: true
  }, args);

  var baseDir = this.base_dir;
  var target = args._[0] ? pathFn.resolve(baseDir, args._[0]) : baseDir;
  var log = this.log;
  var promise;
  var npmCommand;

  if (fs.existsSync(target) && fs.readdirSync(target).length !== 0) {
    log.fatal(chalk.magenta(tildify(target)) +
      ' not empty, please run `hexo init` on an empty folder and then copy your files into it');
    return Promise.reject(new Error('target not empty'));
  }

  log.info('Cloning hexo-starter to', chalk.magenta(tildify(target)));

  if (args.clone) {
    promise = spawn('git', ['clone', '--recursive', GIT_REPO_URL, target], {
      stdio: 'inherit'
    });
  } else {
    promise = copyAsset(target);
  }

  return promise.catch(function() {
    log.warn('git clone failed. Copying data instead');

    return copyAsset(target);
  }).then(function() {
    return Promise.all([
      removeGitDir(target),
      removeGitModules(target)
    ]);
  }).then(function() {
    if (!args.install) return;

    log.info('Install dependencies');

    if (commandExistsSync('yarn')) {
      npmCommand = 'yarn';
    } else {
      npmCommand = 'npm';
    }

    return spawn(npmCommand, ['install', '--production'], {
      cwd: target,
      stdio: 'inherit'
    });
  }).then(function() {
    log.info('Start blogging with Hexo!');
  }).catch(function() {
    log.warn('Failed to install dependencies. Please run \'npm install\' manually!');
  });
}

function copyAsset(target) {
  return fs.copyDir(ASSET_DIR, target, {
    ignoreHidden: false
  });
}

function removeGitDir(target) {
  var gitDir = pathFn.join(target, '.git');

  return fs.stat(gitDir).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  }).then(function(stats) {
    if (stats) {
      if (stats.isDirectory()) return fs.rmdir(gitDir);
      return fs.unlink(gitDir);
    }
  }).then(function() {
    return fs.readdir(target);
  }).map(function(path) {
    return pathFn.join(target, path);
  }).filter(function(path) {
    return fs.stat(path).then(function(stats) {
      return stats.isDirectory();
    });
  }).each(removeGitDir);
}

function removeGitModules(target) {
  return fs.unlink(pathFn.join(target, '.gitmodules')).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  });
}

module.exports = initConsole;
<commit_msg>reveal GIT_REPO_URL in log<commit_after>'use strict';

var Promise = require('bluebird');
var pathFn = require('path');
var chalk = require('chalk');
var fs = require('hexo-fs');
var tildify = require('tildify');
var spawn = require('hexo-util/lib/spawn');
var assign = require('object-assign');
var commandExistsSync = require('command-exists').sync;

var ASSET_DIR = pathFn.join(__dirname, '../../assets');
var GIT_REPO_URL = 'https://github.com/hexojs/hexo-starter.git';

function initConsole(args) {
  args = assign({
    install: true,
    clone: true
  }, args);

  var baseDir = this.base_dir;
  var target = args._[0] ? pathFn.resolve(baseDir, args._[0]) : baseDir;
  var log = this.log;
  var promise;
  var npmCommand;

  if (fs.existsSync(target) && fs.readdirSync(target).length !== 0) {
    log.fatal(chalk.magenta(tildify(target)) +
      ' not empty, please run `hexo init` on an empty folder and then copy your files into it');
    return Promise.reject(new Error('target not empty'));
  }

  log.info('Cloning hexo-starter', GIT_REPO_URL);

  if (args.clone) {
    promise = spawn('git', ['clone', '--recursive', GIT_REPO_URL, target], {
      stdio: 'inherit'
    });
  } else {
    promise = copyAsset(target);
  }

  return promise.catch(function() {
    log.warn('git clone failed. Copying data instead');

    return copyAsset(target);
  }).then(function() {
    return Promise.all([
      removeGitDir(target),
      removeGitModules(target)
    ]);
  }).then(function() {
    if (!args.install) return;

    log.info('Install dependencies');

    if (commandExistsSync('yarn')) {
      npmCommand = 'yarn';
    } else {
      npmCommand = 'npm';
    }

    return spawn(npmCommand, ['install', '--production'], {
      cwd: target,
      stdio: 'inherit'
    });
  }).then(function() {
    log.info('Start blogging with Hexo!');
  }).catch(function() {
    log.warn('Failed to install dependencies. Please run \'npm install\' manually!');
  });
}

function copyAsset(target) {
  return fs.copyDir(ASSET_DIR, target, {
    ignoreHidden: false
  });
}

function removeGitDir(target) {
  var gitDir = pathFn.join(target, '.git');

  return fs.stat(gitDir).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  }).then(function(stats) {
    if (stats) {
      if (stats.isDirectory()) return fs.rmdir(gitDir);
      return fs.unlink(gitDir);
    }
  }).then(function() {
    return fs.readdir(target);
  }).map(function(path) {
    return pathFn.join(target, path);
  }).filter(function(path) {
    return fs.stat(path).then(function(stats) {
      return stats.isDirectory();
    });
  }).each(removeGitDir);
}

function removeGitModules(target) {
  return fs.unlink(pathFn.join(target, '.gitmodules')).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  });
}

module.exports = initConsole;
<|endoftext|>


<commit_before>/**
 * Connects keystone to the application's mongoose instance.
 *
 * ####Example:
 *
 *     var mongoose = require('mongoose');
 *
 *     keystone.connect(mongoose);
 *
 * @param {Object} connections
 * @api public
 */

var debug = require('debug')('keystone:core:connect');

function connect() {
	var warningMsg = 'keystone.connect() is now deprecated and will not be available in future versions of KeystoneJS\n' +
		'It has been replaced with the Keystone "app" and "mongoose" options.\n' +
		'Due to changes in Express 4, "keystone.connect()" no longer works as expected.\n\n'
		'See http://localhost:8080/docs/configuration#options-project for more information.'

	keystone.console.err('Deprecation Warning', warningMsg);

	// detect type of each argument
	for (var i = 0; i < arguments.length; i++) {
		if (arguments[i].constructor.name === 'Mongoose') {
			debug('detected mongoose');
			this.mongoose = arguments[i];
		} else if (arguments[i].name === 'app') {
			debug('detected express app');
			this.app = arguments[i];
		}
	}
	return this;
}

module.exports = connect;
<commit_msg>fixed undefined keystone variable<commit_after>/**
 * Connects keystone to the application's mongoose instance.
 *
 * ####Example:
 *
 *     var mongoose = require('mongoose');
 *
 *     keystone.connect(mongoose);
 *
 * @param {Object} connections
 * @api public
 */

var debug = require('debug')('keystone:core:connect');

function connect() {
	var warningMsg = 'keystone.connect() is now deprecated and will not be available in future versions of KeystoneJS\n' +
		'It has been replaced with the Keystone "app" and "mongoose" options.\n' +
		'Due to changes in Express 4, "keystone.connect()" no longer works as expected.\n\n'
		'See http://localhost:8080/docs/configuration#options-project for more information.'

	this.console.err('Deprecation Warning', warningMsg);

	// detect type of each argument
	for (var i = 0; i < arguments.length; i++) {
		if (arguments[i].constructor.name === 'Mongoose') {
			debug('detected mongoose');
			this.mongoose = arguments[i];
		} else if (arguments[i].name === 'app') {
			debug('detected express app');
			this.app = arguments[i];
		}
	}
	return this;
}

module.exports = connect;
<|endoftext|>


<commit_before>/* Magic Mirror
 * Module: MMM-MovieListing
 *
 * By Christian Jens https://tueti.github.io
 * Modified by Kyle Johnson
 * MIT Licensed.
 */

Module.register('MMM-MovieListings', {

  // Default module config.
	defaults: {
    apiKey: '',
		region: 'DE',
    language: 'de-DE',
    interface: 'poster', //'list', 'poster', 'detailed'
    includeMoviePlot: false,
    maxPlotLength: 198,
    header: 'Kinofilme',
    moviesPerPage: 0,
    refreshInterval: 1000 * 60 * 60 * 24, //Once a day
    baseUrl: 'https://api.themoviedb.org/3/movie/now_playing',
    animationSpeed: 2.5 * 1000,
    pageChangeInterval: 30 * 1000
	},

  getStyles: function() {
		return ['MMM-MovieListings.css'];
	},

  getTranslations: function() {
    return {
      en: "translations/en.json",
      de: "translations/de.json",
      sv: "translations/sv.json"
    }
  },

  start: function() {
    Log.log(this.name + ' is started');
    this.movies = {};

    var self = this;
    self.sendSocketNotification('FETCH_MOVIE_LIST', this.config); //run once now, then set Interval for once a day
    setInterval(function() {
      self.sendSocketNotification('FETCH_MOVIE_LIST', this.config);
    }, this.config.refreshInterval);
  },

  socketNotificationReceived: function(notification, payload) {
    Log.log(this.name + ': received socket notification ' + notification + ' with payload:', payload);

    if (notification === 'MOVIE_ERROR') {
      Log.log(this.name + ': Error');
    }

    if (notification === 'MOVIE_LIST_DONE') {
      // Log.log(this.name + ': Got movies');
      // Prepare DOM data
      this.movies = payload.results;
      this.prepareDomUpdate(this.movies);
    }

    if (notification === 'MOVIE_ID_DONE') {
      // Log.log(this.name + ': Got movie details', payload);
      this.posterToDisplay = payload
      this.updateDom(this.config.animationSpeed);
    }
  },

  /*
   * DOM MANIPULATION
   */

	getDom: function() {
    var wrapper = document.createElement('div')
    var header = document.createElement('header');
    header.innerHTML = this.config.header;
    wrapper.appendChild(header);

    // No movies fetched yet
    if (!this.moviesToDisplay && !this.posterToDisplay) {
      var loadingPlaceholder = document.createElement('div');
      loadingPlaceholder.className = 'small dimmed';
      loadingPlaceholder.innerHTML = this.translate('LOADING');

      wrapper.appendChild(loadingPlaceholder);
      return wrapper;
    }

    switch (this.config.interface) {
      case 'list':
        var tableContainer = document.createElement('div').appendChild(this.createTableView(this.moviesToDisplay));
        wrapper.appendChild(tableContainer);
        return wrapper;
      case 'poster':
        var posterContainer = document.createElement('div').appendChild(this.createPosterView(this.posterToDisplay));
        wrapper.appendChild(posterContainer);
        return wrapper;
      default:
        break;
    }
	},

  // Different view styles
  createTableView: function(movies) {
    var table = document.createElement('table');
    table.className = 'small';

    for (var i = 0; i <= movies.length - 1; i++) {
      var movie = movies[i];

      var tableRow = document.createElement('tr');
      var tableData = document.createElement('td');

      var cell = document.createElement('span');
      cell.innerHTML = movie.title;

      tableData.appendChild(cell);
      tableRow.appendChild(tableData);
      table.appendChild(tableRow);
    }

    return table;
  },

  createPosterView: function(movieSet) {

    var movie = movieSet.details;
    var credits = movieSet.credits;

    // create container
    var posterWrapper = document.createElement('div');
    posterWrapper.className = 'xsmall';

    // set up title
    var title = document.createElement('div');
    title.classList = 'small';
    title.innerHTML = movie.title;

    // set up tagline
    var tagline = document.createElement('div');
    tagline.classList = 'dimmed';
    tagline.innerHTML = movie.tagline;

    // set up plot
    if (this.config.includeMoviePlot) {
      var plot = document.createElement('div');
      plot.classList = 'dimmed';
      var plotContent = "";
      if (this.config.maxPlotLength == 0) {
        plotContent = movie.overview
      } else {
        plotContent = movie.overviewShort;
      }
      plot.innerHTML = plotContent.split(/((?:\w+.?,?;?!?\?? ){10})/g).filter(Boolean).join("
");;
    }

    // Set up details => image
    var image = document.createElement('img');
    image.src = 'https://image.tmdb.org/t/p/w154/' + movie.poster_path; // "w92", "w154", "w185", "w342", "w500", "w780", or "original"

    // Set up details => textArea
    var detailsContainer = document.createElement('p');
    detailsContainer.className = this.data.position.toLowerCase().indexOf('right') < 0 ? 'marginLeft' : 'marginRight';

    // Set up details => rating
    var detailsRatingContainer = document.createElement('div');
    detailsRatingContainer.className = 'xsmall';
    var detailsRatingVote = document.createElement('span');
    detailsRatingVote.innerHTML = movie.vote_average + ' / 10';
    var detailsRatingVotings = document.createElement('span');
    detailsRatingVotings.className = 'xsmall dimmed';
    detailsRatingVotings.innerHTML = ' (' + movie.vote_count + ' ' + this.translate('RATINGS') + ')';

    detailsRatingContainer.appendChild(detailsRatingVote);
    detailsRatingContainer.appendChild(detailsRatingVotings);

    // Set up details => runtime
    var runtimeContent = document.createElement('div');
    runtimeContent.className = 'xsmall';
    runtimeContent.innerHTML = movie.runtime + ' ' + this.translate('MIN');

    // Set up details => credits actors
    var creditsContainer = document.createElement('div');
    creditsContainer.className = 'marginTop xsmall';
/*  Header(?)
    var castHeader = document.createElement('div');
    castHeader.className = 'xsmall dimmed';
    castHeader.innerHTML = this.translate('CAST');
    creditsContainer.appendChild(castHeader);
*/
    var castContent = document.createElement('div');
    castContent.className = 'xsmall';
    if (credits.cast && credits.cast.length > 0) {
      for (var i = 0; i < Math.min(6, credits.cast.length); i++) {
        castContent.innerHTML += credits.cast[i].name + '
';
      }
    }
    creditsContainer.appendChild(castContent);

    // Set up details => credits director
    var directorContainer = document.createElement('div');
    var directorHeader = document.createElement('span');
    directorHeader.className = 'xsmall dimmed';
    directorHeader.innerHTML = ', ' + this.translate('DIRECTOR');
    var directorContent = document.createElement('span');
    directorContent.className = 'xsmall';
    if (credits.crew && credits.crew.length > 0) {
      for (var i = 0; i <= credits.crew.length - 1; i++) {
        if (credits.crew[i].job === 'Director') {
          directorContent.innerHTML = credits.crew[i].name;
        };
      };
    }
    directorContainer.appendChild(directorContent);
    directorContainer.appendChild(directorHeader);
    creditsContainer.appendChild(directorContainer);

    // Set up details => genres
    if (movie.genres) {
      var genres = '';
      for (var i = 0; i <= movie.genres.length -1; i++) {
        genres += movie.genres[i].name;
        if (i < movie.genres.length - 1) {
          genres += ', ';
        }
      }
    }

    // Add all details
    detailsContainer.appendChild(detailsRatingContainer);
    detailsContainer.appendChild(runtimeContent);
    detailsContainer.appendChild(creditsContainer);

    // Set up details => table
    var detailsTable = document.createElement('table');
    detailsTable.className = 'xsMarginTop';
    var tableRow = document.createElement('tr');
    var imageCell = document.createElement('td');
    var textCell = document.createElement('td');
    textCell.className = 'top';
    imageCell.className = 'top';

    imageCell.appendChild(image);
    textCell.appendChild(detailsContainer);
    if (this.data.position.toLowerCase().indexOf('right') < 0) {
      tableRow.appendChild(imageCell);
      textCell.className = 'top left';
      tableRow.appendChild(textCell);
    } else {
      tableRow.appendChild(textCell);
      tableRow.appendChild(imageCell);
    };
    detailsTable.appendChild(tableRow);

    // Set up entire view in container
    posterWrapper.appendChild(title);
    posterWrapper.appendChild(tagline);
    posterWrapper.appendChild(detailsTable);
    if (this.config.includeMoviePlot) {
      posterWrapper.appendChild(plot);
    }

    return posterWrapper;
  },

  /*
   * HELPER
   */
  prepareDomUpdate: function(movies) {
    switch (this.config.interface) {
      case 'list':
        // If pagination enabled, turn to DOM update scheduler, else just display all movies
        if (this.config.moviesPerPage > 0) {
          this.scheduleDomUpdatesForList(movies);
        } else {
          this.moviesToDisplay = movies
          this.updateDom();
        }
        break;
      case 'poster':
        this.scheduleDomUpdatesForPoster(movies);
      default:
        break;
    }
  },

  scheduleDomUpdatesForList: function(movies) {
    var self = this;
    var pages = Math.ceil(movies.length / self.config.moviesPerPage);
    self.movieChunks = [];
    self.nextIndex = 0;

    for (var i = 0; i < pages; i++) {
      self.movieChunks.push(movies.splice(0, self.config.moviesPerPage))
    }

    self.moviesToDisplay = self.movieChunks[self.nextIndex];
    self.nextIndex++;
    self.updateDom();

    setInterval(function() {
      self.moviesToDisplay = self.movieChunks[self.nextIndex];
      self.nextIndex++;

      // reset index if end is reached
      if (self.nextIndex > self.movieChunks.length - 1) {
        self.nextIndex = 0;
      }

      self.updateDom(self.config.animationSpeed);
    }, this.config.pageChangeInterval);
  },

  scheduleDomUpdatesForPoster: function(movies) {
    var self = this;
    self.nextIndex = 0;
    self.sendSocketNotification('FETCH_MOVIE_ID', {
      movieId: movies[self.nextIndex].id,
      apiKey: self.config.apiKey,
      language: self.config.language,
      config: self.config
    });
    self.nextIndex++;

    setInterval(function() {
      self.sendSocketNotification('FETCH_MOVIE_ID', {
        movieId: movies[self.nextIndex].id,
        apiKey: self.config.apiKey,
        language: self.config.language,
        config: self.config
      });
      self.nextIndex++;

      // reset when end of array is reached
      if (self.nextIndex > movies.length - 1) {
        self.nextIndex = 0;
      }
    }, this.config.pageChangeInterval);
  },
});
<commit_msg>switched to \S for RegEx to include all non-whitespaces in word-wrap<commit_after>/* Magic Mirror
 * Module: MMM-MovieListing
 *
 * By Christian Jens https://tueti.github.io
 * Modified by Kyle Johnson
 * MIT Licensed.
 */

Module.register('MMM-MovieListings', {

  // Default module config.
	defaults: {
    apiKey: '',
		region: 'DE',
    language: 'de-DE',
    interface: 'poster', //'list', 'poster', 'detailed'
    includeMoviePlot: false,
    maxPlotLength: 198,
    header: 'Kinofilme',
    moviesPerPage: 0,
    refreshInterval: 1000 * 60 * 60 * 24, //Once a day
    baseUrl: 'https://api.themoviedb.org/3/movie/now_playing',
    animationSpeed: 2.5 * 1000,
    pageChangeInterval: 30 * 1000
	},

  getStyles: function() {
		return ['MMM-MovieListings.css'];
	},

  getTranslations: function() {
    return {
      en: "translations/en.json",
      de: "translations/de.json",
      sv: "translations/sv.json"
    }
  },

  start: function() {
    Log.log(this.name + ' is started');
    this.movies = {};

    var self = this;
    self.sendSocketNotification('FETCH_MOVIE_LIST', this.config); //run once now, then set Interval for once a day
    setInterval(function() {
      self.sendSocketNotification('FETCH_MOVIE_LIST', this.config);
    }, this.config.refreshInterval);
  },

  socketNotificationReceived: function(notification, payload) {
    Log.log(this.name + ': received socket notification ' + notification + ' with payload:', payload);

    if (notification === 'MOVIE_ERROR') {
      Log.log(this.name + ': Error');
    }

    if (notification === 'MOVIE_LIST_DONE') {
      // Log.log(this.name + ': Got movies');
      // Prepare DOM data
      this.movies = payload.results;
      this.prepareDomUpdate(this.movies);
    }

    if (notification === 'MOVIE_ID_DONE') {
      // Log.log(this.name + ': Got movie details', payload);
      this.posterToDisplay = payload
      this.updateDom(this.config.animationSpeed);
    }
  },

  /*
   * DOM MANIPULATION
   */

	getDom: function() {
    var wrapper = document.createElement('div')
    var header = document.createElement('header');
    header.innerHTML = this.config.header;
    wrapper.appendChild(header);

    // No movies fetched yet
    if (!this.moviesToDisplay && !this.posterToDisplay) {
      var loadingPlaceholder = document.createElement('div');
      loadingPlaceholder.className = 'small dimmed';
      loadingPlaceholder.innerHTML = this.translate('LOADING');

      wrapper.appendChild(loadingPlaceholder);
      return wrapper;
    }

    switch (this.config.interface) {
      case 'list':
        var tableContainer = document.createElement('div').appendChild(this.createTableView(this.moviesToDisplay));
        wrapper.appendChild(tableContainer);
        return wrapper;
      case 'poster':
        var posterContainer = document.createElement('div').appendChild(this.createPosterView(this.posterToDisplay));
        wrapper.appendChild(posterContainer);
        return wrapper;
      default:
        break;
    }
	},

  // Different view styles
  createTableView: function(movies) {
    var table = document.createElement('table');
    table.className = 'small';

    for (var i = 0; i <= movies.length - 1; i++) {
      var movie = movies[i];

      var tableRow = document.createElement('tr');
      var tableData = document.createElement('td');

      var cell = document.createElement('span');
      cell.innerHTML = movie.title;

      tableData.appendChild(cell);
      tableRow.appendChild(tableData);
      table.appendChild(tableRow);
    }

    return table;
  },

  createPosterView: function(movieSet) {

    var movie = movieSet.details;
    var credits = movieSet.credits;

    // create container
    var posterWrapper = document.createElement('div');
    posterWrapper.className = 'xsmall';

    // set up title
    var title = document.createElement('div');
    title.classList = 'small';
    title.innerHTML = movie.title;

    // set up tagline
    var tagline = document.createElement('div');
    tagline.classList = 'dimmed';
    tagline.innerHTML = movie.tagline;

    // set up plot
    if (this.config.includeMoviePlot) {
      var plot = document.createElement('div');
      plot.classList = 'dimmed';
      var plotContent = "";
      if (this.config.maxPlotLength == 0) {
        plotContent = movie.overview
      } else {
        plotContent = movie.overviewShort;
      }
      plot.innerHTML = plotContent.split(/((?:\S+ ){10})/g).filter(Boolean).join("
");;
    }

    // Set up details => image
    var image = document.createElement('img');
    image.src = 'https://image.tmdb.org/t/p/w154/' + movie.poster_path; // "w92", "w154", "w185", "w342", "w500", "w780", or "original"

    // Set up details => textArea
    var detailsContainer = document.createElement('p');
    detailsContainer.className = this.data.position.toLowerCase().indexOf('right') < 0 ? 'marginLeft' : 'marginRight';

    // Set up details => rating
    var detailsRatingContainer = document.createElement('div');
    detailsRatingContainer.className = 'xsmall';
    var detailsRatingVote = document.createElement('span');
    detailsRatingVote.innerHTML = movie.vote_average + ' / 10';
    var detailsRatingVotings = document.createElement('span');
    detailsRatingVotings.className = 'xsmall dimmed';
    detailsRatingVotings.innerHTML = ' (' + movie.vote_count + ' ' + this.translate('RATINGS') + ')';

    detailsRatingContainer.appendChild(detailsRatingVote);
    detailsRatingContainer.appendChild(detailsRatingVotings);

    // Set up details => runtime
    var runtimeContent = document.createElement('div');
    runtimeContent.className = 'xsmall';
    runtimeContent.innerHTML = movie.runtime + ' ' + this.translate('MIN');

    // Set up details => credits actors
    var creditsContainer = document.createElement('div');
    creditsContainer.className = 'marginTop xsmall';
/*  Header(?)
    var castHeader = document.createElement('div');
    castHeader.className = 'xsmall dimmed';
    castHeader.innerHTML = this.translate('CAST');
    creditsContainer.appendChild(castHeader);
*/
    var castContent = document.createElement('div');
    castContent.className = 'xsmall';
    if (credits.cast && credits.cast.length > 0) {
      for (var i = 0; i < Math.min(6, credits.cast.length); i++) {
        castContent.innerHTML += credits.cast[i].name + '
';
      }
    }
    creditsContainer.appendChild(castContent);

    // Set up details => credits director
    var directorContainer = document.createElement('div');
    var directorHeader = document.createElement('span');
    directorHeader.className = 'xsmall dimmed';
    directorHeader.innerHTML = ', ' + this.translate('DIRECTOR');
    var directorContent = document.createElement('span');
    directorContent.className = 'xsmall';
    if (credits.crew && credits.crew.length > 0) {
      for (var i = 0; i <= credits.crew.length - 1; i++) {
        if (credits.crew[i].job === 'Director') {
          directorContent.innerHTML = credits.crew[i].name;
        };
      };
    }
    directorContainer.appendChild(directorContent);
    directorContainer.appendChild(directorHeader);
    creditsContainer.appendChild(directorContainer);

    // Set up details => genres
    if (movie.genres) {
      var genres = '';
      for (var i = 0; i <= movie.genres.length -1; i++) {
        genres += movie.genres[i].name;
        if (i < movie.genres.length - 1) {
          genres += ', ';
        }
      }
    }

    // Add all details
    detailsContainer.appendChild(detailsRatingContainer);
    detailsContainer.appendChild(runtimeContent);
    detailsContainer.appendChild(creditsContainer);

    // Set up details => table
    var detailsTable = document.createElement('table');
    detailsTable.className = 'xsMarginTop';
    var tableRow = document.createElement('tr');
    var imageCell = document.createElement('td');
    var textCell = document.createElement('td');
    textCell.className = 'top';
    imageCell.className = 'top';

    imageCell.appendChild(image);
    textCell.appendChild(detailsContainer);
    if (this.data.position.toLowerCase().indexOf('right') < 0) {
      tableRow.appendChild(imageCell);
      textCell.className = 'top left';
      tableRow.appendChild(textCell);
    } else {
      tableRow.appendChild(textCell);
      tableRow.appendChild(imageCell);
    };
    detailsTable.appendChild(tableRow);

    // Set up entire view in container
    posterWrapper.appendChild(title);
    posterWrapper.appendChild(tagline);
    posterWrapper.appendChild(detailsTable);
    if (this.config.includeMoviePlot) {
      posterWrapper.appendChild(plot);
    }

    return posterWrapper;
  },

  /*
   * HELPER
   */
  prepareDomUpdate: function(movies) {
    switch (this.config.interface) {
      case 'list':
        // If pagination enabled, turn to DOM update scheduler, else just display all movies
        if (this.config.moviesPerPage > 0) {
          this.scheduleDomUpdatesForList(movies);
        } else {
          this.moviesToDisplay = movies
          this.updateDom();
        }
        break;
      case 'poster':
        this.scheduleDomUpdatesForPoster(movies);
      default:
        break;
    }
  },

  scheduleDomUpdatesForList: function(movies) {
    var self = this;
    var pages = Math.ceil(movies.length / self.config.moviesPerPage);
    self.movieChunks = [];
    self.nextIndex = 0;

    for (var i = 0; i < pages; i++) {
      self.movieChunks.push(movies.splice(0, self.config.moviesPerPage))
    }

    self.moviesToDisplay = self.movieChunks[self.nextIndex];
    self.nextIndex++;
    self.updateDom();

    setInterval(function() {
      self.moviesToDisplay = self.movieChunks[self.nextIndex];
      self.nextIndex++;

      // reset index if end is reached
      if (self.nextIndex > self.movieChunks.length - 1) {
        self.nextIndex = 0;
      }

      self.updateDom(self.config.animationSpeed);
    }, this.config.pageChangeInterval);
  },

  scheduleDomUpdatesForPoster: function(movies) {
    var self = this;
    self.nextIndex = 0;
    self.sendSocketNotification('FETCH_MOVIE_ID', {
      movieId: movies[self.nextIndex].id,
      apiKey: self.config.apiKey,
      language: self.config.language,
      config: self.config
    });
    self.nextIndex++;

    setInterval(function() {
      self.sendSocketNotification('FETCH_MOVIE_ID', {
        movieId: movies[self.nextIndex].id,
        apiKey: self.config.apiKey,
        language: self.config.language,
        config: self.config
      });
      self.nextIndex++;

      // reset when end of array is reached
      if (self.nextIndex > movies.length - 1) {
        self.nextIndex = 0;
      }
    }, this.config.pageChangeInterval);
  },
});
<|endoftext|>


<commit_before>"use strict";

var _ = require("./lodash"),
    addLabel = require("./label/add-label"),
    addSubnodes = require("./add-subnodes"),
    util = require("./util"),
    d3 = require("./d3");

module.exports = createNodes;

function createNodes(selection, g, shapes) {
  var simpleNodes = g.nodes().filter(function(v) { return !util.isSubgraph(g, v); });
  var svgNodes = selection.selectAll("g.node")
    .data(simpleNodes, function(v) { return v; })
    .classed("update", true);

  svgNodes.selectAll("*").remove();
  svgNodes.enter()
    .append("g")
      .attr("class", "node")
      .style("opacity", 0);
  svgNodes.each(function(v) {
    var subnodeGroup, subnodeDom;
    var subnodeBBox = {width: 0, height: 0};
    var node = g.node(v),
        thisGroup = d3.select(this),
        labelGroup = thisGroup.append("g").attr("class", "label"),
        labelDom = addLabel(labelGroup, node),
        shape = shapes[node.shape],
        bbox = _.pick(labelDom.node().getBBox(), "width", "height");

    node.elem = this;

    // If the node has subnodes, add them to the node and modify the bbox.
    if (node.subnodes && node.subnodes.length) {
      subnodeGroup = addSubnodes(thisGroup, node);

      // Calculate the box surrounding the subnode elements. Adjust bbox to hold them.
      subnodeBBox = _.pick(subnodeGroup.node().getBBox(), "width", "height");
      bbox.height += subnodeBBox.height;
      bbox.width = Math.max(bbox.width, subnodeBBox.width);
    } else {
      // The node doesn't have subnodes.
      subnodeGroup = subnodeDom = null;
      subnodeBBox.width = subnodeBBox.height = 0;
    }

    if (node.id) { thisGroup.attr("id", node.id); }
    if (node.labelId) { labelGroup.attr("id", node.labelId); }
    util.applyClass(thisGroup, node["class"],
      (thisGroup.classed("update") ? "update " : "") + "node");

    if (_.has(node, "width")) { bbox.width = node.width; }
    if (_.has(node, "height")) { bbox.height = node.height; }

    bbox.width += node.paddingLeft + node.paddingRight;
    bbox.height += node.paddingTop + node.paddingBottom;
    labelGroup.attr("transform", "translate(" +
      ((node.paddingLeft - node.paddingRight) / 2) + "," +
      ((node.paddingTop - node.paddingBottom - subnodeBBox.height) / 2) + ")");
    if (subnodeGroup) {
      subnodeGroup.attr("transform", "translate(" +
        -((subnodeBBox.width / 2) - 10) + "," +
        ((node.paddingTop - node.paddingBottom + subnodeBBox.height) / 2) + ")");
    }

    var shapeSvg = shape(d3.select(this), bbox, node);
    util.applyStyle(shapeSvg, node.style);

    var shapeBBox = shapeSvg.node().getBBox();
    node.width = shapeBBox.width;
    node.height = shapeBBox.height;

    // If the tooltip is open, render it
    if (node.tooltip) {
      d3.select(this).append("rect")
        .attr("x", 0)
        .attr("y", "20")
        .attr("width", 100)
        .attr("height", 30);
    }
  });

  util.applyTransition(svgNodes.exit(), g)
    .style("opacity", 0)
    .remove();

  return svgNodes;
}
<commit_msg>Try adding to the file node group<commit_after>"use strict";

var _ = require("./lodash"),
    addLabel = require("./label/add-label"),
    addSubnodes = require("./add-subnodes"),
    util = require("./util"),
    d3 = require("./d3");

module.exports = createNodes;

function createNodes(selection, g, shapes) {
  var simpleNodes = g.nodes().filter(function(v) { return !util.isSubgraph(g, v); });
  var svgNodes = selection.selectAll("g.node")
    .data(simpleNodes, function(v) { return v; })
    .classed("update", true);

  svgNodes.selectAll("*").remove();
  svgNodes.enter()
    .append("g")
      .attr("class", "node")
      .style("opacity", 0);
  svgNodes.each(function(v) {
    var subnodeGroup, subnodeDom;
    var subnodeBBox = {width: 0, height: 0};
    var node = g.node(v),
        thisGroup = d3.select(this),
        labelGroup = thisGroup.append("g").attr("class", "label"),
        labelDom = addLabel(labelGroup, node),
        shape = shapes[node.shape],
        bbox = _.pick(labelDom.node().getBBox(), "width", "height");

    node.elem = this;

    // If the node has subnodes, add them to the node and modify the bbox.
    if (node.subnodes && node.subnodes.length) {
      subnodeGroup = addSubnodes(thisGroup, node);

      // Calculate the box surrounding the subnode elements. Adjust bbox to hold them.
      subnodeBBox = _.pick(subnodeGroup.node().getBBox(), "width", "height");
      bbox.height += subnodeBBox.height;
      bbox.width = Math.max(bbox.width, subnodeBBox.width);

      // If the tooltip is open, render it
      if (_(node.subnodes).any(subnode => subnode.tooltip)) {
        thisGroup.append("rect")
          .attr("x", 0)
          .attr("y", "20")
          .attr("width", 100)
          .attr("height", 30);
      }
    } else {
      // The node doesn't have subnodes.
      subnodeGroup = subnodeDom = null;
      subnodeBBox.width = subnodeBBox.height = 0;
    }

    if (node.id) { thisGroup.attr("id", node.id); }
    if (node.labelId) { labelGroup.attr("id", node.labelId); }
    util.applyClass(thisGroup, node["class"],
      (thisGroup.classed("update") ? "update " : "") + "node");

    if (_.has(node, "width")) { bbox.width = node.width; }
    if (_.has(node, "height")) { bbox.height = node.height; }

    bbox.width += node.paddingLeft + node.paddingRight;
    bbox.height += node.paddingTop + node.paddingBottom;
    labelGroup.attr("transform", "translate(" +
      ((node.paddingLeft - node.paddingRight) / 2) + "," +
      ((node.paddingTop - node.paddingBottom - subnodeBBox.height) / 2) + ")");
    if (subnodeGroup) {
      subnodeGroup.attr("transform", "translate(" +
        -((subnodeBBox.width / 2) - 10) + "," +
        ((node.paddingTop - node.paddingBottom + subnodeBBox.height) / 2) + ")");
    }

    var shapeSvg = shape(d3.select(this), bbox, node);
    util.applyStyle(shapeSvg, node.style);

    var shapeBBox = shapeSvg.node().getBBox();
    node.width = shapeBBox.width;
    node.height = shapeBBox.height;
  });

  util.applyTransition(svgNodes.exit(), g)
    .style("opacity", 0)
    .remove();

  return svgNodes;
}
<|endoftext|>


<commit_before>/**
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*global exports:true*/
"use strict";

var Syntax = require('esprima').Syntax;
var catchup = require('../lib/utils').catchup;
var append = require('../lib/utils').append;
var getDocblock = require('../lib/utils').getDocblock;

/**
 * Transforms the following:
 *
 * var MyComponent = React.createClass({
 *    render: ...
 * });
 *
 * into:
 *
 * var MyComponent = React.createClass({
 *    displayName: 'MyComponent',
 *    render: ...
 * });
 */
function visitReactDisplayName(traverse, object, path, state) {
  object.declarations.forEach(function(dec) {
    if (dec.type === Syntax.VariableDeclarator &&
        dec.id.type === Syntax.Identifier &&
        dec.init &&
        dec.init.type === Syntax.CallExpression &&
        dec.init.callee.type === Syntax.MemberExpression &&
        dec.init.callee.object.type === Syntax.Identifier &&
        dec.init.callee.object.name === 'React' &&
        dec.init.callee.property.type === Syntax.Identifier &&
        dec.init.callee.property.name === 'createClass' &&
        dec.init['arguments'].length === 1 &&
        dec.init['arguments'][0].type === Syntax.ObjectExpression) {

      var displayName = dec.id.name;
      catchup(dec.init['arguments'][0].range[0] + 1, state);
      append("displayName: '" + displayName + "',", state);
    }
  });
}

/**
 * Will only run on @jsx files for now.
 */
visitReactDisplayName.test = function(object, path, state) {
  return object.type === Syntax.VariableDeclaration && !!getDocblock(state).jsx;
};

exports.visitReactDisplayName = visitReactDisplayName;
<commit_msg>Fixing Bug in JSX transformer<commit_after>/**
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*global exports:true*/
"use strict";

var Syntax = require('esprima').Syntax;
var catchup = require('../lib/utils').catchup;
var append = require('../lib/utils').append;
var getDocblock = require('../lib/utils').getDocblock;

/**
 * Transforms the following:
 *
 * var MyComponent = React.createClass({
 *    render: ...
 * });
 *
 * into:
 *
 * var MyComponent = React.createClass({
 *    displayName: 'MyComponent',
 *    render: ...
 * });
 */
function visitReactDisplayName(traverse, object, path, state) {
  if (object.type === Syntax.VariableDeclarator &&
      object.id.type === Syntax.Identifier &&
      object.init &&
      object.init.type === Syntax.CallExpression &&
      object.init.callee.type === Syntax.MemberExpression &&
      object.init.callee.object.type === Syntax.Identifier &&
      object.init.callee.object.name === 'React' &&
      object.init.callee.property.type === Syntax.Identifier &&
      object.init.callee.property.name === 'createClass' &&
      object.init['arguments'].length === 1 &&
      object.init['arguments'][0].type === Syntax.ObjectExpression) {

    var displayName = object.id.name;
    catchup(object.init['arguments'][0].range[0] + 1, state);
    append("displayName: '" + displayName + "',", state);
  }
}

/**
 * Will only run on @jsx files for now.
 */
visitReactDisplayName.test = function(object, path, state) {
  return object.type === Syntax.VariableDeclarator && !!getDocblock(state).jsx;
};

exports.visitReactDisplayName = visitReactDisplayName;
<|endoftext|>


<commit_before>/* @flow */

import type {
  Screen,
  Location,
  History,
  Transition,
  Listener,
  Unlisten,
  Router
} from './types'

export default function createRouter(history: History, transition: Transition): Router {
  var listeners: Array<Listener<[Location, Screen]>> = []
  var queue: Array<Location> = []
  var waiting: Array<Function> = []
  var inProcess: boolean = false

  function listen(listener: Listener<[Location, Screen]>): Unlisten {
    listeners.push(listener)

    return function unlisten(): void {
      listeners = listeners.filter(l => l !== listener)
    }
  }

  function navigateTo(location: Location): Promise<void> {
    return transition(location)
      .then(function (screen: ?Screen): ?Screen {
        listeners.forEach(listener => {
          if (screen) {
            listener([location, screen])
          }
        })
      })
  }

  function processQueue() {
    if (inProcess) {
      return
    }

    if (queue.length === 0) {
      waiting.forEach(resolve => resolve())
      waiting = []
      return
    }

    var location: Location = queue.shift()
    inProcess = true
    navigateTo(location)
      .then(() => {
        inProcess = false
        processQueue()
      })
      .catch((error) => {
        console.error(error.stack)
        inProcess = false
        processQueue()
      })
  }

  function waitQueue(): Promise<void> {
    return new Promise(resolve => {
      waiting.push(resolve)
    })
  }

  history.listen(location => {
    // Reset the queue to skip unreachable transitions
    queue = [location]
    processQueue()
  })

  return {
    listen,
    waitQueue
  }
}
<commit_msg>Fix waitQueue<commit_after>/* @flow */

import type {
  Screen,
  Location,
  History,
  Transition,
  Listener,
  Unlisten,
  Router
} from './types'

export default function createRouter(history: History, transition: Transition): Router {
  var listeners: Array<Listener<[Location, Screen]>> = []
  var queue: Array<Location> = []
  var waiting: Array<Function> = []
  var inProcess: boolean = false

  function listen(listener: Listener<[Location, Screen]>): Unlisten {
    listeners.push(listener)

    return function unlisten(): void {
      listeners = listeners.filter(l => l !== listener)
    }
  }

  function navigateTo(location: Location): Promise<void> {
    return transition(location)
      .then(function (screen: ?Screen): ?Screen {
        listeners.forEach(listener => {
          if (screen) {
            listener([location, screen])
          }
        })
      })
  }

  function processQueue() {
    if (inProcess) {
      return
    }

    if (queue.length === 0) {
      waiting.forEach(resolve => resolve())
      waiting = []
      return
    }

    var location: Location = queue.shift()
    inProcess = true
    navigateTo(location)
      .then(() => {
        inProcess = false
        processQueue()
      })
      .catch((error) => {
        console.error(error.stack)
        inProcess = false
        processQueue()
      })
  }

  function waitQueue(): Promise<void> {
    return new Promise(resolve => {
      if (inProcess) {
        waiting.push(resolve)
      } else {
        resolve()
      }
    })
  }

  history.listen(location => {
    // Reset the queue to skip unreachable transitions
    queue = [location]
    processQueue()
  })

  return {
    listen,
    waitQueue
  }
}
<|endoftext|>


<commit_before>var util = require("./util"),
    _ = require("lodash"),
    when = require("when");

//TODO: break down into local/remote cruds

module.exports = function(app, resources,actionNames){
  var crud = {
    fancy: {},
    simple: {}
  };

  if(_.isObject(app)){
    initWithLocalFortune();
  }else{
    initWithRemoteFortune();
  }

  //check if the query is for a whole, possibly filtered collection
  function isCollectionQuery(query){
    return ((query === null) || (query === undefined) || _.isPlainObject(query));
  };

  //check if the query is for a single document only
  function isSingleDocQuery(query,name){
    if(name === "create"){
      return !_.isArray(query);
    }else{
      return _.isString(query) || _.isNumber(query);
    }
  }

  function wrapDirectCall(method, resource, request, options){
    options = options || {};
    return function(cb){
      var dispatch = function(){
        return app.direct[method](resource, request);
      };

      if(!cb){
        return dispatch();
      }else{
        return cb({
          resource: resource,
          method: method,
          request: request,
          parentRequest: options.parentRequest
        }, dispatch);
      }
    };
  };

  function toDirectRequest(query, options, resourceName, data){
    options = options || {};
    //REFACTOR: bit ugly this extend...
    request = _.extend({query: {}, params: {}}, _.omit(options, "linked"));

    if(isCollectionQuery(query)){
      if(query) request.query.filter = query;
    }else{
      request.params.id = _.isArray(query) ? query.join(",") : query;
    }

    if(data){
      data =  _.isArray(data) ? data : [data];

      if(resourceName){
        (request.body = {})[resourceName] = data;
      }else{
        request.body = data;
      }

      if(options.linked) request.body.linked = options.linked;
    }

    _.each(["include", "fields"], function(keyword){
      if(request[keyword]){
        request.query[keyword] = request[keyword];
        delete request[keyword];
      }

      var kArgs = request.query[keyword];

      if(kArgs && _.isArray(kArgs)){
        request.query[keyword] = kArgs.join(",");
      }
    });

    return request;
  }

  function makeAction(name, resource){
    /*NOTE: in all of these, 'options' should thought of as fortune-client settings rather than
     * something that is meant to go through directly into fortune direct calls
     */
    return {
      get: function(query,options){
        return wrapDirectCall(name, resource.route, toDirectRequest(query,options),options);
      },
      destroy: function(query,options){
        return wrapDirectCall(name, resource.route, toDirectRequest(query,options),options);
      },
      create: function(data, options){
        if(!(_.isPlainObject(data)||_.isArray(data))){
          throw new Error("First argument must be an object or an array.");
        }
        return wrapDirectCall(name,
                              resource.route,
                              toDirectRequest(null, options, resource.route,data),
                              options);
      },
      replace: function(id, data, options){
        if(isCollectionQuery(id)) throw new Error("Collection queries not allowed in replace!");

        return wrapDirectCall(name,
                              resource.route,
                              toDirectRequest(id,options,resource.route, data),
                              options);
      },
      update: function(id, data, options){
        if(isCollectionQuery(id)) throw new Error("Collection queries not allowed in update!");
        return wrapDirectCall(name, resource.route, toDirectRequest(id,options,null,data),options);
      }
    }[name];
  }

  function makePluralAction(name, resource){
    var action = makeAction(name,resource);

    return function(query){
      if(isSingleDocQuery(query)){
        console.warn("Single document operations with pluralised actions are deprecated. "
                     + "Use the singularised form.");
      }
      return action.apply(null,arguments);
    };
  };

  function makeSingularAction(name,resource){
    var action = makeAction(name, resource);

    return function(query){
      if(!isSingleDocQuery(query,name)){
        throw new Error("Operating on a collection with a singularised action. "
                        + "Use the pluralised form.");
      }

      return action.apply(null,arguments);
    };
  }

  function initWithLocalFortune(){
    _.each(resources, function(resource){
      var plural = util.toCapitalisedCamelCase(resource.route),
          singular = util.toCapitalisedCamelCase(resource.name);

      _.each(actionNames, function(name){
        (crud.simple[name] = crud.simple[name] || {})[resource.route] = makeAction(name,resource);

        if(plural !== singular){
          crud.fancy[name + plural] = makePluralAction(name,resource);
          crud.fancy[name + singular] = makeSingularAction(name,resource);
        }else{
          crud.fancy[name + plural] = crud.simple[name][resource.route];
        }
      });
    });

    //OPTIMISE: calling makeAction on every request looks suboptimal

    _.each(actionNames, function(name){
      crud[name] = function(route){
        return makeAction(name, {route: route}).apply(crud, _.rest(arguments));
      };
    });
  }

  function initWithRemoteFortune(){
    throw new Error("initWithRemoteFortune not implemented");
  }

  return crud;
};
<commit_msg>Proxy non-destructive deletes special keys<commit_after>var util = require("./util"),
    _ = require("lodash"),
    when = require("when");

//TODO: break down into local/remote cruds

module.exports = function(app, resources,actionNames){
  var crud = {
    fancy: {},
    simple: {}
  };

  if(_.isObject(app)){
    initWithLocalFortune();
  }else{
    initWithRemoteFortune();
  }

  //check if the query is for a whole, possibly filtered collection
  function isCollectionQuery(query){
    return ((query === null) || (query === undefined) || _.isPlainObject(query));
  };

  //check if the query is for a single document only
  function isSingleDocQuery(query,name){
    if(name === "create"){
      return !_.isArray(query);
    }else{
      return _.isString(query) || _.isNumber(query);
    }
  }

  function wrapDirectCall(method, resource, request, options){
    options = options || {};
    return function(cb){
      var dispatch = function(){
        return app.direct[method](resource, request);
      };

      if(!cb){
        return dispatch();
      }else{
        return cb({
          resource: resource,
          method: method,
          request: request,
          parentRequest: options.parentRequest
        }, dispatch);
      }
    };
  };

  function toDirectRequest(query, options, resourceName, data){
    options = options || {};
    //REFACTOR: bit ugly this extend...
    var request = _.extend({query: {}, params: {}}, _.omit(options, "linked"));

    if(isCollectionQuery(query)){
      if(query) request.query.filter = query;
    }else{
      request.params.id = _.isArray(query) ? query.join(",") : query;
    }

    if(data){
      data =  _.isArray(data) ? data : [data];

      if(resourceName){
        (request.body = {})[resourceName] = data;
      }else{
        request.body = data;
      }

      if(options.linked) request.body.linked = options.linked;
    }

    if (!_.isUndefined(request.includeDeleted)){
      request.query.includeDeleted = true;
    }
    if (!_.isUndefined(request.destroy){
      request.query.destroy = true;
    };

    _.each(["include", "fields"], function(keyword){
      if(request[keyword]){
        request.query[keyword] = request[keyword];
        delete request[keyword];
      }

      var kArgs = request.query[keyword];

      if(kArgs && _.isArray(kArgs)){
        request.query[keyword] = kArgs.join(",");
      }
    });

    return request;
  }

  function makeAction(name, resource){
    /*NOTE: in all of these, 'options' should thought of as fortune-client settings rather than
     * something that is meant to go through directly into fortune direct calls
     */
    return {
      get: function(query,options){
        return wrapDirectCall(name, resource.route, toDirectRequest(query,options),options);
      },
      destroy: function(query,options){
        return wrapDirectCall(name, resource.route, toDirectRequest(query,options),options);
      },
      create: function(data, options){
        if(!(_.isPlainObject(data)||_.isArray(data))){
          throw new Error("First argument must be an object or an array.");
        }
        return wrapDirectCall(name,
                              resource.route,
                              toDirectRequest(null, options, resource.route,data),
                              options);
      },
      replace: function(id, data, options){
        if(isCollectionQuery(id)) throw new Error("Collection queries not allowed in replace!");

        return wrapDirectCall(name,
                              resource.route,
                              toDirectRequest(id,options,resource.route, data),
                              options);
      },
      update: function(id, data, options){
        if(isCollectionQuery(id)) throw new Error("Collection queries not allowed in update!");
        return wrapDirectCall(name, resource.route, toDirectRequest(id,options,null,data),options);
      }
    }[name];
  }

  function makePluralAction(name, resource){
    var action = makeAction(name,resource);

    return function(query){
      if(isSingleDocQuery(query)){
        console.warn("Single document operations with pluralised actions are deprecated. "
                     + "Use the singularised form.");
      }
      return action.apply(null,arguments);
    };
  };

  function makeSingularAction(name,resource){
    var action = makeAction(name, resource);

    return function(query){
      if(!isSingleDocQuery(query,name)){
        throw new Error("Operating on a collection with a singularised action. "
                        + "Use the pluralised form.");
      }

      return action.apply(null,arguments);
    };
  }

  function initWithLocalFortune(){
    _.each(resources, function(resource){
      var plural = util.toCapitalisedCamelCase(resource.route),
          singular = util.toCapitalisedCamelCase(resource.name);

      _.each(actionNames, function(name){
        (crud.simple[name] = crud.simple[name] || {})[resource.route] = makeAction(name,resource);

        if(plural !== singular){
          crud.fancy[name + plural] = makePluralAction(name,resource);
          crud.fancy[name + singular] = makeSingularAction(name,resource);
        }else{
          crud.fancy[name + plural] = crud.simple[name][resource.route];
        }
      });
    });

    //OPTIMISE: calling makeAction on every request looks suboptimal

    _.each(actionNames, function(name){
      crud[name] = function(route){
        return makeAction(name, {route: route}).apply(crud, _.rest(arguments));
      };
    });
  }

  function initWithRemoteFortune(){
    throw new Error("initWithRemoteFortune not implemented");
  }

  return crud;
};
<|endoftext|>