<commit_before>/*!
 * jQuery UI Selectmenu @VERSION
 * http://jqueryui.com
 *
 * Copyright 2012 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/selectmenu
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *	jquery.ui.position.js
 *	jquery.ui.menu.js
 */
(function( $, undefined ) {

$.widget( "ui.selectmenu", {
	version: "@VERSION",
	defaultElement: "<select>",
	options: {
		appendTo: "body",
		dropdown: true,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},

		// callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		select: null
	},

	_create: function() {
		// make / set unique id
		var selectmenuId = this.element.uniqueId().attr( "id" );

		// array of button and menu id's
		this.ids = { id: selectmenuId, button: selectmenuId + "-button", menu: selectmenuId + "-menu" };

		this._drawButton();
		this._on( this.button, this._buttonEvents );
		this._hoverable( this.button );
		this._focusable( this.button );

		this._drawMenu();

		// document click closes menu
		this._on( document, {
			click: function( event ) {
				if ( this.isOpen && !$( event.target ).closest( "li.ui-state-disabled, li.ui-selectmenu-optgroup, #" + this.ids.button ).length ) {
					this.close( event );
				}
			}
		});

		if ( this.options.disabled ) {
			this.disable();
		}
	},

	_drawButton: function() {
		var tabindex = this.element.attr( "tabindex" );

		// fix existing label
		this.label = $( "label[for='" + this.ids.id + "']" ).attr( "for", this.ids.button );
		// catch click event of the label
		this._on( this.label, {
			"click":  function( event ) {
				this.button.focus();
				event.preventDefault();
			}
		});

		// hide original select tag
		this.element.hide();

		// create button
		this.button = $( "<a />", {
			"class": "ui-button ui-widget ui-state-default ui-corner-all",
			href: "#" + this.ids.id,
			tabindex: ( tabindex ? tabindex : this.options.disabled ? -1 : 0 ),
			id: this.ids.button,
			width: this.element.outerWidth(),
			role: "combobox",
			"aria-expanded": false,
			"aria-autocomplete": "list",
			"aria-owns": this.ids.menu,
			"aria-haspopup": true
		});

		this.button.prepend( $( "<span />", {
			"class": "ui-icon " + ( ( this.options.dropdown ) ? "ui-icon-triangle-1-s" : "ui-icon-triangle-2-n-s" )
		}));

		this.buttonText = $( "<span />", {
				"class": "ui-selectmenu-text" ,
				html: this.element.find( "option:selected" ).text() || " "
			})
			.appendTo( this.button );

		// wrap and insert new button
		this.buttonWrap = $( "<span />", {
				"class": "ui-selectmenu-button"
			})
			.append( this.button )
			.insertAfter( this.element );
	},

	_drawMenu: function() {
		var menuInstance,
			that = this;

		// create menu portion, append to body
		this.menu = $( "<ul />", {
			"aria-hidden": true,
			"aria-labelledby": this.ids.button,
			id: this.ids.menu
		});

		// wrap menu
		this.menuWrap = $( "<div />", {
				"class": "ui-selectmenu-menu",
				width: ( this.options.dropdown ) ? this.button.outerWidth() : this.buttonText.width() + parseFloat( this.buttonText.css( "padding-left" ) ) || 0 + parseFloat( this.buttonText.css( "margin-left") ) || 0
			})
			.append( this.menu )
			.appendTo( this.options.appendTo );

		// init menu widget
		menuInstance = this.menu.menu({
			select: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				that._select( item, event );

				if ( that.isOpen ) {
					event.preventDefault();
					that.close( event );
				}
			},
			focus: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				if ( that.focus !== undefined ) {
					if ( item.index !== that.focus ) {
						that._trigger( "focus", event, { item: item } );
						if ( !that.isOpen ) {
							that._select( item, event );
						}
					}
				}
				that.focus = item.index;

				// Set ARIA active decendent
				that.button.attr( "aria-activedescendant", that.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
			},
			// set ARIA role
			role: "listbox"
		})
		.data( "ui-menu" );

		// change menu styles?
		if ( this.options.dropdown ) {
			this.menu.addClass( "ui-corner-bottom" ).removeClass( "ui-corner-all" );
		}

		// make sure focus stays on selected item
		menuInstance.delay = 999999999;
		// unbind uneeded Menu events
		menuInstance._off( this.menu, "mouseleave" );
	},

	refresh: function() {
		this.menu.empty();

		var item,
			options = this.element.find( "option" );
		if ( options.length ) {
			this._readOptions( options );
			this._renderMenu( this.menu, this.items );

			this.menu.menu( "refresh" );
			this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );

			// select current item
			item = this._getSelectedItem();
			this.menu.menu( "focus", null, item );
			this._setSelected( item.data( "ui-selectmenu-item" ) );

			// set disabled state
			this._setOption( "disabled", this._getCreateOptions().disabled );
		}
	},

	open: function( event ) {
		if ( !this.options.disabled ) {
			var _position = {
				of: this.button
			};

			// make sure menu is refreshed on first init (needed at least for IE9)
			if ( this.isOpen === undefined ) {
				this.button.trigger( "focus" );
			}

			this.isOpen = true;
			this._toggleAttr();
			this.menu.menu( "focus", event, this._getSelectedItem() );

			if ( this.items && !this.options.dropdown && this.options.position.my == "left top" && this.options.position.at == "left bottom" ) {
				var currentItem = this._getSelectedItem();
				// center current item
				if ( this.menu.outerHeight() < this.menu.prop( "scrollHeight" ) ) {
					this.menuWrap.css( "left" , -10000 );
					this.menu.scrollTop( this.menu.scrollTop() + currentItem.position().top - this.menu.outerHeight() / 2 + currentItem.outerHeight() / 2 );
					this.menuWrap.css( "left" , "auto" );
				}
				_position.my = "left top" + ( this.menu.offset().top  - currentItem.offset().top + ( this.button.outerHeight() - currentItem.outerHeight() ) / 2 );
				_position.at = "left top";
			}

			this.menuWrap
				.zIndex( this.element.zIndex() + 1 )
				.position( $.extend( {}, this.options.position, _position ) );

			this._trigger( "open", event );
		}
	},

	close: function( event ) {
		if ( this.isOpen ) {
			var id = this._getSelectedItem().find( "a" ).attr( "id" );
			this.isOpen = false;
			this._toggleAttr();
			this.button.attr( "aria-activedescendant", id );
			this.menu.attr( "aria-activedescendant", id );
			this._trigger( "close", event );
		}
	},

	widget: function() {
		return this.button;
	},

	menuWidget: function() {
		return this.menu;
	},

	_renderMenu: function( ul, items ) {
		var that = this,
			currentOptgroup = "";

		$.each( items, function( index, item ) {
			if ( item.optgroup !== currentOptgroup ) {
				$( "<li />", {
					"class": "ui-selectmenu-optgroup" + ( item.element.parent( "optgroup" ).attr( "disabled" ) ? " ui-state-disabled" : "" ),
					html: item.optgroup
				}).appendTo( ul );
				currentOptgroup = item.optgroup;
			}
			that._renderItem( ul, item );
		});
	},

	_renderItem: function( ul, item ) {
		var li = $( "<li />" ).data( "ui-selectmenu-item", item );
		if ( item.disabled ) {
			li.addClass( "ui-state-disabled" );
		}
		li.append( $( "<a />", {
				html: item.label,
				href: "#"
			})
		);

		return li.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( direction === "first" || direction === "last" ) {
			// set focus manually for first or last item
			this.menu.menu( "focus", event, this.menuItems[ direction ]() );
		} else {
			// move to and focus next or prev item
			this.menu.menu( direction, event );
		}
	},

	_getSelectedItem: function() {
		return this.menuItems.eq( this.element[ 0 ].selectedIndex );
	},

	_toggle: function( event ) {
		if ( this.isOpen ) {
			this.close( event );
		} else {
			this.open( event );
		}
	},

	_buttonEvents: {
		focus: function() {
			// init Menu on first focus
			this.refresh();
			// reset focus class as its removed by ui.widget._setOption
			this.button.addClass( "ui-state-focus" );
			this._off( this.button, "focus" );
		},
		click: function( event ) {
			this._toggle( event );
			event.preventDefault();
		},
		keydown: function( event ) {
			var prevDef = true;
			switch ( event.keyCode ) {
				case $.ui.keyCode.TAB:
				case $.ui.keyCode.ESCAPE:
					if ( this.isOpen ) {
						this.close( event );
					}
					prevDef = false;
					break;
				case $.ui.keyCode.ENTER:
					if ( this.isOpen ) {
						this.menu.menu( "select", event );
					}
					break;
				case $.ui.keyCode.UP:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "previous", event );
					}
					break;
				case $.ui.keyCode.DOWN:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "next", event );
					}
					break;
				case $.ui.keyCode.SPACE:
					this._toggle( event );
					break;
				case $.ui.keyCode.LEFT:
					this._move( "previous", event );
					break;
				case $.ui.keyCode.RIGHT:
					this._move( "next", event );
					break;
				case $.ui.keyCode.HOME:
				case $.ui.keyCode.PAGE_UP:
					this._move( "first", event );
					break;
				case $.ui.keyCode.END:
				case $.ui.keyCode.PAGE_DOWN:
					this._move( "last", event );
					break;
				default:
					this.menu.trigger( event );
					prevDef = false;
			}
			if ( prevDef ) {
				event.preventDefault();
			}
		}
	},

	_select: function( item, event ) {
		var oldIndex = this.element[ 0 ].selectedIndex;
		// change native select element
		this.element[ 0 ].selectedIndex = item.index;
		this._setSelected( item );
		this._trigger( "select", event, { item: item } );

		if ( item.index !== oldIndex ) {
			this._trigger( "change", event, { item: item } );
		}
	},

	_setSelected: function( item ) {
		// update button text
		this.buttonText.html( item.label );
		// change ARIA attr
		this.menuItems.find( "a" ).attr( "aria-selected", false );
		this._getSelectedItem().find( "a" ).attr( "aria-selected", true );
		this.button.attr( "aria-labelledby", this.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
	},

	_setOption: function( key, value ) {
		this._super( key, value );

		if ( key === "appendTo" ) {
			this.menuWrap.appendTo( $( value || "body", this.element[ 0 ].ownerDocument )[ 0 ] );
		}
		if ( key === "disabled" ) {
			this.menu.menu( "option", "disabled", value );
			if ( value ) {
				this.element.attr( "disabled", "disabled" );
				this.button.attr( "tabindex", -1 );
				this.close();
			} else {
				this.element.removeAttr( "disabled" );
				this.button.attr( "tabindex", 0 );
			}
		}
	},

	_toggleAttr: function(){
		if ( this.options.dropdown ) {
			this.button.toggleClass( "ui-corner-top", this.isOpen ).toggleClass( "ui-corner-all", !this.isOpen );
		}
		this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
		this.menu.attr( "aria-hidden", !this.isOpen);
		this.button.attr( "aria-expanded", this.isOpen);
	},

	_getCreateOptions: function() {
		return { disabled: !!this.element.attr( "disabled" ) };
	},

	_readOptions: function( options ) {
		var data = [];
		$.each( options, function( index, item ) {
			var option = $( item ),
				optgroup = option.parent( "optgroup" );
			data.push({
				element: option,
				index: index,
				value: option.attr( "value" ),
				label: option.text() || " ",
				optgroup: optgroup.attr( "label" ) || "",
				disabled: optgroup.attr( "disabled" ) || option.attr( "disabled" )
			});
		});
		this.items = data;
	},

	_destroy: function() {
		this.menuWrap.remove();
		this.buttonWrap.remove();
		this.element.show();
		this.element.removeUniqueId();
		this.label.attr( "for", this.ids.id );
	}
});

}( jQuery ));
<commit_msg>Selectmenu: remove unnecessary comments from _create<commit_after>/*!
 * jQuery UI Selectmenu @VERSION
 * http://jqueryui.com
 *
 * Copyright 2012 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/selectmenu
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *	jquery.ui.position.js
 *	jquery.ui.menu.js
 */
