<commit_before>/******************************************
 ****** Helpers
 ******************************************/

/**
 * @private
 * Helper function which will assign principal[key] to secondary[key] if
 * defined, otherwise to defaultValue.
 */
function setParam(principal, secondary, key, defaultValue) {
	if(typeof(secondary[key]) == 'undefined') {
		principal[key] = defaultValue;
	} else {
		principal[key] = secondary[key];
	}
}

/**
 * @private
 * Helper function which converts ms to years
 * @param {Integer} ms
 * @return {Integer} years
 */
function msToYears(ms) {
  return ms / 3.15569e10;
}

/**
 * @private
 * Helper function which takes a string with '%%' as placeholders. Replaces
 * ith placeholder with (i+1)th param (first being the string)
 * @param {String} str with '%%' placeholders
 * @param {...*} [items] items to replace placeholders with
 * @return {String}
 */
function sprintf(str) {
  var args = arguments;
  var i = 1;
  return str.replace(/%%/g, function() { return args[i++];});
}

/**
 * @private
 * returns the end timestamp, or, if its undefined, present timestamp
 * @param {object} item
 * @returns {timestamp}
 */
function getEndTime(item) {
	return !item.end && item.end !== 0 ? (new Date()).getTime() : item.end;
}

/******************************************
 ****** Main
 ******************************************/

/**
 * @class
 * @param {Array<Object>} items items to plot on timeline. Objects must have name, and
 * start, defined. 'end' is optional; if undefined, assumed the present.
 * @param {Object} opts config object
 *   @config {Integer}   [widthOfYear]
 *   @config {Integer}   [itemHeight]
 *   @config {Integer}   [itemSpacing] @todo
 *   @config {Timestamp} [startDate] @todo
 *   @config {Timestamp} [endDate] @todo
 *   @config {Integer}   [padding]
 *   @config {Integer}   [axisLabelSize] @todo
 */
function Timeline(items, opts) {
  this.items = items;
  opts = opts || {};

  setParam(this, opts, 'widthOfYear',                     20); //px
  setParam(this, opts, 'itemHeight',                      20); //px
  setParam(this, opts, 'itemSpacing',                      2); //px
  setParam(this, opts, 'startDate',                        0);
  setParam(this, opts, 'endDate',     (new Date()).getTime()); // present
  setParam(this, opts, 'padding',                          5);
  setParam(this, opts, 'axisLabelSize',                   20); //px
}

// getters/setters
Object.defineProperty(Timeline.prototype, 'canvasWidth',
  { get: function() { return this.gridWidth + 2*this.padding; }});
Object.defineProperty(Timeline.prototype, 'canvasHeight',
  { get: function() { return this.gridHeight +  2*this.padding + this.axisLabelSize; }});
Object.defineProperty(Timeline.prototype, 'gridStartPoint',
  { get: function() { return {
    x: this.padding,
    y: 0
  }}});

/**
 * Tells if the timeline has been drawn yet.
 * @return {Boolean}
 */
Timeline.prototype.isDrawn = function() {
	return !!this.svg;
};

/** Creates the timeline and appends it to HTMLContainer
 * @param{HTMLElement} HTMLContainer
 */
Timeline.prototype.draw = function(HTMLContainer) {
  this.container = HTMLContainer;

	this.gridWidth = 0;
	this.gridHeight = 0;

	// scale
	var timeMin = d3.min(this.items, function(d) { return d.start; });
	var timeMax = d3.max(this.items, function(d) { return getEndTime(d); });
	this.gridWidth = msToYears(timeMax - timeMin) * this.widthOfYear;
  this.xScale = d3.time.scale()
		.domain([timeMin, timeMax])
		.range([this.padding, this.padding + this.gridWidth]);

	// the svg
  this.svg = d3.select(this.container).append('svg')
    .classed('timeline', true);

	// x axis
	this._xAxis = d3.svg.axis()
		.scale(this.xScale)
    .orient("bottom")
	  .tickPadding(4);
	this._xAxisGroup = this.svg.append('g').classed('x axis', true)
		.call(this._xAxis);

	// grid
	this._gridAxis = d3.svg.axis()
		.scale(this.xScale)
		.tickFormat('')
    .orient("bottom")
		.innerTickSize(-1*this.gridHeight);
	this._gridGroup = this.svg.append('g').classed('grid', true)
		.call(this._gridAxis);

	// the items
	this.svg._itemsGroup = this.svg.append('g').classed('items', true);
	// these rows store the items in each row of the timeline, sorted. Used to
	// pack events in the _drawItems method.
	this.rows = [];
	this.nextRow = 0;

  this._drawItems();
};

/**Draws the individual items
 * @private
 */
Timeline.prototype._drawItems = function(items) {
  var _this = this;

	// Group
  var groups = this.svg._itemsGroup.selectAll('g')
    .data(this.items)
    .enter()
    .append('g')
    .attr({
			class: 'item'
		});

	// Rect
  groups.append('rect')
    .attr({
      x:      function(d) {return (_this.xScale(getEndTime(d)) - _this.xScale(d.start))/2 },
      y:      0,
      width:  0,
      height: _this.itemHeight,
    })
    // .transition().duration(80)
    // .delay(function(d, i) { return 60*Math.log(i); })
    .attr({
      x: 0,
      width: function(d) {return _this.xScale(getEndTime(d)) - _this.xScale(d.start)}
    });

	// Item text
  groups.append('text')
    .attr({
      x: function(d) {return (_this.xScale(getEndTime(d)) - _this.xScale(d.start))/2 },
      y: _this.itemHeight / 2
    })
		.append('tspan')
		.text(function(d) { return d.name; })
    .style({
      fill: '#000',
      'text-anchor': 'middle',
      'alignment-baseline': 'central',
      opacity: 0
    })
    // .transition().duration(80).delay(function(d, i) { return 60*Math.log(i); })
    .style('opacity', 1);

		// position the group
		groups.attr({
      transform: function(d, i) {
				var defaultY = _this.gridStartPoint.y - (_this.nextRow+1) * _this.itemHeight;
				var finalY = defaultY;
				var bbox = this.getBBox();
				var xRange = {
					start: _this.xScale(d.start) + bbox.x,
					end: _this.xScale(d.start) + bbox.x + bbox.width
				};

				// first item; just add it
				if (_this.nextRow === 0) {
					finalY = defaultY;
					_this.rows[_this.nextRow] = [ xRange ];
					_this.nextRow++;
				} else {
					var rowWithRoom = -1;
					var indexInRow = -1;

					// starting from row 0, check if there is room.
					for(var i = 0; i < _this.nextRow; ++i) {
						// check left
						if (xRange.end < _this.rows[i][0].start) {
							rowWithRoom = i;
							indexInRow = 0;
							break;
						}
						// check right
						if (xRange.start > _this.rows[i][_this.rows[i].length - 1].end) {
							rowWithRoom = i;
							indexInRow = _this.rows[i].length;
							break;
						}
						// check middle
						for(var j = 0; j < _this.rows[i].length - 1; j++) {
							if (_this.rows[i][j].end < xRange.start && _this.rows[i][j+1].start > xRange.end) {
								rowWithRoom = i;
								indexInRow = j+1;
								break;
							}
						}

						if (rowWithRoom !== -1) break;
					}

					if (rowWithRoom != -1) {
						// success! put it here
						finalY = _this.gridStartPoint.y - (rowWithRoom+1) * _this.itemHeight;

						// add it to row (in correct position)
						_this.rows[rowWithRoom] = _this.rows[rowWithRoom].slice(0, indexInRow)
							.concat(xRange)
							.concat(_this.rows[rowWithRoom].slice(indexInRow));
					} else {
						finalY = defaultY;
						_this.rows[_this.nextRow] = [ xRange ];
						_this.nextRow++;
					}
				}

				return sprintf('translate(%%, %%)', _this.xScale(d.start), finalY);
			}
    });

		// Add anchors (where appropriate)
		groups.each(function(d) {
			if (d.href) {
				var group = d3.select(this);
				// move all the groups children into the anchor
				var anchor = group.append('a')
				.attr({
					'class': 'main-link',
					'xlink:href': function(d) { return d.href; },
					'xlink:show': 'new'
				});

				var anchorNode = anchor.node();

				var children = this.children;
				while(children.length > 1) {
					anchorNode.appendChild(children[0]);
				}
			}
		});

		// the height has probably changed because of stacking; should shrink doc
		this.gridHeight = this.svg._itemsGroup.node().getBBox().height;
		this._gridAxis.innerTickSize(-1*this.gridHeight); // FIXME: put me in better place T_T
		this._gridGroup.call(this._gridAxis);
		this._updateSVGSize();
};

