<commit_before>dojo.provide("dijit.form.Button");

dojo.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.require("dijit._HasDropDown");

dojo.declare("dijit.form.Button",
	dijit.form._FormWidget,
	{
	// summary:
	//		Basically the same thing as a normal HTML button, but with special styling.
	// description:
	//		Buttons can display a label, an icon, or both.
	//		A label should always be specified (through innerHTML) or the label
	//		attribute.  It can be hidden via showLabel=false.
	// example:
	// |	<button dojoType="dijit.form.Button" onClick="...">Hello world</button>
	//
	// example:
	// |	var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
	// |	dojo.body().appendChild(button1.domNode);

	// label: HTML String
	//		Text to display in button.
	//		If the label is hidden (showLabel=false) then and no title has
	//		been specified, then label is also set as title attribute of icon.
	label: "",

	// showLabel: Boolean
	//		Set this to true to hide the label text and display only the icon.
	//		(If showLabel=false then iconClass must be specified.)
	//		Especially useful for toolbars.
	//		If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
	//
	//		The exception case is for computers in high-contrast mode, where the label
	//		will still be displayed, since the icon doesn't appear.
	showLabel: true,

	// iconClass: String
	//		Class to apply to DOMNode in button to make it display an icon
	iconClass: "",

	// type: String
	//		Defines the type of button.  "button", "submit", or "reset".
	type: "button",

	baseClass: "dijitButton",

	templateString: dojo.cache("dijit.form", "templates/Button.html"),

	attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
		label: { node: "containerNode", type: "innerHTML" },
		iconClass: { node: "iconNode", type: "class" }
	}),

	_onClick: function(/*Event*/ e){
		// summary:
		//		Internal function to handle click actions
		if(this.disabled){
			return false;
		}
		this._clicked(); // widget click actions
		return this.onClick(e); // user click actions
	},

	_onButtonClick: function(/*Event*/ e){
		// summary:
		//		Handler when the user activates the button portion.
		if(this._onClick(e) === false){ // returning nothing is same as true
			e.preventDefault(); // needed for checkbox
		}else if(this.type == "submit" && !this.focusNode.form){ // see if a nonform widget needs to be signalled
			for(var node=this.domNode; node.parentNode/*#5935*/; node=node.parentNode){
				var widget=dijit.byNode(node);
				if(widget && typeof widget._onSubmit == "function"){
					widget._onSubmit(e);
					break;
				}
			}
		}
	},

	_setValueAttr: function(/*String*/ value){
		// Verify that value cannot be set for BUTTON elements.
		var attr = this.attributeMap.value || '';
		if(this[attr.node || attr || 'domNode'].tagName == 'BUTTON'){
			// On IE, setting value actually overrides innerHTML, so disallow for everyone for consistency
			if(value != this.value){
				console.debug('Cannot change the value attribute on a Button widget.');
			}
		}
	},

	_fillContent: function(/*DomNode*/ source){
		// Overrides _Templated._fillContent().
		// If button label is specified as srcNodeRef.innerHTML rather than
		// this.params.label, handle it here.
		if(source && (!this.params || !("label" in this.params))){
			this.attr('label', source.innerHTML);
		}
	},

	postCreate: function(){
		dojo.setSelectable(this.focusNode, false);
		this.inherited(arguments);
	},

	_setShowLabelAttr: function(val){
		if(this.containerNode){
			dojo.toggleClass(this.containerNode, "dijitDisplayNone", !val);
		}
		this.showLabel = val;
	},

	onClick: function(/*Event*/ e){
		// summary:
		//		Callback for when button is clicked.
		//		If type="submit", return true to perform submit, or false to cancel it.
		// type:
		//		callback
		return true;		// Boolean
	},

	_clicked: function(/*Event*/ e){
		// summary:
		//		Internal overridable function for when the button is clicked
	},

	setLabel: function(/*String*/ content){
		// summary:
		//		Deprecated.  Use attr('label', ...) instead.
		dojo.deprecated("dijit.form.Button.setLabel() is deprecated.  Use attr('label', ...) instead.", "", "2.0");
		this.attr("label", content);
	},
	_setLabelAttr: function(/*String*/ content){
		// summary:
		//		Hook for attr('label', ...) to work.
		// description:
		//		Set the label (text) of the button; takes an HTML string.
		this.containerNode.innerHTML = this.label = content;
		if(this.showLabel == false && !this.params.title){
			this.titleNode.title = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
		}
	}
});

dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container, dijit._HasDropDown], {
	// summary:
	//		A button with a drop down
	//
	// example:
	// |	<button dojoType="dijit.form.DropDownButton" label="Hello world">
	// |
...

	// |	</button>
	//
	// example:
	// |	var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
	// |	dojo.body().appendChild(button1);
	//

	baseClass : "dijitDropDownButton",

	templateString: dojo.cache("dijit.form" , "templates/DropDownButton.html"),

	_fillContent: function(){
		// Overrides Button._fillContent().
		//
		// My inner HTML contains both the button contents and a drop down widget, like
		// <DropDownButton>  push me  <Menu> ... </Menu> </DropDownButton>
		// The first node is assumed to be the button content. The widget is the popup.

		if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
			//FIXME: figure out how to filter out the widget and use all remaining nodes as button
			//	content, not just nodes[0]
			var nodes = dojo.query("*", this.srcNodeRef);
			dijit.form.DropDownButton.superclass._fillContent.call(this, nodes[0]);

			// save pointer to srcNode so we can grab the drop down widget after it's instantiated
			this.dropDownContainer = this.srcNodeRef;
		}
	},

	startup: function(){
		if(this._started){ return; }

		// the child widget from srcNodeRef is the dropdown widget.  Insert it in the page DOM,
		// make it invisible, and store a reference to pass to the popup code.
		if(!this.dropDown){
			var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
			this.dropDown = dijit.byNode(dropDownNode);
			delete this.dropDownContainer;
		}

		this.inherited(arguments);
	},

	isLoaded: function(){
		// Returns whether or not we are loaded - if our dropdown has an href,
		// then we want to check that.
		var dropDown = this.dropDown;
		return (!dropDown.href || dropDown.isLoaded);
	},

	loadDropDown: function(){
		// Loads our dropdown
		var dropDown = this.dropDown;
		if(!dropDown){ return; }
		if(!this.isLoaded()){
			var handler = dojo.connect(dropDown, "onLoad", function(){
				dojo.disconnect(handler);
				this.openDropDown();
			});
			dropDown.refresh();
		}else{
			this.openDropDown();
		}
	},

	isFocusable: function(){
		// Overridden so that focus is handled by the _HasDropDown mixin, not by
		// the _FormWidget mixin.
		return this.inherited(arguments) && !this._mouseDown;
	}
});

dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
	// summary:
	//		A combination button and drop-down button.
	//		Users can click one side to "press" the button, or click an arrow
	//		icon to display the drop down.
	//
	// example:
	// |	<button dojoType="dijit.form.ComboButton" onClick="...">
	// |		Hello world
	// |
...

	// |	</button>
	//
	// example:
	// |	var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
	// |	dojo.body().appendChild(button1.domNode);
	//

	templateString: dojo.cache("dijit.form", "templates/ComboButton.html"),

	attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
		id: "",
		tabIndex: ["focusNode", "titleNode"],
		title: "titleNode"
	}),

	// optionsTitle: String
	//		Text that describes the options menu (accessibility)
	optionsTitle: "",

	baseClass: "dijitComboButton",

	// Set classes like dijitButtonContentsHover or dijitArrowButtonActive depending on
	// mouse action over specified node
	cssStateNodes: {
		"buttonNode": "dijitButtonNode",
		"titleNode": "dijitButtonContents",
		"_popupStateNode": "dijitDownArrowButton"
	},

	_focusedNode: null,

	postCreate: function(){
		this.inherited(arguments);

		var isIE = dojo.isIE;
		if(isIE && (isIE < 8 || dojo.isQuirks)){ // fixed in IE8/strict
			with(this.titleNode){ // resize BUTTON tag so parent TD won't inherit extra padding
				style.width = scrollWidth + "px";
				this.connect(this.titleNode, "onresize", function(){
					setTimeout( function(){ style.width = scrollWidth + "px"; }, 0);
				});
			}
		}
	},

	_onButtonKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handler for right arrow key when focus is on left part of button
		if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
			dijit.focus(this._popupStateNode);
			dojo.stopEvent(evt);
		}
	},

	_onArrowKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handler for left arrow key when focus is on right part of button
		if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
			dijit.focus(this.titleNode);
			dojo.stopEvent(evt);
		}
	},

	focus: function(/*String*/ position){
		// summary:
		//		Focuses this widget to according to position, if specified,
		//		otherwise on arrow node
		// position:
		//		"start" or "end"

		dijit.focus(position == "start" ? this.titleNode : this._popupStateNode);
	}
});

dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
	// summary:
	//		A button that can be in two states (checked or not).
	//		Can be base class for things like tabs or checkbox or radio buttons

	baseClass: "dijitToggleButton",

	// checked: Boolean
	//		Corresponds to the native HTML <input> element's attribute.
	//		In markup, specified as "checked='checked'" or just "checked".
	//		True if the button is depressed, or the checkbox is checked,
	//		or the radio button is selected, etc.
	checked: false,

	attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
		checked:"focusNode"
	}),

	_clicked: function(/*Event*/ evt){
		this.attr('checked', !this.checked);
	},

	_setCheckedAttr: function(/*Boolean*/ value, /* Boolean? */ priorityChange){
		this.checked = value;
		dojo.attr(this.focusNode || this.domNode, "checked", value);
		dijit.setWaiState(this.focusNode || this.domNode, "pressed", value);
		this._handleOnChange(value, priorityChange);
	},

	setChecked: function(/*Boolean*/ checked){
		// summary:
		//		Deprecated.   Use attr('checked', true/false) instead.
		dojo.deprecated("setChecked("+checked+") is deprecated. Use attr('checked',"+checked+") instead.", "", "2.0");
		this.attr('checked', checked);
	},

	reset: function(){
		// summary:
		//		Reset the widget's value to what it was at initialization time

		this._hasBeenBlurred = false;

		// set checked state to original setting
		this.attr('checked', this.params.checked || false);
	}
});
<commit_msg>Adding 'this' to the connect in Button's loadDropDown so the function is called with the widget as context. fixes #10650<commit_after>dojo.provide("dijit.form.Button");