(function( $, undefined ) {

$.widget( "ui.selectmenu", {
	version: "@VERSION",
	defaultElement: "<select>",
	options: {
		appendTo: "body",
		dropdown: true,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},

		// callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		select: null
	},

	_create: function() {
		var selectmenuId = this.element.uniqueId().attr( "id" );
		this.ids = { id: selectmenuId, button: selectmenuId + "-button", menu: selectmenuId + "-menu" };

		this._drawButton();
		this._on( this.button, this._buttonEvents );
		this._hoverable( this.button );
		this._focusable( this.button );

		this._drawMenu();

		// document click closes menu
		this._on( document, {
			click: function( event ) {
				if ( this.isOpen && !$( event.target ).closest( "li.ui-state-disabled, li.ui-selectmenu-optgroup, #" + this.ids.button ).length ) {
					this.close( event );
				}
			}
		});

		if ( this.options.disabled ) {
			this.disable();
		}
	},

	_drawButton: function() {
		var tabindex = this.element.attr( "tabindex" );

		// fix existing label
		this.label = $( "label[for='" + this.ids.id + "']" ).attr( "for", this.ids.button );
		// catch click event of the label
		this._on( this.label, {
			"click":  function( event ) {
				this.button.focus();
				event.preventDefault();
			}
		});

		// hide original select tag
		this.element.hide();

		// create button
		this.button = $( "<a />", {
			"class": "ui-button ui-widget ui-state-default ui-corner-all",
			href: "#" + this.ids.id,
			tabindex: ( tabindex ? tabindex : this.options.disabled ? -1 : 0 ),
			id: this.ids.button,
			width: this.element.outerWidth(),
			role: "combobox",
			"aria-expanded": false,
			"aria-autocomplete": "list",
			"aria-owns": this.ids.menu,
			"aria-haspopup": true
		});

		this.button.prepend( $( "<span />", {
			"class": "ui-icon " + ( ( this.options.dropdown ) ? "ui-icon-triangle-1-s" : "ui-icon-triangle-2-n-s" )
		}));

		this.buttonText = $( "<span />", {
				"class": "ui-selectmenu-text" ,
				html: this.element.find( "option:selected" ).text() || " "
			})
			.appendTo( this.button );

		// wrap and insert new button
		this.buttonWrap = $( "<span />", {
				"class": "ui-selectmenu-button"
			})
			.append( this.button )
			.insertAfter( this.element );
	},

	_drawMenu: function() {
		var menuInstance,
			that = this;

		// create menu portion, append to body
		this.menu = $( "<ul />", {
			"aria-hidden": true,
			"aria-labelledby": this.ids.button,
			id: this.ids.menu
		});

		// wrap menu
		this.menuWrap = $( "<div />", {
				"class": "ui-selectmenu-menu",
				width: ( this.options.dropdown ) ? this.button.outerWidth() : this.buttonText.width() + parseFloat( this.buttonText.css( "padding-left" ) ) || 0 + parseFloat( this.buttonText.css( "margin-left") ) || 0
			})
			.append( this.menu )
			.appendTo( this.options.appendTo );

		// init menu widget
		menuInstance = this.menu.menu({
			select: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				that._select( item, event );

				if ( that.isOpen ) {
					event.preventDefault();
					that.close( event );
				}
			},
			focus: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				if ( that.focus !== undefined ) {
					if ( item.index !== that.focus ) {
						that._trigger( "focus", event, { item: item } );
						if ( !that.isOpen ) {
							that._select( item, event );
						}
					}
				}
				that.focus = item.index;

				// Set ARIA active decendent
				that.button.attr( "aria-activedescendant", that.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
			},
			// set ARIA role
			role: "listbox"
		})
		.data( "ui-menu" );

		// change menu styles?
		if ( this.options.dropdown ) {
			this.menu.addClass( "ui-corner-bottom" ).removeClass( "ui-corner-all" );
		}

		// make sure focus stays on selected item
		menuInstance.delay = 999999999;
		// unbind uneeded Menu events
		menuInstance._off( this.menu, "mouseleave" );
	},

	refresh: function() {
		this.menu.empty();

		var item,
			options = this.element.find( "option" );
		if ( options.length ) {
			this._readOptions( options );
			this._renderMenu( this.menu, this.items );

			this.menu.menu( "refresh" );
			this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );

			// select current item
			item = this._getSelectedItem();
			this.menu.menu( "focus", null, item );
			this._setSelected( item.data( "ui-selectmenu-item" ) );

			// set disabled state
			this._setOption( "disabled", this._getCreateOptions().disabled );
		}
	},

	open: function( event ) {
		if ( !this.options.disabled ) {
			var _position = {
				of: this.button
			};

			// make sure menu is refreshed on first init (needed at least for IE9)
			if ( this.isOpen === undefined ) {
				this.button.trigger( "focus" );
			}

			this.isOpen = true;
			this._toggleAttr();
			this.menu.menu( "focus", event, this._getSelectedItem() );

			if ( this.items && !this.options.dropdown && this.options.position.my == "left top" && this.options.position.at == "left bottom" ) {
				var currentItem = this._getSelectedItem();
				// center current item
				if ( this.menu.outerHeight() < this.menu.prop( "scrollHeight" ) ) {
					this.menuWrap.css( "left" , -10000 );
					this.menu.scrollTop( this.menu.scrollTop() + currentItem.position().top - this.menu.outerHeight() / 2 + currentItem.outerHeight() / 2 );
					this.menuWrap.css( "left" , "auto" );
				}
				_position.my = "left top" + ( this.menu.offset().top  - currentItem.offset().top + ( this.button.outerHeight() - currentItem.outerHeight() ) / 2 );
				_position.at = "left top";
			}

			this.menuWrap
				.zIndex( this.element.zIndex() + 1 )
				.position( $.extend( {}, this.options.position, _position ) );

			this._trigger( "open", event );
		}
	},

	close: function( event ) {
		if ( this.isOpen ) {
			var id = this._getSelectedItem().find( "a" ).attr( "id" );
			this.isOpen = false;
			this._toggleAttr();
			this.button.attr( "aria-activedescendant", id );
			this.menu.attr( "aria-activedescendant", id );
			this._trigger( "close", event );
		}
	},

	widget: function() {
		return this.button;
	},

	menuWidget: function() {
		return this.menu;
	},

	_renderMenu: function( ul, items ) {
		var that = this,
			currentOptgroup = "";

		$.each( items, function( index, item ) {
			if ( item.optgroup !== currentOptgroup ) {
				$( "<li />", {
					"class": "ui-selectmenu-optgroup" + ( item.element.parent( "optgroup" ).attr( "disabled" ) ? " ui-state-disabled" : "" ),
					html: item.optgroup
				}).appendTo( ul );
				currentOptgroup = item.optgroup;
			}
			that._renderItem( ul, item );
		});
	},

	_renderItem: function( ul, item ) {
		var li = $( "<li />" ).data( "ui-selectmenu-item", item );
		if ( item.disabled ) {
			li.addClass( "ui-state-disabled" );
		}
		li.append( $( "<a />", {
				html: item.label,
				href: "#"
			})
		);

		return li.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( direction === "first" || direction === "last" ) {
			// set focus manually for first or last item
			this.menu.menu( "focus", event, this.menuItems[ direction ]() );
		} else {
			// move to and focus next or prev item
			this.menu.menu( direction, event );
		}
	},

	_getSelectedItem: function() {
		return this.menuItems.eq( this.element[ 0 ].selectedIndex );
	},

	_toggle: function( event ) {
		if ( this.isOpen ) {
			this.close( event );
		} else {
			this.open( event );
		}
	},

	_buttonEvents: {
		focus: function() {
			// init Menu on first focus
			this.refresh();
			// reset focus class as its removed by ui.widget._setOption
			this.button.addClass( "ui-state-focus" );
			this._off( this.button, "focus" );
		},
		click: function( event ) {
			this._toggle( event );
			event.preventDefault();
		},
		keydown: function( event ) {
			var prevDef = true;
			switch ( event.keyCode ) {
				case $.ui.keyCode.TAB:
				case $.ui.keyCode.ESCAPE:
					if ( this.isOpen ) {
						this.close( event );
					}
					prevDef = false;
					break;
				case $.ui.keyCode.ENTER:
					if ( this.isOpen ) {
						this.menu.menu( "select", event );
					}
					break;
				case $.ui.keyCode.UP:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "previous", event );
					}
					break;
				case $.ui.keyCode.DOWN:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "next", event );
					}
					break;
				case $.ui.keyCode.SPACE:
					this._toggle( event );
					break;
				case $.ui.keyCode.LEFT:
					this._move( "previous", event );
					break;
				case $.ui.keyCode.RIGHT:
					this._move( "next", event );
					break;
				case $.ui.keyCode.HOME:
				case $.ui.keyCode.PAGE_UP:
					this._move( "first", event );
					break;
				case $.ui.keyCode.END:
				case $.ui.keyCode.PAGE_DOWN:
					this._move( "last", event );
					break;
				default:
					this.menu.trigger( event );
					prevDef = false;
			}
			if ( prevDef ) {
				event.preventDefault();
			}
		}
	},

	_select: function( item, event ) {
		var oldIndex = this.element[ 0 ].selectedIndex;
		// change native select element
		this.element[ 0 ].selectedIndex = item.index;
		this._setSelected( item );
		this._trigger( "select", event, { item: item } );

		if ( item.index !== oldIndex ) {
			this._trigger( "change", event, { item: item } );
		}
	},

	_setSelected: function( item ) {
		// update button text
		this.buttonText.html( item.label );
		// change ARIA attr
		this.menuItems.find( "a" ).attr( "aria-selected", false );
		this._getSelectedItem().find( "a" ).attr( "aria-selected", true );
		this.button.attr( "aria-labelledby", this.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
	},

	_setOption: function( key, value ) {
		this._super( key, value );

		if ( key === "appendTo" ) {
			this.menuWrap.appendTo( $( value || "body", this.element[ 0 ].ownerDocument )[ 0 ] );
		}
		if ( key === "disabled" ) {
			this.menu.menu( "option", "disabled", value );
			if ( value ) {
				this.element.attr( "disabled", "disabled" );
				this.button.attr( "tabindex", -1 );
				this.close();
			} else {
				this.element.removeAttr( "disabled" );
				this.button.attr( "tabindex", 0 );
			}
		}
	},

	_toggleAttr: function(){
		if ( this.options.dropdown ) {
			this.button.toggleClass( "ui-corner-top", this.isOpen ).toggleClass( "ui-corner-all", !this.isOpen );
		}
		this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
		this.menu.attr( "aria-hidden", !this.isOpen);
		this.button.attr( "aria-expanded", this.isOpen);
	},

	_getCreateOptions: function() {
		return { disabled: !!this.element.attr( "disabled" ) };
	},

	_readOptions: function( options ) {
		var data = [];
		$.each( options, function( index, item ) {
			var option = $( item ),
				optgroup = option.parent( "optgroup" );
			data.push({
				element: option,
				index: index,
				value: option.attr( "value" ),
				label: option.text() || " ",
				optgroup: optgroup.attr( "label" ) || "",
				disabled: optgroup.attr( "disabled" ) || option.attr( "disabled" )
			});
		});
		this.items = data;
	},

	_destroy: function() {
		this.menuWrap.remove();
		this.buttonWrap.remove();
		this.element.show();
		this.element.removeUniqueId();
		this.label.attr( "for", this.ids.id );
	}
});

}( jQuery ));
<|endoftext|>


<commit_before>'use strict';
var _ = require('lodash');