/**
 * Adds the supplied items to the internal array and the chart. Updates chart's
 * axes to ensure the items fit. Use if adding a large number of items, to avoid
 * updating the axes a lot. Otherwise just add the array of items as per usual.
 * @param {array<object>} itemsArr items to add
 * @return {Timeline} @this
 */
Timeline.prototype.addItems = function(itemsArr) {
  if (!this.isDrawn()) {
    this.items = this.items.concat(itemsArr);
    return this;
  }

	var currentDomain = this.xScale.domain();
	var newItemsDomain = [
		d3.min(itemsArr, function(d) { return d.start; }),
		d3.max(itemsArr, function(d) { return getEndTime(d); })
	];

	var mustChangeDomain = (newItemsDomain[0] < currentDomain[0])
		|| (newItemsDomain[1] > currentDomain[1]);

	if (mustChangeDomain) {
		// change domain :)
		var newDomain = [
			Math.min(newItemsDomain[0], currentDomain[0]),
			Math.max(newItemsDomain[1], currentDomain[1])
		];
		this.xScale.domain(newDomain);
	}

	this.items = this.items.concat(itemsArr);

  // update xScale Range
  this.gridWidth = msToYears(this.xScale.domain()[1] - this.xScale.domain()[0]) * this.widthOfYear;
  this.xScale.range([this.padding, this.padding + this.gridWidth]);

  // update axes
  this._xAxisGroup.call(this._xAxis);
  this._gridGroup.call(this._gridAxis);

  // draw the new items
  this._drawItems();
};

Timeline.prototype._updateSVGSize = function() {
  this.svg.attr({
    width: this.canvasWidth,
    height: this.canvasHeight,
    viewBox: sprintf("0 %% %% %%", -1*this.gridHeight, this.canvasWidth, this.canvasHeight)
  });
};
<commit_msg>fix: items shifted when scale changes<commit_after>/******************************************
 ****** Helpers
 ******************************************/

/**
 * @private
 * Helper function which will assign principal[key] to secondary[key] if
 * defined, otherwise to defaultValue.
 */
function setParam(principal, secondary, key, defaultValue) {
	if(typeof(secondary[key]) == 'undefined') {
		principal[key] = defaultValue;
	} else {
		principal[key] = secondary[key];
	}
}

/**
 * @private
 * Helper function which converts ms to years
 * @param {Integer} ms
 * @return {Integer} years
 */
function msToYears(ms) {
  return ms / 3.15569e10;
}

/**
 * @private
 * Helper function which takes a string with '%%' as placeholders. Replaces
 * ith placeholder with (i+1)th param (first being the string)
 * @param {String} str with '%%' placeholders
 * @param {...*} [items] items to replace placeholders with
 * @return {String}
 */
function sprintf(str) {
  var args = arguments;
  var i = 1;
  return str.replace(/%%/g, function() { return args[i++];});
}

/**
 * @private
 * returns the end timestamp, or, if its undefined, present timestamp
 * @param {object} item
 * @returns {timestamp}
 */
function getEndTime(item) {
	return !item.end && item.end !== 0 ? (new Date()).getTime() : item.end;
}

/******************************************
 ****** Main
 ******************************************/

/**
 * @class
 * @param {Array<Object>} items items to plot on timeline. Objects must have name, and
 * start, defined. 'end' is optional; if undefined, assumed the present.
 * @param {Object} opts config object
 *   @config {Integer}   [widthOfYear]
 *   @config {Integer}   [itemHeight]
 *   @config {Integer}   [itemSpacing] @todo
 *   @config {Timestamp} [startDate] @todo
 *   @config {Timestamp} [endDate] @todo
 *   @config {Integer}   [padding]
 *   @config {Integer}   [axisLabelSize] @todo
 */
function Timeline(items, opts) {
  this.items = items;
  opts = opts || {};

  setParam(this, opts, 'widthOfYear',                     20); //px
  setParam(this, opts, 'itemHeight',                      20); //px
  setParam(this, opts, 'itemSpacing',                      2); //px
  setParam(this, opts, 'startDate',                        0);
  setParam(this, opts, 'endDate',     (new Date()).getTime()); // present
  setParam(this, opts, 'padding',                          5);
  setParam(this, opts, 'axisLabelSize',                   20); //px
}

// getters/setters
Object.defineProperty(Timeline.prototype, 'canvasWidth',
  { get: function() { return this.gridWidth + 2*this.padding; }});
Object.defineProperty(Timeline.prototype, 'canvasHeight',
  { get: function() { return this.gridHeight +  2*this.padding + this.axisLabelSize; }});
Object.defineProperty(Timeline.prototype, 'gridStartPoint',
  { get: function() { return {
    x: this.padding,
    y: 0
  }}});

/**
 * Tells if the timeline has been drawn yet.
 * @return {Boolean}
 */
Timeline.prototype.isDrawn = function() {
	return !!this.svg;
};

/** Creates the timeline and appends it to HTMLContainer
 * @param{HTMLElement} HTMLContainer
 */
Timeline.prototype.draw = function(HTMLContainer) {
  this.container = HTMLContainer;

	this.gridWidth = 0;
	this.gridHeight = 0;

	// scale
	var timeMin = d3.min(this.items, function(d) { return d.start; });
	var timeMax = d3.max(this.items, function(d) { return getEndTime(d); });
	this.gridWidth = msToYears(timeMax - timeMin) * this.widthOfYear;
  this.xScale = d3.time.scale()
		.domain([timeMin, timeMax])
		.range([this.padding, this.padding + this.gridWidth]);

	// the svg
  this.svg = d3.select(this.container).append('svg')
    .classed('timeline', true);

	// x axis
	this._xAxis = d3.svg.axis()
		.scale(this.xScale)
		.ticks(100)
    .orient("bottom")
	  .tickPadding(4);
	this._xAxisGroup = this.svg.append('g').classed('x axis', true)
		.call(this._xAxis);

	// grid
	this._gridAxis = d3.svg.axis()
		.scale(this.xScale)
		.ticks(100)
		.tickFormat('')
    .orient("bottom")
		.innerTickSize(-1*this.gridHeight);
	this._gridGroup = this.svg.append('g').classed('grid', true)
		.call(this._gridAxis);

	// the items
	this.svg._itemsGroup = this.svg.append('g').classed('items', true);
	// these rows store the items in each row of the timeline, sorted. Used to
	// pack events in the _drawItems method.
	this.rows = [];
	this.nextRow = 0;

  this._drawItems();
};

/**Draws the individual items
 * @private
 */
Timeline.prototype._drawItems = function(items) {
  var _this = this;

	// Group
  var groups = this.svg._itemsGroup.selectAll('g')
    .data(this.items)
    .enter()
    .append('g')
    .attr({
			class: 'item'
		});

	// Rect
  groups.append('rect')
    .attr({
      x:      function(d) {return (_this.xScale(getEndTime(d)) - _this.xScale(d.start))/2 },
      y:      0,
      width:  0,
      height: _this.itemHeight,
    })
    // .transition().duration(80)
    // .delay(function(d, i) { return 60*Math.log(i); })
    .attr({
      x: 0,
      width: function(d) {return _this.xScale(getEndTime(d)) - _this.xScale(d.start)}
    });

	// Item text
  groups.append('text')
    .attr({
      x: function(d) {return (_this.xScale(getEndTime(d)) - _this.xScale(d.start))/2 },
      y: _this.itemHeight / 2
    })
		.append('tspan')
		.text(function(d) { return d.name; })
    .style({
      fill: '#000',
      'text-anchor': 'middle',
      'alignment-baseline': 'central',
      opacity: 0
    })
    // .transition().duration(80).delay(function(d, i) { return 60*Math.log(i); })
    .style('opacity', 1);

		// position the group
		groups.attr({
      transform: function(d, i) {
				var defaultY = _this.gridStartPoint.y - (_this.nextRow+1) * _this.itemHeight;
				var finalY = defaultY;
				var bbox = this.getBBox();
				var xRange = {
					start: _this.xScale(d.start) + bbox.x,
					end: _this.xScale(d.start) + bbox.x + bbox.width
				};

				// first item; just add it
				if (_this.nextRow === 0) {
					finalY = defaultY;
					_this.rows[_this.nextRow] = [ xRange ];
					_this.nextRow++;
				} else {
					var rowWithRoom = -1;
					var indexInRow = -1;

					// starting from row 0, check if there is room.
					for(var i = 0; i < _this.nextRow; ++i) {
						// check left
						if (xRange.end < _this.rows[i][0].start) {
							rowWithRoom = i;
							indexInRow = 0;
							break;
						}
						// check right
						if (xRange.start > _this.rows[i][_this.rows[i].length - 1].end) {
							rowWithRoom = i;
							indexInRow = _this.rows[i].length;
							break;
						}
						// check middle
						for(var j = 0; j < _this.rows[i].length - 1; j++) {
							if (_this.rows[i][j].end < xRange.start && _this.rows[i][j+1].start > xRange.end) {
								rowWithRoom = i;
								indexInRow = j+1;
								break;
							}
						}

						if (rowWithRoom !== -1) break;
					}

					if (rowWithRoom != -1) {
						// success! put it here
						finalY = _this.gridStartPoint.y - (rowWithRoom+1) * _this.itemHeight;

						// add it to row (in correct position)
						_this.rows[rowWithRoom] = _this.rows[rowWithRoom].slice(0, indexInRow)
							.concat(xRange)
							.concat(_this.rows[rowWithRoom].slice(indexInRow));
					} else {
						finalY = defaultY;
						_this.rows[_this.nextRow] = [ xRange ];
						_this.nextRow++;
					}
				}

				return sprintf('translate(%%, %%)', _this.xScale(d.start), finalY);
			}
    });

		// Add anchors (where appropriate)
		groups.each(function(d) {
			if (d.href) {
				var group = d3.select(this);
				// move all the groups children into the anchor
				var anchor = group.append('a')
				.attr({
					'class': 'main-link',
					'xlink:href': function(d) { return d.href; },
					'xlink:show': 'new'
				});

				var anchorNode = anchor.node();

				var children = this.children;
				while(children.length > 1) {
					anchorNode.appendChild(children[0]);
				}
			}
		});

		// the height has probably changed because of stacking; should shrink doc
		this.gridHeight = this.svg._itemsGroup.node().getBBox().height;
		this._gridAxis.innerTickSize(-1*this.gridHeight); // FIXME: put me in better place T_T
		this._gridGroup.call(this._gridAxis);
		this._updateSVGSize();
};