dojo.require("dijit.form._FormWidget");
dojo.require("dijit._Container");
dojo.require("dijit._HasDropDown");

dojo.declare("dijit.form.Button",
	dijit.form._FormWidget,
	{
	// summary:
	//		Basically the same thing as a normal HTML button, but with special styling.
	// description:
	//		Buttons can display a label, an icon, or both.
	//		A label should always be specified (through innerHTML) or the label
	//		attribute.  It can be hidden via showLabel=false.
	// example:
	// |	<button dojoType="dijit.form.Button" onClick="...">Hello world</button>
	//
	// example:
	// |	var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
	// |	dojo.body().appendChild(button1.domNode);

	// label: HTML String
	//		Text to display in button.
	//		If the label is hidden (showLabel=false) then and no title has
	//		been specified, then label is also set as title attribute of icon.
	label: "",

	// showLabel: Boolean
	//		Set this to true to hide the label text and display only the icon.
	//		(If showLabel=false then iconClass must be specified.)
	//		Especially useful for toolbars.
	//		If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
	//
	//		The exception case is for computers in high-contrast mode, where the label
	//		will still be displayed, since the icon doesn't appear.
	showLabel: true,

	// iconClass: String
	//		Class to apply to DOMNode in button to make it display an icon
	iconClass: "",

	// type: String
	//		Defines the type of button.  "button", "submit", or "reset".
	type: "button",

	baseClass: "dijitButton",

	templateString: dojo.cache("dijit.form", "templates/Button.html"),

	attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
		label: { node: "containerNode", type: "innerHTML" },
		iconClass: { node: "iconNode", type: "class" }
	}),

	_onClick: function(/*Event*/ e){
		// summary:
		//		Internal function to handle click actions
		if(this.disabled){
			return false;
		}
		this._clicked(); // widget click actions
		return this.onClick(e); // user click actions
	},

	_onButtonClick: function(/*Event*/ e){
		// summary:
		//		Handler when the user activates the button portion.
		if(this._onClick(e) === false){ // returning nothing is same as true
			e.preventDefault(); // needed for checkbox
		}else if(this.type == "submit" && !this.focusNode.form){ // see if a nonform widget needs to be signalled
			for(var node=this.domNode; node.parentNode/*#5935*/; node=node.parentNode){
				var widget=dijit.byNode(node);
				if(widget && typeof widget._onSubmit == "function"){
					widget._onSubmit(e);
					break;
				}
			}
		}
	},

	_setValueAttr: function(/*String*/ value){
		// Verify that value cannot be set for BUTTON elements.
		var attr = this.attributeMap.value || '';
		if(this[attr.node || attr || 'domNode'].tagName == 'BUTTON'){
			// On IE, setting value actually overrides innerHTML, so disallow for everyone for consistency
			if(value != this.value){
				console.debug('Cannot change the value attribute on a Button widget.');
			}
		}
	},

	_fillContent: function(/*DomNode*/ source){
		// Overrides _Templated._fillContent().
		// If button label is specified as srcNodeRef.innerHTML rather than
		// this.params.label, handle it here.
		if(source && (!this.params || !("label" in this.params))){
			this.attr('label', source.innerHTML);
		}
	},

	postCreate: function(){
		dojo.setSelectable(this.focusNode, false);
		this.inherited(arguments);
	},

	_setShowLabelAttr: function(val){
		if(this.containerNode){
			dojo.toggleClass(this.containerNode, "dijitDisplayNone", !val);
		}
		this.showLabel = val;
	},

	onClick: function(/*Event*/ e){
		// summary:
		//		Callback for when button is clicked.
		//		If type="submit", return true to perform submit, or false to cancel it.
		// type:
		//		callback
		return true;		// Boolean
	},

	_clicked: function(/*Event*/ e){
		// summary:
		//		Internal overridable function for when the button is clicked
	},

	setLabel: function(/*String*/ content){
		// summary:
		//		Deprecated.  Use attr('label', ...) instead.
		dojo.deprecated("dijit.form.Button.setLabel() is deprecated.  Use attr('label', ...) instead.", "", "2.0");
		this.attr("label", content);
	},
	_setLabelAttr: function(/*String*/ content){
		// summary:
		//		Hook for attr('label', ...) to work.
		// description:
		//		Set the label (text) of the button; takes an HTML string.
		this.containerNode.innerHTML = this.label = content;
		if(this.showLabel == false && !this.params.title){
			this.titleNode.title = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
		}
	}
});

dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container, dijit._HasDropDown], {
	// summary:
	//		A button with a drop down
	//
	// example:
	// |	<button dojoType="dijit.form.DropDownButton" label="Hello world">
	// |
...

	// |	</button>
	//
	// example:
	// |	var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
	// |	dojo.body().appendChild(button1);
	//

	baseClass : "dijitDropDownButton",

	templateString: dojo.cache("dijit.form" , "templates/DropDownButton.html"),

	_fillContent: function(){
		// Overrides Button._fillContent().
		//
		// My inner HTML contains both the button contents and a drop down widget, like
		// <DropDownButton>  push me  <Menu> ... </Menu> </DropDownButton>
		// The first node is assumed to be the button content. The widget is the popup.

		if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
			//FIXME: figure out how to filter out the widget and use all remaining nodes as button
			//	content, not just nodes[0]
			var nodes = dojo.query("*", this.srcNodeRef);
			dijit.form.DropDownButton.superclass._fillContent.call(this, nodes[0]);

			// save pointer to srcNode so we can grab the drop down widget after it's instantiated
			this.dropDownContainer = this.srcNodeRef;
		}
	},

	startup: function(){
		if(this._started){ return; }

		// the child widget from srcNodeRef is the dropdown widget.  Insert it in the page DOM,
		// make it invisible, and store a reference to pass to the popup code.
		if(!this.dropDown){
			var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
			this.dropDown = dijit.byNode(dropDownNode);
			delete this.dropDownContainer;
		}

		this.inherited(arguments);
	},

	isLoaded: function(){
		// Returns whether or not we are loaded - if our dropdown has an href,
		// then we want to check that.
		var dropDown = this.dropDown;
		return (!dropDown.href || dropDown.isLoaded);
	},

	loadDropDown: function(){
		// Loads our dropdown
		var dropDown = this.dropDown;
		if(!dropDown){ return; }
		if(!this.isLoaded()){
			var handler = dojo.connect(dropDown, "onLoad", this, function(){
				dojo.disconnect(handler);
				this.openDropDown();
			});
			dropDown.refresh();
		}else{
			this.openDropDown();
		}
	},

	isFocusable: function(){
		// Overridden so that focus is handled by the _HasDropDown mixin, not by
		// the _FormWidget mixin.
		return this.inherited(arguments) && !this._mouseDown;
	}
});

dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
	// summary:
	//		A combination button and drop-down button.
	//		Users can click one side to "press" the button, or click an arrow
	//		icon to display the drop down.
	//
	// example:
	// |	<button dojoType="dijit.form.ComboButton" onClick="...">
	// |		Hello world
	// |
...

	// |	</button>
	//
	// example:
	// |	var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
	// |	dojo.body().appendChild(button1.domNode);
	//

	templateString: dojo.cache("dijit.form", "templates/ComboButton.html"),

	attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
		id: "",
		tabIndex: ["focusNode", "titleNode"],
		title: "titleNode"
	}),

	// optionsTitle: String
	//		Text that describes the options menu (accessibility)
	optionsTitle: "",

	baseClass: "dijitComboButton",

	// Set classes like dijitButtonContentsHover or dijitArrowButtonActive depending on
	// mouse action over specified node
	cssStateNodes: {
		"buttonNode": "dijitButtonNode",
		"titleNode": "dijitButtonContents",
		"_popupStateNode": "dijitDownArrowButton"
	},

	_focusedNode: null,

	postCreate: function(){
		this.inherited(arguments);

		var isIE = dojo.isIE;
		if(isIE && (isIE < 8 || dojo.isQuirks)){ // fixed in IE8/strict
			with(this.titleNode){ // resize BUTTON tag so parent TD won't inherit extra padding
				style.width = scrollWidth + "px";
				this.connect(this.titleNode, "onresize", function(){
					setTimeout( function(){ style.width = scrollWidth + "px"; }, 0);
				});
			}
		}
	},

	_onButtonKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handler for right arrow key when focus is on left part of button
		if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
			dijit.focus(this._popupStateNode);
			dojo.stopEvent(evt);
		}
	},

	_onArrowKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handler for left arrow key when focus is on right part of button
		if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
			dijit.focus(this.titleNode);
			dojo.stopEvent(evt);
		}
	},

	focus: function(/*String*/ position){
		// summary:
		//		Focuses this widget to according to position, if specified,
		//		otherwise on arrow node
		// position:
		//		"start" or "end"

		dijit.focus(position == "start" ? this.titleNode : this._popupStateNode);
	}
});

dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
	// summary:
	//		A button that can be in two states (checked or not).
	//		Can be base class for things like tabs or checkbox or radio buttons

	baseClass: "dijitToggleButton",

	// checked: Boolean
	//		Corresponds to the native HTML <input> element's attribute.
	//		In markup, specified as "checked='checked'" or just "checked".
	//		True if the button is depressed, or the checkbox is checked,
	//		or the radio button is selected, etc.
	checked: false,

	attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
		checked:"focusNode"
	}),

	_clicked: function(/*Event*/ evt){
		this.attr('checked', !this.checked);
	},

	_setCheckedAttr: function(/*Boolean*/ value, /* Boolean? */ priorityChange){
		this.checked = value;
		dojo.attr(this.focusNode || this.domNode, "checked", value);
		dijit.setWaiState(this.focusNode || this.domNode, "pressed", value);
		this._handleOnChange(value, priorityChange);
	},

	setChecked: function(/*Boolean*/ checked){
		// summary:
		//		Deprecated.   Use attr('checked', true/false) instead.
		dojo.deprecated("setChecked("+checked+") is deprecated. Use attr('checked',"+checked+") instead.", "", "2.0");
		this.attr('checked', checked);
	},

	reset: function(){
		// summary:
		//		Reset the widget's value to what it was at initialization time

		this._hasBeenBlurred = false;

		// set checked state to original setting
		this.attr('checked', this.params.checked || false);
	}
});
<|endoftext|>