module.exports = function bullet(name, numerator, denominator, ranges) {

	function model(data) {
		var obj   = {
			campaign: {
				start_date: 0
			},
			value: null
		};
		var whole = 0;
		var part  = 0;

		for (var i = data.objects.length - 1; i >= 0; i--) {
			var d          = data.objects[i];
			var indicators = _.indexBy(d.indicators, 'indicator');

			if (!indicators.hasOwnProperty(denominator) ||
				!indicators.hasOwnProperty(numerator)) {

				console.warn(name + ': ' + d.campaign.name + ' only has indicators ' + _.keys(indicators));
				continue;
			}

			var w = Number(indicators[denominator].value);
			var p = Number(indicators[numerator].value);

			if (!obj || d.campaign.start_date > obj.campaign.start_date) {
				obj = d;
				obj.value = (w > 0) ? p / w : null;
			}

			whole += w;
			part  += p;
		}

		return _.assign(obj, {
			name  : name,
			marker: part / whole,
			ranges: ranges
		});
	}

	return model;
};
<commit_msg>Keep the indicators array in the bullet model<commit_after>'use strict';
var _ = require('lodash');

module.exports = function bullet(name, numerator, denominator, ranges) {

	function model(data) {
		var obj   = {
			campaign: {
				start_date: 0
			},
			value: null
		};
		var whole = 0;
		var part  = 0;

		for (var i = data.objects.length - 1; i >= 0; i--) {
			var d          = data.objects[i];
			var indicators = _.indexBy(d.indicators, 'indicator');

			if (!indicators.hasOwnProperty(denominator) ||
				!indicators.hasOwnProperty(numerator)) {

				console.warn(name + ': ' + d.campaign.name + ' only has indicators ' + _.keys(indicators));
				continue;
			}

			var w = Number(indicators[denominator].value);
			var p = Number(indicators[numerator].value);

			if (!obj || d.campaign.start_date > obj.campaign.start_date) {
				obj = d;
				obj.value = (w > 0) ? p / w : null;
			}

			whole += w;
			part  += p;
		}

		return _.assign(obj, {
			name      : name,
			marker    : part / whole,
			ranges    : ranges,
			indicators: [numerator, denominator]
		});
	}

	return model;
};
<|endoftext|>


<commit_before>const Discord = require('discord.js');
const embed = new Discord.RichEmbed();
class embedMessage {
  constructor(msg) {
    this.message = msg
  }

  descEmbed(options) {
    if (!options) {
      throw Error('You must specify the options, options list {content, type}')
    }
    if (options.type === "desc" ) {
      if (!options.content) {
        throw Error ('You did not specify the text inside the constructor options.')
      } else {
        embed.setDescription(options.content)
      }
      if (options.color) {
        embed.setColor(options.color)
      }
      this.message.channel.send({embed})
    } else {
      throw Error ('You chose descEmbed but your option does not have "desc" in it.')
    }
  }
  advanced(options) {
    /**
    *@returns {Error}
    */
    if (!options) {
      throw Error('You must specify at list one option, list {desc, footer, thumbnail, title, author fields[field1, content, field2, content]}')
    }

    const embed = new Discord.RichEmbed();

    /**
    *@returns {Object}
    *@param {boolean} inline
    *@param {string} title
    *@param {string} content
    */
    if (options.fields) {
      for (let i = 0; i < options.fields.length; i++) {
        let inline;
        if (!options.fields[i].inline) {
          inline = false
        } else if (options.fields[i].inline === true) {
          inline = true
        }
        embed.addField(options.fields[i].title, options.fields[i].content, inline)
      }
    }

    /**
    *@param {String} desc
    */
    if (options.desc) {
      embed.setDescription(options.desc)
    }

    /**
    *@param {String} footer
    */
    if (options.footer) {
      embed.setFooter(options.footer)
    }

    /**
    *@param {String} title
    */
    if(options.title) {
      embed.setTitle(options.title)
    }

    /**
    *@param {String} thumbnail
    */
    if (options.thumbnail) {
      embed.setThumbnail(options.thumbnail)
    }

    /**
    *@param {String} author
    */
    if (options.author) {
      embed.setAuthor(options.author.name, options.author.pic);
    }

    if (options.color) {
      embed.setColor(options.color);
    }

    this.message.channel.send({embed}) //Send the embed after all the options been selected
  }
}
module.exports = embedMessage;
<commit_msg>Indentation<commit_after>const Discord = require('discord.js');
const embed = new Discord.RichEmbed();
class embedMessage {
    constructor(msg) {
        this.message = msg
    }

    descEmbed(options) {
        if (!options) {
            throw Error('You must specify the options, options list {content, type}')
        }
        if (options.type === "desc" ) {
            if (!options.content) {
                throw Error ('You did not specify the text inside the constructor options.')
            } else {
                embed.setDescription(options.content)
            }
            if (options.color) {
                embed.setColor(options.color)
            }
            this.message.channel.send({embed})
        } else {
            throw Error ('You chose descEmbed but your option does not have "desc" in it.')
        }
    }
    advanced(options) {
        /**
         *@returns {Error}
         */
        if (!options) {
            throw Error('You must specify at list one option, list {desc, footer, thumbnail, title, author fields[field1, content, field2, content]}')
        }

        const embed = new Discord.RichEmbed();

        /**
         *@returns {Object}
         *@param {boolean} inline
         *@param {string} title
         *@param {string} content
         */
        if (options.fields) {
            for (let i = 0; i < options.fields.length; i++) {
                let inline;
                if (!options.fields[i].inline) {
                    inline = false
                } else if (options.fields[i].inline === true) {
                    inline = true
                }
                embed.addField(options.fields[i].title, options.fields[i].content, inline)
            }
        }

        /**
         *@param {String} desc
         */
        if (options.desc) {
            embed.setDescription(options.desc)
        }

        /**
         *@param {String} footer
         */
        if (options.footer) {
            embed.setFooter(options.footer)
        }

        /**
         *@param {String} title
         */
        if(options.title) {
            embed.setTitle(options.title)
        }

        /**
         *@param {String} thumbnail
         */
        if (options.thumbnail) {
            embed.setThumbnail(options.thumbnail)
        }

        /**
         *@param {String} author
         */
        if (options.author) {
            embed.setAuthor(options.author.name, options.author.pic);
        }

        if (options.color) {
            embed.setColor(options.color);
        }

        this.message.channel.send({embed}) //Send the embed after all the options been selected
    }
}
module.exports = embedMessage;
<|endoftext|>


<commit_before>import * as types from "constants/action_types";
import lbry from "lbry";
import {
  selectUpdateUrl,
  selectUpgradeDownloadPath,
  selectUpgradeDownloadItem,
  selectUpgradeFilename,
} from "redux/selectors/app";
import { doFetchDaemonSettings } from "redux/actions/settings";
import { doBalanceSubscribe } from "redux/actions/wallet";
import { doAuthenticate } from "redux/actions/user";
import { doFetchFileInfosAndPublishedClaims } from "redux/actions/file_info";
import * as modals from "constants/modal_types";

const { remote, ipcRenderer, shell } = require("electron");
const path = require("path");
const { download } = remote.require("electron-dl");
const fs = remote.require("fs");
const { lbrySettings: config } = require("../../../app/package.json");

export function doOpenModal(modal, modalProps = {}) {
  return {
    type: types.OPEN_MODAL,
    data: {
      modal,
      modalProps,
    },
  };
}

export function doCloseModal() {
  return {
    type: types.CLOSE_MODAL,
  };
}

export function doUpdateDownloadProgress(percent) {
  return {
    type: types.UPGRADE_DOWNLOAD_PROGRESSED,
    data: {
      percent: percent,
    },
  };
}

export function doSkipUpgrade() {
  return {
    type: types.SKIP_UPGRADE,
  };
}

export function doStartUpgrade() {
  return function(dispatch, getState) {
    const state = getState();
    const upgradeDownloadPath = selectUpgradeDownloadPath(state);

    ipcRenderer.send("upgrade", upgradeDownloadPath);
  };
}

export function doDownloadUpgrade() {
  return function(dispatch, getState) {
    const state = getState();
    // Make a new directory within temp directory so the filename is guaranteed to be available
    const dir = fs.mkdtempSync(
      remote.app.getPath("temp") + require("path").sep
    ),
      upgradeFilename = selectUpgradeFilename(state);

    let options = {
      onProgress: p => dispatch(doUpdateDownloadProgress(Math.round(p * 100))),
      directory: dir,
    };
    download(
      remote.getCurrentWindow(),
      selectUpdateUrl(state),
      options
    ).then(downloadItem => {
      /**
         * TODO: get the download path directly from the download object. It should just be
         * downloadItem.getSavePath(), but the copy on the main process is being garbage collected
         * too soon.
         */

      dispatch({
        type: types.UPGRADE_DOWNLOAD_COMPLETED,
        data: {
          downloadItem,
          path: path.join(dir, upgradeFilename),
        },
      });
    });

    dispatch({
      type: types.UPGRADE_DOWNLOAD_STARTED,
    });
    dispatch({
      type: types.OPEN_MODAL,
      data: {
        modal: modals.DOWNLOADING,
      },
    });
  };
}

export function doCancelUpgrade() {
  return function(dispatch, getState) {
    const state = getState();
    const upgradeDownloadItem = selectUpgradeDownloadItem(state);

    if (upgradeDownloadItem) {
      /*
       * Right now the remote reference to the download item gets garbage collected as soon as the
       * the download is over (maybe even earlier), so trying to cancel a finished download may
       * throw an error.
       */
      try {
        upgradeDownloadItem.cancel();
      } catch (err) {
        console.error(err);
        // Do nothing
      }
    }

    dispatch({ type: types.UPGRADE_CANCELLED });
  };
}

export function doCheckUpgradeAvailable() {
  return function(dispatch, getState) {
    const state = getState();

    lbry.getAppVersionInfo().then(({ remoteVersion, upgradeAvailable }) => {
      if (upgradeAvailable) {
        dispatch({
          type: types.UPDATE_VERSION,
          data: {
            version: remoteVersion,
          },
        });
        dispatch({
          type: types.OPEN_MODAL,
          data: {
            modal: modals.UPGRADE,
          },
        });
      }
    });
  };
}

export function doCheckDaemonVersion() {
  return function(dispatch, getState) {
    lbry.version().then(({ lbrynet_version }) => {
      dispatch({
        type: config.lbrynetDaemonVersion == lbrynet_version
          ? types.DAEMON_VERSION_MATCH
          : types.DAEMON_VERSION_MISMATCH,
      });
    });
  };
}

export function doAlertError(errorList) {
  return function(dispatch, getState) {
    const state = getState();
    dispatch({
      type: types.OPEN_MODAL,
      data: {
        modal: modals.ERROR,
        modalProps: { error: errorList },
      },
    });
  };
}

export function doDaemonReady() {
  return function(dispatch, getState) {
    dispatch(doAuthenticate());
    dispatch({ type: types.DAEMON_READY });
    dispatch(doFetchDaemonSettings());
    dispatch(doBalanceSubscribe());
    dispatch(doFetchFileInfosAndPublishedClaims());
  };
}

export function doShowSnackBar(data) {
  return {
    type: types.SHOW_SNACKBAR,
    data,
  };
}

export function doRemoveSnackBarSnack() {
  return {
    type: types.REMOVE_SNACKBAR_SNACK,
  };
}

export function doClearCache() {
  return function(dispatch, getState) {
    window.cacheStore.purge();

    return Promise.resolve();
  };
}

export function doQuit() {
  return function(dispatch, getState) {
    remote.app.quit();
  };
}