/**
 * Adds the supplied items to the internal array and the chart. Updates chart's
 * axes to ensure the items fit. Use if adding a large number of items, to avoid
 * updating the axes a lot. Otherwise just add the array of items as per usual.
 * @param {array<object>} itemsArr items to add
 * @return {Timeline} @this
 */
Timeline.prototype.addItems = function(itemsArr) {
	var _this = this;

  if (!this.isDrawn()) {
    this.items = this.items.concat(itemsArr);
    return this;
  }

	var currentDomain = this.xScale.domain();
	var newItemsDomain = [
		d3.min(itemsArr, function(d) { return d.start; }),
		d3.max(itemsArr, function(d) { return getEndTime(d); })
	];

	var mustChangeDomain = (newItemsDomain[0] < currentDomain[0])
		|| (newItemsDomain[1] > currentDomain[1]);

	if (mustChangeDomain) {
		var newDomain = [
			Math.min(newItemsDomain[0], currentDomain[0]),
			Math.max(newItemsDomain[1], currentDomain[1])
		];
		var xTmp = this.xScale(0);
		this.xScale.domain(newDomain);
	}

	this.items = this.items.concat(itemsArr);

  // update xScale Range
  this.gridWidth = msToYears(this.xScale.domain()[1] - this.xScale.domain()[0]) * this.widthOfYear;
  this.xScale.range([this.padding, this.padding + this.gridWidth]);

  // update axes
  this._xAxisGroup.call(this._xAxis);
  this._gridGroup.call(this._gridAxis);

	if (mustChangeDomain) {
		var xChange = this.xScale(0) - xTmp;
		// move all the existing items over
		this.svg._itemsGroup.selectAll('g.item')
		.each(function(d, i) {
			var currentTransform = this.getAttribute('transform');
			var translation = currentTransform.match(/[-+]?((\d*\.\d+)|\d+)/g);

			this.setAttribute('transform', sprintf('translate(%%, %%)', _this.xScale(d.start), translation[1]));
		});

		// update ranges in rows so that things stay correct
		for (var i = 0; i < this.rows.length; ++i ) {
			for (var j = 0; j < this.rows[i].length; ++j) {
				this.rows[i][j].start += xChange;
				this.rows[i][j].end += xChange;
			}
		}
	}

  // draw the new items
  this._drawItems();
};

Timeline.prototype._updateSVGSize = function() {
  this.svg.attr({
    width: this.canvasWidth,
    height: this.canvasHeight,
    viewBox: sprintf("0 %% %% %%", -1*this.gridHeight, this.canvasWidth, this.canvasHeight)
  });
};
<|endoftext|>


<commit_before>$(function() {

	var publicComponents = {
		tabWithDropdown: function() {
			var tab_with_dropdown_buttons = $('ul.nav li a').not('[data-toggle="dropdown"]');
			var tab_with_dropdown_all = $('ul.nav li');
			tab_with_dropdown_buttons.on('click', function(e) {
				e.preventDefault();
				tab_with_dropdown_all.removeClass('active');
				$(this).closest('li').addClass('active');
				$(this).parents('li')[1] ? $($(this).parents('li')[1]).addClass('active') : false;
			});
			$(tab_with_dropdown_buttons[0]).trigger('click');
		}()
	}

})<commit_msg>tab trigger bug fix<commit_after>var component = {
	tabWithDropdown: function() {
		$(document).on('click', 'ul.nav li a', function(e) {
			e.preventDefault();
			if($(this).attr('data-toggle') == 'dropdown') {
				console.log('toggle');
			} else {
				console.log($(this).closest('li'));
				$('ul.nav li').removeClass('active');
				$(this).closest('li').addClass('active');
			}
			$(this).parents('li')[1] ? $($(this).parents('li')[1]).addClass('active') : false;
		});
	}
}

$(function() {

	component.tabWithDropdown();

})

<|endoftext|>