<commit_before>var scope = angular.element('body').scope();
var game = scope.game;
var units = game.units();
var buyMeat = true;
var buyTerr = true;
var autobuy = 0;
var fasterUpgrades = [];

var autoSpeed = 10000;
var mothN4 = 2013;
var mothEnd = 5546;
var batCount = 393;

game.unitlist().forEach(function(u) {
  var upgrade = u.upgrades.byName[u.name + 'prod'];
  if (upgrade != null) {
    fasterUpgrades.push(upgrade);
  }
});

var empowerList = units.territory._parents().map(function(u) {return game.upgrade(u.name + 'empower')});

function unitRatio(u) {
  if (u._producerPath.getCoefficients().length > 1) {
    return u._producerPath.getCoefficientsNow()[1].dividedBy(u.maxCostMetOfVelocity().times(u.twinMult())).toNumber();
  } else {
    return 0;
  }
}

function currentMeat(unit) {
  if (unitRatio(unit) > 2) {
    return currentMeat(unit.next);
  } else {
    return unit;
  }
}

function buyMeatTwin(unit, amount) {
  var twin = game.upgrade(unit.name + 'twin');
  var realAmount = amount == 0 ? unit.maxCostMet(1).times(unit.twinMult()) : amount;
  if (twin) {
    var parentCost = twin.totalCost()[0].val;
    var parent = twin.totalCost()[0].unit;
    var unitCost = parent.costByName[unit.name].val.dividedBy(parent.twinMult());
    var totalUnitCost = unitCost.times(parentCost);

    if (totalUnitCost.times(1.5).lessThan(realAmount)) {
      if (!twin.isBuyable()) {
        if (unit.count().lessThan(totalUnitCost)) {
          console.log('Twinning-Bought', totalUnitCost.minus(unit.count()).toExponential(2), unit.unittype.slug);
          unit.buy(unitCost.times(parentCost).minus(unit.count()));
        }
        console.log('Twinning-Bought', parentCost.toExponential(2), parent.unittype.slug);
        buyMeatTwin(parent, parentCost);
      }
      if (twin.isBuyable()) {
        twin.buy(1);
        console.log('Bought Twin', unit.unittype.slug);
        buyMeatTwin(unit, amount);
      }
    } else {
      console.log('Bought', realAmount.toExponential(2), unit.unittype.slug);
      unit.buy(realAmount);
    }
  }
}

function currentTerritory() {
  var current = units.swarmling;
  var currentProd = 0;
  units.territory._parents().forEach(function(u) {
    var uProd = u.maxCostMet(1).times(u.twinMult()).times(u.eachProduction().territory);
    if (uProd.greaterThan(currentProd)) {
      currentProd = uProd;
      current = u;
    }
  });
  return current;
}

function unitCostAsPercentOfVelocity (unit, cost) {
  var MAX = new Decimal(9999.99);
  var count = cost.unit.velocity();
  if (count.lessThanOrEqualTo(0)) {
    return MAX;
  }
  return Decimal.min(MAX, cost.val.times(unit.maxCostMetOfVelocity()).dividedBy(count));
}

// var buyList = [game.upgrade('expansion')].concat(units.nexus.upgrades.list);
var buyListProto = _.flatten([units.larva.upgrades.list, units.nexus.upgrades.list, units.meat.upgrades.list, units.territory._parents().map(function(p){return game.upgrade(p.name + 'twin')})]);
var buyList = buyListProto.slice(0);

var buyFunc = function() {
  buyList.forEach(function(u) {
    if (u.isBuyable()) {
      console.log('Bought', u.maxCostMet(1).toNumber(), u.name);
      u.buyMax(1);
    }
  });
  fasterUpgrades.forEach(function(u) {
    if (u.isBuyable() && u.totalCost()[0].val.times(2).lessThan(u.totalCost()[0].unit.count())) {
      console.log('Bought Faster', u.unit.unittype.slug, u.maxCostMet(1).toNumber(), 'times');
      u.buyMax(1);
    }
  });

  var currTerr = currentTerritory();

  empowerList.forEach(function(u) {
    if (u.isBuyable() && currTerr.eachCost()[0].val.greaterThan(u.unit.eachCost()[0].val) && u.unit.totalProduction().territory.times(1000).lessThan(units.territory.velocity())) {
      console.log('Bought Empower', u.unit.unittype.slug);
      u.buy(1);
    }
  });

  currTerr = currentTerritory();

  if (buyTerr && currTerr.isBuyable()) {
    setTimeout(function() {
	  console.log('Bought', currTerr.maxCostMet(1).times(currTerr.twinMult()).toExponential(2), currTerr.unittype.slug);
	  currTerr.buyMax(1);
	}, 1000);
  }

  var currMeat = currentMeat(units.drone);
  var meatList = unitRatio(currMeat) > 0.01 ? [currMeat.next, currMeat] : [currMeat];

  meatList.forEach(function(m) {
    if (buyMeat && m.isBuyable()) {
      setTimeout(function() {
        buyMeatTwin(m, 0);
      }, 2000)
    }
  });
  autobuy = setTimeout(buyFunc, autoSpeed);
};

var autoEnergy = 0;
var autoEnergyF = function() {
  buyList = buyListProto.slice(0);
  if (units.moth.count().toNumber() >= mothN4) {
    if (game.upgrade('nexus5').count().toNumber() == 0) {
      buyList = buyList.concat(game.upgrade('nexus5'));
    } else if (units.moth.count().toNumber() < mothEnd) {
      buyList = buyList.concat(units.moth);
    } else if (units.bat.count().toNumber() < batCount) {
      buyList = buyList.concat(units.bat);
    } else {
      return 0;
    }
  } else {
    buyList = buyList.concat(units.moth);
  }

  autoEnergy = setTimeout(autoEnergyF, autoSpeed);
};
<commit_msg>Update autoEnergy<commit_after>var scope = angular.element('body').scope();
var game = scope.game;
var units = game.units();
var buyMeat = true;
var buyTerr = true;
var buyEnergy = true;
var autobuy = 0;
var fasterUpgrades = [];

var autoSpeed = 10000;
var mothN4 = 2013;
var mothEnd = 5546;
var batCount = 393;

game.unitlist().forEach(function(u) {
  var upgrade = u.upgrades.byName[u.name + 'prod'];
  if (upgrade != null) {
    fasterUpgrades.push(upgrade);
  }
});

var empowerList = units.territory._parents().map(function(u) {return game.upgrade(u.name + 'empower')});

function unitRatio(u) {
  if (u._producerPath.getCoefficients().length > 1) {
    return u._producerPath.getCoefficientsNow()[1].dividedBy(u.maxCostMetOfVelocity().times(u.twinMult())).toNumber();
  } else {
    return 0;
  }
}

function currentMeat(unit) {
  if (unitRatio(unit) > 2) {
    return currentMeat(unit.next);
  } else {
    return unit;
  }
}

function buyMeatTwin(unit, amount) {
  var twin = game.upgrade(unit.name + 'twin');
  var realAmount = amount == 0 ? unit.maxCostMet(1).times(unit.twinMult()) : amount;
  if (twin) {
    var parentCost = twin.totalCost()[0].val;
    var parent = twin.totalCost()[0].unit;
    var unitCost = parent.costByName[unit.name].val.dividedBy(parent.twinMult());
    var totalUnitCost = unitCost.times(parentCost);

    if (totalUnitCost.times(1.5).lessThan(realAmount)) {
      if (!twin.isBuyable()) {
        if (unit.count().lessThan(totalUnitCost)) {
          console.log('Twinning-Bought', totalUnitCost.minus(unit.count()).toExponential(2), unit.unittype.slug);
          unit.buy(unitCost.times(parentCost).minus(unit.count()));
        }
        console.log('Twinning-Bought', parentCost.toExponential(2), parent.unittype.slug);
        buyMeatTwin(parent, parentCost);
      }
      if (twin.isBuyable()) {
        twin.buy(1);
        console.log('Bought Twin', unit.unittype.slug);
        buyMeatTwin(unit, amount);
      }
    } else {
      console.log('Bought', realAmount.toExponential(2), unit.unittype.slug);
      unit.buy(realAmount);
    }
  }
}

function currentTerritory() {
  var current = units.swarmling;
  var currentProd = 0;
  units.territory._parents().forEach(function(u) {
    var uProd = u.maxCostMet(1).times(u.twinMult()).times(u.eachProduction().territory);
    if (uProd.greaterThan(currentProd)) {
      currentProd = uProd;
      current = u;
    }
  });
  return current;
}

function unitCostAsPercentOfVelocity (unit, cost) {
  var MAX = new Decimal(9999.99);
  var count = cost.unit.velocity();
  if (count.lessThanOrEqualTo(0)) {
    return MAX;
  }
  return Decimal.min(MAX, cost.val.times(unit.maxCostMetOfVelocity()).dividedBy(count));
}

// var buyList = [game.upgrade('expansion')].concat(units.nexus.upgrades.list);
var buyListProto = _.flatten([units.larva.upgrades.list, units.nexus.upgrades.list, units.meat.upgrades.list, units.territory._parents().map(function(p){return game.upgrade(p.name + 'twin')})]);
var buyList = buyListProto.slice(0);