export function doChangeVolume(volume) {
  return function(dispatch, getState) {
    dispatch({
      type: types.VOLUME_CHANGED,
      data: {
        volume,
      },
    });
  };
}
<commit_msg>update app import<commit_after>import * as types from "constants/action_types";
import lbry from "lbry";
import {
  selectUpdateUrl,
  selectUpgradeDownloadPath,
  selectUpgradeDownloadItem,
  selectUpgradeFilename,
} from "redux/selectors/app";
import { doFetchDaemonSettings } from "redux/actions/settings";
import { doBalanceSubscribe } from "redux/actions/wallet";
import { doAuthenticate } from "redux/actions/user";
import { doFetchFileInfosAndPublishedClaims } from "redux/actions/file_info";
import * as modals from "constants/modal_types";

const { remote, ipcRenderer, shell } = require("electron");
const path = require("path");
const { download } = remote.require("electron-dl");
const fs = remote.require("fs");
const { lbrySettings: config } = require("../../../../app/package.json");

export function doOpenModal(modal, modalProps = {}) {
  return {
    type: types.OPEN_MODAL,
    data: {
      modal,
      modalProps,
    },
  };
}

export function doCloseModal() {
  return {
    type: types.CLOSE_MODAL,
  };
}

export function doUpdateDownloadProgress(percent) {
  return {
    type: types.UPGRADE_DOWNLOAD_PROGRESSED,
    data: {
      percent: percent,
    },
  };
}

export function doSkipUpgrade() {
  return {
    type: types.SKIP_UPGRADE,
  };
}

export function doStartUpgrade() {
  return function(dispatch, getState) {
    const state = getState();
    const upgradeDownloadPath = selectUpgradeDownloadPath(state);

    ipcRenderer.send("upgrade", upgradeDownloadPath);
  };
}

export function doDownloadUpgrade() {
  return function(dispatch, getState) {
    const state = getState();
    // Make a new directory within temp directory so the filename is guaranteed to be available
    const dir = fs.mkdtempSync(
      remote.app.getPath("temp") + require("path").sep
    ),
      upgradeFilename = selectUpgradeFilename(state);

    let options = {
      onProgress: p => dispatch(doUpdateDownloadProgress(Math.round(p * 100))),
      directory: dir,
    };
    download(
      remote.getCurrentWindow(),
      selectUpdateUrl(state),
      options
    ).then(downloadItem => {
      /**
         * TODO: get the download path directly from the download object. It should just be
         * downloadItem.getSavePath(), but the copy on the main process is being garbage collected
         * too soon.
         */

      dispatch({
        type: types.UPGRADE_DOWNLOAD_COMPLETED,
        data: {
          downloadItem,
          path: path.join(dir, upgradeFilename),
        },
      });
    });

    dispatch({
      type: types.UPGRADE_DOWNLOAD_STARTED,
    });
    dispatch({
      type: types.OPEN_MODAL,
      data: {
        modal: modals.DOWNLOADING,
      },
    });
  };
}

export function doCancelUpgrade() {
  return function(dispatch, getState) {
    const state = getState();
    const upgradeDownloadItem = selectUpgradeDownloadItem(state);

    if (upgradeDownloadItem) {
      /*
       * Right now the remote reference to the download item gets garbage collected as soon as the
       * the download is over (maybe even earlier), so trying to cancel a finished download may
       * throw an error.
       */
      try {
        upgradeDownloadItem.cancel();
      } catch (err) {
        console.error(err);
        // Do nothing
      }
    }

    dispatch({ type: types.UPGRADE_CANCELLED });
  };
}

export function doCheckUpgradeAvailable() {
  return function(dispatch, getState) {
    const state = getState();

    lbry.getAppVersionInfo().then(({ remoteVersion, upgradeAvailable }) => {
      if (upgradeAvailable) {
        dispatch({
          type: types.UPDATE_VERSION,
          data: {
            version: remoteVersion,
          },
        });
        dispatch({
          type: types.OPEN_MODAL,
          data: {
            modal: modals.UPGRADE,
          },
        });
      }
    });
  };
}

export function doCheckDaemonVersion() {
  return function(dispatch, getState) {
    lbry.version().then(({ lbrynet_version }) => {
      dispatch({
        type: config.lbrynetDaemonVersion == lbrynet_version
          ? types.DAEMON_VERSION_MATCH
          : types.DAEMON_VERSION_MISMATCH,
      });
    });
  };
}

export function doAlertError(errorList) {
  return function(dispatch, getState) {
    const state = getState();
    dispatch({
      type: types.OPEN_MODAL,
      data: {
        modal: modals.ERROR,
        modalProps: { error: errorList },
      },
    });
  };
}

export function doDaemonReady() {
  return function(dispatch, getState) {
    dispatch(doAuthenticate());
    dispatch({ type: types.DAEMON_READY });
    dispatch(doFetchDaemonSettings());
    dispatch(doBalanceSubscribe());
    dispatch(doFetchFileInfosAndPublishedClaims());
  };
}

export function doShowSnackBar(data) {
  return {
    type: types.SHOW_SNACKBAR,
    data,
  };
}

export function doRemoveSnackBarSnack() {
  return {
    type: types.REMOVE_SNACKBAR_SNACK,
  };
}

export function doClearCache() {
  return function(dispatch, getState) {
    window.cacheStore.purge();

    return Promise.resolve();
  };
}

export function doQuit() {
  return function(dispatch, getState) {
    remote.app.quit();
  };
}

export function doChangeVolume(volume) {
  return function(dispatch, getState) {
    dispatch({
      type: types.VOLUME_CHANGED,
      data: {
        volume,
      },
    });
  };
}
<|endoftext|>


<commit_before>module.exports = {
  build: [
    'types-as-schema src/back/common.ts --protobuf static/protocol.proto',
    {
      back: [
        `rimraf dist/`,
        'tsc -p src/back/'
      ],
      front: [
        {
          js: [
            {
              image: 'image2base64-cli static/imgs/**/*.png static/imgs/*.png --es6 src/front/variables.ts --base static/imgs',
              file: 'file2variable-cli static/protocol.proto src/front/template.html -o src/front/proto-variables.ts --protobuf --html-minify'
            },
            'rimraf static/dist/',
            'tsc -p src/front/',
            'rimraf static/scripts/',
            'webpack --display-modules --config static/webpack.config.js'
          ],
          css: `cleancss -o static/index.bundle.css static/index.css`,
          clean: `rimraf static/index-*.css`
        },
        'rev-static --config static/rev-static.config.js'
      ]
    }
  ],
  lint: {
    ts: `tslint "src/**/*.ts"`,
    js: `standard "**/*.config.js"`
  },
  test: {
    jasmine: [
      'tsc -p spec',
      'jasmine'
    ],
    karma: [
      'tsc -p static_spec',
      'karma start static_spec/karma.config.js'
    ]
  },
  fix: `standard --fix "**/*.config.js"`,
  release: `clean-release`
}
<commit_msg>add tslint fix script<commit_after>module.exports = {
  build: [
    'types-as-schema src/back/common.ts --protobuf static/protocol.proto',
    {
      back: [
        `rimraf dist/`,
        'tsc -p src/back/'
      ],
      front: [
        {
          js: [
            {
              image: 'image2base64-cli static/imgs/**/*.png static/imgs/*.png --es6 src/front/variables.ts --base static/imgs',
              file: 'file2variable-cli static/protocol.proto src/front/template.html -o src/front/proto-variables.ts --protobuf --html-minify'
            },
            'rimraf static/dist/',
            'tsc -p src/front/',
            'rimraf static/scripts/',
            'webpack --display-modules --config static/webpack.config.js'
          ],
          css: `cleancss -o static/index.bundle.css static/index.css`,
          clean: `rimraf static/index-*.css`
        },
        'rev-static --config static/rev-static.config.js'
      ]
    }
  ],
  lint: {
    ts: `tslint "src/**/*.ts"`,
    js: `standard "**/*.config.js"`
  },
  test: {
    jasmine: [
      'tsc -p spec',
      'jasmine'
    ],
    karma: [
      'tsc -p static_spec',
      'karma start static_spec/karma.config.js'
    ]
  },
  fix: {
    ts: `tslint --fix "src/**/*.ts"`,
    js: `standard --fix "**/*.config.js"`
  },
  release: `clean-release`
}
<|endoftext|>


<commit_before>import { combineReducers } from 'redux'
import { SubmissionError } from 'redux-form'

import { loadingReducer, createSingleValueReducer, createSingleObjectReducer } from 'redux/utils/reducerFactories'
import { RECEIVE_DATA, REQUEST_SAVED_VARIANTS, REQUEST_PROJECTS, loadProject } from 'redux/rootReducer'
import { SHOW_ALL, SORT_BY_XPOS } from 'shared/utils/constants'
import { HttpRequestHelper } from 'shared/utils/httpRequestHelper'

// action creators and reducers in one file as suggested by https://github.com/erikras/ducks-modular-redux
const REQUEST_DISCOVERY_SHEET = 'REQUEST_DISCOVERY_SHEET'
const RECEIVE_DISCOVERY_SHEET = 'RECEIVE_DISCOVERY_SHEET'
const REQUEST_SUCCESS_STORY = 'REQUEST_SUCCESS_STORY'
const RECEIVE_SUCCESS_STORY = 'RECEIVE_SUCCESS_STORY'
const REQUEST_ELASTICSEARCH_STATUS = 'REQUEST_ELASTICSEARCH_STATUS'
const RECEIVE_ELASTICSEARCH_STATUS = 'RECEIVE_ELASTICSEARCH_STATUS'
const REQUEST_MME = 'REQUEST_MME'
const RECEIVE_MME = 'RECEIVE_MME'
const REQUEST_SAMPLE_METADATA = 'REQUEST_SAMPLE_METADATA'
const RECEIVE_SAMPLE_METADATA = 'RECEIVE_SAMPLE_METADATA'
const RECEIVE_SAVED_VARIANT_TAGS = 'RECEIVE_SAVED_VARIANT_TAGS'
const REQUEST_SEARCH_HASH_CONTEXT = 'REQUEST_SEARCH_HASH_CONTEXT'
const RECEIVE_SEARCH_HASH_CONTEXT = 'RECEIVE_SEARCH_HASH_CONTEXT'
const REQUEST_SEQR_STATS = 'REQUEST_SEQR_STATS'
const RECEIVE_SEQR_STATS = 'RECEIVE_SEQR_STATS'
const RECEIVE_PIPELINE_UPLOAD_STATS = 'RECEIVE_PIPELINE_UPLOAD_STATS'
const UPDATE_STAFF_SAVED_VARIANT_TABLE_STATE = 'UPDATE_STAFF_VARIANT_STATE'

// Data actions
export const loadElasticsearchStatus = () => {
  return (dispatch) => {
    dispatch({ type: REQUEST_ELASTICSEARCH_STATUS })
    new HttpRequestHelper('/api/staff/elasticsearch_status',
      (responseJson) => {
        dispatch({ type: RECEIVE_ELASTICSEARCH_STATUS, newValue: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_ELASTICSEARCH_STATUS, error: e.message, newValue: { errors: [e.message] } })
      },
    ).get()
  }
}

export const loadMme = () => {
  return (dispatch) => {
    dispatch({ type: REQUEST_MME })
    new HttpRequestHelper('/api/staff/matchmaker',
      (responseJson) => {
        dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
        dispatch({ type: RECEIVE_MME, newValue: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_MME, error: e.message, newValue: [] })
      },
    ).get()
  }
}