<commit_before>;
(function(mag) {

  'use strict';

  var mod = {
    modules: [],
    promises: [],
    deferreds: [],
    controllers: [],
    elements: []
  }

  mod.getController = function(index, module) {
    //var controller

    // FireFox support only
    // Removing since we are now native with Object.observe which is only Chrome & Opera

    /*
    if (typeof Proxy !== 'undefined') {
      controller = new Proxy(new module.controller, {
        get: function(target, prop) {
          //more default props like willload, didload, willupdate, didupdate, isupdate
          if (target[prop] === undefined && ['watchers', 'toJSON', 'called', 'onload', 'onunload'].indexOf(prop) === -1) {
            var a = fill.find(element, prop),
              greedy = prop[0] === '$',
              v, // can be an array, object or string
              // for each
              tmp = []
            a.forEach(function(item, index) {
              if (a[index]) {
                if (a[index].value && a[index].value.length > 0) {
                  v = a[index].value
                  if (a[index].type && (a[index].type == 'checkbox' || a[index].type == 'radio')) {
                    v = {
                      _text: v,
                      _checked: a[index].checked
                    }
                    tmp.push(v)
                  }
                } else if (a[index].innerText && a[index].innerText.length > 0) {
                  v = a[index].innerText
                } else if (a[0].innerHTML && a[index].innerHTML.length > 0) {
                  v = a[index].innerHTML
                }
              }
            })
            if (tmp.length > 0 && greedy) return tmp
            return v
          }
          return target[prop]
        }
      })
    } else {
      controller = new module.controller
    }
    */

    // get if exists
    if (this.controllers[index]) {
      return this.controllers[index]
    }

    return new module.controller
  }

  // function deepFreeze(o) {
  //   var prop, propKey;
  //   Object.freeze(o); // First freeze the object.
  //   for (propKey in o) {
  //     prop = o[propKey];
  //     if (!o.hasOwnProperty(propKey) || !(typeof prop === 'object') || Object.isFrozen(prop)) {
  //       // If the object is on the prototype, not an object, or is already frozen,
  //       // skip it. Note that this might leave an unfrozen reference somewhere in the
  //       // object if there is an already frozen object containing an unfrozen object.
  //       continue;
  //     }

  //     deepFreeze(prop); // Recursively call deepFreeze.
  //   }
  // }

  mod.submodule = function(module, args) {
    // do we need/want this? view/controller will always get the same args
    // difference is that that can't be changed within those functions - does that matter?
    //deepFreeze(args)

    // TODO: Enforce single call to controllers?

    var controller = function() {
        return (module.controller || function() {}).apply(this, args) || this
      },
      view = function(ctrl, ele) {
        // container element available to sub components
        //TODO: removed until valid use case
        //module.view._nodeId = ele.id

        if (arguments.length > 1) var nargs = args.concat([].slice.call(arguments, 1))
        module.view.apply(module, nargs ? [ctrl].concat(nargs) : [ctrl])

      },
      output = {
        controller: controller,
        view: view
      }
      // why do we need these?

    //controller.$original = module.controller
    //view.$original = module.view
    controller.$$args = args
    return output
  }

  mod.getArgs = function(i) {
    var args = mod.modules[i] && mod.modules[i].controller && mod.modules[i].controller.$$args ? [mod.controllers[i]].concat(mod.modules[i].controller.$$args) : [mod.controllers[i]]
      // args that contaian circular references will throw an exception up the chain

    attachToArgs(i, args[0], this.elements[i]);

    return args
  }

  var getParent = function(parts, parentElement) {
    for (var i = 1; i < parts.length; i += 2) {
      var key = parts[i];
      var index = parts[i + 1];
      parentElement = mag.fill.find(parentElement, key);
      // console.log(key, index, parentElement[index])
      parentElement = parentElement[index];
    }
    return parentElement;
  };
  var getElement = function(obj, k, i, parentElement) {

    // search within _key if there
    var parts = i.toString().split('.'),
      found;

    if (parts.length >= 3) {
      // recurse
      parentElement = getParent(parts, parentElement)
      found = mag.fill.find(parentElement, k);

    } else {

      var last = parseInt(parts.pop()),
        index = !isNaN(last) ? last : 0;
      found = mag.fill.find(parentElement[index] ? parentElement[index] : parentElement, k);
    }
    // first user input field
    var founder = isInput(found);
    if (founder && !founder.eventOnFocus) {

      var onfocus = function() {
        if (!this.classList.contains('mag-dirty')) {
          this.classList.add('mag-dirty');
        }
      }

      founder.addEventListener("focus", onfocus, false);
      founder.eventOnFocus = true;
    }
    return founder;
  }

  function isInput(items) {

    for (var k in items) {
      if (items[k] && ['INPUT', 'SELECT', 'TEXTAREA'].indexOf(items[k].tagName) !== -1) {
        return items[k];
      }
    }
    return false;
  }
  var attacher = function(i, k, obj, element) {
    var oval = obj[k];
    // if k =='_value' use parent
    if (k === '_value') k = i.split('.').pop();

    // only for user input fields
    var found = mag.fill.find(element, k);
    var founder = isInput(found);
    if (typeof oval !== 'function' && founder) {

      var founderCall = getElement.bind({}, obj, k, i, element);
      founderCall();
      Object.defineProperty(obj, k, {
        configurable: true,
        get: function() {
          var founder = founderCall();

          // set on focus listener once
          if (founder && founder.value !== 'undefined' && founder.classList.contains('mag-dirty') && founder.value !== oval) {
            oval = founder.value;
            return founder.value;
          }
          return oval;
        },
        set: function(newValue) {
          var founder = founderCall();

          if (founder && founder.value !== 'undefined' && founder.value !== newValue && newValue !== oval) {
            founder.value = newValue;
            oval = newValue;
          }
        }
      });
    }
  };

  function attachToArgs(i, args, element) {

    // for each property set accessor property

    // get notification when accessed

    // call fill to get and assign

    //if (!added[i]) added[i] = [];
    for (var k in args) {

      var value = args[k]

      if (Array.isArray(value) && value[0] && !value[0].__$$i && typeof value[0].then !== 'undefined' && typeof value[0].type != 'fun') {
        value[0].__$$i = 1

        Promise.all(value).then(function(args, k, val) {
          if (val) {
            value[0].__$$i == 0
            args[k] = val

            mag.redraw()
          }
        }.bind(this, args, k))

      } else

      if (typeof value === 'object' && (!value || typeof value.then === 'undefined')) {
        // recurse
        attachToArgs(i + '.' + k, value, element);
      } else {
        if (value && !Array.isArray(value) && !value.__$$i && typeof value.then !== 'undefined' && typeof value.type != 'fun') {
          value.__$$i = 1
            // promise
          value.then(function(args, k, val) {
            if (val) {
              args[k].__$$i = 0
              args[k] = val
              mag.redraw()
            }
          }.bind(this, args, k))

        }

        //if (!added[i][k]) {
        attacher(i, k, args, element);
        //  added[i][k] = true;
        // }
      }
    }
  }

  mag.mod = mod

})(window.mag || {})
<commit_msg>Update module.js<commit_after>;
(function(mag) {

  'use strict';

  var mod = {
    modules: [],
    promises: [],
    deferreds: [],
    controllers: [],
    elements: []
  }

  mod.getController = function(index, module) {
    //var controller

    // FireFox support only
    // Removing since we are now native with Object.observe which is only Chrome & Opera

    /*
    if (typeof Proxy !== 'undefined') {
      controller = new Proxy(new module.controller, {
        get: function(target, prop) {
          //more default props like willload, didload, willupdate, didupdate, isupdate
          if (target[prop] === undefined && ['watchers', 'toJSON', 'called', 'onload', 'onunload'].indexOf(prop) === -1) {
            var a = fill.find(element, prop),
              greedy = prop[0] === '$',
              v, // can be an array, object or string
              // for each
              tmp = []
            a.forEach(function(item, index) {
              if (a[index]) {
                if (a[index].value && a[index].value.length > 0) {
                  v = a[index].value
                  if (a[index].type && (a[index].type == 'checkbox' || a[index].type == 'radio')) {
                    v = {
                      _text: v,
                      _checked: a[index].checked
                    }
                    tmp.push(v)
                  }
                } else if (a[index].innerText && a[index].innerText.length > 0) {
                  v = a[index].innerText
                } else if (a[0].innerHTML && a[index].innerHTML.length > 0) {
                  v = a[index].innerHTML
                }
              }
            })
            if (tmp.length > 0 && greedy) return tmp
            return v
          }
          return target[prop]
        }
      })
    } else {
      controller = new module.controller
    }
    */

    // get if exists
    if (this.controllers[index]) {
      return this.controllers[index]
    }

    return new module.controller
  }

  // function deepFreeze(o) {
  //   var prop, propKey;
  //   Object.freeze(o); // First freeze the object.
  //   for (propKey in o) {
  //     prop = o[propKey];
  //     if (!o.hasOwnProperty(propKey) || !(typeof prop === 'object') || Object.isFrozen(prop)) {
  //       // If the object is on the prototype, not an object, or is already frozen,
  //       // skip it. Note that this might leave an unfrozen reference somewhere in the
  //       // object if there is an already frozen object containing an unfrozen object.
  //       continue;
  //     }

  //     deepFreeze(prop); // Recursively call deepFreeze.
  //   }
  // }

  mod.submodule = function(module, args) {
    // do we need/want this? view/controller will always get the same args
    // difference is that that can't be changed within those functions - does that matter?
    //deepFreeze(args)

    // TODO: Enforce single call to controllers?

    var controller = function() {
        return (module.controller || function() {}).apply(this, args) || this
      },
      view = function(ctrl, ele) {
        // container element available to sub components
        //module.view._nodeId = ele.id

        if (arguments.length > 1) var nargs = args.concat([].slice.call(arguments, 1))
        module.view.apply(module, nargs ? [ctrl].concat(nargs) : [ctrl])
      },
      output = {
        controller: controller,
        view: view
      }
      // why do we need these?

    //controller.$original = module.controller
    //view.$original = module.view
    controller.$$args = args
    return output
  }

  mod.getArgs = function(i) {
    var args = mod.modules[i] && mod.modules[i].controller && mod.modules[i].controller.$$args ? [mod.controllers[i]].concat(mod.modules[i].controller.$$args) : [mod.controllers[i]]
      // args that contaian circular references will throw an exception up the chain

    attachToArgs(i, args[0], this.elements[i]);

    return args
  }

  var getParent = function(parts, parentElement) {
    for (var i = 1; i < parts.length; i += 2) {
      var key = parts[i];
      var index = parts[i + 1];
      parentElement = mag.fill.find(parentElement, key);
      // console.log(key, index, parentElement[index])
      parentElement = parentElement[index];
    }
    return parentElement;
  };
  var getElement = function(obj, k, i, parentElement) {

    // search within _key if there
    var parts = i.toString().split('.'),
      found;

    if (parts.length >= 3) {
      // recurse
      parentElement = getParent(parts, parentElement)
      found = mag.fill.find(parentElement, k);

    } else {

      var last = parseInt(parts.pop()),
        index = !isNaN(last) ? last : 0;
      found = mag.fill.find(parentElement[index] ? parentElement[index] : parentElement, k);
    }
    // first user input field
    var founder = isInput(found);
    if (founder && !founder.eventOnFocus) {

      var onfocus = function() {
        if (!this.classList.contains('mag-dirty')) {
          this.classList.add('mag-dirty');
        }
      }

      founder.addEventListener("focus", onfocus, false);
      founder.eventOnFocus = true;
    }
    return founder;
  }

  function isInput(items) {

    for (var k in items) {
      if (items[k] && ['INPUT', 'SELECT', 'TEXTAREA'].indexOf(items[k].tagName) !== -1) {
        return items[k];
      }
    }
    return false;
  }
  var attacher = function(i, k, obj, element) {
    var oval = obj[k];
    // if k =='_value' use parent
    if (k === '_value') k = i.split('.').pop();

    // only for user input fields
    var found = mag.fill.find(element, k);
    var founder = isInput(found);
    if (typeof oval !== 'function' && founder) {

      var founderCall = getElement.bind({}, obj, k, i, element);
      founderCall();
      Object.defineProperty(obj, k, {
        configurable: true,
        get: function() {
          var founder = founderCall();

          // set on focus listener once
          if (founder && founder.value !== 'undefined' && founder.classList.contains('mag-dirty') && founder.value !== oval) {
            oval = founder.value;
            return founder.value;
          }
          return oval;
        },
        set: function(newValue) {
          var founder = founderCall();

          if (founder && founder.value !== 'undefined' && founder.value !== newValue && newValue !== oval) {
            founder.value = newValue;
            oval = newValue;
            mag.redraw()
          }
        }
      });
    }
  };

  function attachToArgs(i, args, element) {

    // for each property set accessor property

    // get notification when accessed

    // call fill to get and assign

    //if (!added[i]) added[i] = [];

    for (var k in args) {

      var value = args[k]

      if (Array.isArray(value) && value[0] && !value[0].__$$i && typeof value[0].then !== 'undefined' && typeof value[0].type != 'fun') {
        value[0].__$$i = 1
        Promise.all(value).then(function(args, k, val) {
          if (val) {
            value[0].__$$i == 0
            args[k] = val
            mag.redraw()
          }
        }.bind(this, args, k))

      } else if (typeof value === 'object' && (!value || typeof value.then === 'undefined')) {
        // recurse
        attachToArgs(i + '.' + k, value, element);
      } else {
        if (value && !Array.isArray(value) && !value.__$$i && typeof value.then !== 'undefined' && typeof value.type != 'fun') {
          value.__$$i = 1
            // promise
          value.then(function(args, k, val) {
            if (val) {
              args[k].__$$i = 0
              args[k] = val
              mag.redraw()
            }
          }.bind(this, args, k))

        }

        //if (!added[i][k]) {
        attacher(i, k, args, element);
        //  added[i][k] = true;
        // }
      }
    }
  }

  mag.mod = mod

})(window.mag || {})
<|endoftext|>