var buyFunc = function() {
  if (buyEnergy) {
    autoEnergy();
  }

  buyList.forEach(function(u) {
    if (u.isBuyable()) {
      console.log('Bought', u.maxCostMet(1).toNumber(), u.name);
      u.buyMax(1);
    }
  });
  fasterUpgrades.forEach(function(u) {
    if (u.isBuyable() && u.totalCost()[0].val.times(2).lessThan(u.totalCost()[0].unit.count())) {
      console.log('Bought Faster', u.unit.unittype.slug, u.maxCostMet(1).toNumber(), 'times');
      u.buyMax(1);
    }
  });

  var currTerr = currentTerritory();

  empowerList.forEach(function(u) {
    if (u.isBuyable() && currTerr.eachCost()[0].val.greaterThan(u.unit.eachCost()[0].val) && u.unit.totalProduction().territory.times(1000).lessThan(units.territory.velocity())) {
      console.log('Bought Empower', u.unit.unittype.slug);
      u.buy(1);
    }
  });

  currTerr = currentTerritory();

  if (buyTerr && currTerr.isBuyable()) {
    setTimeout(function() {
	  console.log('Bought', currTerr.maxCostMet(1).times(currTerr.twinMult()).toExponential(2), currTerr.unittype.slug);
	  currTerr.buyMax(1);
	}, 1000);
  }

  var currMeat = currentMeat(units.drone);
  var meatList = unitRatio(currMeat) > 0.01 ? [currMeat.next, currMeat] : [currMeat];

  meatList.forEach(function(m) {
    if (buyMeat && m.isBuyable()) {
      setTimeout(function() {
        buyMeatTwin(m, 0);
      }, 2000)
    }
  });
  autobuy = setTimeout(buyFunc, autoSpeed);
};

var autoEnergy = function() {
  buyList = buyListProto.slice(0);
  if (units.moth.count().toNumber() >= mothN4) {
    if (game.upgrade('nexus5').count().toNumber() == 0) {
      buyList = buyList.concat(game.upgrade('nexus5'));
    } else if (units.moth.count().toNumber() < mothEnd) {
      buyList = buyList.concat(units.moth);
    } else if (units.bat.count().toNumber() < batCount) {
      buyList = buyList.concat(units.bat);
    } else if (game.ascendCost().gt(units.energy._getCap())) {
      buyList.unshift(game.upgrade('swarmwarp'));
    } else {
      // Add ascension?
      return 0;
    }
  } else {
    buyList = buyList.concat(units.moth);
  }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

var path = require('path');

if (typeof(String.prototype.repeat) !== 'function') {
    String.prototype.repeat = function( len )
    {
        return new Array( len + 1 ).join( this );
    }
}

// Parse args
var args = {};
var raw = process.argv.slice(2);
for (var i = 0; i < raw.length; i++) {
    if (raw[i].substr(0, 2) === '--' && raw[i].indexOf('=') !== -1) {
        raw[i] = raw[i].split('=');
        args[raw[i][0].replace('--', '')] = raw[i].slice(1).join('=');
        continue;
    }
    if (raw[i].substr(0, 2) === '--') {
        args[raw[i].replace('--', '')] = raw[++i];
        continue;
    }
    if (raw[i].substr(0, 1) === '-') {
        args[raw[i].replace('-', '')] = raw[++i];
        continue;
    }
    args[raw[i]] = raw[++i];
}

// If there is no function - exit;
var name = args.f || args.function;
if (typeof(name) === 'undefined') {
    console.log('Invalid function name. It should be accessible from invocation place');
    process.exit(1);
}
var basename = path.basename(name);

// Function path recognition
try {
    if (name.substr(-3) !== '.js') name += '.js';
    name = path.resolve(name);
} catch (e) {
    console.log('Cannot resolve given function ' + name);
    process.exit(1);
}

var resolve = function(file) {
    try {
        if (file.substr(-5) !== '.json') file += '.json';
        file = path.resolve(file);
        file = require.resolve(file);
        file = require(file);
        if (typeof(file) === 'string') file = JSON.parse(file);
        return file;
    } catch (e) {}
    return undefined;
};

// Resolve event object
var event = args.e || args.event;
if (typeof(event) !== 'undefined') event = resolve(event);
if (!event) event = {};

// if input argument Context exists - use it
var context = args.c || args.context;
if (typeof(context) !== 'undefined') context = resolve(context);
if (!context) {
    var hash = (Math.random().toString(16).slice(2) + Math.random().toString(16).slice(2) + Math.random().toString(16).slice(2)).substr(0, 32);
    context = {
        awsRequestId    : [
            hash.substr(0, 8), hash.substr(9, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12)
        ].join('-'),
        logGroupName    : '/aws/lambda/' + basename,
        logStreamName   : (new Date()).toISOString().substr(0, 10).replace(/-/g, '/') + '/[$LATEST]' + hash,
        functionName    : basename,
        memoryLimitInMB : '128',
        functionVersion : '$LATEST',
        invokedFunctionArn : 'arn:aws:lambda:aws-region:1234567890123:function:' + basename
    };
    context.invokeId = context.awsRequestId;
}
context._dumpOutput = function(output)
{
    if (Object.prototype.toString.call(output) === '[object Object]') output = JSON.stringify(output, null, 4);
    console.log('OUTPUT');
    console.log('-'.repeat(32));
    console.log(output);
};
context._dumpError = function(error)
{
    console.log('ERROR');
    console.log('-'.repeat(32));
    if (typeof(error) === 'object') {
        if (error.constructor.name == 'Error') {
            console.log(JSON.stringify({
                errorMessage : error.message ? error.message : 'null',
                errorType    : error.constructor.name,
                stackTrace   : error.stack
            }, null, 4));
        } else {
            console.log(JSON.stringify(error, null, 4));
        }
    } else {
        console.log(JSON.stringify({ errorMessage : error }, null, 4));
    }
};
context.done = function(error, message)
{
    if (error) {
        this._dumpError(error);
        console.log();
    }
    this._dumpOutput(message);
    process.exit();
};
context.succeed = function(output)
{
    this._dumpOutput(output);
    process.exit();
};
context.fail = function(error)
{
    this._dumpError(error);
    process.exit();
};

var timeout = args.t || args.timeout || 30;
var exitTimer = setTimeout(function() {
    console.log('Lambda function ' + basename + ' was timed out after ' + timeout + ' seconds');
    process.exit(1);
}, timeout*1000);

var getHandler = function(filename) {
    var exported = require(filename);
    for (var property in exported) {
        if (exported.hasOwnProperty(property) && typeof(exported[property]) === 'function') {
            return exported[property];
        }
    }
    process.exit();
};

if (parseInt((process.version.replace('v', '').replace(/\./g, '') + '00000').substring(0, 5)) >= 43000) {
    var callbackCallFlag = false;
    getHandler(name).call({}, event, context, function(error, output) {
        if (callbackCallFlag) return;
        if (typeof(error) !== 'undefined' && error !== null) {
            context._dumpError(error);
        }
        if (typeof(output) === 'undefined') output = null;
        context._dumpOutput(output);
        callbackCallFlag = true;
    });
} else {
    getHandler(name).call({}, event, context);
}
exitTimer.unref();
<commit_msg>Fixed *context.invokeid* and *context.awsRequestId* format (now HEX only)<commit_after>#!/usr/bin/env node
'use strict';

var path = require('path');

if (typeof(String.prototype.repeat) !== 'function') {
    String.prototype.repeat = function( len )
    {
        return new Array( len + 1 ).join( this );
    }
}

// Parse args
var args = {};
var raw = process.argv.slice(2);
for (var i = 0; i < raw.length; i++) {
    if (raw[i].substr(0, 2) === '--' && raw[i].indexOf('=') !== -1) {
        raw[i] = raw[i].split('=');
        args[raw[i][0].replace('--', '')] = raw[i].slice(1).join('=');
        continue;
    }
    if (raw[i].substr(0, 2) === '--') {
        args[raw[i].replace('--', '')] = raw[++i];
        continue;
    }
    if (raw[i].substr(0, 1) === '-') {
        args[raw[i].replace('-', '')] = raw[++i];
        continue;
    }
    args[raw[i]] = raw[++i];
}

// If there is no function - exit;
var name = args.f || args.function;
if (typeof(name) === 'undefined') {
    console.log('Invalid function name. It should be accessible from invocation place');
    process.exit(1);
}
var basename = path.basename(name);

// Function path recognition
try {
    if (name.substr(-3) !== '.js') name += '.js';
    name = path.resolve(name);
} catch (e) {
    console.log('Cannot resolve given function ' + name);
    process.exit(1);
}

var resolve = function(file) {
    try {
        if (file.substr(-5) !== '.json') file += '.json';
        file = path.resolve(file);
        file = require.resolve(file);
        file = require(file);
        if (typeof(file) === 'string') file = JSON.parse(file);
        return file;
    } catch (e) {}
    return undefined;
};

// Resolve event object
var event = args.e || args.event;
if (typeof(event) !== 'undefined') event = resolve(event);
if (!event) event = {};

// if input argument Context exists - use it
var context = args.c || args.context;
if (typeof(context) !== 'undefined') context = resolve(context);
if (!context) {
    var hash = (Math.random().toString(16).slice(2) + Math.random().toString(16).slice(2) + Math.random().toString(16).slice(2)).substr(0, 32);
    context = {
        awsRequestId    : [
            hash.substr(0, 8), hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12)
        ].join('-'),
        logGroupName    : '/aws/lambda/' + basename,
        logStreamName   : (new Date()).toISOString().substr(0, 10).replace(/-/g, '/') + '/[$LATEST]' + hash,
        functionName    : basename,
        memoryLimitInMB : '128',
        functionVersion : '$LATEST',
        invokedFunctionArn : 'arn:aws:lambda:aws-region:1234567890123:function:' + basename
    };
    context.invokeId = context.awsRequestId;
}
context._dumpOutput = function(output)
{
    if (Object.prototype.toString.call(output) === '[object Object]') output = JSON.stringify(output, null, 4);
    console.log('OUTPUT');
    console.log('-'.repeat(32));
    console.log(output);
};
context._dumpError = function(error)
{
    console.log('ERROR');
    console.log('-'.repeat(32));
    if (typeof(error) === 'object') {
        if (error.constructor.name == 'Error') {
            console.log(JSON.stringify({
                errorMessage : error.message ? error.message : 'null',
                errorType    : error.constructor.name,
                stackTrace   : error.stack
            }, null, 4));
        } else {
            console.log(JSON.stringify(error, null, 4));
        }
    } else {
        console.log(JSON.stringify({ errorMessage : error }, null, 4));
    }
};
context.done = function(error, message)
{
    if (error) {
        this._dumpError(error);
        console.log();
    }
    this._dumpOutput(message);
    process.exit();
};
context.succeed = function(output)
{
    this._dumpOutput(output);
    process.exit();
};
context.fail = function(error)
{
    this._dumpError(error);
    process.exit();
};