const loadMultiProjectData = (requestAction, receiveAction, urlPath) => (projectGuid, filterValues) => {
  return (dispatch) => {
    if (projectGuid === 'all') {
      dispatch({ type: requestAction })

      const errors = new Set()
      const rows = []
      new HttpRequestHelper('/api/staff/projects_for_category/CMG',
        (projectsResponseJson) => {
          Promise.all(projectsResponseJson.projectGuids.map(cmgProjectGuid =>
            new HttpRequestHelper(`/api/staff/${urlPath}/${cmgProjectGuid}`,
              (responseJson) => {
                if (responseJson.errors && responseJson.errors.length) {
                  console.log(responseJson.errors)
                }
                rows.push(...responseJson.rows)
              },
              e => errors.add(e.message),
            ).get(),
          )).then(() => {
            if (errors.size) {
              dispatch({ type: receiveAction, error: [...errors].join(', '), newValue: [] })
            } else {
              dispatch({ type: receiveAction, newValue: rows })
            }
          })
        },
        (e) => {
          dispatch({ type: receiveAction, error: e.message, newValue: [] })
        },
      ).get(filterValues)
    }

    else if (projectGuid) {
      dispatch({ type: requestAction })
      new HttpRequestHelper(`/api/staff/${urlPath}/${projectGuid}`,
        (responseJson) => {
          console.log(responseJson.errors)
          dispatch({ type: receiveAction, newValue: responseJson.rows })
        },
        (e) => {
          dispatch({ type: receiveAction, error: e.message, newValue: [] })
        },
      ).get(filterValues)
    }
  }
}

export const loadDiscoverySheet = loadMultiProjectData(REQUEST_DISCOVERY_SHEET, RECEIVE_DISCOVERY_SHEET, 'discovery_sheet')

export const loadSampleMetadata = loadMultiProjectData(REQUEST_SAMPLE_METADATA, RECEIVE_SAMPLE_METADATA, 'sample_metadata')

export const loadSuccessStory = (successStoryTypes) => {
  return (dispatch) => {
    if (successStoryTypes) {
      dispatch({ type: REQUEST_SUCCESS_STORY })
      new HttpRequestHelper(`/api/staff/success_story/${successStoryTypes}`,
        (responseJson) => {
          console.log(responseJson.errors)
          dispatch({ type: RECEIVE_SUCCESS_STORY, newValue: responseJson.rows })
        },
        (e) => {
          dispatch({ type: RECEIVE_SUCCESS_STORY, error: e.message, newValue: [] })
        },
      ).get()
    }
  }
}

export const createStaffUser = (values) => {
  return () => {
    return new HttpRequestHelper('/api/users/create_staff_user',
      () => {},
      (e) => {
        if (e.body && e.body.error) {
          throw new SubmissionError({ _error: [e.body.error] })
        } else {
          throw new SubmissionError({ _error: [e.message] })
        }
      },
    ).post(values)
  }
}

export const loadSeqrStats = () => {
  return (dispatch) => {
    dispatch({ type: REQUEST_SEQR_STATS })
    new HttpRequestHelper('/api/staff/seqr_stats',
      (responseJson) => {
        dispatch({ type: RECEIVE_SEQR_STATS, newValue: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_SEQR_STATS, error: e.message, newValue: {} })
      },
    ).get()
  }
}

export const uploadQcPipelineOutput = (values) => {
  return (dispatch) => {
    return new HttpRequestHelper('/api/staff/upload_qc_pipeline_output',
      (responseJson) => {
        dispatch({ type: RECEIVE_PIPELINE_UPLOAD_STATS, newValue: responseJson })
      },
      (e) => {
        if (e.body && e.body.errors) {
          throw new SubmissionError({ _error: e.body.errors })
        } else {
          throw new SubmissionError({ _error: [e.message] })
        }
      },
    ).post(values)
  }
}

export const loadSavedVariants = ({ tag, gene = '' }) => {
  return (dispatch, getState) => {
    // Do not load if already loaded
    if (tag) {
      if (getState().savedVariantTags[tag]) {
        return
      }
    } else {
      return
    }

    dispatch({ type: REQUEST_SAVED_VARIANTS })
    new HttpRequestHelper(`/api/staff/saved_variants/${tag}`,
      (responseJson) => {
        if (tag && !gene) {
          dispatch({
            type: RECEIVE_SAVED_VARIANT_TAGS,
            updates: { [tag]: true },
          })
        }
        dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_DATA, error: e.message, updatesById: {} })
      },
    ).get({ gene })
  }
}

export const loadSearchHashContext = (searchHash) => {
  return (dispatch, getState) => {
    if (!searchHash) {
      return
    }
    const state = getState()
    if (state.searchHashContextLoading.isLoading) {
      return
    }

    if (!state.searchesByHash[searchHash] || !state.searchesByHash[searchHash].projectGuids ||
        state.searchesByHash[searchHash].projectGuids.some(projectGuid => !state.projectsByGuid[projectGuid])) {
      dispatch({ type: REQUEST_SEARCH_HASH_CONTEXT })
      new HttpRequestHelper('/api/search_context',
        (responseJson) => {
          dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
          dispatch({ type: RECEIVE_SEARCH_HASH_CONTEXT })
        },
        (e) => {
          dispatch({ type: RECEIVE_SEARCH_HASH_CONTEXT, error: e.message })
        },
      ).post({ searchHash, searchParams: state.searchesByHash[searchHash] })
    }
  }
}

export const loadProjectContext = (projectGuid) => {
  return (dispatch, getState) => {
    const state = getState()
    if (state.searchHashContextLoading.isLoading) {
      return
    }
    loadProject(projectGuid)(dispatch, getState)
  }
}

export const loadProjectGroupContext = (projectCategoryGuid, addElementCallback) => {
  return (dispatch, getState) => {
    const state = getState()

    if (state.projectCategoriesByGuid[projectCategoryGuid]) {
      Object.values(state.projectsByGuid).filter(({ projectCategoryGuids }) =>
        projectCategoryGuids.includes(projectCategoryGuid),
      ).forEach(({ projectGuid }) => addElementCallback(projectGuid))
    }

    else {
      dispatch({ type: REQUEST_PROJECTS })
      new HttpRequestHelper('/api/search_context',
        (responseJson) => {
          dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
          Object.keys(responseJson.projectsByGuid).forEach(projectGuid => addElementCallback(projectGuid))
        },
        (e) => {
          dispatch({ type: RECEIVE_DATA, error: e.message, updatesById: {} })
        },
      ).post({ projectCategoryGuid })
    }
  }
}

export const updateStaffSavedVariantTable = updates => ({ type: UPDATE_STAFF_SAVED_VARIANT_TABLE_STATE, updates })

export const reducers = {
  sampleMetadataLoading: loadingReducer(REQUEST_SAMPLE_METADATA, RECEIVE_SAMPLE_METADATA),
  sampleMetadataRows: createSingleValueReducer(RECEIVE_SAMPLE_METADATA, []),
  discoverySheetLoading: loadingReducer(REQUEST_DISCOVERY_SHEET, RECEIVE_DISCOVERY_SHEET),
  discoverySheetRows: createSingleValueReducer(RECEIVE_DISCOVERY_SHEET, []),
  successStoryLoading: loadingReducer(REQUEST_SUCCESS_STORY, RECEIVE_SUCCESS_STORY),
  successStoryRows: createSingleValueReducer(RECEIVE_SUCCESS_STORY, []),
  elasticsearchStatusLoading: loadingReducer(REQUEST_ELASTICSEARCH_STATUS, RECEIVE_ELASTICSEARCH_STATUS),
  elasticsearchStatus: createSingleValueReducer(RECEIVE_ELASTICSEARCH_STATUS, {}),
  mmeLoading: loadingReducer(REQUEST_MME, RECEIVE_MME),
  mmeMetrics: createSingleValueReducer(RECEIVE_MME, {}, 'metrics'),
  mmeSubmissions: createSingleValueReducer(RECEIVE_MME, [], 'submissions'),
  projectGroupContextLoading: loadingReducer(REQUEST_PROJECTS, RECEIVE_DATA),
  savedVariantTags: createSingleObjectReducer(RECEIVE_SAVED_VARIANT_TAGS),
  searchHashContextLoading: loadingReducer(REQUEST_SEARCH_HASH_CONTEXT, RECEIVE_SEARCH_HASH_CONTEXT),
  seqrStatsLoading: loadingReducer(REQUEST_SEQR_STATS, RECEIVE_SEQR_STATS),
  seqrStats: createSingleValueReducer(RECEIVE_SEQR_STATS, {}),
  qcUploadStats: createSingleValueReducer(RECEIVE_PIPELINE_UPLOAD_STATS, {}),
  staffSavedVariantTableState: createSingleObjectReducer(UPDATE_STAFF_SAVED_VARIANT_TABLE_STATE, {
    categoryFilter: SHOW_ALL,
    sort: SORT_BY_XPOS,
    page: 1,
    recordsPerPage: 25,
  }, false),
}

const rootReducer = combineReducers(reducers)

export default rootReducer
<commit_msg>chunk requests for all project staff pages<commit_after>import { combineReducers } from 'redux'
import { SubmissionError } from 'redux-form'

import { loadingReducer, createSingleValueReducer, createSingleObjectReducer } from 'redux/utils/reducerFactories'
import { RECEIVE_DATA, REQUEST_SAVED_VARIANTS, REQUEST_PROJECTS, loadProject } from 'redux/rootReducer'
import { SHOW_ALL, SORT_BY_XPOS } from 'shared/utils/constants'
import { HttpRequestHelper } from 'shared/utils/httpRequestHelper'

// action creators and reducers in one file as suggested by https://github.com/erikras/ducks-modular-redux
const REQUEST_DISCOVERY_SHEET = 'REQUEST_DISCOVERY_SHEET'
const RECEIVE_DISCOVERY_SHEET = 'RECEIVE_DISCOVERY_SHEET'
const REQUEST_SUCCESS_STORY = 'REQUEST_SUCCESS_STORY'
const RECEIVE_SUCCESS_STORY = 'RECEIVE_SUCCESS_STORY'
const REQUEST_ELASTICSEARCH_STATUS = 'REQUEST_ELASTICSEARCH_STATUS'
const RECEIVE_ELASTICSEARCH_STATUS = 'RECEIVE_ELASTICSEARCH_STATUS'
const REQUEST_MME = 'REQUEST_MME'
const RECEIVE_MME = 'RECEIVE_MME'
const REQUEST_SAMPLE_METADATA = 'REQUEST_SAMPLE_METADATA'
const RECEIVE_SAMPLE_METADATA = 'RECEIVE_SAMPLE_METADATA'
const RECEIVE_SAVED_VARIANT_TAGS = 'RECEIVE_SAVED_VARIANT_TAGS'
const REQUEST_SEARCH_HASH_CONTEXT = 'REQUEST_SEARCH_HASH_CONTEXT'
const RECEIVE_SEARCH_HASH_CONTEXT = 'RECEIVE_SEARCH_HASH_CONTEXT'
const REQUEST_SEQR_STATS = 'REQUEST_SEQR_STATS'
const RECEIVE_SEQR_STATS = 'RECEIVE_SEQR_STATS'
const RECEIVE_PIPELINE_UPLOAD_STATS = 'RECEIVE_PIPELINE_UPLOAD_STATS'
const UPDATE_STAFF_SAVED_VARIANT_TABLE_STATE = 'UPDATE_STAFF_VARIANT_STATE'

// Data actions
export const loadElasticsearchStatus = () => {
  return (dispatch) => {
    dispatch({ type: REQUEST_ELASTICSEARCH_STATUS })
    new HttpRequestHelper('/api/staff/elasticsearch_status',
      (responseJson) => {
        dispatch({ type: RECEIVE_ELASTICSEARCH_STATUS, newValue: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_ELASTICSEARCH_STATUS, error: e.message, newValue: { errors: [e.message] } })
      },
    ).get()
  }
}

export const loadMme = () => {
  return (dispatch) => {
    dispatch({ type: REQUEST_MME })
    new HttpRequestHelper('/api/staff/matchmaker',
      (responseJson) => {
        dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
        dispatch({ type: RECEIVE_MME, newValue: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_MME, error: e.message, newValue: [] })
      },
    ).get()
  }
}