<commit_before>(function($) {

    $.fn.uploader = function(options)
    {
        if(typeof options !== 'object') {
            return $.data(this, 'selfInstance');
        }

        // config
        options = $.extend({}, {
            transport               : null,   // set upload transport
            progressHandlerUrl      : null,   // only for iframe
            uploadHandlerUrl        : null,
            uploadHandlerParams     : function() {},
            classname               : null,
            onsuccess               : function(response) {},
            onerror                 : function(response) {},
            onbeforeupload          : function() {},
            onafterupload           : function() {},
            onprogress              : function(loaded, total) {},
            supportedFormats        : [],
            maxSize                 : null
        }, options);

        // init
        $.data(this, 'selfInstance', new uploader(this, options));
    };

    function uploader(fileInput, options)
    {
        var self = this;

        this.fileInput = fileInput;
        this.options = options;

        // container
        this.container = this.fileInput.parent()
            .css({
                position: 'relative',
                overflow: 'hidden'
            });

        if(this.options.classname) {
            this.container.addClass(this.options.classname);
        }

        // button
        this.fileInput
            .change(function() {
                self.uploadFile();
            })
            .css({
                opacity: 0,
                position: 'absolute',
                zIndex: 100,
                top: '0px',
                right: '0px',
                fontSize: '200px',
                padding: '0px',
                margin: '0px',
                cursor: 'pointer'
            });

        this.fileInput.appendTo(this.container);
    }

    uploader.prototype =
    {
        // check allowed file size and format
        _validate: function()
        {
            var file = this.fileInput.get(0).files[0];

            // size
            if(this.options.maxSize && file.size > this.options.maxSize) {
                throw new Error('File size greater than allowed');
            }

            // format
            if(this.options.supportedFormats.length) {
                var currentFormat = file.name.substr(file.name.lastIndexOf('.') + 1),
                    formatAllowed = false;

                for(var i = 0; i < this.options.supportedFormats.length; i++) {
                    if(currentFormat === this.options.supportedFormats[i]) {
                        formatAllowed = true;
                        break;
                    }
                }

                if(!formatAllowed) {
                    throw new Error('Format of file not allowed');
                }
            }
        },

        uploadFile: function()
        {
            if(this.options.onbeforeupload.call(this) === false) {
                return;
            }

            try {
                this._validate();
            }
            catch(e) {
                this.options.onerror.call(self, e.message);
            }

            // upload
            if(this.options.transport) {
                this['_' + this.options.transport + 'Upload']();
            }
            else {
                try {
                    this._xhrUpload();
                }
                catch(e) {
                    this._iframeUpload();
                }
            }
        },

        _xhrUpload: function()
        {
            var xhr = new XMLHttpRequest();
            if(!('upload' in xhr)) {
                throw new Error('XMLHttpRequest do not support file upload');
            }

            var file = this.fileInput.get(0).files[0];
            var uri = this._getRequestUri({f: file.name});

            var self = this;
            xhr.onreadystatechange = function() {
                if (xhr.readyState !== 4) {
                    return;
                }

                try {
                    if(xhr.status !== 200) {
                        throw new Error('Server returns error code ' + xhr.status);
                    }

                    var response = xhr.responseText
                        ? eval("(" + xhr.responseText + ")")
                        : {};

                    (response.error == 1)
                        ? self.options.onerror.call(self, response)
                        : self.options.onsuccess.call(self, response);

                }
                catch(e) {
                    self.options.onerror.call(self, e.message);
                }

                self.options.onafterupload.call(self);
            };

            xhr.upload.onprogress = function(e) {
                self.options.onprogress.call(self, e.loaded, e.total);
            };

            xhr.open("POST", uri, true);
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.setRequestHeader("X-File-Name", encodeURIComponent(file.fileName));
            xhr.setRequestHeader("Content-Type", "application/octet-stream");
            xhr.send(file);

        },

        _iframeUpload: function()
        {
            // generate X-Progress-ID
            var uuid = "";
            for (var i = 0; i < 32; i++) {
                uuid += Math.floor(Math.random() * 16).toString(16);
            }

            // prepare request uri
            var requestUri = this._getRequestUri({
                'X-Progress-ID': uuid
            });

            // create iframe
            var $iframe = $('').appendTo(document.body);
            var $form = $('<form method="post" enctype="multipart/form-data" action="' +requestUri + '" target="iframeUpload" style="display:none;"></form>').appendTo(document.body);

            // move file input to iframe form
            $(this.fileInput).attr('name', 'f').appendTo($form);

            // add clean file input to old location
            this.fileInput = $('<input type="file" />').appendTo(this.fileInput.parent());

            var self = this;
            $iframe.load(function() {
                try
                {
                    var json = $iframe.contents().text();
                    var response = json
                        ? eval("(" + json + ")")
                        : {};

                    (response.error == 1)
                        ? self.options.onerror.call(self, response)
                        : self.options.onsuccess.call(self, response);
                }
                catch(e)
                {
                    self.options.onerror.call(self, e);

                }

                self.options.onafterupload.call(self);

                $iframe.remove();
                $form.remove();
            });

            // get progress from nginx upload progress module
            var updateProgress = function() {
                $.get(
                    self.options.progressHandlerUrl,
                    {'X-Progress-ID': uuid},
                    function(responseText) {

                        var response = eval(responseText);

                        switch(response.state)
                        {
                            case 'uploading':
                                self.options.onprogress.call(self, response.received, response.size);
                                setTimeout(updateProgress, 5000);
                                break;
                        }

                    });
            };

            setTimeout(updateProgress, 1000);

            // submit form
            $form.submit();
        },

        _getRequestUri: function(additionalParams)
        {
            var uri = this.options.uploadHandlerUrl + '';

            var queryString = [];

            var params = this.options.uploadHandlerParams();
            for(var key in params) {
                queryString.push(key + '=' + encodeURIComponent(params[key]));
            }

            if(typeof additionalParams !== 'undefined') {
                for(key in additionalParams) {
                    queryString.push(key + '=' + encodeURIComponent(additionalParams[key]));
                }
            }

            if(queryString !== '') {
                uri += '?' + queryString.join('&');
            }

            return uri;
        }

    };

})(jQuery);<commit_msg>skip upload on validate error<commit_after>(function($) {

    $.fn.uploader = function(options)
    {
        if(typeof options !== 'object') {
            return $.data(this, 'selfInstance');
        }

        // config
        options = $.extend({}, {
            transport               : null,   // set upload transport
            progressHandlerUrl      : null,   // only for iframe
            uploadHandlerUrl        : null,
            uploadHandlerParams     : function() {},
            classname               : null,
            onsuccess               : function(response) {},
            onerror                 : function(response) {},
            onbeforeupload          : function() {},
            onafterupload           : function() {},
            onprogress              : function(loaded, total) {},
            supportedFormats        : [],
            maxSize                 : null
        }, options);

        // init
        $.data(this, 'selfInstance', new uploader(this, options));
    };

    function uploader(fileInput, options)
    {
        var self = this;

        this.fileInput = fileInput;
        this.options = options;

        // container
        this.container = this.fileInput.parent()
            .css({
                position: 'relative',
                overflow: 'hidden'
            });

        if(this.options.classname) {
            this.container.addClass(this.options.classname);
        }

        // button
        this.fileInput
            .change(function() {
                self.uploadFile();
            })
            .css({
                opacity: 0,
                position: 'absolute',
                zIndex: 100,
                top: '0px',
                right: '0px',
                fontSize: '200px',
                padding: '0px',
                margin: '0px',
                cursor: 'pointer'
            });

        this.fileInput.appendTo(this.container);
    }

    uploader.prototype =
    {
        // check allowed file size and format
        _validate: function()
        {
            var file = this.fileInput.get(0).files[0];

            // size
            if(this.options.maxSize && file.size > this.options.maxSize) {
                throw new Error('File size greater than allowed');
            }

            // format
            if(this.options.supportedFormats.length) {
                var currentFormat = file.name.substr(file.name.lastIndexOf('.') + 1),
                    formatAllowed = false;

                for(var i = 0; i < this.options.supportedFormats.length; i++) {
                    if(currentFormat === this.options.supportedFormats[i]) {
                        formatAllowed = true;
                        break;
                    }
                }

                if(!formatAllowed) {
                    throw new Error('Format of file not allowed');
                }
            }
        },

        uploadFile: function()
        {
            if(this.options.onbeforeupload.call(this) === false) {
                return;
            }

            try {
                this._validate();
            }
            catch(e) {
                this.options.onerror.call(self, e.message);
                return;
            }

            // upload
            if(this.options.transport) {
                this['_' + this.options.transport + 'Upload']();
            }
            else {
                try {
                    this._xhrUpload();
                }
                catch(e) {
                    this._iframeUpload();
                }
            }
        },

        _xhrUpload: function()
        {
            var xhr = new XMLHttpRequest();
            if(!('upload' in xhr)) {
                throw new Error('XMLHttpRequest do not support file upload');
            }

            var file = this.fileInput.get(0).files[0];
            var uri = this._getRequestUri({f: file.name});

            var self = this;
            xhr.onreadystatechange = function() {
                if (xhr.readyState !== 4) {
                    return;
                }

                try {
                    if(xhr.status !== 200) {
                        throw new Error('Server returns error code ' + xhr.status);
                    }

                    var response = xhr.responseText
                        ? eval("(" + xhr.responseText + ")")
                        : {};

                    (response.error == 1)
                        ? self.options.onerror.call(self, response)
                        : self.options.onsuccess.call(self, response);

                }
                catch(e) {
                    self.options.onerror.call(self, e.message);
                }

                self.options.onafterupload.call(self);
            };

            xhr.upload.onprogress = function(e) {
                self.options.onprogress.call(self, e.loaded, e.total);
            };

            xhr.open("POST", uri, true);
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.setRequestHeader("X-File-Name", encodeURIComponent(file.fileName));
            xhr.setRequestHeader("Content-Type", "application/octet-stream");
            xhr.send(file);

        },

        _iframeUpload: function()
        {
            // generate X-Progress-ID
            var uuid = "";
            for (var i = 0; i < 32; i++) {
                uuid += Math.floor(Math.random() * 16).toString(16);
            }

            // prepare request uri
            var requestUri = this._getRequestUri({
                'X-Progress-ID': uuid
            });

            // create iframe
            var $iframe = $('').appendTo(document.body);
            var $form = $('<form method="post" enctype="multipart/form-data" action="' +requestUri + '" target="iframeUpload" style="display:none;"></form>').appendTo(document.body);

            // move file input to iframe form
            $(this.fileInput).attr('name', 'f').appendTo($form);

            // add clean file input to old location
            this.fileInput = $('<input type="file" />').appendTo(this.fileInput.parent());

            var self = this;
            $iframe.load(function() {
                try
                {
                    var json = $iframe.contents().text();
                    var response = json
                        ? eval("(" + json + ")")
                        : {};

                    (response.error == 1)
                        ? self.options.onerror.call(self, response)
                        : self.options.onsuccess.call(self, response);
                }
                catch(e)
                {
                    self.options.onerror.call(self, e);

                }

                self.options.onafterupload.call(self);

                $iframe.remove();
                $form.remove();
            });

            // get progress from nginx upload progress module
            var updateProgress = function() {
                $.get(
                    self.options.progressHandlerUrl,
                    {'X-Progress-ID': uuid},
                    function(responseText) {

                        var response = eval(responseText);

                        switch(response.state)
                        {
                            case 'uploading':
                                self.options.onprogress.call(self, response.received, response.size);
                                setTimeout(updateProgress, 5000);
                                break;
                        }

                    });
            };

            setTimeout(updateProgress, 1000);

            // submit form
            $form.submit();
        },

        _getRequestUri: function(additionalParams)
        {
            var uri = this.options.uploadHandlerUrl + '';

            var queryString = [];

            var params = this.options.uploadHandlerParams();
            for(var key in params) {
                queryString.push(key + '=' + encodeURIComponent(params[key]));
            }

            if(typeof additionalParams !== 'undefined') {
                for(key in additionalParams) {
                    queryString.push(key + '=' + encodeURIComponent(additionalParams[key]));
                }
            }

            if(queryString !== '') {
                uri += '?' + queryString.join('&');
            }

            return uri;
        }

    };

})(jQuery);<|endoftext|>