var timeout = args.t || args.timeout || 30;
var exitTimer = setTimeout(function() {
    console.log('Lambda function ' + basename + ' was timed out after ' + timeout + ' seconds');
    process.exit(1);
}, timeout*1000);

var getHandler = function(filename) {
    var exported = require(filename);
    for (var property in exported) {
        if (exported.hasOwnProperty(property) && typeof(exported[property]) === 'function') {
            return exported[property];
        }
    }
    process.exit();
};

if (parseInt((process.version.replace('v', '').replace(/\./g, '') + '00000').substring(0, 5)) >= 43000) {
    var callbackCallFlag = false;
    getHandler(name).call({}, event, context, function(error, output) {
        if (callbackCallFlag) return;
        if (typeof(error) !== 'undefined' && error !== null) {
            context._dumpError(error);
        }
        if (typeof(output) === 'undefined') output = null;
        context._dumpOutput(output);
        callbackCallFlag = true;
    });
} else {
    getHandler(name).call({}, event, context);
}
exitTimer.unref();
<|endoftext|>


<commit_before>'use strict';

logViewerApp.controller('LogviewerCtrl', [
    '$anchorScroll', '$http', '$location', '$q', '$rootScope', '$scope',
    '$timeout', 'ThJobArtifactModel', 'ThLog', 'ThLogSliceModel', 'ThJobModel', 'thNotify',
    'dateFilter', 'thJobSearchStr', 'ThResultSetModel', 'thDateFormat', 'thReftestStatus',
    function Logviewer(
        $anchorScroll, $http, $location, $q, $rootScope, $scope,
        $timeout, ThJobArtifactModel, ThLog, ThLogSliceModel, ThJobModel, thNotify,
        dateFilter, thJobSearchStr, ThResultSetModel, thDateFormat, thReftestStatus) {

        var $log = new ThLog('LogviewerCtrl');

        // changes the size of chunks pulled from server
        var LINE_BUFFER_SIZE = 100;
        var LogSlice;

        $rootScope.urlBasePath = $location.absUrl().split('logviewer')[0];

        var query_string = $location.search();
        if (query_string.repo !== "") {
            $rootScope.repoName = query_string.repo;
        }
        if (query_string.job_id !== "") {
            $scope.job_id= query_string.job_id;
            LogSlice = new ThLogSliceModel($scope.job_id, LINE_BUFFER_SIZE);
        }

        $scope.displayedLogLines = [];
        $scope.loading = false;
        $scope.logError = false;
        $scope.jobExists = true;
        $scope.currentLineNumber = 0;
        $scope.highestLine = 0;
        $scope.showSuccessful = true;

        $scope.$watch('artifact', function () {
            if (!$scope.artifact) {
                return;
            }
            $scope.showSuccessful = !$scope.hasFailedSteps();
        });

        $scope.hasFailedSteps = function () {
            var steps = $scope.artifact.step_data.steps;
            for (var i = 0; i < steps.length; i++) {
                // We only recently generated step results as part of ingestion,
                // so we have to check the results property is present.
                // TODO: Remove this when the old data has expired, so long as
                // other data submitters also provide a step result.
                if ('result' in steps[i] && steps[i].result !== 'success' &&
                    steps[i].result !== 'skipped') {

                    return true;
                }
            }
            return false;
        };

        // get the css class for the result color
        // used for the whole job, as well as for each step
        $scope.getShadingClass = function(result) {
            return "result-status-shading-" + result;
        };

        $scope.loadMore = function(bounds, element) {
            var deferred = $q.defer(), range, req, above, below;

            if (!$scope.loading) {
                // move the line number either up or down depending which boundary was hit
                $scope.currentLineNumber = moveLineNumber(bounds);

                range = {
                    start: $scope.currentLineNumber,
                    end: $scope.currentLineNumber
                };

                if (bounds.top) {
                    above = getChunkAbove(range);
                } else if (bounds.bottom) {
                    below = getChunkBelow(range);
                } else {
                    range = getChunksSurrounding($scope.currentLineNumber);
                }

                // dont do the call if we already have all the lines
                if (range.start === range.end) {
                    return deferred.promise;
                }

                $scope.loading = true;
                var lineRangeParams = {
                    job_id: $scope.job_id,
                    start_line: range.start,
                    end_line: range.end
                };
                if ($scope.artifact.logname) {
                    lineRangeParams.name = $scope.artifact.logname;
                }
                LogSlice.get_line_range(lineRangeParams, {
                    buffer_size: LINE_BUFFER_SIZE
                }).then(function(data) {
                    var slicedData, length;

                    drawErrorLines(data);

                    if (bounds.top) {
                        for (var i = data.length - 1; i >= 0; i--) {
                            // make sure we are inserting at the right place
                            if ($scope.displayedLogLines[0].index !== data[i].index + 1) {
                                continue;
                            }
                            $scope.displayedLogLines.unshift(data[i]);
                        }

                        $timeout(function () {
                            if (above) {
                                removeChunkBelow();
                            }
                        }, 100);
                    } else if (bounds.bottom) {
                        var sh = element.scrollHeight;
                        var lines = $scope.displayedLogLines;

                        for (var j = 0; j < data.length; j++) {
                            // make sure we are inserting at the right place
                            if (lines[lines.length - 1].index !== data[j].index - 1) {
                                continue;
                            }
                            $scope.displayedLogLines.push(data[j]);
                        }

                        $timeout(function () {
                            if (below) {
                                removeChunkAbove();
                                element.scrollTop -= element.scrollHeight - sh;
                            }
                        }, 100);
                    } else {
                        $scope.displayedLogLines = data;
                    }

                    $scope.loading = false;
                    deferred.resolve();
                }, function (error) {
                    $scope.loading = false;
                    $scope.logError = true;
                    thNotify.send("The log no longer exists or has expired", 'warning', true);
                    deferred.reject();
                });
            } else {
                deferred.reject();
            }

            return deferred.promise;
        };

        // @@@ it may be possible to do this with the angular date filter?
        $scope.formatTime = function(sec) {
            var h = Math.floor(sec/3600);
            var m = Math.floor(sec%3600/60);
            var s = Math.floor(sec%3600 % 60);
            var secStng = sec.toString();
            var ms = secStng.substr(secStng.indexOf(".")+1, 2);
            return ((h > 0 ? h + "h " : "") + (m > 0 ? m + "m " : "") +
                   (s > 0 ? s + "s " : "") + (ms > 0 ? ms + "ms " : "00ms"));
        };

        $scope.displayTime = function(started, finished) {
            var start = started ? started.substr(started.indexOf(" ")+1, 8) : '?';
            var end = finished ? finished.substr(finished.indexOf(" ")+1, 8) : '?';
            return start + "-" + end;
        };

        $scope.init = function() {

            $scope.logProperties = [];
            ThJobModel.get($scope.repoName, $scope.job_id).then(function(job) {
                var jobStr = thJobSearchStr(job);

                // set the title of the browser window/tab
                $scope.logViewerTitle = "Log for " + jobStr;

                // set the result value and shading color class
                $scope.result = {label: "Result", value: job.result};
                $scope.resultStatusShading = $scope.getShadingClass(job.result);

                // other properties, in order of appearance
                $scope.logProperties = [
                    {label: "Job", value: jobStr},
                    {label: "Machine", value: job.machine_name},
                    {label: "Start", value: dateFilter(job.start_timestamp*1000, thDateFormat)},
                    {label: "End", value: dateFilter(job.end_timestamp*1000, thDateFormat)}
                ];

                // Test to expose the reftest button in the logviewer actionbar
                $scope.isReftest = function() {
                    if (job.job_group_name) {
                        return thReftestStatus(job);
                    }
                };

                // get the revision and linkify it
                ThResultSetModel.getResultSet($scope.repoName, job.result_set_id).then(function(data){
                    var revision = data.data.revision;
                    $scope.logProperties.push({label: "Revision", value: revision});
                });

            }, function (error) {
                $scope.loading = false;
                $scope.jobExists = false;
                thNotify.send("The job does not exist or has expired", 'danger', true);
            });

            // Make the log and job artifacts available
            ThJobArtifactModel.get_list({job_id: $scope.job_id, name__in: 'text_log_summary,Job Info'})
            .then(function(artifactList) {
                artifactList.forEach(function(artifact) {
                    if (artifact.name === 'text_log_summary') {
                        $scope.artifact = artifact.blob;
                        $scope.step_data = artifact.blob.step_data;

                        // If the log contains no errors load the head otherwise
                        // load the first failure step line in the artifact. We
                        // also need to test for the 0th element for outlier jobs.
                        if ($scope.step_data.steps[0]) {

                            if ($scope.step_data.all_errors.length == 0) {
                                angular.element(document).ready(function () {
                                    $scope.displayLog($scope.step_data.steps[0], 'initialLoad');
                                });
                            } else {
                                $timeout(function() {
                                    angular.element('.lv-error-line').first().trigger('click');
                                }, 100);
                            }
                        }

                    } else if (artifact.name === 'Job Info') {
                        $scope.job_details = artifact.blob.job_details;
                    }
                });
            });
        };

        /** utility functions **/

        function logFileLineCount () {
            var steps = $scope.artifact.step_data.steps;
            return steps[ steps.length - 1 ].finished_linenumber;
        }

        function moveLineNumber (bounds) {
            var lines = $scope.displayedLogLines, newLine;

            if (bounds.top) {
                return lines[0].index;
            } else if (bounds.bottom) {
                newLine = lines[lines.length - 1].index + 1;
                return (newLine > logFileLineCount()) ? logFileLineCount(): newLine;
            }

            return $scope.currentLineNumber;
        }

        function drawErrorLines (data) {
            if (data.length === 0) {
                return;
            }

            var min = data[0].index;
            var max = data[ data.length - 1 ].index;

            $scope.artifact.step_data.steps.forEach(function(step) {
                step.errors.forEach(function(err) {
                    var line = err.linenumber;

                    if (line < min || line > max) {
                        return;
                    }

                    var index = line - min;
                    data[index].hasError = true;
                });
            });
        }

        function getChunksSurrounding(line) {
            var request = {start: null, end: null};

            getChunkContaining(line, request);
            getChunkAbove(request);
            getChunkBelow(request);

            return request;
        }

        function getChunkContaining (line, request) {
            var index = Math.floor(line/LINE_BUFFER_SIZE);

            request.start = index * LINE_BUFFER_SIZE;
            request.end = (index + 1) * LINE_BUFFER_SIZE;
        }

        function getChunkAbove (request) {
            request.start -= LINE_BUFFER_SIZE;
            request.start = Math.floor(request.start/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.start >= 0) {
                return true;
            } else {
                request.start = 0;
                return false;
            }
        }

        function getChunkBelow (request) {
            var lastLine = logFileLineCount();

            request.end += LINE_BUFFER_SIZE;
            request.end = Math.ceil(request.end/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.end <= lastLine) {
                return true;
            } else {
                request.end = lastLine;
                return false;
            }
        }

        function removeChunkAbove (request) {
            $scope.displayedLogLines = $scope.displayedLogLines.slice(LINE_BUFFER_SIZE);
        }

        function removeChunkBelow (request) {
            var endSlice = $scope.displayedLogLines.length - LINE_BUFFER_SIZE;
            $scope.displayedLogLines = $scope.displayedLogLines.slice(0, endSlice);
        }
    }
]);
<commit_msg>Bug 1192199 - Return a correct line count for logviewer navigation<commit_after>'use strict';