const loadMultiProjectData = (requestAction, receiveAction, urlPath) => (projectGuid, filterValues) => {
  return (dispatch) => {
    if (projectGuid === 'all') {
      dispatch({ type: requestAction })

      const errors = new Set()
      const rows = []
      new HttpRequestHelper('/api/staff/projects_for_category/CMG',
        (projectsResponseJson) => {
          const chunkedProjects = projectsResponseJson.projectGuids.reduce((acc, guid) => {
            if (acc[0].length === 5) {
              acc.unshift([])
            }
            acc[0].push(guid)
            return acc
          }, [[]])
          chunkedProjects.reduce((previousPromise, projectsChunk) => {
            return previousPromise.then(() => {
              return Promise.all(projectsChunk.map(cmgProjectGuid =>
                new HttpRequestHelper(`/api/staff/${urlPath}/${cmgProjectGuid}`,
                  (responseJson) => {
                    if (responseJson.errors && responseJson.errors.length) {
                      console.log(responseJson.errors)
                    }
                    rows.push(...responseJson.rows)
                  },
                  e => errors.add(e.message),
                ).get(),
              ))
            })
          }, Promise.resolve()).then(() => {
            if (errors.size) {
              dispatch({ type: receiveAction, error: [...errors].join(', '), newValue: [] })
            } else {
              dispatch({ type: receiveAction, newValue: rows })
            }
          })
        },
        (e) => {
          dispatch({ type: receiveAction, error: e.message, newValue: [] })
        },
      ).get(filterValues)
    }

    else if (projectGuid) {
      dispatch({ type: requestAction })
      new HttpRequestHelper(`/api/staff/${urlPath}/${projectGuid}`,
        (responseJson) => {
          console.log(responseJson.errors)
          dispatch({ type: receiveAction, newValue: responseJson.rows })
        },
        (e) => {
          dispatch({ type: receiveAction, error: e.message, newValue: [] })
        },
      ).get(filterValues)
    }
  }
}

export const loadDiscoverySheet = loadMultiProjectData(REQUEST_DISCOVERY_SHEET, RECEIVE_DISCOVERY_SHEET, 'discovery_sheet')

export const loadSampleMetadata = loadMultiProjectData(REQUEST_SAMPLE_METADATA, RECEIVE_SAMPLE_METADATA, 'sample_metadata')

export const loadSuccessStory = (successStoryTypes) => {
  return (dispatch) => {
    if (successStoryTypes) {
      dispatch({ type: REQUEST_SUCCESS_STORY })
      new HttpRequestHelper(`/api/staff/success_story/${successStoryTypes}`,
        (responseJson) => {
          console.log(responseJson.errors)
          dispatch({ type: RECEIVE_SUCCESS_STORY, newValue: responseJson.rows })
        },
        (e) => {
          dispatch({ type: RECEIVE_SUCCESS_STORY, error: e.message, newValue: [] })
        },
      ).get()
    }
  }
}

export const createStaffUser = (values) => {
  return () => {
    return new HttpRequestHelper('/api/users/create_staff_user',
      () => {},
      (e) => {
        if (e.body && e.body.error) {
          throw new SubmissionError({ _error: [e.body.error] })
        } else {
          throw new SubmissionError({ _error: [e.message] })
        }
      },
    ).post(values)
  }
}

export const loadSeqrStats = () => {
  return (dispatch) => {
    dispatch({ type: REQUEST_SEQR_STATS })
    new HttpRequestHelper('/api/staff/seqr_stats',
      (responseJson) => {
        dispatch({ type: RECEIVE_SEQR_STATS, newValue: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_SEQR_STATS, error: e.message, newValue: {} })
      },
    ).get()
  }
}

export const uploadQcPipelineOutput = (values) => {
  return (dispatch) => {
    return new HttpRequestHelper('/api/staff/upload_qc_pipeline_output',
      (responseJson) => {
        dispatch({ type: RECEIVE_PIPELINE_UPLOAD_STATS, newValue: responseJson })
      },
      (e) => {
        if (e.body && e.body.errors) {
          throw new SubmissionError({ _error: e.body.errors })
        } else {
          throw new SubmissionError({ _error: [e.message] })
        }
      },
    ).post(values)
  }
}

export const loadSavedVariants = ({ tag, gene = '' }) => {
  return (dispatch, getState) => {
    // Do not load if already loaded
    if (tag) {
      if (getState().savedVariantTags[tag]) {
        return
      }
    } else {
      return
    }

    dispatch({ type: REQUEST_SAVED_VARIANTS })
    new HttpRequestHelper(`/api/staff/saved_variants/${tag}`,
      (responseJson) => {
        if (tag && !gene) {
          dispatch({
            type: RECEIVE_SAVED_VARIANT_TAGS,
            updates: { [tag]: true },
          })
        }
        dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
      },
      (e) => {
        dispatch({ type: RECEIVE_DATA, error: e.message, updatesById: {} })
      },
    ).get({ gene })
  }
}

export const loadSearchHashContext = (searchHash) => {
  return (dispatch, getState) => {
    if (!searchHash) {
      return
    }
    const state = getState()
    if (state.searchHashContextLoading.isLoading) {
      return
    }

    if (!state.searchesByHash[searchHash] || !state.searchesByHash[searchHash].projectGuids ||
        state.searchesByHash[searchHash].projectGuids.some(projectGuid => !state.projectsByGuid[projectGuid])) {
      dispatch({ type: REQUEST_SEARCH_HASH_CONTEXT })
      new HttpRequestHelper('/api/search_context',
        (responseJson) => {
          dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
          dispatch({ type: RECEIVE_SEARCH_HASH_CONTEXT })
        },
        (e) => {
          dispatch({ type: RECEIVE_SEARCH_HASH_CONTEXT, error: e.message })
        },
      ).post({ searchHash, searchParams: state.searchesByHash[searchHash] })
    }
  }
}

export const loadProjectContext = (projectGuid) => {
  return (dispatch, getState) => {
    const state = getState()
    if (state.searchHashContextLoading.isLoading) {
      return
    }
    loadProject(projectGuid)(dispatch, getState)
  }
}

export const loadProjectGroupContext = (projectCategoryGuid, addElementCallback) => {
  return (dispatch, getState) => {
    const state = getState()

    if (state.projectCategoriesByGuid[projectCategoryGuid]) {
      Object.values(state.projectsByGuid).filter(({ projectCategoryGuids }) =>
        projectCategoryGuids.includes(projectCategoryGuid),
      ).forEach(({ projectGuid }) => addElementCallback(projectGuid))
    }

    else {
      dispatch({ type: REQUEST_PROJECTS })
      new HttpRequestHelper('/api/search_context',
        (responseJson) => {
          dispatch({ type: RECEIVE_DATA, updatesById: responseJson })
          Object.keys(responseJson.projectsByGuid).forEach(projectGuid => addElementCallback(projectGuid))
        },
        (e) => {
          dispatch({ type: RECEIVE_DATA, error: e.message, updatesById: {} })
        },
      ).post({ projectCategoryGuid })
    }
  }
}

export const updateStaffSavedVariantTable = updates => ({ type: UPDATE_STAFF_SAVED_VARIANT_TABLE_STATE, updates })

export const reducers = {
  sampleMetadataLoading: loadingReducer(REQUEST_SAMPLE_METADATA, RECEIVE_SAMPLE_METADATA),
  sampleMetadataRows: createSingleValueReducer(RECEIVE_SAMPLE_METADATA, []),
  discoverySheetLoading: loadingReducer(REQUEST_DISCOVERY_SHEET, RECEIVE_DISCOVERY_SHEET),
  discoverySheetRows: createSingleValueReducer(RECEIVE_DISCOVERY_SHEET, []),
  successStoryLoading: loadingReducer(REQUEST_SUCCESS_STORY, RECEIVE_SUCCESS_STORY),
  successStoryRows: createSingleValueReducer(RECEIVE_SUCCESS_STORY, []),
  elasticsearchStatusLoading: loadingReducer(REQUEST_ELASTICSEARCH_STATUS, RECEIVE_ELASTICSEARCH_STATUS),
  elasticsearchStatus: createSingleValueReducer(RECEIVE_ELASTICSEARCH_STATUS, {}),
  mmeLoading: loadingReducer(REQUEST_MME, RECEIVE_MME),
  mmeMetrics: createSingleValueReducer(RECEIVE_MME, {}, 'metrics'),
  mmeSubmissions: createSingleValueReducer(RECEIVE_MME, [], 'submissions'),
  projectGroupContextLoading: loadingReducer(REQUEST_PROJECTS, RECEIVE_DATA),
  savedVariantTags: createSingleObjectReducer(RECEIVE_SAVED_VARIANT_TAGS),
  searchHashContextLoading: loadingReducer(REQUEST_SEARCH_HASH_CONTEXT, RECEIVE_SEARCH_HASH_CONTEXT),
  seqrStatsLoading: loadingReducer(REQUEST_SEQR_STATS, RECEIVE_SEQR_STATS),
  seqrStats: createSingleValueReducer(RECEIVE_SEQR_STATS, {}),
  qcUploadStats: createSingleValueReducer(RECEIVE_PIPELINE_UPLOAD_STATS, {}),
  staffSavedVariantTableState: createSingleObjectReducer(UPDATE_STAFF_SAVED_VARIANT_TABLE_STATE, {
    categoryFilter: SHOW_ALL,
    sort: SORT_BY_XPOS,
    page: 1,
    recordsPerPage: 25,
  }, false),
}

const rootReducer = combineReducers(reducers)

export default rootReducer
<|endoftext|>


<commit_before>const { Service, execAsync } = require('clean-scripts')

const tsFiles = `"*.ts" "spec/**/*.ts" "screenshots/**/*.ts" "prerender/**/*.ts"`
const jsFiles = `"*.config.js" "spec/**/*.config.js"`

module.exports = {
  build: [
    {
      js: [
        `file2variable-cli app.template.html -o variables.ts --html-minify`,
        `tsc`,
        `webpack --display-modules`
      ],
      css: {
        vendor: `cleancss ./node_modules/bootstrap/dist/css/bootstrap.min.css ./node_modules/github-fork-ribbon-css/gh-fork-ribbon.css -o vendor.bundle.css`,
        index: [
          `postcss index.css -o index.postcss.css`,
          `cleancss index.postcss.css -o index.bundle.css`
        ]
      },
      clean: `rimraf vendor.bundle-*.js vendor.bundle-*.css index.bundle-*.js index.bundle-*.css`
    },
    `rev-static`,
    [
      `sw-precache --config sw-precache.config.js`,
      `uglifyjs service-worker.js -o service-worker.bundle.js`
    ]
  ],
  lint: {
    ts: `tslint ${tsFiles}`,
    js: `standard ${jsFiles}`,
    export: `no-unused-export ${tsFiles}`
  },
  test: [
    'tsc -p spec',
    'karma start spec/karma.config.js',
    async () => {
      const { stdout } = await execAsync('git status -s')
      if (stdout) {
        console.log(stdout)
        throw new Error(`generated files doesn't match.`)
      }
    }
  ],
  fix: {
    ts: `tslint --fix ${tsFiles}`,
    js: `standard --fix ${jsFiles}`
  },
  release: `clean-release`,
  watch: {
    template: `file2variable-cli app.template.html -o variables.ts --html-minify --watch`,
    src: `tsc --watch`,
    webpack: `webpack --watch`,
    css: `watch-then-execute "index.css" --script "clean-scripts build[0].css.index"`,
    rev: `rev-static --watch`,
    sw: `watch-then-execute "vendor.bundle-*.js" "index.html" "worker.bundle.js" --script "clean-scripts build[2]"`
  },
  screenshot: [
    new Service(`http-server -p 8000`),
    `tsc -p screenshots`,
    `node screenshots/index.js`
  ],
  prerender: [
    new Service(`http-server -p 8000`),
    `tsc -p prerender`,
    `node prerender/index.js`,
    `clean-scripts build[1]`,
    `clean-scripts build[2]`
  ]
}
<commit_msg>improve watch script<commit_after>const { Service, execAsync } = require('clean-scripts')