<commit_before>'use strict';

define(['bitcoinjs-lib', 'util/stealth'], function(Bitcoin, Stealth) {
  var convert = Bitcoin.convert;

  var genesisTime = 1231006505;
  var tzOffset = (new Date()).getTimezoneOffset()*60;

  var allowedVersions = [Bitcoin.network.mainnet.addressVersion, Bitcoin.network.mainnet.p2shVersion, Stealth.version];

  function isSmallIntOp(opcode) {
    return ((opcode == Bitcoin.Opcode.map.OP_0) ||
    ((opcode >= Bitcoin.Opcode.map.OP_1) && (opcode <= Bitcoin.Opcode.map.OP_16)))
  }

  var BtcUtils = {
    lastBlock: 296405,
    lastTimestamp: 1397780085,
    blockDiff: 562.65,

    /*
     * Set timestamp for the last block to adjust timestamp heuristics
     */
    setLastTimestamp: function(block, timestamp) {
        BtcUtils.lastBlock = block;
        BtcUtils.lastTimestamp = timestamp;
        BtcUtils.blockDiff = ((timestamp-genesisTime) / block);
    },

    /**
     * Get the address for an input
     */
    getInputAddress: function(anIn, versions) {
        if (!versions) throw Error("No versions!");
        var ops = Bitcoin.Opcode.map;
        var buffer = anIn.script.buffer;
        var lastByte = buffer[buffer.length-1];
        var pubKeys = anIn.script.extractPubkeys();
        if (isSmallIntOp(buffer[0]) && lastByte == ops.OP_CHECKMULTISIG) {
            var multisig = BtcUtils.importMultiSig(convert.bytesToHex(anIn.script.chunks[anIn.script.chunks.length-1]), versions.p2sh);
            return multisig.address;
        } else if (pubKeys && pubKeys.length) {
            var pubKey = new Bitcoin.ECPubKey(pubKeys[0], pubKeys[0].length==33);
            return pubKey.getAddress(versions.address).toString();
        }
    },

    /*
     * Decode a block header
     */
    decodeBlockHeader: function(headerHex) {
        // Don't really need all of these at the moment
        var header = convert.hexToBytes(headerHex);
        var version = convert.bytesToNum(header.splice(0,4));
        var prevBlock = header.splice(0,32);
        var merkleRoot = header.splice(0,32);
        var timestamp = convert.bytesToNum(header.splice(0,4));
        var difficulty = header.splice(0,4);
        var nonce = convert.bytesToNum(header.splice(0,4));
        var difficultyNum = convert.bytesToNum(header.splice(0,4));

        return {version: version, prevBlock: prevBlock, merkleRoot: merkleRoot, timestamp: timestamp, difficulty: difficulty, nonce: nonce};
    },
    /*
     * Start a multisig structure out of participant public keys and m
     */
    multiSig: function(m, participants, version){
        if (version === null || version == undefined) version = Bitcoin.network.mainnet.p2shVersion;
        // Create script
        var script = Bitcoin.Script.createMultiSigOutputScript(m, participants);
        // Hash for address
        var hashed = Bitcoin.crypto.hash160(script.buffer);
        // Encode in base58, v0x05 is multisig
        var address = Bitcoin.base58check.encode(hashed, version);
        // Encoded script
        var scriptHex = convert.bytesToHex(script.buffer);
        return {address: address, script: scriptHex, m: m, pubKeys: participants};
    },

    deriveMpk: function(mpk, index) {
        var mpKey = Bitcoin.HDWallet.fromBase58(mpk);
        var childKey = mpKey.derive(index);
        return childKey.toBase58(false);
    },

    importMultiSig: function(data, version){
        if (version === null || version == undefined) version = Bitcoin.network.mainnet.p2shVersion;
        var script = new Bitcoin.Script(convert.hexToBytes(data));
        var hashed = Bitcoin.crypto.hash160(script.buffer);
        var address = Bitcoin.base58check.encode(hashed, version);
        var pubKeys = script.extractPubkeys();
        var m = script.chunks[0] - Bitcoin.Opcode.map.OP_1 + 1;
        return {address: address, script: data, m: m, pubKeys: pubKeys};
    },

    fixTxVersions: function(tx, identity) {
        // XXX fix trouble with bitcoinjs..
        if (identity.wallet.network == 'testnet') {
            var versions = identity.wallet.versions;
            tx.outs.forEach(function(txOut) {
                switch(txOut.address.version) {
                    case 0:
                        txOut.address.version = versions.address;
                        break;
                    case 5:
                        txOut.address.version = versions.p2sh;
                        break;
                }
            });
        }
        return tx;
    },

    /*
     *  Uncompress a public address
     */
    compressPublicKey: function(bytes) {
        var key = Bitcoin.ECPubKey(bytes, false);
        return key.toBytes(true);
    },

    /*
     *  Uncompress a public address
     */
    uncompressPublicKey: function(bytes) {
        var key = Bitcoin.ECPubKey(bytes, true);
        return key.toBytes(false);
    },

    /*
     * See if this is a valid address
     */
    isAddress: function(address, allowed) {
       if (!allowed) allowed = allowedVersions;
       if (address) {
          // Check for base58 encoded addresses
          if (Bitcoin.Address.validate(address) && allowed.indexOf(Bitcoin.Address.getVersion(address)) != -1) {
            return true;
          }
        }
    },

    /*
     * Validate an address
     */
    validateAddress: function(address, allowed) {
       if (!allowed) allowed = allowedVersions;
       if (address) {
          // Check for base58 encoded addresses
          if (BtcUtils.isAddress(address, allowed)) {
            return true;
          }
          // Check for public keys in different formats
          try {
            BtcUtils.extractPublicKey(address);
            return true;
          } catch (e) {
          }
        }
    },

    parseURI: function(uri) {
      uri = decodeURIComponent(uri);
      var pars = {};
      var req; // BIP-0021
      pars.address = uri.replace('bitcoin:', '').split('?')[0];
      if (uri.split('?')[1]) {
        uri.split('?')[1].split('&').forEach(function(parsed) {
          if(parsed) {
            pars[parsed.split('=')[0]] = parsed.split('=')[1];
            if (parsed.split('=')[0].indexOf('req-') == 0) {
              req = true;
            }
          }
        });
      }
      return !req ? pars : null;
    },

    /*
     * Decode an address from string to bytes
     * Supports the following formats:
     *  - uncompressed hex
     *  - compressed hex
     *  - stealth (6...)
     *  - mpk (xpub...)
     */
    extractPublicKey: function(address, compressed) {
        var bytes;
        if (compressed === undefined) {
            compressed = true;
        }
        if (address.length == 130) {
            // Hex uncompressed address
            bytes = convert.hexToBytes(address)
        } else if (address.length == 66) {
            // Hex compressed address
            bytes = convert.hexToBytes(address);
        } else if (address.length >= 102 && (address[0] == 'v' || address[0] == 'w')) {
            // Stealth address
            var parsed = Stealth.parseAddress(address);
            // Take the first spendKey otherwise the scanKey
            if (parsed.spendKeys.length) {
                bytes = parsed.spendKeys[0];
            } else {
                bytes = parsed.scanKey;
            }
        } else if (address.length == 111 && address.slice(0,4) == 'xpub') {
            // Master public key
            var mpKey = Bitcoin.HDWallet.fromBase58(address);
            bytes = mpKey.pub.toBytes(false);
        } else {
            // Unknown
            throw Error("Can't decode address for multisig with length " + address.length);
        }
        // Decompress if needed
        if (!compressed && bytes.length == 33) {
            bytes = BtcUtils.uncompressPublicKey(bytes);
        }
        else if (compressed && bytes.length == 65) {
            bytes = BtcUtils.compressPublicKey(bytes);
        }
        return bytes;
    },
    // Convert height to js timestamp
    heightToTimestamp: function(height, diff) {
        diff = diff || BtcUtils.blockDiff;
        return (genesisTime+(height*diff))*1000;
    }
  };

  return BtcUtils;
});
<commit_msg>Add a function to calculate raw tx hash.<commit_after>'use strict';