logViewerApp.controller('LogviewerCtrl', [
    '$anchorScroll', '$http', '$location', '$q', '$rootScope', '$scope',
    '$timeout', 'ThJobArtifactModel', 'ThLog', 'ThLogSliceModel', 'ThJobModel', 'thNotify',
    'dateFilter', 'thJobSearchStr', 'ThResultSetModel', 'thDateFormat', 'thReftestStatus',
    function Logviewer(
        $anchorScroll, $http, $location, $q, $rootScope, $scope,
        $timeout, ThJobArtifactModel, ThLog, ThLogSliceModel, ThJobModel, thNotify,
        dateFilter, thJobSearchStr, ThResultSetModel, thDateFormat, thReftestStatus) {

        var $log = new ThLog('LogviewerCtrl');

        // changes the size of chunks pulled from server
        var LINE_BUFFER_SIZE = 100;
        var LogSlice;

        $rootScope.urlBasePath = $location.absUrl().split('logviewer')[0];

        var query_string = $location.search();
        if (query_string.repo !== "") {
            $rootScope.repoName = query_string.repo;
        }
        if (query_string.job_id !== "") {
            $scope.job_id= query_string.job_id;
            LogSlice = new ThLogSliceModel($scope.job_id, LINE_BUFFER_SIZE);
        }

        $scope.displayedLogLines = [];
        $scope.loading = false;
        $scope.logError = false;
        $scope.jobExists = true;
        $scope.currentLineNumber = 0;
        $scope.highestLine = 0;
        $scope.showSuccessful = true;

        $scope.$watch('artifact', function () {
            if (!$scope.artifact) {
                return;
            }
            $scope.showSuccessful = !$scope.hasFailedSteps();
        });

        $scope.hasFailedSteps = function () {
            var steps = $scope.artifact.step_data.steps;
            for (var i = 0; i < steps.length; i++) {
                // We only recently generated step results as part of ingestion,
                // so we have to check the results property is present.
                // TODO: Remove this when the old data has expired, so long as
                // other data submitters also provide a step result.
                if ('result' in steps[i] && steps[i].result !== 'success' &&
                    steps[i].result !== 'skipped') {

                    return true;
                }
            }
            return false;
        };

        // get the css class for the result color
        // used for the whole job, as well as for each step
        $scope.getShadingClass = function(result) {
            return "result-status-shading-" + result;
        };

        $scope.loadMore = function(bounds, element) {
            var deferred = $q.defer(), range, req, above, below;

            if (!$scope.loading) {
                // move the line number either up or down depending which boundary was hit
                $scope.currentLineNumber = moveLineNumber(bounds);

                range = {
                    start: $scope.currentLineNumber,
                    end: $scope.currentLineNumber
                };

                if (bounds.top) {
                    above = getChunkAbove(range);
                } else if (bounds.bottom) {
                    below = getChunkBelow(range);
                } else {
                    range = getChunksSurrounding($scope.currentLineNumber);
                }

                // dont do the call if we already have all the lines
                if (range.start === range.end) {
                    return deferred.promise;
                }

                $scope.loading = true;
                var lineRangeParams = {
                    job_id: $scope.job_id,
                    start_line: range.start,
                    end_line: range.end
                };
                if ($scope.artifact.logname) {
                    lineRangeParams.name = $scope.artifact.logname;
                }
                LogSlice.get_line_range(lineRangeParams, {
                    buffer_size: LINE_BUFFER_SIZE
                }).then(function(data) {

                    drawErrorLines(data);

                    if (bounds.top) {
                        for (var i = data.length - 1; i >= 0; i--) {
                            // make sure we are inserting at the right place
                            if ($scope.displayedLogLines[0].index !== data[i].index + 1) {
                                continue;
                            }
                            $scope.displayedLogLines.unshift(data[i]);
                        }

                        $timeout(function () {
                            if (above) {
                                removeChunkBelow();
                            }
                        }, 100);
                    } else if (bounds.bottom) {
                        var sh = element.scrollHeight;
                        var lines = $scope.displayedLogLines;

                        for (var j = 0; j < data.length; j++) {
                            // make sure we are inserting at the right place
                            if (lines[lines.length - 1].index !== data[j].index - 1) {
                                continue;
                            }
                            $scope.displayedLogLines.push(data[j]);
                        }

                        $timeout(function () {
                            if (below) {
                                removeChunkAbove();
                                element.scrollTop -= element.scrollHeight - sh;
                            }
                        }, 100);
                    } else {
                        $scope.displayedLogLines = data;
                    }

                    $scope.loading = false;
                    deferred.resolve();
                }, function (error) {
                    $scope.loading = false;
                    $scope.logError = true;
                    thNotify.send("The log no longer exists or has expired", 'warning', true);
                    deferred.reject();
                });
            } else {
                deferred.reject();
            }

            return deferred.promise;
        };

        // @@@ it may be possible to do this with the angular date filter?
        $scope.formatTime = function(sec) {
            var h = Math.floor(sec/3600);
            var m = Math.floor(sec%3600/60);
            var s = Math.floor(sec%3600 % 60);
            var secStng = sec.toString();
            var ms = secStng.substr(secStng.indexOf(".")+1, 2);
            return ((h > 0 ? h + "h " : "") + (m > 0 ? m + "m " : "") +
                   (s > 0 ? s + "s " : "") + (ms > 0 ? ms + "ms " : "00ms"));
        };

        $scope.displayTime = function(started, finished) {
            var start = started ? started.substr(started.indexOf(" ")+1, 8) : '?';
            var end = finished ? finished.substr(finished.indexOf(" ")+1, 8) : '?';
            return start + "-" + end;
        };

        $scope.init = function() {

            $scope.logProperties = [];
            ThJobModel.get($scope.repoName, $scope.job_id).then(function(job) {
                var jobStr = thJobSearchStr(job);

                // set the title of the browser window/tab
                $scope.logViewerTitle = "Log for " + jobStr;

                // set the result value and shading color class
                $scope.result = {label: "Result", value: job.result};
                $scope.resultStatusShading = $scope.getShadingClass(job.result);

                // other properties, in order of appearance
                $scope.logProperties = [
                    {label: "Job", value: jobStr},
                    {label: "Machine", value: job.machine_name},
                    {label: "Start", value: dateFilter(job.start_timestamp*1000, thDateFormat)},
                    {label: "End", value: dateFilter(job.end_timestamp*1000, thDateFormat)}
                ];

                // Test to expose the reftest button in the logviewer actionbar
                $scope.isReftest = function() {
                    if (job.job_group_name) {
                        return thReftestStatus(job);
                    }
                };

                // get the revision and linkify it
                ThResultSetModel.getResultSet($scope.repoName, job.result_set_id).then(function(data){
                    var revision = data.data.revision;
                    $scope.logProperties.push({label: "Revision", value: revision});
                });

            }, function (error) {
                $scope.loading = false;
                $scope.jobExists = false;
                thNotify.send("The job does not exist or has expired", 'danger', true);
            });

            // Make the log and job artifacts available
            ThJobArtifactModel.get_list({job_id: $scope.job_id, name__in: 'text_log_summary,Job Info'})
            .then(function(artifactList) {
                artifactList.forEach(function(artifact) {
                    if (artifact.name === 'text_log_summary') {
                        $scope.artifact = artifact.blob;
                        $scope.step_data = artifact.blob.step_data;

                        // If the log contains no errors load the head otherwise
                        // load the first failure step line in the artifact. We
                        // also need to test for the 0th element for outlier jobs.
                        if ($scope.step_data.steps[0]) {

                            if ($scope.step_data.all_errors.length == 0) {
                                angular.element(document).ready(function () {
                                    $scope.displayLog($scope.step_data.steps[0], 'initialLoad');
                                });
                            } else {
                                $timeout(function() {
                                    angular.element('.lv-error-line').first().trigger('click');
                                }, 100);
                            }
                        }

                    } else if (artifact.name === 'Job Info') {
                        $scope.job_details = artifact.blob.job_details;
                    }
                });
            });
        };

        /** utility functions **/

        function logFileLineCount () {
            var steps = $scope.artifact.step_data.steps;
            return steps[ steps.length - 1 ].finished_linenumber + 1;
        }

        function moveLineNumber (bounds) {
            var lines = $scope.displayedLogLines, newLine;

            if (bounds.top) {
                return lines[0].index;
            } else if (bounds.bottom) {
                newLine = lines[lines.length - 1].index + 1;
                return (newLine > logFileLineCount()) ? logFileLineCount(): newLine;
            }

            return $scope.currentLineNumber;
        }

        function drawErrorLines (data) {
            if (data.length === 0) {
                return;
            }

            var min = data[0].index;
            var max = data[ data.length - 1 ].index;

            $scope.artifact.step_data.steps.forEach(function(step) {
                step.errors.forEach(function(err) {
                    var line = err.linenumber;

                    if (line < min || line > max) {
                        return;
                    }

                    var index = line - min;
                    data[index].hasError = true;
                });
            });
        }

        function getChunksSurrounding(line) {
            var request = {start: null, end: null};

            getChunkContaining(line, request);
            getChunkAbove(request);
            getChunkBelow(request);

            return request;
        }

        function getChunkContaining (line, request) {
            var index = Math.floor(line/LINE_BUFFER_SIZE);

            request.start = index * LINE_BUFFER_SIZE;
            request.end = (index + 1) * LINE_BUFFER_SIZE;
        }

        function getChunkAbove (request) {
            request.start -= LINE_BUFFER_SIZE;
            request.start = Math.floor(request.start/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.start >= 0) {
                return true;
            } else {
                request.start = 0;
                return false;
            }
        }

        function getChunkBelow (request) {
            var lastLine = logFileLineCount();

            request.end += LINE_BUFFER_SIZE;
            request.end = Math.ceil(request.end/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.end <= lastLine) {
                return true;
            } else {
                request.end = lastLine;
                return false;
            }
        }

        function removeChunkAbove (request) {
            $scope.displayedLogLines = $scope.displayedLogLines.slice(LINE_BUFFER_SIZE);
        }

        function removeChunkBelow (request) {
            var endSlice = $scope.displayedLogLines.length - LINE_BUFFER_SIZE;
            $scope.displayedLogLines = $scope.displayedLogLines.slice(0, endSlice);
        }
    }
]);
<|endoftext|>