const tsFiles = `"*.ts" "spec/**/*.ts" "screenshots/**/*.ts" "prerender/**/*.ts"`
const jsFiles = `"*.config.js" "spec/**/*.config.js"`

const templateCommand = `file2variable-cli app.template.html -o variables.ts --html-minify`
const tscCommand = `tsc`
const webpackCommand = `webpack --display-modules`
const revStaticCommand = `rev-static`

module.exports = {
  build: [
    {
      js: [
        templateCommand,
        tscCommand,
        webpackCommand
      ],
      css: {
        vendor: `cleancss ./node_modules/bootstrap/dist/css/bootstrap.min.css ./node_modules/github-fork-ribbon-css/gh-fork-ribbon.css -o vendor.bundle.css`,
        index: [
          `postcss index.css -o index.postcss.css`,
          `cleancss index.postcss.css -o index.bundle.css`
        ]
      },
      clean: `rimraf vendor.bundle-*.js vendor.bundle-*.css index.bundle-*.js index.bundle-*.css`
    },
    revStaticCommand,
    [
      `sw-precache --config sw-precache.config.js`,
      `uglifyjs service-worker.js -o service-worker.bundle.js`
    ]
  ],
  lint: {
    ts: `tslint ${tsFiles}`,
    js: `standard ${jsFiles}`,
    export: `no-unused-export ${tsFiles}`
  },
  test: [
    'tsc -p spec',
    'karma start spec/karma.config.js',
    async () => {
      const { stdout } = await execAsync('git status -s')
      if (stdout) {
        console.log(stdout)
        throw new Error(`generated files doesn't match.`)
      }
    }
  ],
  fix: {
    ts: `tslint --fix ${tsFiles}`,
    js: `standard --fix ${jsFiles}`
  },
  release: `clean-release`,
  watch: {
    template: `${templateCommand} --watch`,
    src: `${tscCommand} --watch`,
    webpack: `${webpackCommand} --watch`,
    css: `watch-then-execute "index.css" --script "clean-scripts build[0].css.index"`,
    rev: `${revStaticCommand} --watch`,
    sw: `watch-then-execute "vendor.bundle-*.js" "index.html" "worker.bundle.js" --script "clean-scripts build[2]"`
  },
  screenshot: [
    new Service(`http-server -p 8000`),
    `tsc -p screenshots`,
    `node screenshots/index.js`
  ],
  prerender: [
    new Service(`http-server -p 8000`),
    `tsc -p prerender`,
    `node prerender/index.js`,
    `clean-scripts build[1]`,
    `clean-scripts build[2]`
  ]
}
<|endoftext|>


<commit_before>import { isKeyCode } from './key-composition.js'

let handlers = []

export default {
  __install () {
    this.__installed = true
    window.addEventListener('keyup', evt => {
      if (handlers.length !== 0 && isKeyCode(evt, 27) === true) {
        handlers[handlers.length - 1].fn(evt)
      }
    })
  },

  register (comp, fn) {
    if (comp.$q.platform.is.desktop === true) {
      this.__installed !== true && this.__install()
      handlers.push({ comp, fn })
    }
  },

  pop (comp) {
    if (comp.$q.platform.is.desktop === true) {
      const index = handlers.findIndex(h => h.comp === comp)
      if (index > -1) {
        handlers.splice(index, 1)
      }
    }
  }
}
<commit_msg>feat(EscapeKey): Only accept ESC key if it was pressed while the app had focus #7335 (#7343)<commit_after>import { isKeyCode } from './key-composition.js'

let handlers = []
let escDown = false

export default {
  __install () {
    this.__installed = true
    window.addEventListener('keydown', evt => {
      escDown = evt.keyCode === 27
    })
    window.addEventListener('blur', () => {
      escDown === true && (escDown = false)
    })
    window.addEventListener('keyup', evt => {
      if (escDown === true) {
        escDown = false

        if (handlers.length !== 0 && isKeyCode(evt, 27) === true) {
          handlers[handlers.length - 1].fn(evt)
        }
      }
    })
  },

  register (comp, fn) {
    if (comp.$q.platform.is.desktop === true) {
      this.__installed !== true && this.__install()
      handlers.push({ comp, fn })
    }
  },

  pop (comp) {
    if (comp.$q.platform.is.desktop === true) {
      const index = handlers.findIndex(h => h.comp === comp)
      if (index > -1) {
        handlers.splice(index, 1)
      }
    }
  }
}
<|endoftext|>


<commit_before>// @flow

import fs from 'fs';
import url from 'url';
import R from 'ramda';
import { writeFile } from '../util/fs';
import yaml from 'js-yaml';
import findup from 'findup-sync';

// TODO: Type the rest of the config
export type LagoonConfig = {|
  api?: string,
  branches?: boolean | RegExp,
  customer?: number,
  git_url?: string,
  openshift?: number,
  production_environment?: string,
  project?: string,
  pullrequests?: boolean,
  ssh?: string,
|};

export type LagoonConfigInput = {|
  project: string,
  api?: string,
  ssh?: string,
|};

export function createConfig(
  filepath: string,
  inputOptions: LagoonConfigInput,
): Promise<void> {
  const inputOptionsWithoutEmptyStrings = R.reject(
    option =>
      // Reject (filter out) empty strings
      R.both(R.is(String), R.isEmpty)(option),
    inputOptions,
  );
  const yamlConfig = yaml.safeDump(inputOptionsWithoutEmptyStrings);
  return writeFile(filepath, yamlConfig);
}

export function parseConfig(yamlContent: string): LagoonConfig {
  // TODO: Add schema validation in here if necessary
  return yaml.safeLoad(yamlContent);
}

/**
 * Finds and reads the lagoon.yml file
 */
function readConfig(): LagoonConfig | null {
  const configPath = findup('.lagoon.yml');

  if (configPath == null) {
    return null;
  }

  const yamlContent = fs.readFileSync(configPath);
  return parseConfig(yamlContent.toString());
}

export const config = readConfig();

export const getApiConfig: () => { hostname: string, port: number } = (() => {
  let allApiConfig;

  return () => {
    if (!allApiConfig) {
      const env = Object.freeze({ ...process.env });
      const envApiUrl: string | null = R.ifElse(
        R.allPass([
          R.prop('API_PROTOCOL'),
          R.prop('API_HOST'),
          R.prop('API_PORT'),
        ]),
        R.always(
          `${R.prop('API_PROTOCOL', env)}://${R.prop('API_HOST', env)}:${R.prop(
            'API_PORT',
            env,
          )}`,
        ),
        R.always(null),
      )(env);

      const apiUrl: string =
        // API URL from environment variables
        envApiUrl ||
        // API URL from config
        R.prop('api', config) ||
        // Default API URL
        'https://api.lagoon.amazeeio.cloud';

      const { protocol, hostname, port } = url.parse(apiUrl);

      if (!hostname) {
        throw new Error(
          'API URL configured under the "api" key in .lagoon.yml doesn\'t contain a valid hostname.',
        );
      }

      const defaultProtocol = 'https:';
      const protocolPorts = {
        'https:': 443,
        'http:': 80,
      };

      allApiConfig = {
        hostname,
        port: R.ifElse(
          // If port is truthy...
          R.identity,
          // ...convert string to number...
          Number,
          // ...else assign the port based on the protocol or the default port
          R.always(R.prop(protocol || defaultProtocol, protocolPorts)),
        )(port),
      };
    }

    return allApiConfig;
  };
})();

export const getSshConfig = (() => {
  let allSshConfig;
  return () => {
    if (!allSshConfig) {
      const env = Object.freeze({ ...process.env });

      const [configSshHost: string | null, configSshPort: null] = R.compose(
        (sshConfig) => {
          if (sshConfig && R.contains(':', sshConfig)) {
            const split = R.split(':', sshConfig);
            if (R.length(split) === 2) return split;
          }
          return [null, null];
        },
      )(R.prop('ssh', config));

      const host: string =
        // Host from environment variable
        R.prop('SSH_HOST', env) ||
        // Host from config
        configSshHost ||
        // Default host
        'ssh.lagoon.amazeeio.cloud';

      const port: number =
        // Port from environment variable (needs to be number for .connect())
        Number(R.prop('SSH_HOST', env)) ||
        // Port from config (needs to be number for .connect())
        Number(configSshPort) ||
        // Default port
        32222;

      allSshConfig = {
        username: 'lagoon',
        host,
        port,
      };
    }
    return allSshConfig;
  };
})();
<commit_msg>Improve comments and type<commit_after>// @flow

import fs from 'fs';
import url from 'url';
import R from 'ramda';
import { writeFile } from '../util/fs';
import yaml from 'js-yaml';
import findup from 'findup-sync';

// TODO: Type the rest of the config
export type LagoonConfig = {|
  api?: string,
  branches?: boolean | RegExp,
  customer?: number,
  git_url?: string,
  openshift?: number,
  production_environment?: string,
  project?: string,
  pullrequests?: boolean,
  ssh?: string,
|};

export type LagoonConfigInput = {|
  project: string,
  api?: string,
  ssh?: string,
|};

export function createConfig(
  filepath: string,
  inputOptions: LagoonConfigInput,
): Promise<void> {
  const inputOptionsWithoutEmptyStrings = R.reject(
    option =>
      // Reject (filter out) empty strings
      R.both(R.is(String), R.isEmpty)(option),
    inputOptions,
  );
  const yamlConfig = yaml.safeDump(inputOptionsWithoutEmptyStrings);
  return writeFile(filepath, yamlConfig);
}

export function parseConfig(yamlContent: string): LagoonConfig {
  // TODO: Add schema validation in here if necessary
  return yaml.safeLoad(yamlContent);
}

/**
 * Finds and reads the lagoon.yml file
 */
function readConfig(): LagoonConfig | null {
  const configPath = findup('.lagoon.yml');

  if (configPath == null) {
    return null;
  }

  const yamlContent = fs.readFileSync(configPath);
  return parseConfig(yamlContent.toString());
}

export const config = readConfig();

export const getApiConfig: () => { hostname: string, port: number } = (() => {
  let allApiConfig;

  return () => {
    if (!allApiConfig) {
      // Freeze process.env for Flow
      const env = Object.freeze({ ...process.env });

      // Build API URL from environment variables if protocol, host and port exist
      const envApiUrl: string | null = R.ifElse(
        R.allPass([
          R.prop('API_PROTOCOL'),
          R.prop('API_HOST'),
          R.prop('API_PORT'),
        ]),
        R.always(
          `${R.prop('API_PROTOCOL', env)}://${R.prop('API_HOST', env)}:${R.prop(
            'API_PORT',
            env,
          )}`,
        ),
        R.always(null),
      )(env);

      const apiUrl: string =
        // API URL from environment variables
        envApiUrl ||
        // API URL from config
        R.prop('api', config) ||
        // Default API URL
        'https://api.lagoon.amazeeio.cloud';

      const { protocol, hostname, port } = url.parse(apiUrl);

      if (!hostname) {
        throw new Error(
          'API URL configured under the "api" key in .lagoon.yml doesn\'t contain a valid hostname.',
        );
      }

      const defaultProtocol = 'https:';
      const protocolPorts = {
        'https:': 443,
        'http:': 80,
      };

      allApiConfig = {
        hostname,
        port: R.ifElse(
          // If port is truthy...
          R.identity,
          // ...convert string to number...
          Number,
          // ...else assign the port based on the protocol or the default port
          R.always(R.prop(protocol || defaultProtocol, protocolPorts)),
        )(port),
      };
    }

    return allApiConfig;
  };
})();