define(['bitcoinjs-lib', 'util/stealth'], function(Bitcoin, Stealth) {
  var convert = Bitcoin.convert;

  var genesisTime = 1231006505;
  var tzOffset = (new Date()).getTimezoneOffset()*60;

  var allowedVersions = [Bitcoin.network.mainnet.addressVersion, Bitcoin.network.mainnet.p2shVersion, Stealth.version];

  function isSmallIntOp(opcode) {
    return ((opcode == Bitcoin.Opcode.map.OP_0) ||
    ((opcode >= Bitcoin.Opcode.map.OP_1) && (opcode <= Bitcoin.Opcode.map.OP_16)))
  }

  var BtcUtils = {
    lastBlock: 296405,
    lastTimestamp: 1397780085,
    blockDiff: 562.65,

    /*
     * Set timestamp for the last block to adjust timestamp heuristics
     */
    setLastTimestamp: function(block, timestamp) {
        BtcUtils.lastBlock = block;
        BtcUtils.lastTimestamp = timestamp;
        BtcUtils.blockDiff = ((timestamp-genesisTime) / block);
    },

    /**
     * Get the address for an input
     */
    getInputAddress: function(anIn, versions) {
        if (!versions) throw Error("No versions!");
        var ops = Bitcoin.Opcode.map;
        var buffer = anIn.script.buffer;
        var lastByte = buffer[buffer.length-1];
        var pubKeys = anIn.script.extractPubkeys();
        if (isSmallIntOp(buffer[0]) && lastByte == ops.OP_CHECKMULTISIG) {
            var multisig = BtcUtils.importMultiSig(convert.bytesToHex(anIn.script.chunks[anIn.script.chunks.length-1]), versions.p2sh);
            return multisig.address;
        } else if (pubKeys && pubKeys.length) {
            var pubKey = new Bitcoin.ECPubKey(pubKeys[0], pubKeys[0].length==33);
            return pubKey.getAddress(versions.address).toString();
        }
    },

    /*
     * Decode a block header
     */
    decodeBlockHeader: function(headerHex) {
        // Don't really need all of these at the moment
        var header = convert.hexToBytes(headerHex);
        var version = convert.bytesToNum(header.splice(0,4));
        var prevBlock = header.splice(0,32);
        var merkleRoot = header.splice(0,32);
        var timestamp = convert.bytesToNum(header.splice(0,4));
        var difficulty = header.splice(0,4);
        var nonce = convert.bytesToNum(header.splice(0,4));
        var difficultyNum = convert.bytesToNum(header.splice(0,4));

        return {version: version, prevBlock: prevBlock, merkleRoot: merkleRoot, timestamp: timestamp, difficulty: difficulty, nonce: nonce};
    },
    /*
     * Start a multisig structure out of participant public keys and m
     */
    multiSig: function(m, participants, version){
        if (version === null || version == undefined) version = Bitcoin.network.mainnet.p2shVersion;
        // Create script
        var script = Bitcoin.Script.createMultiSigOutputScript(m, participants);
        // Hash for address
        var hashed = Bitcoin.crypto.hash160(script.buffer);
        // Encode in base58, v0x05 is multisig
        var address = Bitcoin.base58check.encode(hashed, version);
        // Encoded script
        var scriptHex = convert.bytesToHex(script.buffer);
        return {address: address, script: scriptHex, m: m, pubKeys: participants};
    },

    deriveMpk: function(mpk, index) {
        var mpKey = Bitcoin.HDWallet.fromBase58(mpk);
        var childKey = mpKey.derive(index);
        return childKey.toBase58(false);
    },

    importMultiSig: function(data, version){
        if (version === null || version == undefined) version = Bitcoin.network.mainnet.p2shVersion;
        var script = new Bitcoin.Script(convert.hexToBytes(data));
        var hashed = Bitcoin.crypto.hash160(script.buffer);
        var address = Bitcoin.base58check.encode(hashed, version);
        var pubKeys = script.extractPubkeys();
        var m = script.chunks[0] - Bitcoin.Opcode.map.OP_1 + 1;
        return {address: address, script: data, m: m, pubKeys: pubKeys};
    },

    fixTxVersions: function(tx, identity) {
        // XXX fix trouble with bitcoinjs..
        if (identity.wallet.network == 'testnet') {
            var versions = identity.wallet.versions;
            tx.outs.forEach(function(txOut) {
                switch(txOut.address.version) {
                    case 0:
                        txOut.address.version = versions.address;
                        break;
                    case 5:
                        txOut.address.version = versions.p2sh;
                        break;
                }
            });
        }
        return tx;
    },

    /*
     *  Uncompress a public address
     */
    compressPublicKey: function(bytes) {
        var key = Bitcoin.ECPubKey(bytes, false);
        return key.toBytes(true);
    },

    /*
     *  Uncompress a public address
     */
    uncompressPublicKey: function(bytes) {
        var key = Bitcoin.ECPubKey(bytes, true);
        return key.toBytes(false);
    },

    /*
     * See if this is a valid address
     */
    isAddress: function(address, allowed) {
       if (!allowed) allowed = allowedVersions;
       if (address) {
          // Check for base58 encoded addresses
          if (Bitcoin.Address.validate(address) && allowed.indexOf(Bitcoin.Address.getVersion(address)) != -1) {
            return true;
          }
        }
    },

    /*
     * Validate an address
     */
    validateAddress: function(address, allowed) {
       if (!allowed) allowed = allowedVersions;
       if (address) {
          // Check for base58 encoded addresses
          if (BtcUtils.isAddress(address, allowed)) {
            return true;
          }
          // Check for public keys in different formats
          try {
            BtcUtils.extractPublicKey(address);
            return true;
          } catch (e) {
          }
        }
    },

    parseURI: function(uri) {
      uri = decodeURIComponent(uri);
      var pars = {};
      var req; // BIP-0021
      pars.address = uri.replace('bitcoin:', '').split('?')[0];
      if (uri.split('?')[1]) {
        uri.split('?')[1].split('&').forEach(function(parsed) {
          if(parsed) {
            pars[parsed.split('=')[0]] = parsed.split('=')[1];
            if (parsed.split('=')[0].indexOf('req-') == 0) {
              req = true;
            }
          }
        });
      }
      return !req ? pars : null;
    },

    /*
     * Decode an address from string to bytes
     * Supports the following formats:
     *  - uncompressed hex
     *  - compressed hex
     *  - stealth (6...)
     *  - mpk (xpub...)
     */
    extractPublicKey: function(address, compressed) {
        var bytes;
        if (compressed === undefined) {
            compressed = true;
        }
        if (address.length == 130) {
            // Hex uncompressed address
            bytes = convert.hexToBytes(address)
        } else if (address.length == 66) {
            // Hex compressed address
            bytes = convert.hexToBytes(address);
        } else if (address.length >= 102 && (address[0] == 'v' || address[0] == 'w')) {
            // Stealth address
            var parsed = Stealth.parseAddress(address);
            // Take the first spendKey otherwise the scanKey
            if (parsed.spendKeys.length) {
                bytes = parsed.spendKeys[0];
            } else {
                bytes = parsed.scanKey;
            }
        } else if (address.length == 111 && address.slice(0,4) == 'xpub') {
            // Master public key
            var mpKey = Bitcoin.HDWallet.fromBase58(address);
            bytes = mpKey.pub.toBytes(false);
        } else {
            // Unknown
            throw Error("Can't decode address for multisig with length " + address.length);
        }
        // Decompress if needed
        if (!compressed && bytes.length == 33) {
            bytes = BtcUtils.uncompressPublicKey(bytes);
        }
        else if (compressed && bytes.length == 65) {
            bytes = BtcUtils.compressPublicKey(bytes);
        }
        return bytes;
    },
    // Convert height to js timestamp
    heightToTimestamp: function(height, diff) {
        diff = diff || BtcUtils.blockDiff;
        return (genesisTime+(height*diff))*1000;
    },
    // Calculate hash for a raw hex transaction
    hash256: function(txHex) {
        var SHA256 = Bitcoin.CryptoJS.SHA256;
        var buffer = convert.bytesToWordArray(convert.hexToBytes(txHex));
        var hash = convert.wordArrayToBytes(SHA256(SHA256(buffer)));
        return convert.bytesToHex(hash);
    }
  };

  return BtcUtils;
});
<|endoftext|>