<commit_before>var clear_results = function (form) {
  form = $(form);
  form.find('.body').text("");
  form.find('.response-body').addClass('hidden');
  form.find('.response-headers').addClass('hidden');
  form.find('.request-data').addClass('hidden');
  form.find('.data').text("");
  form.find('.headers').text("");
  form.find('.call').text("");
  form.find('.method').text("");

  form.hide();
};

function toggle_livedoc(identifier, show) {
  if (show) {
    $('#parameters-' + identifier).hide();
    $('#apiexample-' + identifier).hide();
    $('#livedoc-' + identifier).show();
    $('#cancel-' + identifier).show();
    $('#tryit-' + identifier).hide();
  }
  else {
    $('#parameters-' + identifier).show();
    $('#apiexample-' + identifier).show();
    $('#livedoc-' + identifier).hide();
    $('#cancel-' + identifier).hide();
    $('#tryit-' + identifier).show();
  }
}

function getParamHtml(data) {
  var required = $(data[1]).text().trim().toLowerCase() == "true" || $(data[1]).text().trim().toLowerCase() == "yes";

  var param = {
    name: $(data[0]).text().trim(),
    required: required,
    requirements: $(data[2]).text().trim(),
    description: $(data[3]).text().trim(),
    class: required == true ? "required" : ""
  };

  return $.render.form_field_template(param);
}