export const getSshConfig = (() => {
  let allSshConfig;

  return () => {
    if (!allSshConfig) {
      // Freeze process.env for Flow
      const env = Object.freeze({ ...process.env });

      // Parse the host and the port from the config string under `ssh`
      const [
        configSshHost: string | null,
        configSshPort: string | null,
      ] = R.compose((sshConfig) => {
        if (sshConfig && R.contains(':', sshConfig)) {
          const split = R.split(':', sshConfig);
          if (R.length(split) === 2) return split;
        }
        return [null, null];
      })(R.prop('ssh', config));

      const host: string =
        // Host from environment variable
        R.prop('SSH_HOST', env) ||
        // Host from config
        configSshHost ||
        // Default host
        'ssh.lagoon.amazeeio.cloud';

      const port: number =
        // Port from environment variable (needs to be number for .connect())
        Number(R.prop('SSH_HOST', env)) ||
        // Port from config (needs to be number for .connect())
        Number(configSshPort) ||
        // Default port
        32222;

      allSshConfig = {
        username: 'lagoon',
        host,
        port,
      };
    }
    return allSshConfig;
  };
})();
<|endoftext|>


<commit_before>#!/usr/bin/env node
var path = require("path"),
    fs = require("fs"),
    util = require("util"),
    api = require("./api"),
    bundle = require("./bundle"),
    config = require("./config"),
    logger = require("../../server/logger.js"),
    jshint = require("./jshint_runner");

    require("./fs_extension");

// Copies all Resource files and prepares JS files
function prepare(src, dst, callback) {
  var app_name = config.app_name;
  if (src.match("js$")){
    var src_text = "var __p = require('/api/PlatformRequire'), __log = require('/api/Log'), assert = require('/api/Assert'), L = require('/api/Localisation').fetchString;\n"
      + fs.readFileSync(src).toString()
      .replace(/Ti(tanium)?.Filesystem.(resourcesDirectory|getResourcesDirectory\(\))/g, "Ti.Filesystem.applicationDataDirectory + '"+app_name.replace(/ /g,"_")+"/'")
      .replace(/require\(/g, "__p.require(")
      .replace(/Ti(tanium)?.include\(/g, "__p.include(this,")
      .replace(/Ti.Locale.getString/g, "L")
      .replace(/([ :=\(])(['"])(\/[^'"].*?)(['"])/g, "$1__p.file($2$3$4)") // ignores "/"
      // Replace strings like ".titleid = 'save'" -> "title = L('save')"
      .replace(/\.(title|text)id\s{0,}\=\s{0,}['"](\w+)['"]/g, '.$1 = L(\'$2\')')
      // Replace strings like "titleid: 'save'" -> "title: L('save')"
      .replace(/\b(title|text)id:\s{0,}['"](\w+)['"]/g, '$1: L(\'$2\')')
      .replace(/Ti(tanium)?.API/g, "__log");
    if (src.match("_spec.js$")) {
      src_text =  "var jasmine = require('/lib/jasmine-1.2.0');var methods = ['spyOn','it','xit','expect','runs','waits','waitsFor','beforeEach','afterEach','describe','xdescribe'];methods.forEach(function(method) {this[method] = jasmine[method];});"
        +src_text;
    }
    fs.writeFile(dst,src_text, callback);
  } else { // Non-JS file - just pump it
    var  is = fs.createReadStream(src);
    var  os = fs.createWriteStream(dst);
    is.on("end", callback).pipe(os);
  }
}

function prepareFiles(index, file_list, isSpec, callback) {
  if (file_list.files.length === index) {
    callback();
  } else {
    var file = file_list.files[index];
    prepare(path.join(isSpec? config.base : config.resources_path,file), path.join(config.tishadow_src, file), function(){
      index++;
      prepareFiles(index, file_list, isSpec, callback);
    });
  }
}

function finalise(file_list,callback) {
  // Bundle up to go
  var total = file_list.files.length;
  // Send the directories and files (see bundle.zip)
  bundle.pack(file_list.dirs.concat(file_list.files),function(written) {
    logger.info(total+ " file(s) bundled.");
    fs.touch(config.last_updated_file);
    if (config.isBundle) {
      logger.info("Bundle Ready: " + config.bundle_file);
      if (callback) {
        callback();
      }
    } else {
      api.newBundle();
    }
  });
}

module.exports = function(env, callback) {
  if (!fs.existsSync(path.join(config.base,'tiapp.xml'))) {
    logger.error("Script must be executed in the Titanium project's root directory");
    process.exit();
  }

  config.buildPaths(env, function() {
    if (env.jshint) {
      logger.info("Running JSHint");
      jshint.checkPath(config.jshint_path);
    }

    logger.info("Beginning Build Process");
    var file_list,i18n_list,spec_list;
    if( config.isUpdate) {
       var last_stat = fs.statSync(config.last_updated_file);
       file_list = fs.getList(config.resources_path,last_stat.mtime);
       i18n_list = fs.getList(config.i18n_path,last_stat.mtime);
       spec_list = fs.getList(config.spec_path,last_stat.mtime);

       if (file_list.files.length === 0 && i18n_list.files.length === 0 && spec_list.files.length === 0) {
         logger.error("Nothing to update.");
         process.exit();
       }
     } else {
       if (!fs.existsSync(config.build_path)){
         fs.mkdirSync(config.build_path, 0755);
       }
       //Clean Build Directory
       if (fs.existsSync(config.tishadow_build)) {
         fs.rm_rf(config.tishadow_build);
       }
       // Create the tishadow build paths
       fs.mkdirs([config.tishadow_build, config.tishadow_src, config.tishadow_dist]);
       file_list = fs.getList(config.resources_path);
       i18n_list = fs.getList(config.i18n_path);
       spec_list = fs.getList(config.spec_path);
     }

     // Build the required directory structure
     fs.mkdirs(file_list.dirs, config.tishadow_src);
     fs.mkdirs(i18n_list.dirs, config.tishadow_src);
     if(spec_list.files.length > 0) {
       fs.mkdirSync(config.tishadow_spec, 0755);
       fs.mkdirs(spec_list.dirs, config.tishadow_spec);
       spec_list.files = spec_list.files.map(function(file) { return "spec/" + file;});
     }

     // Just pump out localisation files
     i18n_list.files.forEach(function(file, idx) {
       util.pump(fs.createReadStream(path.join(config.i18n_path,file)),fs.createWriteStream(path.join(config.tishadow_src, file)));
     });

     // Process Files
     prepareFiles(0, file_list, false, function() {
       prepareFiles(0, spec_list, true, function() {
          file_list.files = file_list.files.concat(i18n_list.files).concat(spec_list.files);
          finalise(file_list,callback);
       });
     });
  });
}
<commit_msg>replaced pump with pipe<commit_after>#!/usr/bin/env node
var path = require("path"),
    fs = require("fs"),
    api = require("./api"),
    bundle = require("./bundle"),
    config = require("./config"),
    logger = require("../../server/logger.js"),
    jshint = require("./jshint_runner");

    require("./fs_extension");

// Copies all Resource files and prepares JS files
function prepare(src, dst, callback) {
  var app_name = config.app_name;
  if (src.match("js$")){
    var src_text = "var __p = require('/api/PlatformRequire'), __log = require('/api/Log'), assert = require('/api/Assert'), L = require('/api/Localisation').fetchString;\n"
      + fs.readFileSync(src).toString()
      .replace(/Ti(tanium)?.Filesystem.(resourcesDirectory|getResourcesDirectory\(\))/g, "Ti.Filesystem.applicationDataDirectory + '"+app_name.replace(/ /g,"_")+"/'")
      .replace(/require\(/g, "__p.require(")
      .replace(/Ti(tanium)?.include\(/g, "__p.include(this,")
      .replace(/Ti.Locale.getString/g, "L")
      .replace(/([ :=\(])(['"])(\/[^'"].*?)(['"])/g, "$1__p.file($2$3$4)") // ignores "/"
      // Replace strings like ".titleid = 'save'" -> "title = L('save')"
      .replace(/\.(title|text)id\s{0,}\=\s{0,}['"](\w+)['"]/g, '.$1 = L(\'$2\')')
      // Replace strings like "titleid: 'save'" -> "title: L('save')"
      .replace(/\b(title|text)id:\s{0,}['"](\w+)['"]/g, '$1: L(\'$2\')')
      .replace(/Ti(tanium)?.API/g, "__log");
    if (src.match("_spec.js$")) {
      src_text =  "var jasmine = require('/lib/jasmine-1.2.0');var methods = ['spyOn','it','xit','expect','runs','waits','waitsFor','beforeEach','afterEach','describe','xdescribe'];methods.forEach(function(method) {this[method] = jasmine[method];});"
        +src_text;
    }
    fs.writeFile(dst,src_text, callback);
  } else { // Non-JS file - just pump it
    var  is = fs.createReadStream(src);
    var  os = fs.createWriteStream(dst);
    is.on("end", callback).pipe(os);
  }
}

function prepareFiles(index, file_list, isSpec, callback) {
  if (file_list.files.length === index) {
    callback();
  } else {
    var file = file_list.files[index];
    prepare(path.join(isSpec? config.base : config.resources_path,file), path.join(config.tishadow_src, file), function(){
      index++;
      prepareFiles(index, file_list, isSpec, callback);
    });
  }
}

function finalise(file_list,callback) {
  // Bundle up to go
  var total = file_list.files.length;
  // Send the directories and files (see bundle.zip)
  bundle.pack(file_list.dirs.concat(file_list.files),function(written) {
    logger.info(total+ " file(s) bundled.");
    fs.touch(config.last_updated_file);
    if (config.isBundle) {
      logger.info("Bundle Ready: " + config.bundle_file);
      if (callback) {
        callback();
      }
    } else {
      api.newBundle();
    }
  });
}

module.exports = function(env, callback) {
  if (!fs.existsSync(path.join(config.base,'tiapp.xml'))) {
    logger.error("Script must be executed in the Titanium project's root directory");
    process.exit();
  }

  config.buildPaths(env, function() {
    if (env.jshint) {
      logger.info("Running JSHint");
      jshint.checkPath(config.jshint_path);
    }

    logger.info("Beginning Build Process");
    var file_list,i18n_list,spec_list;
    if( config.isUpdate) {
       var last_stat = fs.statSync(config.last_updated_file);
       file_list = fs.getList(config.resources_path,last_stat.mtime);
       i18n_list = fs.getList(config.i18n_path,last_stat.mtime);
       spec_list = fs.getList(config.spec_path,last_stat.mtime);

       if (file_list.files.length === 0 && i18n_list.files.length === 0 && spec_list.files.length === 0) {
         logger.error("Nothing to update.");
         process.exit();
       }
     } else {
       if (!fs.existsSync(config.build_path)){
         fs.mkdirSync(config.build_path, 0755);
       }
       //Clean Build Directory
       if (fs.existsSync(config.tishadow_build)) {
         fs.rm_rf(config.tishadow_build);
       }
       // Create the tishadow build paths
       fs.mkdirs([config.tishadow_build, config.tishadow_src, config.tishadow_dist]);
       file_list = fs.getList(config.resources_path);
       i18n_list = fs.getList(config.i18n_path);
       spec_list = fs.getList(config.spec_path);
     }

     // Build the required directory structure
     fs.mkdirs(file_list.dirs, config.tishadow_src);
     fs.mkdirs(i18n_list.dirs, config.tishadow_src);
     if(spec_list.files.length > 0) {
       fs.mkdirSync(config.tishadow_spec, 0755);
       fs.mkdirs(spec_list.dirs, config.tishadow_spec);
       spec_list.files = spec_list.files.map(function(file) { return "spec/" + file;});
     }

     // Just pump out localisation files
     i18n_list.files.forEach(function(file, idx) {
       fs.createReadStream(path.join(config.i18n_path,file)).pipe(fs.createWriteStream(path.join(config.tishadow_src, file)));
     });

     // Process Files
     prepareFiles(0, file_list, false, function() {
       prepareFiles(0, spec_list, true, function() {
          file_list.files = file_list.files.concat(i18n_list.files).concat(spec_list.files);
          finalise(file_list,callback);
       });
     });
  });
}
<|endoftext|>