<commit_before>// Raw
// -------
var _ = require('lodash');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;

function Raw(sql, bindings) {
  if (sql && sql.toSQL) {
    var output = sql.toSQL();
    sql = output.sql;
    bindings = output.bindings;
  }
  this.sql = sql;
  this.bindings = _.isArray(bindings) ? bindings :
    bindings ? [bindings] : [];

  if (_.isString(sql)) {
    var replacements = [];
    this.bindings = _.reduce(this.bindings, function(accum, param, index) {
      var innerBindings = [param];
      if (param instanceof Raw) {
        var result = this.splicer(param, index);
        innerBindings = result.bindings;
        replacements.push(result.replacer);
      }
      return accum.concat(innerBindings);
    }.bind(this), []);

    // we run this in reverse order, because ? concats earlier in the
    // query string will disrupt indices for later ones
    this.sql = _.reduce(replacements.reverse(), function(accum, fn) {
      return fn(accum);
    }, this.sql.split('?')).join('?');
  }

  this._debug = void 0;
  this._transacting = void 0;
}
inherits(Raw, EventEmitter);

// Wraps the current sql with `before` and `after`.
Raw.prototype.wrap = function(before, after) {
  this.sql = before + this.sql + after;
  return this;
};

// Calls `toString` on the Knex object.
Raw.prototype.toString = function() {
  return this.toQuery();
};

// Returns a replacer function that splices into the i'th
// ? in the sql string the inner raw's sql,
// and the bindings associated with it
Raw.prototype.splicer = function(raw, i) {
  var obj = raw.toSQL();

  // the replacer function assumes that the sql has been
  // already sql.split('?') and will be arr.join('?')
  var replacer = function(arr) {
    arr[i] = arr[i] + obj.sql + arr[i+1];
    arr.splice(i+1,1);
    return arr;
  };

  return {
    replacer: replacer,
    bindings: obj.bindings
  };
};

// Returns the raw sql for the query.
Raw.prototype.toSQL = function() {
  return {
    sql: this.sql,
    method: 'raw',
    bindings: this.bindings
  };
};

// Allow the `Raw` object to be utilized with full access to the relevant
// promise API.
require('./interface')(Raw);

module.exports = Raw;<commit_msg>Use reduce context rather than .bind<commit_after>// Raw
// -------
var _ = require('lodash');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;

function Raw(sql, bindings) {
  if (sql && sql.toSQL) {
    var output = sql.toSQL();
    sql = output.sql;
    bindings = output.bindings;
  }
  this.sql = sql;
  this.bindings = _.isArray(bindings) ? bindings :
    bindings ? [bindings] : [];

  if (_.isString(sql)) {
    var replacements = [];
    this.bindings = _.reduce(this.bindings, function(accum, param, index) {
      var innerBindings = [param];
      if (param instanceof Raw) {
        var result = this.splicer(param, index);
        innerBindings = result.bindings;
        replacements.push(result.replacer);
      }
      return accum.concat(innerBindings);
    }, [], this);

    // we run this in reverse order, because ? concats earlier in the
    // query string will disrupt indices for later ones
    this.sql = _.reduce(replacements.reverse(), function(accum, fn) {
      return fn(accum);
    }, this.sql.split('?')).join('?');
  }

  this._debug = void 0;
  this._transacting = void 0;
}
inherits(Raw, EventEmitter);

// Wraps the current sql with `before` and `after`.
Raw.prototype.wrap = function(before, after) {
  this.sql = before + this.sql + after;
  return this;
};

// Calls `toString` on the Knex object.
Raw.prototype.toString = function() {
  return this.toQuery();
};

// Returns a replacer function that splices into the i'th
// ? in the sql string the inner raw's sql,
// and the bindings associated with it
Raw.prototype.splicer = function(raw, i) {
  var obj = raw.toSQL();

  // the replacer function assumes that the sql has been
  // already sql.split('?') and will be arr.join('?')
  var replacer = function(arr) {
    arr[i] = arr[i] + obj.sql + arr[i+1];
    arr.splice(i+1,1);
    return arr;
  };

  return {
    replacer: replacer,
    bindings: obj.bindings
  };
};

// Returns the raw sql for the query.
Raw.prototype.toSQL = function() {
  return {
    sql: this.sql,
    method: 'raw',
    bindings: this.bindings
  };
};

// Allow the `Raw` object to be utilized with full access to the relevant
// promise API.
require('./interface')(Raw);

module.exports = Raw;<|endoftext|>