$(function () {
  //using jsrender for templates https://github.com/BorisMoore/jsrender
  var form_field_template = '
{{>name}}	<input type="text" class="{{>class}}" name="{{>name}}" {{if required}} placeholder="required" {{/if}} 	{{>requirements}}	{{>description}}
';
  var cancel_button = '<button class="btn btn-danger cancel" id="cancel-{{>identifier}}">Cancel</button>';
  var tryit_button = '<button class="btn btn-success tryit" id="tryit-{{>identifier}}"> Try It</button>';

  $.templates({
    form_field_template: form_field_template,
    cancel_button: cancel_button,
    tryit_button: tryit_button
  });

  $('.live-doc').each(function () {
    var livedoc = $(this);
    var form = $(this).find('form');
    var form_table = $(this).find('form>table');

    var id = $(this).attr('id');
    var identifier = id.substr(id.indexOf('-') + 1, id.length);

    var tryit_html = $.render.tryit_button({ identifier: identifier });
    var cancel_html = $.render.cancel_button({ identifier: identifier });
    livedoc.prevAll('.anchor-wrap').first().after(tryit_html + cancel_html);

    var params_table = $('#parameters-' + identifier);
    var rows = params_table.find('tr').slice(1); //throw out the header row

    var form_fields_html = "";
    rows.each(function () {
      form_fields_html += getParamHtml($(this).children('td'));
    });
    form_table.append(form_fields_html);

    if (rows.length == 0) {
      form_table.append('
No Parameters Needed
');
    }

    form.append('<button type="input" class="btn btn-primary form-control">Make Request</button>');
  });

  $('.tryit').click(function () {
    var id = $(this).attr('id');
    var identifier = id.substr(id.indexOf('-') + 1, id.length);
    toggle_livedoc(identifier, true);
  });

  $('.cancel').click(function () {
    var id = $(this).attr('id');
    var identifier = id.substr(id.indexOf('-') + 1, id.length);
    toggle_livedoc(identifier, false);
  });

  $('.clear-request').click(function () {
    clear_results($(this).closest('.live-call'));
  });

  $('.live-doc form').submit(function (e) {
    e.preventDefault();

    //TODO validate that all required inputs have values

    //TODO check that the user has set username/password and json/xml response

    url = $(this).parent().find('.url').val();
    method = $(this).parent().find('.method').val().toUpperCase().trim();
    data = $(this).serialize().replace(/[^&]+=(?:&|$)/g, '').replace(/&$/, ''); //throw out empty params
    format = "json"; //TODO

    if (method == "GET") {
      call = url + "." + format + "?" + data
    } else {
      call = url + "." + format
    }

    live_call = $(this).nextAll('.live-call');
    live_call.find('.method').text(method);
    live_call.find('.call').text(call);

    if (method != "GET") {
      live_call.find('.request-data').removeClass("hidden");
      live_call.find('.data').text(decodeURIComponent(data));
    }

    live_call.find(".bar-indicator").show();
    live_call.show();

    $.ajax({
      type: method,
      url: url,
      data: data
    })
      .done(function (response, statusText, jqXHR) {
        live_call.find('.body').text(response);
        live_call.find('.response-body').removeClass('hidden');

        live_call.find('.headers').text(jqXHR.getAllResponseHeaders());
        live_call.find('.response-headers').removeClass('hidden');
      })
      .fail(function (response, statusText) {
        live_call.find('.body').text(statusText);
        live_call.find('.response-body').removeClass('hidden');
      })
      .always(function () {
        live_call.find(".bar-indicator").hide();
      });
  });
});
<commit_msg>further compose methods<commit_after>var clear_results = function (form) {
  form = $(form);
  form.find('.body').text("");
  form.find('.response-body').addClass('hidden');
  form.find('.response-headers').addClass('hidden');
  form.find('.request-data').addClass('hidden');
  form.find('.data').text("");
  form.find('.headers').text("");
  form.find('.call').text("");
  form.find('.method').text("");

  form.hide();
};

function toggle_livedoc(identifier, show) {
  if (show) {
    $('#parameters-' + identifier).hide();
    $('#apiexample-' + identifier).hide();
    $('#livedoc-' + identifier).show();
    $('#cancel-' + identifier).show();
    $('#tryit-' + identifier).hide();
  }
  else {
    $('#parameters-' + identifier).show();
    $('#apiexample-' + identifier).show();
    $('#livedoc-' + identifier).hide();
    $('#cancel-' + identifier).hide();
    $('#tryit-' + identifier).show();
  }
}

function getParamHtml(data) {
  var required = $(data[1]).text().trim().toLowerCase() == "true" || $(data[1]).text().trim().toLowerCase() == "yes";

  var param = {
    name: $(data[0]).text().trim(),
    required: required,
    requirements: $(data[2]).text().trim(),
    description: $(data[3]).text().trim(),
    class: required == true ? "required" : ""
  };

  return $.render.form_field_template(param);
}

function addButtons(identifier, livedoc) {
  var tryit_html = $.render.tryit_button({ identifier: identifier });
  var cancel_html = $.render.cancel_button({ identifier: identifier });
  livedoc.prevAll('.anchor-wrap').first().after(tryit_html + cancel_html);
}

function getFormFieldHtml(identifier) {
  var params_table = $('#parameters-' + identifier);
  var rows = params_table.find('tr').slice(1); //throw out the header row

  var form_fields_html = "";
  rows.each(function () {
    form_fields_html += getParamHtml($(this).children('td'));
  });

  if (rows.length == 0) {
    form_fields_html += '
No Parameters Needed
';
  }

  return form_fields_html;
}

$(function () {
  //using jsrender for templates https://github.com/BorisMoore/jsrender
  var form_field_template = '
{{>name}}	<input type="text" class="{{>class}}" name="{{>name}}" {{if required}} placeholder="required" {{/if}} 	{{>requirements}}	{{>description}}
';
  var cancel_button = '<button class="btn btn-danger cancel" id="cancel-{{>identifier}}">Cancel</button>';
  var tryit_button = '<button class="btn btn-success tryit" id="tryit-{{>identifier}}"> Try It</button>';

  $.templates({
    form_field_template: form_field_template,
    cancel_button: cancel_button,
    tryit_button: tryit_button
  });

  $('.live-doc').each(function () {
    var livedoc = $(this);
    var form = $(this).find('form');
    var form_table = $(this).find('form>table');

    var id = $(this).attr('id');
    var identifier = id.substr(id.indexOf('-') + 1, id.length);

    addButtons(identifier, livedoc);
    form_table.append(getFormFieldHtml(identifier));

    form.append('<button type="input" class="btn btn-primary form-control">Make Request</button>');
  });

  $('.tryit').click(function () {
    var id = $(this).attr('id');
    var identifier = id.substr(id.indexOf('-') + 1, id.length);
    toggle_livedoc(identifier, true);
  });

  $('.cancel').click(function () {
    var id = $(this).attr('id');
    var identifier = id.substr(id.indexOf('-') + 1, id.length);
    toggle_livedoc(identifier, false);
  });

  $('.clear-request').click(function () {
    clear_results($(this).closest('.live-call'));
  });

  $('.live-doc form').submit(function (e) {
    e.preventDefault();

    //TODO validate that all required inputs have values

    //TODO check that the user has set username/password and json/xml response

    url = $(this).parent().find('.url').val();
    method = $(this).parent().find('.method').val().toUpperCase().trim();
    data = $(this).serialize().replace(/[^&]+=(?:&|$)/g, '').replace(/&$/, ''); //throw out empty params
    format = "json"; //TODO

    if (method == "GET") {
      call = url + "." + format + "?" + data
    } else {
      call = url + "." + format
    }

    live_call = $(this).nextAll('.live-call');
    live_call.find('.method').text(method);
    live_call.find('.call').text(call);

    if (method != "GET") {
      live_call.find('.request-data').removeClass("hidden");
      live_call.find('.data').text(decodeURIComponent(data));
    }

    live_call.find(".bar-indicator").show();
    live_call.show();

    $.ajax({
      type: method,
      url: url,
      data: data
    })
      .done(function (response, statusText, jqXHR) {
        live_call.find('.body').text(response);
        live_call.find('.response-body').removeClass('hidden');

        live_call.find('.headers').text(jqXHR.getAllResponseHeaders());
        live_call.find('.response-headers').removeClass('hidden');
      })
      .fail(function (response, statusText) {
        live_call.find('.body').text(statusText);
        live_call.find('.response-body').removeClass('hidden');
      })
      .always(function () {
        live_call.find(".bar-indicator").hide();
      });
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router';
import { getTagName, getAttributes, getChildren, isElement } from 'jsonml.js/lib/utils';
import toReactComponent from 'jsonml-to-react-component';
import VideoPlayer from './VideoPlayer';
import ImagePreview from './ImagePreview';

function isHeading(type) {
  return /h[1-6]/i.test(type);
}

export function jsonmlToComponent(pathname, jsonml) {
  return toReactComponent(jsonml, [
    [(node) => React.isValidElement(node), (node, index) => {
      return React.cloneElement(node, { key: index });
    }],
    [(node) => typeof node === 'function', (node, index) => {
      return React.cloneElement(node(React, ReactDOM), { key: index });
    }],
    [(node) => isHeading(getTagName(node)), (node, index) => {
      const children = getChildren(node);
      return React.createElement(getTagName(node), {
        key: index,
        id: children,
        ...getAttributes(node),
      }, [
        {children.map((child) => toReactComponent(child))},
        <Link to={{ pathname, query: { scrollTo: children } }} className="anchor" key="anchor">#</Link>,
      ]);
    }],
    [(node) => getTagName(node) === 'pre' && getAttributes(node).highlighted, (node, index) => {
      return React.createElement('pre', { key: index, lang: getAttributes(node).lang }, React.createElement(
        'code',
        { dangerouslySetInnerHTML: { __html: getChildren(getChildren(node)[0])[0] } }
      ));
    }],
    [(node) => getTagName(node) === 'video', (node, index) =>
      <VideoPlayer video={getAttributes(node)} key={index} />
    ],
    [(node) => getTagName(node) === 'a', (node, index) =>
      <Link to={getAttributes(node).href} key={index}>{toReactComponent(getChildren(node)[0])}</Link>
    ],
    [(node) => {
      return isElement(node) &&
        getTagName(node) === 'p' &&
        getTagName(getChildren(node)[0]) === 'img' &&
        /preview-img/gi.test(getAttributes(getChildren(node)[0]).class);
    }, (node, index) => {
      const imgs = getChildren(node)
              .filter((img) => isElement(img) && Object.keys(getAttributes(img)).length > 0)
              .map((img) => getAttributes(img));
      return <ImagePreview imgs={imgs} key={index} />;
    }],
  ]);
}

export function setTitle(title) {
  document.title = title;
}
<commit_msg>site: fix bug<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router';
import { getTagName, getAttributes, getChildren, isElement } from 'jsonml.js/lib/utils';
import toReactComponent from 'jsonml-to-react-component';
import VideoPlayer from './VideoPlayer';
import ImagePreview from './ImagePreview';

function isHeading(type) {
  return /h[1-6]/i.test(type);
}

export function jsonmlToComponent(pathname, jsonml) {
  return toReactComponent(jsonml, [
    [(node) => React.isValidElement(node), (node, index) => {
      return React.cloneElement(node, { key: index });
    }],
    [(node) => typeof node === 'function', (node, index) => {
      return React.cloneElement(node(React, ReactDOM), { key: index });
    }],
    [(node) => isHeading(getTagName(node)), (node, index) => {
      const children = getChildren(node);
      return React.createElement(getTagName(node), {
        key: index,
        id: children,
        ...getAttributes(node),
      }, [
        {children.map((child) => toReactComponent(child))},
        <Link to={{ pathname, query: { scrollTo: children } }} className="anchor" key="anchor">#</Link>,
      ]);
    }],
    [(node) => getTagName(node) === 'pre' && getAttributes(node).highlighted, (node, index) => {
      return React.createElement('pre', { key: index, lang: getAttributes(node).lang }, React.createElement(
        'code',
        { dangerouslySetInnerHTML: { __html: getChildren(getChildren(node)[0])[0] } }
      ));
    }],
    [(node) => getTagName(node) === 'video', (node, index) =>
      <VideoPlayer video={getAttributes(node)} key={index} />
    ],
    [(node) => isElement(node) && getTagName(node) === 'a', (node, index) =>
      <Link to={getAttributes(node).href} key={index}>{toReactComponent(getChildren(node)[0])}</Link>
    ],
    [(node) => {
      return isElement(node) &&
        getTagName(node) === 'p' &&
        getTagName(getChildren(node)[0]) === 'img' &&
        /preview-img/gi.test(getAttributes(getChildren(node)[0]).class);
    }, (node, index) => {
      const imgs = getChildren(node)
              .filter((img) => isElement(img) && Object.keys(getAttributes(img)).length > 0)
              .map((img) => getAttributes(img));
      return <ImagePreview imgs={imgs} key={index} />;
    }],
  ]);
}

export function setTitle(title) {
  document.title = title;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * Responsible for quality control
 */
export class QualityControl {

   /**
    * Creates an quality control instance
    */
    constructor(context, blob) {
        this.context = context;
        this.blob = blob;
        this.audioBuffer;
    }

   /**
    * Checks if sound is of good quality: not too short or silent
    */
    async isQualitySound() {
        const blobArrayBuffer = await this.blob.arrayBuffer();
        this.audioBuffer = await this.context.decodeAudioData(blobArrayBuffer);

        const qualityResult = {
            success: true,
            errorMessage: '',
        };

        const audioResult = this.soundCheck();

        if (this.audioBuffer.duration < 2.0) {
            qualityResult.success = false;
            qualityResult.errorMessage += 'Audio recording failed: recording was too short. Try again';
        } else if (audioResult) {
            qualityResult.success = false;
            qualityResult.errorMessage += audioResult;
        }

        return qualityResult;
    }

   /**
    * Checks if the sound is too silent
    */
    soundCheck() {
        const bufferArray = this.audioBuffer.getChannelData(0);;
        const bufferSet = new Set(bufferArray);
        const arrOfSet = [];
        for (let data of bufferSet) {
            arrOfSet.push(data);
        }
        const arrOfBiggest = [];
        for(let i = 0; i < 100; i++){
            const max = Math.max(...arrOfSet);
            arrOfBiggest.push(max);
            const index = arrOfSet.indexOf(max);
            arrOfSet.splice(index, 1);
        }
        let total = 0;
        for (let i = 0; i < arrOfBiggest.length; i++) {
            total += arrOfBiggest[i];
        }
        const avg = total / arrOfBiggest.length;
        if (avg > 0.2) {
            return null;
        } else {
            return 'Audio recording failed: recording was silent. Try again';
        }
    }
}<commit_msg>remove extra semicolon<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * Responsible for quality control
 */
export class QualityControl {

   /**
    * Creates an quality control instance
    */
    constructor(context, blob) {
        this.context = context;
        this.blob = blob;
        this.audioBuffer;
    }

   /**
    * Checks if sound is of good quality: not too short or silent
    */
    async isQualitySound() {
        const blobArrayBuffer = await this.blob.arrayBuffer();
        this.audioBuffer = await this.context.decodeAudioData(blobArrayBuffer);

        const qualityResult = {
            success: true,
            errorMessage: '',
        };

        const audioResult = this.soundCheck();

        if (this.audioBuffer.duration < 2.0) {
            qualityResult.success = false;
            qualityResult.errorMessage += 'Audio recording failed: recording was too short. Try again';
        } else if (audioResult) {
            qualityResult.success = false;
            qualityResult.errorMessage += audioResult;
        }

        return qualityResult;
    }

   /**
    * Checks if the sound is too silent
    */
    soundCheck() {
        const bufferArray = this.audioBuffer.getChannelData(0);
        const bufferSet = new Set(bufferArray);
        const arrOfSet = [];
        for (let data of bufferSet) {
            arrOfSet.push(data);
        }
        const arrOfBiggest = [];
        for(let i = 0; i < 100; i++){
            const max = Math.max(...arrOfSet);
            arrOfBiggest.push(max);
            const index = arrOfSet.indexOf(max);
            arrOfSet.splice(index, 1);
        }
        let total = 0;
        for (let i = 0; i < arrOfBiggest.length; i++) {
            total += arrOfBiggest[i];
        }
        const avg = total / arrOfBiggest.length;
        if (avg > 0.2) {
            return null;
        } else {
            return 'Audio recording failed: recording was silent. Try again';
        }
    }
}<|endoftext|>