{"version":3,"sources":["../lib/Base.js","../src/Garnish.js","../src/BaseDrag.js","../src/CheckboxSelect.js","../src/ContextMenu.js","../src/Drag.js","../src/DragDrop.js","../src/DragMove.js","../src/DragSort.js","../src/EscManager.js","../src/HUD.js","../src/Menu.js","../src/MenuBtn.js","../src/MixedInput.js","../src/Modal.js","../src/NiceText.js","../src/Pill.js","../src/Select.js","../src/SelectMenu.js","garnish.js"],"names":["$","getErd","erd","elementResizeDetectorMaker","callOnAdd","triggerResizeEvent","elem","trigger","Base","extend","_instance","_static","prototype","_prototyping","proto","this","call","base","constructor","klass","_constructing","apply","arguments","ancestor","forEach","implement","toString","valueOf","type","init","source","value","length","test","method","previous","returnValue","toSource","hidden","i","key","desc","Object","getOwnPropertyDescriptor","defineProperty","version","object","block","context","undefined","String","Garnish","$win","window","$doc","document","$bod","body","rtl","hasClass","ltr","$scrollContainer","DELETE_KEY","SHIFT_KEY","CTRL_KEY","ALT_KEY","RETURN_KEY","ESC_KEY","SPACE_KEY","LEFT_KEY","UP_KEY","RIGHT_KEY","DOWN_KEY","A_KEY","S_KEY","CMD_KEY","PRIMARY_CLICK","SECONDARY_CLICK","X_AXIS","Y_AXIS","FX_DURATION","TEXT_NODE","log","msg","console","_isMobileBrowser","_isMobileOrTabletBrowser","isMobileBrowser","detectTablets","a","navigator","userAgent","vendor","opera","RegExp","substr","isArray","val","Array","isJquery","jQuery","isString","hasAttr","attr","isTextNode","nodeType","getOffset","_offset","offset","top","scrollTop","left","scrollLeft","getDist","x1","y1","x2","y2","Math","sqrt","pow","hitTest","x","y","_$elem","_x1","_y1","_x2","outerWidth","_y2","outerHeight","isCursorOver","ev","pageX","pageY","copyTextStyles","target","$source","$target","css","fontFamily","fontSize","fontWeight","letterSpacing","lineHeight","textAlign","textIndent","whiteSpace","wordSpacing","wordWrap","getBodyScrollTop","_scrollTop","_maxScrollTop","height","requestAnimationFrame","raf","mozRequestAnimationFrame","webkitRequestAnimationFrame","fn","setTimeout","cancelAnimationFrame","cancel","mozCancelAnimationFrame","webkitCancelAnimationFrame","clearTimeout","id","scrollContainerToElement","container","$elem","$container","scrollParent","prop","elemScrollOffset","elemOffset","targetScrollTop","elemHeight","containerHeight","innerHeight","clientHeight","velocity","mobileHA","SHAKE_STEPS","SHAKE_STEP_DURATION","shake","startingPoint","parseInt","isNaN","_properties","getElement","makeArray","getInputBasename","name","replace","getInputPostVal","$input","findInputs","find","getPostData","inputName","postData","arrayInputCounters","$inputs","eq","inputVal","isArrayInput","croppedName","substring","j","copyInputValues","$sourceInputs","$targetInputs","isCtrlKeyPressed","platform","match","metaKey","ctrlKey","altKey","_eventHandlers","_normalizeEvents","events","split","on","data","handler","push","namespace","off","eventHandler","splice","settings","_namespace","_$listeners","_disabled","floor","random","_listeners","noop","setSettings","defaults","baseSettings","_ev","_splitEvents","trim","_formatEvents","slice","join","addListener","func","proxy","inArray","removeListener","removeAllListeners","disable","enable","destroy","event","special","activate","setup","namespaces","eventHandle","mousedown.garnish-activate","e","preventDefault","click.garnish-activate","keydown.garnish-activate","keyCode","addClass","removeClass","removeAttr","teardown","textchange","handle","el","args","delay","handleObj","targetData","delayTimeout","resize","listenTo","each","BaseDrag","$items","dragging","mousedownX","mousedownY","realMouseX","realMouseY","mouseX","mouseY","mouseDistX","mouseDistY","mouseOffsetX","mouseOffsetY","$targetItem","scrollProperty","scrollAxis","scrollDist","scrollProxy","scrollFrame","_","items","isPlainObject","addItems","allowDragging","startDragging","onDragStart","drag","didMouseMove","_scrollProperty","axis","_winScrollTop","_minMouseScrollY","windowScrollTargetSize","_scrollAxis","_scrollDist","round","_maxMouseScrollY","_winScrollLeft","_minMouseScrollX","_maxMouseScrollX","width","_cancelWindowScroll","onDrag","stopDragging","onDragStop","item","removeItems","add","index","_deinitItem","removeAllItems","_handleMouseDown","which","$handle","_getItemHandle","currentTarget","is","closest","ignoreHandleSelector","_handleMouseMove","_mouseDist","minMouseDist","_handleMouseUp","_scrollWindow","scrollPos","removeData","CheckboxSelect","$all","$options","$checkboxes","filter","not","onAllChange","isAllChecked","checked","disabled","ContextMenu","options","$menu","showingMenu","counter","buildMenu","menuClass","$ul","appendTo","hasOwnProperty","option","$li","$a","label","onClick","mousedown","hideMenu","showMenu","showing","show","hide","Drag","targetItemWidth","targetItemHeight","targetItemPositionInDraggee","$draggee","otherItems","totalOtherItems","helpers","helperTargets","helperPositions","helperLagIncrement","updateHelperPosProxy","updateHelperPosFrame","lastMouseX","lastMouseY","_returningHelpersToDraggees","draggeeDisplay","setDraggee","findDraggee","helperLagIncrementDividend","concat","toArray","singleHelper","_createHelper","removeDraggee","collapseDraggees","appendDraggee","$newDraggee","oldLength","newLength","draggeeVirtualMidpointX","draggeeVirtualMidpointY","getHelperTargetX","getHelperTargetY","returnHelpersToDraggees","$helper","display","visibility","callback","draggeeOffset","onReturnHelpersToDraggees","$draggeeHelper","clone","copyDraggeeInputValuesToHelper","margin","pointer-events","helper","append","helperPos","_getHelperTarget","position","zIndex","helperBaseZindex","opacity","helperOpacity","_updateHelperPos","_i","_j","_lag","helperLagBase","helperSpacingX","helperSpacingY","_showDraggee","remove","DragDrop","$dropTargets","$activeDropTarget","updateDropTargets","dropTargets","_activeDropTarget","_elem","activeDropTargetClass","onDropTargetChange","fadeOutHelpers","duration","complete","DragMove","DragSort","$heightedContainer","$insertion","insertionVisible","oldDraggeeIndexes","newDraggeeIndexes","closestItem","_midpointVersion","_$prevItem","createInsertion","insertion","magnetStrength","_draggeeOffsetX","_draggeeOffsetY","canInsertBefore","$item","canInsertAfter","_getDraggeeIndexes","moveTargetItemToFront","_getItemIndex","first","insertBefore","_placeInsertionWithDraggee","_clearMidpoints","parent","_removeInsertion","_getClosestItem","_updateInsertion","insertAfter","onSortChange","onInsertionPointChange","indexes","_closestItem","_testForClosestItem","_midpoint","_getItemMidpoint","_startXDist","_lastXDist","abs","_startYDist","_lastYDist","_$otherItem","prev","_xDist","_yDist","last","next","_repositionDraggee","get","_moveDraggeeToItem","_$item","prependTo","_mouseDistX","_mouseDistY","_closestItemMouseDistY","_closestItemMouseDistX","EscManager","handlers","escapeLatest","register","obj","unregister","pop","escManager","HUD","$trigger","$fixedTriggerParent","$hud","$tip","$body","$header","$footer","$mainContainer","$main","$shade","orientation","updatingSizeAndPosition","windowWidth","windowHeight","mainWidth","mainHeight","bodyContents","onShow","onHide","onSubmit","activeHUDs","class","shadeClass","hudClass","tipClass","bodyClass","mainContainerClass","mainClass","updateBody","$parent","offsetParent","closeBtn","html","headerClass","footerClass","stopPropagation","closeOtherHUDs","hudID","updateRecords","updateSizeAndPosition","changed","force","updateSizeAndPositionInternal","triggerWidth","triggerHeight","triggerOffset","windowScrollLeft","windowScrollTop","scrollContainerTriggerOffset","scrollContainerScrollLeft","scrollContainerScrollTop","hudBodyWidth","hudBodyHeight","right","bottom","overflow-x","overflow-y","clearances","orientations","relevantSize","windowSpacing","triggerSpacing","tipClasses","maxHudBodyWidth","maxHudBodyHeight","minBodyWidth","minBodyHeight","triggerCenter","maxLeft","minLeft","tipLeft","tipWidth","maxTop","minTop","tipTop","toggle","submit","_handleSubmit","Menu","$anchor","menuId","_windowWidth","_windowHeight","_windowScrollLeft","_windowScrollTop","_anchorOffset","_anchorWidth","_anchorHeight","_anchorOffsetRight","_anchorOffsetBottom","_menuWidth","_menuHeight","addOptions","$menuList","role","aria-hidden","attachToElement","anchor","optionKey","tabindex","setPositionRelativeToAnchor","topClearance","bottomClearance","maxHeight","min","align","_alignCenter","rightClearance","leftClearance","_alignRight","_alignLeft","detach","selectOption","onOptionSelect","selectedOption","MenuBtn","$btn","menu","btn","menuAnchor","aria-owns","aria-haspopup","aria-expanded","onBlur","onKeyDown","$option","$currentOption","click","focusOption","onMouseDown","onMenuHide","MixedInput","elements","focussedElement","blurTimeout","getElementIndex","isText","onFocus","setFocus","setCarotPos","addTextElement","text","TextElement","addElement","focussedElementIndex","selectionStart","selectionEnd","preVal","postVal","newText","removeElement","$prevElem","$nextElem","prevElemVal","newVal","blurFocussedElement","focus","focusPreviousElement","$from","focusNextElement","pos","parentInput","$stage","focussed","interval","padding","setWidth","getIndex","buildStage","getTextWidth","stageWidth","setInterval","NiceText","checkInput","clearInterval","getVal","setVal","onChange","Modal","visible","dragger","desiredWidth","desiredHeight","resizeDragger","resizeStartWidth","resizeStartHeight","setContainer","autoShow","instances","draggable","dragHandleSelector","resizable","$resizeDragHandle","closeOtherModals","visibleModal","onFadeIn","hideOnShadeClick","hideOnEsc","quickShow","quickHide","max","min-width","min-height","_width","getWidth","minGutter","_height","getHeight","onFadeOut","_handleWindowResize","_handleResizeStart","_handleResize","relativeElemPadding","$hint","$charsLeft","autoHeight","maxLength","showCharsLeft","showingHint","inputBoxSizing","minHeight","initialized","input","isVisible","initialize","getHeightForValue","updateHeight","hint","$hintContainer","charsLeftClass","updateCharsLeft","initializeIfVisible","showHint","hintFadeDuration","hideHint","onTextChange","border-top","border-right","border-bottom","border-left","padding-top","padding-right","padding-bottom","padding-left","-webkit-box-sizing","-moz-box-sizing","box-sizing","spaces","onHeightChange","updateHeightIfWidthChanged","_charsLeft","negativeCharsLeftClass","Pill","$outerContainer","$innerContainer","$btns","$selectedBtn","outerContainer","preventOutlineOnMouseFocus","select","selectNext","nextIndex","_getSelectedBtnIndex","selectPrev","prevIndex","Select","$selectedItems","$focusedItem","mousedownTarget","mouseUpTimeout","callbackFrame","$focusable","$first","$last","allowEmpty","checkboxMode","ignoreClick","deselectAll","getItemIndex","isSelected","selectItem","preventScroll","multi","setFocusableItem","focusItem","_selectItems","selectAll","selectRange","sliceFrom","sliceTo","deselectItem","_deselectItems","clearFirst","deselectOthers","toggleItem","_canDeselect","clearMouseUpTimeout","getFirstItem","getLastItem","isPreviousItem","isNextItem","getPreviousItem","getNextItem","getItemToTheLeft","horizontal","vertical","getClosestItem","getItemToTheRight","getItemAbove","getItemBelow","dir","step","axisProps","closestItemAxisProps","dirProps","closestItemDirectionProps","$thisItem","thisOffset","thisMidpoint","midpointOffset","midpointSizeFunc","otherRowPos","smallestMidpointDiff","$closestItem","$otherItem","otherOffset","isNextRow","rowOffset","otherMidpoint","midpointDiff","isWrongDirection","getFurthestItemToTheLeft","getFurthestItem","getFurthestItemToTheRight","getFurthestItemAbove","getFurthestItemBelow","$testItem","totalSelected","getTotalSelected","updateIndexes","itemsChanged","selectionChanged","selectedIndex","selectedClass","onSelectionChange","resetItemOrder","scrollTo","getSelectedItems","shiftKey","_actAsCheckbox","onMouseUp","<","b",">","SelectMenu","selected","build","_addSelectedOptionClass","dom","ul","className","setBtnText","$btnLabel","ulClass"],"mappings":"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","file":"garnish.min.js","sourcesContent":["/*!\r\n\tBase.js, version 1.1a\r\n\tCopyright 2006-2010, Dean Edwards\r\n\tLicense: http://www.opensource.org/licenses/mit-license.php\r\n*/\r\n\r\nvar Base = function() {\r\n\t// dummy\r\n};\r\n\r\nBase.extend = function(_instance, _static) { // subclass\r\n\tvar extend = Base.prototype.extend;\r\n\r\n\t// build the prototype\r\n\tBase._prototyping = true;\r\n\tvar proto = new this;\r\n\textend.call(proto, _instance);\r\n\tproto.base = function() {\r\n\t\t// call this method from any other method to invoke that method's ancestor\r\n\t};\r\n\tdelete Base._prototyping;\r\n\r\n\t// create the wrapper for the constructor function\r\n\t//var constructor = proto.constructor.valueOf(); //-dean\r\n\tvar constructor = proto.constructor;\r\n\tvar klass = proto.constructor = function() {\r\n\t\tif (!Base._prototyping) {\r\n\t\t\tif (this._constructing || this.constructor == klass) { // instantiation\r\n\t\t\t\tthis._constructing = true;\r\n\t\t\t\tconstructor.apply(this, arguments);\r\n\t\t\t\tdelete this._constructing;\r\n\t\t\t} else if (arguments[0] != null) { // casting\r\n\t\t\t\treturn (arguments[0].extend || extend).call(arguments[0], proto);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\t// build the class interface\r\n\tklass.ancestor = this;\r\n\tklass.extend = this.extend;\r\n\tklass.forEach = this.forEach;\r\n\tklass.implement = this.implement;\r\n\tklass.prototype = proto;\r\n\tklass.toString = this.toString;\r\n\tklass.valueOf = function(type) {\r\n\t\t//return (type == \"object\") ? klass : constructor; //-dean\r\n\t\treturn (type == \"object\") ? klass : constructor.valueOf();\r\n\t};\r\n\textend.call(klass, _static);\r\n\t// class initialisation\r\n\tif (typeof klass.init == \"function\") klass.init();\r\n\treturn klass;\r\n};\r\n\r\nBase.prototype = {\r\n\textend: function(source, value) {\r\n\t\tif (arguments.length > 1) { // extending with a name/value pair\r\n\t\t\tvar ancestor = this[source];\r\n\t\t\tif (ancestor && (typeof value == \"function\") && // overriding a method?\r\n\t\t\t\t// the valueOf() comparison is to avoid circular references\r\n\t\t\t\t(!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) &&\r\n\t\t\t\t/\\bbase\\b/.test(value)) {\r\n\t\t\t\t// get the underlying method\r\n\t\t\t\tvar method = value.valueOf();\r\n\t\t\t\t// override\r\n\t\t\t\tvalue = function() {\r\n\t\t\t\t\tvar previous = this.base || Base.prototype.base;\r\n\t\t\t\t\tthis.base = ancestor;\r\n\t\t\t\t\tvar returnValue = method.apply(this, arguments);\r\n\t\t\t\t\tthis.base = previous;\r\n\t\t\t\t\treturn returnValue;\r\n\t\t\t\t};\r\n\t\t\t\t// point to the underlying method\r\n\t\t\t\tvalue.valueOf = function(type) {\r\n\t\t\t\t\treturn (type == \"object\") ? value : method;\r\n\t\t\t\t};\r\n\t\t\t\tvalue.toString = Base.toString;\r\n\t\t\t}\r\n\t\t\tthis[source] = value;\r\n\t\t} else if (source) { // extending with an object literal\r\n\t\t\tvar extend = Base.prototype.extend;\r\n\t\t\t// if this object has a customised extend method then use it\r\n\t\t\tif (!Base._prototyping && typeof this != \"function\") {\r\n\t\t\t\textend = this.extend || extend;\r\n\t\t\t}\r\n\t\t\tvar proto = {toSource: null};\r\n\t\t\t// do the \"toString\" and other methods manually\r\n\t\t\tvar hidden = [\"constructor\", \"toString\", \"valueOf\"];\r\n\t\t\t// if we are prototyping then include the constructor\r\n\t\t\tvar i = Base._prototyping ? 0 : 1;\r\n\t\t\twhile (key = hidden[i++]) {\r\n\t\t\t\tif (source[key] != proto[key]) {\r\n\t\t\t\t\textend.call(this, key, source[key]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// copy each of the source object's properties to this object\r\n\t\t\tfor (var key in source) {\r\n\t\t\t\tif (!proto[key]) {\r\n\t\t\t\t\tvar desc = Object.getOwnPropertyDescriptor(source, key);\r\n\t\t\t\t\tif (typeof desc.value != typeof undefined) {\r\n\t\t\t\t\t\t// set the value normally in case it's a function that needs to be overwritten\r\n\t\t\t\t\t\textend.call(this, key, desc.value);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// set it while maintaining the original descriptor settings\r\n\t\t\t\t\t\tObject.defineProperty(this, key, desc);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n};\r\n\r\n// initialise\r\nBase = Base.extend({\r\n\tconstructor: function() {\r\n\t\tthis.extend(arguments[0]);\r\n\t}\r\n}, {\r\n\tancestor: Object,\r\n\tversion: \"1.1\",\r\n\r\n\tforEach: function(object, block, context) {\r\n\t\tfor (var key in object) {\r\n\t\t\tif (this.prototype[key] === undefined) {\r\n\t\t\t\tblock.call(context, object[key], key, object);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\timplement: function() {\r\n\t\tfor (var i = 0; i < arguments.length; i++) {\r\n\t\t\tif (typeof arguments[i] == \"function\") {\r\n\t\t\t\t// if it's a function, call it\r\n\t\t\t\targuments[i](this.prototype);\r\n\t\t\t} else {\r\n\t\t\t\t// add the interface using the extend method\r\n\t\t\t\tthis.prototype.extend(arguments[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\ttoString: function() {\r\n\t\treturn String(this.valueOf());\r\n\t}\r\n});\r\n","/**\n * @namespace Garnish\n */\n\n// Bail if Garnish is already defined\nif (typeof Garnish !== 'undefined') {\n    throw 'Garnish is already defined!';\n}\n\nGarnish = {\n\n    // jQuery objects for common elements\n    $win: $(window),\n    $doc: $(document),\n    $bod: $(document.body)\n\n};\n\nGarnish.rtl = Garnish.$bod.hasClass('rtl');\nGarnish.ltr = !Garnish.rtl;\n\nGarnish = $.extend(Garnish, {\n\n    $scrollContainer: Garnish.$win,\n\n    // Key code constants\n    DELETE_KEY: 8,\n    SHIFT_KEY: 16,\n    CTRL_KEY: 17,\n    ALT_KEY: 18,\n    RETURN_KEY: 13,\n    ESC_KEY: 27,\n    SPACE_KEY: 32,\n    LEFT_KEY: 37,\n    UP_KEY: 38,\n    RIGHT_KEY: 39,\n    DOWN_KEY: 40,\n    A_KEY: 65,\n    S_KEY: 83,\n    CMD_KEY: 91,\n\n    // Mouse button constants\n    PRIMARY_CLICK: 1,\n    SECONDARY_CLICK: 3,\n\n    // Axis constants\n    X_AXIS: 'x',\n    Y_AXIS: 'y',\n\n    FX_DURATION: 100,\n\n    // Node types\n    TEXT_NODE: 3,\n\n    /**\n     * Logs a message to the browser's console, if the browser has one.\n     *\n     * @param {string} msg\n     */\n    log: function(msg) {\n        if (typeof console !== 'undefined' && typeof console.log === 'function') {\n            console.log(msg);\n        }\n    },\n\n    _isMobileBrowser: null,\n    _isMobileOrTabletBrowser: null,\n\n    /**\n     * Returns whether this is a mobile browser.\n     * Detection script courtesy of http://detectmobilebrowsers.com\n     *\n     * Last updated: 2014-11-24\n     *\n     * @param {boolean} detectTablets\n     * @return {boolean}\n     */\n    isMobileBrowser: function(detectTablets) {\n        var key = detectTablets ? '_isMobileOrTabletBrowser' : '_isMobileBrowser';\n\n        if (Garnish[key] === null) {\n            var a = navigator.userAgent || navigator.vendor || window.opera;\n            Garnish[key] = ((new RegExp('(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino' + (detectTablets ? '|android|ipad|playbook|silk' : ''), 'i')).test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-/i.test(a.substr(0, 4)));\n        }\n\n        return Garnish[key];\n    },\n\n    /**\n     * Returns whether a variable is an array.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isArray: function(val) {\n        return (val instanceof Array);\n    },\n\n    /**\n     * Returns whether a variable is a jQuery collection.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isJquery: function(val) {\n        return (val instanceof jQuery);\n    },\n\n    /**\n     * Returns whether a variable is a string.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isString: function(val) {\n        return (typeof val === 'string');\n    },\n\n    /**\n     * Returns whether an element has an attribute.\n     *\n     * @see http://stackoverflow.com/questions/1318076/jquery-hasattr-checking-to-see-if-there-is-an-attribute-on-an-element/1318091#1318091\n     */\n    hasAttr: function(elem, attr) {\n        var val = $(elem).attr(attr);\n        return (typeof val !== 'undefined' && val !== false);\n    },\n\n    /**\n     * Returns whether something is a text node.\n     *\n     * @param {object} elem\n     * @return {boolean}\n     */\n    isTextNode: function(elem) {\n        return (elem.nodeType === Garnish.TEXT_NODE);\n    },\n\n    /**\n     * Returns the offset of an element within the scroll container, whether that's the window or something else\n     */\n    getOffset: function(elem) {\n        this.getOffset._offset = $(elem).offset();\n\n        if (Garnish.$scrollContainer[0] !== Garnish.$win[0]) {\n            this.getOffset._offset.top += Garnish.$scrollContainer.scrollTop();\n            this.getOffset._offset.left += Garnish.$scrollContainer.scrollLeft();\n        }\n\n        return this.getOffset._offset;\n    },\n\n    /**\n     * Returns the distance between two coordinates.\n     *\n     * @param {number} x1 The first coordinate's X position.\n     * @param {number} y1 The first coordinate's Y position.\n     * @param {number} x2 The second coordinate's X position.\n     * @param {number} y2 The second coordinate's Y position.\n     * @return {number}\n     */\n    getDist: function(x1, y1, x2, y2) {\n        return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));\n    },\n\n    /**\n     * Returns whether an element is touching an x/y coordinate.\n     *\n     * @param {number}    x    The coordinate's X position.\n     * @param {number}    y    The coordinate's Y position.\n     * @param {object} elem Either an actual element or a jQuery collection.\n     * @return {boolean}\n     */\n    hitTest: function(x, y, elem) {\n        Garnish.hitTest._$elem = $(elem);\n        Garnish.hitTest._offset = Garnish.hitTest._$elem.offset();\n        Garnish.hitTest._x1 = Garnish.hitTest._offset.left;\n        Garnish.hitTest._y1 = Garnish.hitTest._offset.top;\n        Garnish.hitTest._x2 = Garnish.hitTest._x1 + Garnish.hitTest._$elem.outerWidth();\n        Garnish.hitTest._y2 = Garnish.hitTest._y1 + Garnish.hitTest._$elem.outerHeight();\n\n        return (x >= Garnish.hitTest._x1 && x < Garnish.hitTest._x2 && y >= Garnish.hitTest._y1 && y < Garnish.hitTest._y2);\n    },\n\n    /**\n     * Returns whether the cursor is touching an element.\n     *\n     * @param {object} ev   The mouse event object containing pageX and pageY properties.\n     * @param {object} elem Either an actual element or a jQuery collection.\n     * @return {boolean}\n     */\n    isCursorOver: function(ev, elem) {\n        return Garnish.hitTest(ev.pageX, ev.pageY, elem);\n    },\n\n    /**\n     * Copies text styles from one element to another.\n     *\n     * @param {object} source The source element. Can be either an actual element or a jQuery collection.\n     * @param {object} target The target element. Can be either an actual element or a jQuery collection.\n     */\n    copyTextStyles: function(source, target) {\n        var $source = $(source),\n            $target = $(target);\n\n        $target.css({\n            fontFamily: $source.css('fontFamily'),\n            fontSize: $source.css('fontSize'),\n            fontWeight: $source.css('fontWeight'),\n            letterSpacing: $source.css('letterSpacing'),\n            lineHeight: $source.css('lineHeight'),\n            textAlign: $source.css('textAlign'),\n            textIndent: $source.css('textIndent'),\n            whiteSpace: $source.css('whiteSpace'),\n            wordSpacing: $source.css('wordSpacing'),\n            wordWrap: $source.css('wordWrap')\n        });\n    },\n\n    /**\n     * Returns the body's real scrollTop, discarding any window banding in Safari.\n     *\n     * @return {number}\n     */\n    getBodyScrollTop: function() {\n        Garnish.getBodyScrollTop._scrollTop = document.body.scrollTop;\n\n        if (Garnish.getBodyScrollTop._scrollTop < 0) {\n            Garnish.getBodyScrollTop._scrollTop = 0;\n        }\n        else {\n            Garnish.getBodyScrollTop._maxScrollTop = Garnish.$bod.outerHeight() - Garnish.$win.height();\n\n            if (Garnish.getBodyScrollTop._scrollTop > Garnish.getBodyScrollTop._maxScrollTop) {\n                Garnish.getBodyScrollTop._scrollTop = Garnish.getBodyScrollTop._maxScrollTop;\n            }\n        }\n\n        return Garnish.getBodyScrollTop._scrollTop;\n    },\n\n    requestAnimationFrame: (function() {\n            var raf = (\n                window.requestAnimationFrame ||\n                window.mozRequestAnimationFrame ||\n                window.webkitRequestAnimationFrame ||\n                function(fn) {\n                    return window.setTimeout(fn, 20);\n                }\n            );\n\n            return function(fn) {\n                return raf(fn);\n            };\n        })(),\n\n    cancelAnimationFrame: (function() {\n            var cancel = (\n                window.cancelAnimationFrame ||\n                window.mozCancelAnimationFrame ||\n                window.webkitCancelAnimationFrame ||\n                window.clearTimeout\n            );\n\n            return function(id) {\n                return cancel(id);\n            };\n        })(),\n\n    /**\n     * Scrolls a container element to an element within it.\n     *\n     * @param {object} container Either an actual element or a jQuery collection.\n     * @param {object} elem      Either an actual element or a jQuery collection.\n     */\n    scrollContainerToElement: function(container, elem) {\n        var $elem;\n\n        if (typeof elem === 'undefined') {\n            $elem = $(container);\n            $container = $elem.scrollParent();\n        }\n        else {\n            var $container = $(container);\n            $elem = $(elem);\n        }\n\n        if ($container.prop('nodeName') === 'HTML' || $container[0] === Garnish.$doc[0]) {\n            $container = Garnish.$win;\n        }\n\n        var scrollTop = $container.scrollTop(),\n            elemOffset = $elem.offset().top;\n\n        var elemScrollOffset;\n\n        if ($container[0] === window) {\n            elemScrollOffset = elemOffset - scrollTop;\n        }\n        else {\n            elemScrollOffset = elemOffset - $container.offset().top;\n        }\n\n        var targetScrollTop = false;\n\n        // Is the element above the fold?\n        if (elemScrollOffset < 0) {\n            targetScrollTop = scrollTop + elemScrollOffset - 10;\n        }\n        else {\n            var elemHeight = $elem.outerHeight(),\n                containerHeight = ($container[0] === window ? window.innerHeight : $container[0].clientHeight);\n\n            // Is it below the fold?\n            if (elemScrollOffset + elemHeight > containerHeight) {\n                targetScrollTop = scrollTop + (elemScrollOffset - (containerHeight - elemHeight)) + 10;\n            }\n        }\n\n        if (targetScrollTop !== false) {\n            // Velocity only allows you to scroll to an arbitrary position if you're scrolling the main window\n            if ($container[0] === window) {\n                $('html').velocity('scroll', {\n                    offset: targetScrollTop + 'px',\n                    mobileHA: false\n                });\n            }\n            else {\n                $container.scrollTop(targetScrollTop);\n            }\n        }\n    },\n\n    SHAKE_STEPS: 10,\n    SHAKE_STEP_DURATION: 25,\n\n    /**\n     * Shakes an element.\n     *\n     * @param {object}  elem Either an actual element or a jQuery collection.\n     * @param {string} prop The property that should be adjusted (default is 'margin-left').\n     */\n    shake: function(elem, prop) {\n        var $elem = $(elem);\n\n        if (!prop) {\n            prop = 'margin-left';\n        }\n\n        var startingPoint = parseInt($elem.css(prop));\n        if (isNaN(startingPoint)) {\n            startingPoint = 0;\n        }\n\n        for (var i = 0; i <= Garnish.SHAKE_STEPS; i++) {\n            (function(i) {\n                setTimeout(function() {\n                    Garnish.shake._properties = {};\n                    Garnish.shake._properties[prop] = startingPoint + (i % 2 ? -1 : 1) * (10 - i);\n                    $elem.velocity(Garnish.shake._properties, Garnish.SHAKE_STEP_DURATION);\n                }, (Garnish.SHAKE_STEP_DURATION * i));\n            })(i);\n        }\n    },\n\n    /**\n     * Returns the first element in an array or jQuery collection.\n     *\n     * @param {object} elem\n     * @return mixed\n     */\n    getElement: function(elem) {\n        return $.makeArray(elem)[0];\n    },\n\n    /**\n     * Returns the beginning of an input's name= attribute value with any [bracktes] stripped out.\n     *\n     * @param {object} elem\n     * @return string|null\n     */\n    getInputBasename: function(elem) {\n        var name = $(elem).attr('name');\n\n        if (name) {\n            return name.replace(/\\[.*/, '');\n        }\n        else {\n            return null;\n        }\n    },\n\n    /**\n     * Returns an input's value as it would be POSTed.\n     * So unchecked checkboxes and radio buttons return null,\n     * and multi-selects whose name don't end in \"[]\" only return the last selection\n     *\n     * @param {object} $input\n     * @return {(string|string[])}\n     */\n    getInputPostVal: function($input) {\n        var type = $input.attr('type'),\n            val = $input.val();\n\n        // Is this an unchecked checkbox or radio button?\n        if ((type === 'checkbox' || type === 'radio')) {\n            if ($input.prop('checked')) {\n                return val;\n            }\n            else {\n                return null;\n            }\n        }\n\n        // Flatten any array values whose input name doesn't end in \"[]\"\n        //  - e.g. a multi-select\n        else if (Garnish.isArray(val) && $input.attr('name').substr(-2) !== '[]') {\n            if (val.length) {\n                return val[val.length - 1];\n            }\n            else {\n                return null;\n            }\n        }\n\n        // Just return the value\n        else {\n            return val;\n        }\n    },\n\n    /**\n     * Returns the inputs within a container\n     *\n     * @param {object} container The container element. Can be either an actual element or a jQuery collection.\n     * @return {object}\n     */\n    findInputs: function(container) {\n        return $(container).find('input,text,textarea,select,button');\n    },\n\n    /**\n     * Returns the post data within a container.\n     *\n     * @param {object} container\n     * @return {array}\n     */\n    getPostData: function(container) {\n        var postData = {},\n            arrayInputCounters = {},\n            $inputs = Garnish.findInputs(container);\n\n        var inputName;\n\n        for (var i = 0; i < $inputs.length; i++) {\n            var $input = $inputs.eq(i);\n\n            if ($input.prop('disabled')) {\n                continue;\n            }\n\n            inputName = $input.attr('name');\n            if (!inputName) {\n                continue;\n            }\n\n            var inputVal = Garnish.getInputPostVal($input);\n            if (inputVal === null) {\n                continue;\n            }\n\n            var isArrayInput = (inputName.substr(-2) === '[]');\n\n            if (isArrayInput) {\n                // Get the cropped input name\n                var croppedName = inputName.substring(0, inputName.length - 2);\n\n                // Prep the input counter\n                if (typeof arrayInputCounters[croppedName] === 'undefined') {\n                    arrayInputCounters[croppedName] = 0;\n                }\n            }\n\n            if (!Garnish.isArray(inputVal)) {\n                inputVal = [inputVal];\n            }\n\n            for (var j = 0; j < inputVal.length; j++) {\n                if (isArrayInput) {\n                    inputName = croppedName + '[' + arrayInputCounters[croppedName] + ']';\n                    arrayInputCounters[croppedName]++;\n                }\n\n                postData[inputName] = inputVal[j];\n            }\n        }\n\n        return postData;\n    },\n\n    copyInputValues: function(source, target) {\n        var $sourceInputs = Garnish.findInputs(source),\n            $targetInputs = Garnish.findInputs(target);\n\n        for (var i = 0; i < $sourceInputs.length; i++) {\n            if (typeof $targetInputs[i] === 'undefined') {\n                break;\n            }\n\n            $targetInputs.eq(i).val(\n                $sourceInputs.eq(i).val()\n            );\n        }\n    },\n\n    /**\n     * Returns whether the \"Ctrl\" key is pressed (or ⌘ if this is a Mac) for a given keyboard event\n     *\n     * @param ev The keyboard event\n     *\n     * @return {boolean} Whether the \"Ctrl\" key is pressed\n     */\n    isCtrlKeyPressed: function(ev) {\n        if (window.navigator.platform.match(/Mac/)) {\n            // metaKey maps to ⌘ on Macs\n            return ev.metaKey;\n        }\n        else {\n            // Both altKey and ctrlKey == true on some Windows keyboards when the right-hand ALT key is pressed\n            // so just be safe and make sure altKey == false\n            return (ev.ctrlKey && !ev.altKey);\n        }\n    },\n\n    _eventHandlers: [],\n\n    _normalizeEvents: function(events) {\n        if (typeof events === 'string') {\n            events = events.split(' ');\n        }\n\n        for (var i = 0; i < events.length; i++) {\n            if (typeof events[i] === 'string') {\n                events[i] = events[i].split('.');\n            }\n        }\n\n        return events;\n    },\n\n    on: function(target, events, data, handler) {\n        if (typeof data === 'function') {\n            handler = data;\n            data = {};\n        }\n\n        events = this._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n            this._eventHandlers.push({\n                target: target,\n                type: ev[0],\n                namespace: ev[1],\n                data: data,\n                handler: handler\n            });\n        }\n    },\n\n    off: function(target, events, handler) {\n        events = this._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n\n            for (var j = this._eventHandlers.length - 1; j >= 0; j--) {\n                var eventHandler = this._eventHandlers[j];\n\n                if (\n                    eventHandler.target === target &&\n                    eventHandler.type === ev[0] &&\n                    (!ev[1] || eventHandler.namespace === ev[1]) &&\n                    eventHandler.handler === handler\n                ) {\n                    this._eventHandlers.splice(j, 1);\n                }\n            }\n        }\n    }\n});\n\n\n/**\n * Garnish base class\n */\nGarnish.Base = Base.extend({\n\n    settings: null,\n\n    _eventHandlers: null,\n    _namespace: null,\n    _$listeners: null,\n    _disabled: false,\n\n    constructor: function() {\n        this._eventHandlers = [];\n        this._namespace = '.Garnish' + Math.floor(Math.random() * 1000000000);\n        this._listeners = [];\n        this.init.apply(this, arguments);\n    },\n\n    init: $.noop,\n\n    setSettings: function(settings, defaults) {\n        var baseSettings = (typeof this.settings === 'undefined' ? {} : this.settings);\n        this.settings = $.extend({}, baseSettings, defaults, settings);\n    },\n\n    on: function(events, data, handler) {\n        if (typeof data === 'function') {\n            handler = data;\n            data = {};\n        }\n\n        events = Garnish._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n            this._eventHandlers.push({\n                type: ev[0],\n                namespace: ev[1],\n                data: data,\n                handler: handler\n            });\n        }\n    },\n\n    off: function(events, handler) {\n        events = Garnish._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n\n            for (var j = this._eventHandlers.length - 1; j >= 0; j--) {\n                var eventHandler = this._eventHandlers[j];\n\n                if (\n                    eventHandler.type === ev[0] &&\n                    (!ev[1] || eventHandler.namespace === ev[1]) &&\n                    eventHandler.handler === handler\n                ) {\n                    this._eventHandlers.splice(j, 1);\n                }\n            }\n        }\n    },\n\n    trigger: function(type, data) {\n        var ev = {\n            type: type,\n            target: this\n        };\n\n        // instance level event handlers\n        var i, handler, _ev;\n        for (i = 0; i < this._eventHandlers.length; i++) {\n            handler = this._eventHandlers[i];\n\n            if (handler.type === type) {\n                _ev = $.extend({data: handler.data}, data, ev);\n                handler.handler(_ev);\n            }\n        }\n\n        // class level event handlers\n        for (i = 0; i < Garnish._eventHandlers.length; i++) {\n            handler = Garnish._eventHandlers[i];\n\n            if (this instanceof handler.target && handler.type === type) {\n                _ev = $.extend({data: handler.data}, data, ev);\n                handler.handler(_ev);\n            }\n        }\n    },\n\n    _splitEvents: function(events) {\n        if (typeof events === 'string') {\n            events = events.split(',');\n\n            for (var i = 0; i < events.length; i++) {\n                events[i] = $.trim(events[i]);\n            }\n        }\n\n        return events;\n    },\n\n    _formatEvents: function(events) {\n        events = this._splitEvents(events).slice(0);\n\n        for (var i = 0; i < events.length; i++) {\n            events[i] += this._namespace;\n        }\n\n        return events.join(' ');\n    },\n\n    addListener: function(elem, events, data, func) {\n        var $elem = $(elem);\n\n        // Ignore if there aren't any elements\n        if (!$elem.length) {\n            return;\n        }\n\n        events = this._splitEvents(events);\n\n        // Param mapping\n        if (typeof func === 'undefined' && typeof data !== 'object') {\n            // (elem, events, func)\n            func = data;\n            data = {};\n        }\n\n        if (typeof func === 'function') {\n            func = $.proxy(func, this);\n        }\n        else {\n            func = $.proxy(this, func);\n        }\n\n        $elem.on(this._formatEvents(events), data, $.proxy(function() {\n            if (!this._disabled) {\n                return func.apply(this, arguments);\n            }\n        }, this));\n\n        // Remember that we're listening to this element\n        if ($.inArray(elem, this._listeners) === -1) {\n            this._listeners.push(elem);\n        }\n    },\n\n    removeListener: function(elem, events) {\n        $(elem).off(this._formatEvents(events));\n    },\n\n    removeAllListeners: function(elem) {\n        $(elem).off(this._namespace);\n    },\n\n    disable: function() {\n        this._disabled = true;\n    },\n\n    enable: function() {\n        this._disabled = false;\n    },\n\n    destroy: function() {\n        this.trigger('destroy');\n        this.removeAllListeners(this._listeners);\n    }\n});\n\n// Custom events\n// -----------------------------------------------------------------------------\n\nvar erd;\n\nfunction getErd() {\n    if (typeof erd === 'undefined') {\n        erd = elementResizeDetectorMaker({\n            callOnAdd: false\n        });\n    }\n\n    return erd;\n}\n\nfunction triggerResizeEvent(elem) {\n    $(elem).trigger('resize');\n}\n\n// Work them into jQuery's event system\n$.extend(jQuery.event.special, {\n    activate: {\n        setup: function(data, namespaces, eventHandle) {\n            var activateNamespace = this._namespace + '-activate';\n            var $elem = $(this);\n\n            $elem.on({\n                'mousedown.garnish-activate': function(e) {\n                    // Prevent buttons from getting focus on click\n                    e.preventDefault();\n                },\n                'click.garnish-activate': function(e) {\n                    e.preventDefault();\n\n                    if (!$elem.hasClass('disabled')) {\n                        $elem.trigger('activate');\n                    }\n                },\n                'keydown.garnish-activate': function(e) {\n                    // Ignore if the event was bubbled up, or if it wasn't the space key\n                    if (this !== $elem[0] || e.keyCode !== Garnish.SPACE_KEY) {\n                        return;\n                    }\n\n                    e.preventDefault();\n\n                    if (!$elem.hasClass('disabled')) {\n                        $elem.addClass('active');\n\n                        Garnish.$doc.on('keyup.garnish-activate', function(e) {\n                            $elem.removeClass('active');\n\n                            if (e.keyCode === Garnish.SPACE_KEY) {\n                                e.preventDefault();\n                                $elem.trigger('activate');\n                            }\n\n                            Garnish.$doc.off('keyup.garnish-activate');\n                        });\n                    }\n                }\n            });\n\n            if (!$elem.hasClass('disabled')) {\n                $elem.attr('tabindex', '0');\n            } else {\n                $elem.removeAttr('tabindex');\n            }\n        },\n        teardown: function() {\n            $(this).off('.garnish-activate');\n        }\n    },\n\n    textchange: {\n        setup: function(data, namespaces, eventHandle) {\n            var $elem = $(this);\n            $elem.data('garnish-textchange-value', $elem.val());\n            $elem.on('keypress.garnish-textchange keyup.garnish-textchange change.garnish-textchange blur.garnish-textchange', function(e) {\n                var val = $elem.val();\n                if (val !== $elem.data('garnish-textchange-value')) {\n                    $elem.data('garnish-textchange-value', val);\n                    $elem.trigger('textchange');\n                }\n            });\n        },\n        teardown: function() {\n            $(this).off('.garnish-textchange');\n        },\n        handle: function(ev, data) {\n            var el = this;\n            var args = arguments;\n            var delay = data && typeof data.delay !== 'undefined' ? data.delay : (ev.data && ev.data.delay !== undefined ? ev.data.delay : null);\n            var handleObj = ev.handleObj;\n            var targetData = $.data(ev.target);\n\n            // Was this event configured with a delay?\n            if (delay) {\n                if (targetData.delayTimeout) {\n                    clearTimeout(targetData.delayTimeout);\n                }\n\n                targetData.delayTimeout = setTimeout(function() {\n                    handleObj.handler.apply(el, args);\n                }, delay);\n            } else {\n                return handleObj.handler.apply(el, args);\n            }\n        }\n    },\n\n    resize: {\n        setup: function(data, namespaces, eventHandle) {\n            // window is the only element that natively supports a resize event\n            if (this === window) {\n                return false;\n            }\n\n            $('> :last-child', this).addClass('last');\n            getErd().listenTo(this, triggerResizeEvent)\n        },\n        teardown: function() {\n            if (this === window) {\n                return false;\n            }\n\n            getErd().removeListener(this, triggerResizeEvent);\n        }\n    }\n});\n\n// Give them their own element collection chaining methods\njQuery.each(['activate', 'textchange', 'resize'], function(i, name) {\n    jQuery.fn[name] = function(data, fn) {\n        return arguments.length > 0 ?\n            this.on(name, null, data, fn) :\n            this.trigger(name);\n    };\n});\n","/** global: Garnish */\n/**\n * Base drag class\n *\n * Does all the grunt work for manipulating elements via click-and-drag,\n * while leaving the actual element manipulation up to a subclass.\n */\nGarnish.BaseDrag = Garnish.Base.extend(\n    {\n        $items: null,\n\n        dragging: false,\n\n        mousedownX: null,\n        mousedownY: null,\n        realMouseX: null,\n        realMouseY: null,\n        mouseX: null,\n        mouseY: null,\n        mouseDistX: null,\n        mouseDistY: null,\n        mouseOffsetX: null,\n        mouseOffsetY: null,\n\n        $targetItem: null,\n\n        scrollProperty: null,\n        scrollAxis: null,\n        scrollDist: null,\n        scrollProxy: null,\n        scrollFrame: null,\n\n        _: null,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            this.settings = $.extend({}, Garnish.BaseDrag.defaults, settings);\n\n            this.$items = $();\n            this._ = {};\n\n            if (items) {\n                this.addItems(items);\n            }\n        },\n\n        /**\n         * Returns whether dragging is allowed right now.\n         */\n        allowDragging: function() {\n            return true;\n        },\n\n        /**\n         * Start Dragging\n         */\n        startDragging: function() {\n            this.dragging = true;\n            this.onDragStart();\n        },\n\n        /**\n         * Drag\n         */\n        drag: function(didMouseMove) {\n            if (didMouseMove) {\n                // Is the mouse up against one of the window edges?\n                this.drag._scrollProperty = null;\n\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    // Scrolling up?\n                    this.drag._winScrollTop = Garnish.$win.scrollTop();\n                    this.drag._minMouseScrollY = this.drag._winScrollTop + Garnish.BaseDrag.windowScrollTargetSize;\n\n                    if (this.mouseY < this.drag._minMouseScrollY) {\n                        this.drag._scrollProperty = 'scrollTop';\n                        this.drag._scrollAxis = 'Y';\n                        this.drag._scrollDist = Math.round((this.mouseY - this.drag._minMouseScrollY) / 2);\n                    }\n                    else {\n                        // Scrolling down?\n                        this.drag._maxMouseScrollY = this.drag._winScrollTop + Garnish.$win.height() - Garnish.BaseDrag.windowScrollTargetSize;\n\n                        if (this.mouseY > this.drag._maxMouseScrollY) {\n                            this.drag._scrollProperty = 'scrollTop';\n                            this.drag._scrollAxis = 'Y';\n                            this.drag._scrollDist = Math.round((this.mouseY - this.drag._maxMouseScrollY) / 2);\n                        }\n                    }\n                }\n\n                if (!this.drag._scrollProperty && this.settings.axis !== Garnish.Y_AXIS) {\n                    // Scrolling left?\n                    this.drag._winScrollLeft = Garnish.$win.scrollLeft();\n                    this.drag._minMouseScrollX = this.drag._winScrollLeft + Garnish.BaseDrag.windowScrollTargetSize;\n\n                    if (this.mouseX < this.drag._minMouseScrollX) {\n                        this.drag._scrollProperty = 'scrollLeft';\n                        this.drag._scrollAxis = 'X';\n                        this.drag._scrollDist = Math.round((this.mouseX - this.drag._minMouseScrollX) / 2);\n                    }\n                    else {\n                        // Scrolling right?\n                        this.drag._maxMouseScrollX = this.drag._winScrollLeft + Garnish.$win.width() - Garnish.BaseDrag.windowScrollTargetSize;\n\n                        if (this.mouseX > this.drag._maxMouseScrollX) {\n                            this.drag._scrollProperty = 'scrollLeft';\n                            this.drag._scrollAxis = 'X';\n                            this.drag._scrollDist = Math.round((this.mouseX - this.drag._maxMouseScrollX) / 2);\n                        }\n                    }\n                }\n\n                if (this.drag._scrollProperty) {\n                    // Are we starting to scroll now?\n                    if (!this.scrollProperty) {\n                        if (!this.scrollProxy) {\n                            this.scrollProxy = $.proxy(this, '_scrollWindow');\n                        }\n\n                        if (this.scrollFrame) {\n                            Garnish.cancelAnimationFrame(this.scrollFrame);\n                            this.scrollFrame = null;\n                        }\n\n                        this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);\n                    }\n\n                    this.scrollProperty = this.drag._scrollProperty;\n                    this.scrollAxis = this.drag._scrollAxis;\n                    this.scrollDist = this.drag._scrollDist;\n                }\n                else {\n                    this._cancelWindowScroll();\n                }\n            }\n\n            this.onDrag();\n        },\n\n        /**\n         * Stop Dragging\n         */\n        stopDragging: function() {\n            this.dragging = false;\n            this.onDragStop();\n\n            // Clear the scroll animation\n            this._cancelWindowScroll();\n        },\n\n        /**\n         * Add Items\n         *\n         * @param {object} items Elements that should be draggable.\n         */\n        addItems: function(items) {\n            items = $.makeArray(items);\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure this element doesn't belong to another dragger\n                if ($.data(item, 'drag')) {\n                    Garnish.log('Element was added to more than one dragger');\n                    $.data(item, 'drag').removeItems(item);\n                }\n\n                // Add the item\n                $.data(item, 'drag', this);\n\n                // Add the listener\n                this.addListener(item, 'mousedown', '_handleMouseDown');\n            }\n\n            this.$items = this.$items.add(items);\n        },\n\n        /**\n         * Remove Items\n         *\n         * @param {object} items Elements that should no longer be draggable.\n         */\n        removeItems: function(items) {\n            items = $.makeArray(items);\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure we actually know about this item\n                var index = $.inArray(item, this.$items);\n                if (index !== -1) {\n                    this._deinitItem(item);\n                    this.$items.splice(index, 1);\n                }\n            }\n        },\n\n        /**\n         * Remove All Items\n         */\n        removeAllItems: function() {\n            for (var i = 0; i < this.$items.length; i++) {\n                this._deinitItem(this.$items[i]);\n            }\n\n            this.$items = $();\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.removeAllItems();\n            this.base();\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('dragStart');\n                this.settings.onDragStart();\n            }, this));\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('drag');\n                this.settings.onDrag();\n            }, this));\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('dragStop');\n                this.settings.onDragStop();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        /**\n         * Handle Mouse Down\n         */\n        _handleMouseDown: function(ev) {\n            // Ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Ignore if we already have a target\n            if (this.$targetItem) {\n                return;\n            }\n\n            // Ignore if they didn't actually click on the handle\n            var $target = $(ev.target),\n                $handle = this._getItemHandle(ev.currentTarget);\n\n            if (!$target.is($handle) && !$target.closest($handle).length) {\n                return;\n            }\n\n            // Make sure the target isn't a button (unless the button is the handle)\n            if (ev.currentTarget !== ev.target && this.settings.ignoreHandleSelector) {\n                if (\n                    $target.is(this.settings.ignoreHandleSelector) ||\n                    $target.closest(this.settings.ignoreHandleSelector).length\n                ) {\n                    return;\n                }\n            }\n\n            ev.preventDefault();\n\n            // Make sure that dragging is allowed right now\n            if (!this.allowDragging()) {\n                return;\n            }\n\n            // Capture the target\n            this.$targetItem = $(ev.currentTarget);\n\n            // Capture the current mouse position\n            this.mousedownX = this.mouseX = ev.pageX;\n            this.mousedownY = this.mouseY = ev.pageY;\n\n            // Capture the difference between the mouse position and the target item's offset\n            var offset = this.$targetItem.offset();\n            this.mouseOffsetX = ev.pageX - offset.left;\n            this.mouseOffsetY = ev.pageY - offset.top;\n\n            // Listen for mousemove, mouseup\n            this.addListener(Garnish.$doc, 'mousemove', '_handleMouseMove');\n            this.addListener(Garnish.$doc, 'mouseup', '_handleMouseUp');\n        },\n\n        _getItemHandle: function(item) {\n            if (this.settings.handle) {\n                if (typeof this.settings.handle === 'object') {\n                    return $(this.settings.handle);\n                }\n\n                if (typeof this.settings.handle === 'string') {\n                    return $(this.settings.handle, item);\n                }\n\n                if (typeof this.settings.handle === 'function') {\n                    return $(this.settings.handle(item));\n                }\n            }\n\n            return $(item);\n        },\n\n        /**\n         * Handle Mouse Move\n         */\n        _handleMouseMove: function(ev) {\n            ev.preventDefault();\n\n            this.realMouseX = ev.pageX;\n            this.realMouseY = ev.pageY;\n\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this.mouseX = ev.pageX;\n            }\n\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this.mouseY = ev.pageY;\n            }\n\n            this.mouseDistX = this.mouseX - this.mousedownX;\n            this.mouseDistY = this.mouseY - this.mousedownY;\n\n            if (!this.dragging) {\n                // Has the mouse moved far enough to initiate dragging yet?\n                this._handleMouseMove._mouseDist = Garnish.getDist(this.mousedownX, this.mousedownY, this.realMouseX, this.realMouseY);\n\n                if (this._handleMouseMove._mouseDist >= Garnish.BaseDrag.minMouseDist) {\n                    this.startDragging();\n                }\n            }\n\n            if (this.dragging) {\n                this.drag(true);\n            }\n        },\n\n        /**\n         * Handle Moues Up\n         */\n        _handleMouseUp: function(ev) {\n            // Unbind the document events\n            this.removeAllListeners(Garnish.$doc);\n\n            if (this.dragging) {\n                this.stopDragging();\n            }\n\n            this.$targetItem = null;\n        },\n\n        /**\n         * Scroll Window\n         */\n        _scrollWindow: function() {\n            this._.scrollPos = Garnish.$scrollContainer[this.scrollProperty]();\n            Garnish.$scrollContainer[this.scrollProperty](this._.scrollPos + this.scrollDist);\n\n            this['mouse' + this.scrollAxis] -= this._.scrollPos - Garnish.$scrollContainer[this.scrollProperty]();\n            this['realMouse' + this.scrollAxis] = this['mouse' + this.scrollAxis];\n\n            this.drag();\n\n            this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);\n        },\n\n        /**\n         * Cancel Window Scroll\n         */\n        _cancelWindowScroll: function() {\n            if (this.scrollFrame) {\n                Garnish.cancelAnimationFrame(this.scrollFrame);\n                this.scrollFrame = null;\n            }\n\n            this.scrollProperty = null;\n            this.scrollAxis = null;\n            this.scrollDist = null;\n        },\n\n        /**\n         * Deinitialize an item.\n         */\n        _deinitItem: function(item) {\n            this.removeAllListeners(item);\n            $.removeData(item, 'drag');\n        }\n    },\n    {\n        minMouseDist: 1,\n        windowScrollTargetSize: 25,\n\n        defaults: {\n            handle: null,\n            axis: null,\n            ignoreHandleSelector: 'input, textarea, button, select, .btn',\n\n            onDragStart: $.noop,\n            onDrag: $.noop,\n            onDragStop: $.noop\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Checkbox select class\n */\nGarnish.CheckboxSelect = Garnish.Base.extend(\n    {\n        $container: null,\n        $all: null,\n        $options: null,\n\n        init: function(container) {\n            this.$container = $(container);\n\n            // Is this already a checkbox select?\n            if (this.$container.data('checkboxSelect')) {\n                Garnish.log('Double-instantiating a checkbox select on an element');\n                this.$container.data('checkbox-select').destroy();\n            }\n\n            this.$container.data('checkboxSelect', this);\n\n            var $checkboxes = this.$container.find('input');\n            this.$all = $checkboxes.filter('.all:first');\n            this.$options = $checkboxes.not(this.$all);\n\n            this.addListener(this.$all, 'change', 'onAllChange');\n        },\n\n        onAllChange: function() {\n            var isAllChecked = this.$all.prop('checked');\n\n            this.$options.prop({\n                checked: isAllChecked,\n                disabled: isAllChecked\n            });\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$container.removeData('checkboxSelect');\n            this.base();\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Context Menu\n */\nGarnish.ContextMenu = Garnish.Base.extend(\n    {\n        $target: null,\n        options: null,\n        $menu: null,\n        showingMenu: false,\n\n        /**\n         * Constructor\n         */\n        init: function(target, options, settings) {\n            this.$target = $(target);\n\n            // Is this already a context menu target?\n            if (this.$target.data('contextmenu')) {\n                Garnish.log('Double-instantiating a context menu on an element');\n                this.$target.data('contextmenu').destroy();\n            }\n\n            this.$target.data('contextmenu', this);\n\n            this.options = options;\n            this.setSettings(settings, Garnish.ContextMenu.defaults);\n\n            Garnish.ContextMenu.counter++;\n\n            this.enable();\n        },\n\n        /**\n         * Build Menu\n         */\n        buildMenu: function() {\n            this.$menu = $('<div class=\"' + this.settings.menuClass + '\" style=\"display: none\" />');\n\n            var $ul = $('<ul/>').appendTo(this.$menu);\n\n            for (var i in this.options) {\n                if (!this.options.hasOwnProperty(i)) {\n                    continue;\n                }\n\n                var option = this.options[i];\n\n                if (option === '-') {\n                    // Create a new <ul>\n                    $('<hr/>').appendTo(this.$menu);\n                    $ul = $('<ul/>').appendTo(this.$menu);\n                }\n                else {\n                    var $li = $('<li></li>').appendTo($ul),\n                        $a = $('<a>' + option.label + '</a>').appendTo($li);\n\n                    if (typeof option.onClick === 'function') {\n                        // maintain the current $a and options.onClick variables\n                        (function($a, onClick) {\n                            setTimeout($.proxy(function() {\n                                $a.mousedown($.proxy(function(ev) {\n                                    this.hideMenu();\n                                    // call the onClick callback, with the scope set to the item,\n                                    // and pass it the event with currentTarget set to the item as well\n                                    onClick.call(this.currentTarget, $.extend(ev, {currentTarget: this.currentTarget}));\n                                }, this));\n                            }, this), 1);\n                        }).call(this, $a, option.onClick);\n                    }\n                }\n            }\n        },\n\n        /**\n         * Show Menu\n         */\n        showMenu: function(ev) {\n            // Ignore left mouse clicks\n            if (ev.type === 'mousedown' && ev.which !== Garnish.SECONDARY_CLICK) {\n                return;\n            }\n\n            if (ev.type === 'contextmenu') {\n                // Prevent the real context menu from showing\n                ev.preventDefault();\n            }\n\n            // Ignore if already showing\n            if (this.showing && ev.currentTarget === this.currentTarget) {\n                return;\n            }\n\n            this.currentTarget = ev.currentTarget;\n\n            if (!this.$menu) {\n                this.buildMenu();\n            }\n\n            this.$menu.appendTo(document.body);\n            this.$menu.show();\n            this.$menu.css({left: ev.pageX + 1, top: ev.pageY - 4});\n\n            this.showing = true;\n\n            setTimeout($.proxy(function() {\n                this.addListener(Garnish.$doc, 'mousedown', 'hideMenu');\n            }, this), 0);\n        },\n\n        /**\n         * Hide Menu\n         */\n        hideMenu: function() {\n            this.removeListener(Garnish.$doc, 'mousedown');\n            this.$menu.hide();\n            this.showing = false;\n        },\n\n        /**\n         * Enable\n         */\n        enable: function() {\n            this.addListener(this.$target, 'contextmenu,mousedown', 'showMenu');\n        },\n\n        /**\n         * Disable\n         */\n        disable: function() {\n            this.removeListener(this.$target, 'contextmenu,mousedown');\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$target.removeData('contextmenu');\n            this.base();\n        }\n    },\n    {\n        defaults: {\n            menuClass: 'menu'\n        },\n        counter: 0\n    }\n);\n","/** global: Garnish */\n/**\n * Drag class\n *\n * Builds on the BaseDrag class by \"picking up\" the selceted element(s),\n * without worrying about what to do when an element is being dragged.\n */\nGarnish.Drag = Garnish.BaseDrag.extend(\n    {\n        targetItemWidth: null,\n        targetItemHeight: null,\n        targetItemPositionInDraggee: null,\n\n        $draggee: null,\n\n        otherItems: null,\n        totalOtherItems: null,\n\n        helpers: null,\n        helperTargets: null,\n        helperPositions: null,\n        helperLagIncrement: null,\n        updateHelperPosProxy: null,\n        updateHelperPosFrame: null,\n\n        lastMouseX: null,\n        lastMouseY: null,\n\n        _returningHelpersToDraggees: false,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            settings = $.extend({}, Garnish.Drag.defaults, settings);\n            this.base(items, settings);\n        },\n\n        /**\n         * Returns whether dragging is allowed right now.\n         */\n        allowDragging: function() {\n            // Don't allow dragging if we're in the middle of animating the helpers back to the draggees\n            return !this._returningHelpersToDraggees;\n        },\n\n        /**\n         * Start Dragging\n         */\n        startDragging: function() {\n            // Reset some things\n            this.helpers = [];\n            this.helperTargets = [];\n            this.helperPositions = [];\n            this.lastMouseX = this.lastMouseY = null;\n\n            // Capture the target item's width/height\n            this.targetItemWidth = this.$targetItem.outerWidth();\n            this.targetItemHeight = this.$targetItem.outerHeight();\n\n            // Save the draggee's display style (block/table-row) so we can re-apply it later\n            this.draggeeDisplay = this.$targetItem.css('display');\n\n            // Set the $draggee\n            this.setDraggee(this.findDraggee());\n\n            // Create an array of all the other items\n            this.otherItems = [];\n\n            for (var i = 0; i < this.$items.length; i++) {\n                var item = this.$items[i];\n\n                if ($.inArray(item, this.$draggee) === -1) {\n                    this.otherItems.push(item);\n                }\n            }\n\n            this.totalOtherItems = this.otherItems.length;\n\n            // Keep the helpers following the cursor, with a little lag to smooth it out\n            if (!this.updateHelperPosProxy) {\n                this.updateHelperPosProxy = $.proxy(this, '_updateHelperPos');\n            }\n\n            this.helperLagIncrement = this.helpers.length === 1 ? 0 : this.settings.helperLagIncrementDividend / (this.helpers.length - 1);\n            this.updateHelperPosFrame = Garnish.requestAnimationFrame(this.updateHelperPosProxy);\n\n            this.base();\n        },\n\n        /**\n         * Sets the draggee.\n         */\n        setDraggee: function($draggee) {\n            // Record the target item's position in the draggee\n            this.targetItemPositionInDraggee = $.inArray(this.$targetItem[0], $draggee.add(this.$targetItem[0]));\n\n            // Keep the target item at the front of the list\n            this.$draggee = $([this.$targetItem[0]].concat($draggee.not(this.$targetItem).toArray()));\n\n            // Create the helper(s)\n            if (this.settings.singleHelper) {\n                this._createHelper(0);\n            }\n            else {\n                for (var i = 0; i < this.$draggee.length; i++) {\n                    this._createHelper(i);\n                }\n            }\n\n            if (this.settings.removeDraggee) {\n                this.$draggee.hide();\n            }\n            else if (this.settings.collapseDraggees) {\n                this.$targetItem.css('visibility', 'hidden');\n                this.$draggee.not(this.$targetItem).hide();\n            }\n            else {\n                this.$draggee.css('visibility', 'hidden');\n            }\n        },\n\n        /**\n         * Appends additional items to the draggee.\n         */\n        appendDraggee: function($newDraggee) {\n            if (!$newDraggee.length) {\n                return;\n            }\n\n            if (!this.settings.collapseDraggees) {\n                var oldLength = this.$draggee.length;\n            }\n\n            this.$draggee = $(this.$draggee.toArray().concat($newDraggee.toArray()));\n\n            // Create new helpers?\n            if (!this.settings.collapseDraggees) {\n                var newLength = this.$draggee.length;\n\n                for (var i = oldLength; i < newLength; i++) {\n                    this._createHelper(i);\n                }\n            }\n\n            if (this.settings.removeDraggee || this.settings.collapseDraggees) {\n                $newDraggee.hide();\n            }\n            else {\n                $newDraggee.css('visibility', 'hidden');\n            }\n        },\n\n        /**\n         * Drag\n         */\n        drag: function(didMouseMove) {\n            // Update the draggee's virtual midpoint\n            this.draggeeVirtualMidpointX = this.mouseX - this.mouseOffsetX + (this.targetItemWidth / 2);\n            this.draggeeVirtualMidpointY = this.mouseY - this.mouseOffsetY + (this.targetItemHeight / 2);\n\n            this.base(didMouseMove);\n        },\n\n        /**\n         * Stop Dragging\n         */\n        stopDragging: function() {\n            // Clear the helper animation\n            Garnish.cancelAnimationFrame(this.updateHelperPosFrame);\n\n            this.base();\n        },\n\n        /**\n         * Identifies the item(s) that are being dragged.\n         */\n        findDraggee: function() {\n            switch (typeof this.settings.filter) {\n                case 'function': {\n                    return this.settings.filter();\n                }\n\n                case 'string': {\n                    return this.$items.filter(this.settings.filter);\n                }\n\n                default: {\n                    return this.$targetItem;\n                }\n            }\n        },\n\n        /**\n         * Returns the helper’s target X position\n         */\n        getHelperTargetX: function() {\n            return this.mouseX - this.mouseOffsetX;\n        },\n\n        /**\n         * Returns the helper’s target Y position\n         */\n        getHelperTargetY: function() {\n            return this.mouseY - this.mouseOffsetY;\n        },\n\n        /**\n         * Return Helpers to Draggees\n         */\n        returnHelpersToDraggees: function() {\n            this._returningHelpersToDraggees = true;\n\n            for (var i = 0; i < this.helpers.length; i++) {\n                var $draggee = this.$draggee.eq(i),\n                    $helper = this.helpers[i];\n\n                $draggee.css({\n                    display: this.draggeeDisplay,\n                    visibility: 'hidden'\n                });\n\n                var draggeeOffset = $draggee.offset();\n                var callback;\n\n                if (i === 0) {\n                    callback = $.proxy(this, '_showDraggee');\n                }\n                else {\n                    callback = null;\n                }\n\n                $helper.velocity({left: draggeeOffset.left, top: draggeeOffset.top}, Garnish.FX_DURATION, callback);\n            }\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        onReturnHelpersToDraggees: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('returnHelpersToDraggees');\n                this.settings.onReturnHelpersToDraggees();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        /**\n         * Creates a helper.\n         */\n        _createHelper: function(i) {\n            var $draggee = this.$draggee.eq(i),\n                $draggeeHelper = $draggee.clone().addClass('draghelper');\n\n            if (this.settings.copyDraggeeInputValuesToHelper) {\n                Garnish.copyInputValues($draggee, $draggeeHelper);\n            }\n\n            // Remove any name= attributes so radio buttons don't lose their values\n            $draggeeHelper.find('[name]').attr('name', '');\n\n            $draggeeHelper.css({\n                width: $draggee.width() + 1, // Prevent the brower from wrapping text if the width was actually a fraction of a pixel larger\n                height: $draggee.height(),\n                margin: 0,\n                'pointer-events': 'none'\n            });\n\n            if (this.settings.helper) {\n                if (typeof this.settings.helper === 'function') {\n                    $draggeeHelper = this.settings.helper($draggeeHelper);\n                }\n                else {\n                    $draggeeHelper = $(this.settings.helper).append($draggeeHelper);\n                }\n            }\n\n            $draggeeHelper.appendTo(Garnish.$bod);\n\n            var helperPos = this._getHelperTarget(i);\n\n            $draggeeHelper.css({\n                position: 'absolute',\n                top: helperPos.top,\n                left: helperPos.left,\n                zIndex: this.settings.helperBaseZindex + this.$draggee.length - i,\n                opacity: this.settings.helperOpacity\n            });\n\n            this.helperPositions[i] = {\n                top: helperPos.top,\n                left: helperPos.left\n            };\n\n            this.helpers.push($draggeeHelper);\n        },\n\n        /**\n         * Update Helper Position\n         */\n        _updateHelperPos: function() {\n            // Has the mouse moved?\n            if (this.mouseX !== this.lastMouseX || this.mouseY !== this.lastMouseY) {\n                // Get the new target helper positions\n                for (this._updateHelperPos._i = 0; this._updateHelperPos._i < this.helpers.length; this._updateHelperPos._i++) {\n                    this.helperTargets[this._updateHelperPos._i] = this._getHelperTarget(this._updateHelperPos._i);\n                }\n\n                this.lastMouseX = this.mouseX;\n                this.lastMouseY = this.mouseY;\n            }\n\n            // Gravitate helpers toward their target positions\n            for (this._updateHelperPos._j = 0; this._updateHelperPos._j < this.helpers.length; this._updateHelperPos._j++) {\n                this._updateHelperPos._lag = this.settings.helperLagBase + (this.helperLagIncrement * this._updateHelperPos._j);\n\n                this.helperPositions[this._updateHelperPos._j] = {\n                    left: this.helperPositions[this._updateHelperPos._j].left + ((this.helperTargets[this._updateHelperPos._j].left - this.helperPositions[this._updateHelperPos._j].left) / this._updateHelperPos._lag),\n                    top: this.helperPositions[this._updateHelperPos._j].top + ((this.helperTargets[this._updateHelperPos._j].top - this.helperPositions[this._updateHelperPos._j].top) / this._updateHelperPos._lag)\n                };\n\n                this.helpers[this._updateHelperPos._j].css(this.helperPositions[this._updateHelperPos._j]);\n            }\n\n            // Let's do this again on the next frame!\n            this.updateHelperPosFrame = Garnish.requestAnimationFrame(this.updateHelperPosProxy);\n        },\n\n        /**\n         * Get the helper position for a draggee helper\n         */\n        _getHelperTarget: function(i) {\n            return {\n                left: this.getHelperTargetX() + (this.settings.helperSpacingX * i),\n                top: this.getHelperTargetY() + (this.settings.helperSpacingY * i)\n            };\n        },\n\n        _showDraggee: function() {\n            // Remove the helpers\n            for (var i = 0; i < this.helpers.length; i++) {\n                this.helpers[i].remove();\n            }\n\n            this.helpers = null;\n\n            this.$draggee.show().css('visibility', 'inherit');\n\n            this.onReturnHelpersToDraggees();\n\n            this._returningHelpersToDraggees = false;\n        }\n    },\n    {\n        defaults: {\n            filter: null,\n            singleHelper: false,\n            collapseDraggees: false,\n            removeDraggee: false,\n            copyDraggeeInputValuesToHelper: false,\n            helperOpacity: 1,\n            helper: null,\n            helperBaseZindex: 1000,\n            helperLagBase: 1,\n            helperLagIncrementDividend: 1.5,\n            helperSpacingX: 5,\n            helperSpacingY: 5,\n            onReturnHelpersToDraggees: $.noop\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Drag-and-drop class\n *\n * Builds on the Drag class by allowing you to set up \"drop targets\"\n * which the dragged elemements can be dropped onto.\n */\nGarnish.DragDrop = Garnish.Drag.extend({\n\n        $dropTargets: null,\n        $activeDropTarget: null,\n\n        /**\n         * Constructor\n         */\n        init: function(settings) {\n            settings = $.extend({}, Garnish.DragDrop.defaults, settings);\n            this.base(settings);\n        },\n\n        updateDropTargets: function() {\n            if (this.settings.dropTargets) {\n                if (typeof this.settings.dropTargets === 'function') {\n                    this.$dropTargets = $(this.settings.dropTargets());\n                }\n                else {\n                    this.$dropTargets = $(this.settings.dropTargets);\n                }\n\n                // Discard if it's an empty array\n                if (!this.$dropTargets.length) {\n                    this.$dropTargets = null;\n                }\n            }\n        },\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            this.updateDropTargets();\n            this.$activeDropTarget = null;\n            this.base();\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            if (this.$dropTargets) {\n                this.onDrag._activeDropTarget = null;\n\n                // is the cursor over any of the drop target?\n                for (this.onDrag._i = 0; this.onDrag._i < this.$dropTargets.length; this.onDrag._i++) {\n                    this.onDrag._elem = this.$dropTargets[this.onDrag._i];\n\n                    if (Garnish.hitTest(this.mouseX, this.mouseY, this.onDrag._elem)) {\n                        this.onDrag._activeDropTarget = this.onDrag._elem;\n                        break;\n                    }\n                }\n\n                // has the drop target changed?\n                if (\n                    (this.$activeDropTarget && this.onDrag._activeDropTarget !== this.$activeDropTarget[0]) ||\n                    (!this.$activeDropTarget && this.onDrag._activeDropTarget !== null)\n                ) {\n                    // was there a previous one?\n                    if (this.$activeDropTarget) {\n                        this.$activeDropTarget.removeClass(this.settings.activeDropTargetClass);\n                    }\n\n                    // remember the new one\n                    if (this.onDrag._activeDropTarget) {\n                        this.$activeDropTarget = $(this.onDrag._activeDropTarget).addClass(this.settings.activeDropTargetClass);\n                    }\n                    else {\n                        this.$activeDropTarget = null;\n                    }\n\n                    this.settings.onDropTargetChange(this.$activeDropTarget);\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            if (this.$dropTargets && this.$activeDropTarget) {\n                this.$activeDropTarget.removeClass(this.settings.activeDropTargetClass);\n            }\n\n            this.base();\n        },\n\n        /**\n         * Fade Out Helpers\n         */\n        fadeOutHelpers: function() {\n            for (var i = 0; i < this.helpers.length; i++) {\n                (function($draggeeHelper) {\n                    $draggeeHelper.velocity('fadeOut', {\n                        duration: Garnish.FX_DURATION,\n                        complete: function() {\n                            $draggeeHelper.remove();\n                        }\n                    });\n                })(this.helpers[i]);\n            }\n        }\n    },\n    {\n        defaults: {\n            dropTargets: null,\n            onDropTargetChange: $.noop,\n            activeDropTargetClass: 'active'\n        }\n    });\n","/** global: Garnish */\n/**\n * Drag-to-move clas\n *\n * Builds on the BaseDrag class by simply moving the dragged element(s) along with the mouse.\n */\nGarnish.DragMove = Garnish.BaseDrag.extend(\n    {\n        onDrag: function(items, settings) {\n            this.$targetItem.css({\n                left: this.mouseX - this.mouseOffsetX,\n                top: this.mouseY - this.mouseOffsetY\n            });\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Drag-to-sort class\n *\n * Builds on the Drag class by allowing you to sort the elements amongst themselves.\n */\nGarnish.DragSort = Garnish.Drag.extend(\n    {\n        $heightedContainer: null,\n        $insertion: null,\n        insertionVisible: false,\n        oldDraggeeIndexes: null,\n        newDraggeeIndexes: null,\n        closestItem: null,\n\n        _midpointVersion: 0,\n        _$prevItem: null,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            settings = $.extend({}, Garnish.DragSort.defaults, settings);\n            this.base(items, settings);\n        },\n\n        /**\n         * Creates the insertion element.\n         */\n        createInsertion: function() {\n            if (this.settings.insertion) {\n                if (typeof this.settings.insertion === 'function') {\n                    return $(this.settings.insertion(this.$draggee));\n                }\n                else {\n                    return $(this.settings.insertion);\n                }\n            }\n        },\n\n        /**\n         * Returns the helper’s target X position\n         */\n        getHelperTargetX: function() {\n            if (this.settings.magnetStrength !== 1) {\n                this.getHelperTargetX._draggeeOffsetX = this.$draggee.offset().left;\n                return this.getHelperTargetX._draggeeOffsetX + ((this.mouseX - this.mouseOffsetX - this.getHelperTargetX._draggeeOffsetX) / this.settings.magnetStrength);\n            }\n            else {\n                return this.base();\n            }\n        },\n\n        /**\n         * Returns the helper’s target Y position\n         */\n        getHelperTargetY: function() {\n            if (this.settings.magnetStrength !== 1) {\n                this.getHelperTargetY._draggeeOffsetY = this.$draggee.offset().top;\n                return this.getHelperTargetY._draggeeOffsetY + ((this.mouseY - this.mouseOffsetY - this.getHelperTargetY._draggeeOffsetY) / this.settings.magnetStrength);\n            }\n            else {\n                return this.base();\n            }\n        },\n\n        /**\n         * Returns whether the draggee can be inserted before a given item.\n         */\n        canInsertBefore: function($item) {\n            return true;\n        },\n\n        /**\n         * Returns whether the draggee can be inserted after a given item.\n         */\n        canInsertAfter: function($item) {\n            return true;\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            this.oldDraggeeIndexes = this._getDraggeeIndexes();\n\n            // Are we supposed to be moving the target item to the front, and is it not already there?\n            if (\n                this.settings.moveTargetItemToFront &&\n                this.$draggee.length > 1 &&\n                this._getItemIndex(this.$draggee[0]) > this._getItemIndex(this.$draggee[1])\n            ) {\n                // Reposition the target item before the other draggee items in the DOM\n                this.$draggee.first().insertBefore(this.$draggee[1]);\n            }\n\n            // Create the insertion\n            this.$insertion = this.createInsertion();\n            this._placeInsertionWithDraggee();\n\n            this.closestItem = null;\n            this._clearMidpoints();\n\n            //  Get the closest container that has a height\n            if (this.settings.container) {\n                this.$heightedContainer = $(this.settings.container);\n\n                while (!this.$heightedContainer.height()) {\n                    this.$heightedContainer = this.$heightedContainer.parent();\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            // If there's a container set, make sure that we're hovering over it\n            if (this.$heightedContainer && !Garnish.hitTest(this.mouseX, this.mouseY, this.$heightedContainer)) {\n                if (this.closestItem) {\n                    this.closestItem = null;\n                    this._removeInsertion();\n                }\n            }\n            else {\n                // Is there a new closest item?\n                if (\n                    this.closestItem !== (this.closestItem = this._getClosestItem()) &&\n                    this.closestItem !== null\n                ) {\n                    this._updateInsertion();\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            this._removeInsertion();\n\n            // Should we keep the target item where it was?\n            if (!this.settings.moveTargetItemToFront && this.targetItemPositionInDraggee !== 0) {\n                this.$targetItem.insertAfter(this.$draggee.eq(this.targetItemPositionInDraggee));\n            }\n\n            // Return the helpers to the draggees\n            this.returnHelpersToDraggees();\n\n            this.base();\n\n            // Has the item actually moved?\n            this.$items = $().add(this.$items);\n            this.newDraggeeIndexes = this._getDraggeeIndexes();\n\n            if (this.newDraggeeIndexes.join(',') !== this.oldDraggeeIndexes.join(',')) {\n                this.onSortChange();\n            }\n        },\n\n        /**\n         * On Insertion Point Change event\n         */\n        onInsertionPointChange: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('insertionPointChange');\n                this.settings.onInsertionPointChange();\n            }, this));\n        },\n\n        /**\n         * On Sort Change event\n         */\n        onSortChange: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('sortChange');\n                this.settings.onSortChange();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        _getItemIndex: function(item) {\n            return $.inArray(item, this.$items);\n        },\n\n        _getDraggeeIndexes: function() {\n            var indexes = [];\n\n            for (var i = 0; i < this.$draggee.length; i++) {\n                indexes.push(this._getItemIndex(this.$draggee[i]))\n            }\n\n            return indexes;\n        },\n\n        /**\n         * Returns the closest item to the cursor.\n         */\n        _getClosestItem: function() {\n            this._getClosestItem._closestItem = null;\n\n            // Start by checking the draggee/insertion, if either are visible\n            if (!this.settings.removeDraggee) {\n                this._testForClosestItem(this.$draggee[0]);\n            }\n            else if (this.insertionVisible) {\n                this._testForClosestItem(this.$insertion[0]);\n            }\n\n            // Check items before the draggee\n            if (this._getClosestItem._closestItem) {\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._closestItem)\n            }\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this._getClosestItem._startXDist = this._getClosestItem._lastXDist = this._getClosestItem._closestItem ? Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX) : null;\n            }\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this._getClosestItem._startYDist = this._getClosestItem._lastYDist = this._getClosestItem._closestItem ? Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY) : null;\n            }\n\n            this._getClosestItem._$otherItem = this.$draggee.first().prev();\n\n            while (this._getClosestItem._$otherItem.length) {\n                // See if we're just getting further away\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._$otherItem[0]);\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._xDist = Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._yDist = Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n                }\n\n                if (\n                    (this.settings.axis === Garnish.Y_AXIS || (this._getClosestItem._lastXDist !== null && this._getClosestItem._xDist > this._getClosestItem._lastXDist)) &&\n                    (this.settings.axis === Garnish.X_AXIS || (this._getClosestItem._lastYDist !== null && this._getClosestItem._yDist > this._getClosestItem._lastYDist))\n                ) {\n                    break;\n                }\n\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._lastXDist = this._getClosestItem._xDist;\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._lastYDist = this._getClosestItem._yDist;\n                }\n\n                // Give the extending class a chance to allow/disallow this item\n                if (this.canInsertBefore(this._getClosestItem._$otherItem)) {\n                    this._testForClosestItem(this._getClosestItem._$otherItem[0]);\n                }\n\n                // Prep the next item\n                this._getClosestItem._$otherItem = this._getClosestItem._$otherItem.prev();\n            }\n\n            // Check items after the draggee\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this._getClosestItem._lastXDist = this._getClosestItem._startXDist;\n            }\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this._getClosestItem._lastYDist = this._getClosestItem._startYDist;\n            }\n\n            this._getClosestItem._$otherItem = this.$draggee.last().next();\n\n            while (this._getClosestItem._$otherItem.length) {\n                // See if we're just getting further away\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._$otherItem[0]);\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._xDist = Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._yDist = Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n                }\n\n                if (\n                    (this.settings.axis === Garnish.Y_AXIS || (this._getClosestItem._lastXDist !== null && this._getClosestItem._xDist > this._getClosestItem._lastXDist)) &&\n                    (this.settings.axis === Garnish.X_AXIS || (this._getClosestItem._lastYDist !== null && this._getClosestItem._yDist > this._getClosestItem._lastYDist))\n                ) {\n                    break;\n                }\n\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._lastXDist = this._getClosestItem._xDist;\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._lastYDist = this._getClosestItem._yDist;\n                }\n\n                // Give the extending class a chance to allow/disallow this item\n                if (this.canInsertAfter(this._getClosestItem._$otherItem)) {\n                    this._testForClosestItem(this._getClosestItem._$otherItem[0]);\n                }\n\n                // Prep the next item\n                this._getClosestItem._$otherItem = this._getClosestItem._$otherItem.next();\n            }\n\n            // Return the result\n\n            // Ignore if it's the draggee or insertion\n            if (\n                this._getClosestItem._closestItem !== this.$draggee[0] &&\n                (!this.insertionVisible || this._getClosestItem._closestItem !== this.$insertion[0])\n            ) {\n                return this._getClosestItem._closestItem;\n            }\n            else {\n                return null;\n            }\n        },\n\n        _clearMidpoints: function() {\n            this._midpointVersion++;\n            this._$prevItem = null;\n        },\n\n        _getItemMidpoint: function(item) {\n            if ($.data(item, 'midpointVersion') !== this._midpointVersion) {\n                // If this isn't the draggee, temporarily move the draggee to this item\n                this._getItemMidpoint._repositionDraggee = (\n                    !this.settings.axis &&\n                    (!this.settings.removeDraggee || this.insertionVisible) &&\n                    item !== this.$draggee[0] &&\n                    (!this.$insertion || item !== this.$insertion.get(0))\n                );\n\n                if (this._getItemMidpoint._repositionDraggee) {\n                    // Is this the first time we've had to temporarily reposition the draggee since the last midpoint clearing?\n                    if (!this._$prevItem) {\n                        this._$prevItem = (this.insertionVisible ? this.$insertion : this.$draggee).first().prev();\n                    }\n\n                    this._moveDraggeeToItem(item);\n\n                    // Now figure out which element we're actually getting the midpoint of\n                    if (!this.settings.removeDraggee) {\n                        this._getItemMidpoint._$item = this.$draggee;\n                    }\n                    else {\n                        this._getItemMidpoint._$item = this.$insertion;\n                    }\n                }\n                else {\n                    // We're actually getting the midpoint of this item\n                    this._getItemMidpoint._$item = $(item);\n                }\n\n                this._getItemMidpoint._offset = this._getItemMidpoint._$item.offset();\n\n                $.data(item, 'midpoint', {\n                    x: this._getItemMidpoint._offset.left + this._getItemMidpoint._$item.outerWidth() / 2,\n                    y: this._getItemMidpoint._offset.top + this._getItemMidpoint._$item.outerHeight() / 2\n                });\n\n                $.data(item, 'midpointVersion', this._midpointVersion);\n\n                delete this._getItemMidpoint._$item;\n                delete this._getItemMidpoint._offset;\n\n                if (this._getItemMidpoint._repositionDraggee) {\n                    // Move the draggee back\n                    if (this._$prevItem.length) {\n                        this.$draggee.insertAfter(this._$prevItem);\n                    }\n                    else {\n                        this.$draggee.prependTo(this.$draggee.parent());\n                    }\n\n                    this._placeInsertionWithDraggee();\n                }\n            }\n\n            return $.data(item, 'midpoint');\n        },\n\n        _testForClosestItem: function(item) {\n            this._testForClosestItem._midpoint = this._getItemMidpoint(item);\n            this._testForClosestItem._mouseDistX = Math.abs(this._testForClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n            this._testForClosestItem._mouseDistY = Math.abs(this._testForClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n\n            // Don't even consider items that are further away on the Y axis\n            if (\n                this._getClosestItem._closestItem === null ||\n                this._testForClosestItem._mouseDistY < this._getClosestItem._closestItemMouseDistY ||\n                (\n                    this._testForClosestItem._mouseDistY === this._getClosestItem._closestItemMouseDistY &&\n                    this._testForClosestItem._mouseDistX <= this._getClosestItem._closestItemMouseDistX\n                )\n            ) {\n                this._getClosestItem._closestItem = item;\n                this._getClosestItem._closestItemMouseDistX = this._testForClosestItem._mouseDistX;\n                this._getClosestItem._closestItemMouseDistY = this._testForClosestItem._mouseDistY;\n            }\n        },\n\n        /**\n         * Updates the position of the insertion point.\n         */\n        _updateInsertion: function() {\n            if (this.closestItem) {\n                this._moveDraggeeToItem(this.closestItem);\n            }\n\n            // Now that things have shifted around, invalidate the midpoints\n            this._clearMidpoints();\n\n            this.onInsertionPointChange();\n        },\n\n        _moveDraggeeToItem: function(item) {\n            // Going down?\n            if (this.$draggee.index() < $(item).index()) {\n                this.$draggee.insertAfter(item);\n            }\n            else {\n                this.$draggee.insertBefore(item);\n            }\n\n            this._placeInsertionWithDraggee();\n        },\n\n        _placeInsertionWithDraggee: function() {\n            if (this.$insertion) {\n                this.$insertion.insertBefore(this.$draggee.first());\n                this.insertionVisible = true;\n            }\n        },\n\n        /**\n         * Removes the insertion, if it's visible.\n         */\n        _removeInsertion: function() {\n            if (this.insertionVisible) {\n                this.$insertion.remove();\n                this.insertionVisible = false;\n            }\n        }\n    },\n    {\n        defaults: {\n            container: null,\n            insertion: null,\n            moveTargetItemToFront: false,\n            magnetStrength: 1,\n            onInsertionPointChange: $.noop,\n            onSortChange: $.noop\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * ESC key manager class\n */\nGarnish.EscManager = Garnish.Base.extend(\n    {\n        handlers: null,\n\n        init: function() {\n            this.handlers = [];\n\n            this.addListener(Garnish.$bod, 'keyup', function(ev) {\n                if (ev.keyCode === Garnish.ESC_KEY) {\n                    this.escapeLatest(ev);\n                }\n            });\n        },\n\n        register: function(obj, func) {\n            this.handlers.push({\n                obj: obj,\n                func: func\n            });\n        },\n\n        unregister: function(obj) {\n            for (var i = this.handlers.length - 1; i >= 0; i--) {\n                if (this.handlers[i].obj === obj) {\n                    this.handlers.splice(i, 1);\n                }\n            }\n        },\n\n        escapeLatest: function(ev) {\n            if (this.handlers.length) {\n                var handler = this.handlers.pop();\n\n                var func;\n\n                if (typeof handler.func === 'function') {\n                    func = handler.func;\n                }\n                else {\n                    func = handler.obj[handler.func];\n                }\n\n                func.call(handler.obj, ev);\n\n                if (typeof handler.obj.trigger === 'function') {\n                    handler.obj.trigger('escape');\n                }\n            }\n        }\n    }\n);\n\nGarnish.escManager = new Garnish.EscManager();\n","/** global: Garnish */\n/**\n * HUD\n */\nGarnish.HUD = Garnish.Base.extend(\n    {\n        $trigger: null,\n        $fixedTriggerParent: null,\n        $hud: null,\n        $tip: null,\n        $body: null,\n        $header: null,\n        $footer: null,\n        $mainContainer: null,\n        $main: null,\n        $shade: null,\n\n        showing: false,\n        orientation: null,\n\n        updatingSizeAndPosition: false,\n        windowWidth: null,\n        windowHeight: null,\n        scrollTop: null,\n        scrollLeft: null,\n        mainWidth: null,\n        mainHeight: null,\n\n        /**\n         * Constructor\n         */\n        init: function(trigger, bodyContents, settings) {\n\n            this.$trigger = $(trigger);\n\n            this.setSettings(settings, Garnish.HUD.defaults);\n            this.on('show', this.settings.onShow);\n            this.on('hide', this.settings.onHide);\n            this.on('submit', this.settings.onSubmit);\n\n            if (typeof Garnish.HUD.activeHUDs === 'undefined') {\n                Garnish.HUD.activeHUDs = {};\n            }\n\n            this.$shade = $('<div/>', {'class': this.settings.shadeClass});\n            this.$hud = $('<div/>', {'class': this.settings.hudClass}).data('hud', this);\n            this.$tip = $('<div/>', {'class': this.settings.tipClass}).appendTo(this.$hud);\n            this.$body = $('<form/>', {'class': this.settings.bodyClass}).appendTo(this.$hud);\n            this.$mainContainer = $('<div/>', {'class': this.settings.mainContainerClass}).appendTo(this.$body);\n            this.$main = $('<div/>', {'class': this.settings.mainClass}).appendTo(this.$mainContainer);\n\n            this.updateBody(bodyContents);\n\n            // See if the trigger is fixed\n            var $parent = this.$trigger;\n\n            do {\n                if ($parent.css('position') === 'fixed') {\n                    this.$fixedTriggerParent = $parent;\n                    break;\n                }\n\n                $parent = $parent.offsetParent();\n            }\n            while ($parent.length && $parent.prop('nodeName') !== 'HTML');\n\n            if (this.$fixedTriggerParent) {\n                this.$hud.css('position', 'fixed');\n            }\n            else {\n                this.$hud.css('position', 'absolute');\n            }\n\n            // Hide the HUD until it gets positioned\n\t\t\tvar windowWidth = Garnish.$win.width();\n\n\t\t\tthis.$hud.css({\n                left: '-' + windowWidth + 'px',\n\t\t\t});\n\n            this.show();\n\n            this.addListener(this.$body, 'submit', '_handleSubmit');\n            this.addListener(this.$shade, 'tap,click', 'hide');\n\n            if (this.settings.closeBtn) {\n                this.addListener(this.settings.closeBtn, 'activate', 'hide');\n            }\n\n            this.addListener(Garnish.$win, 'resize', 'updateSizeAndPosition');\n            this.addListener(this.$main, 'resize', 'updateSizeAndPosition');\n            if (!this.$fixedTriggerParent && Garnish.$scrollContainer[0] !== Garnish.$win[0]) {\n                this.addListener(Garnish.$scrollContainer, 'scroll', 'updateSizeAndPosition');\n            }\n        },\n\n        /**\n         * Update the body contents\n         */\n        updateBody: function(bodyContents) {\n            // Cleanup\n            this.$main.html('');\n\n            if (this.$header) {\n                this.$hud.removeClass('has-header');\n                this.$header.remove();\n                this.$header = null;\n            }\n\n            if (this.$footer) {\n                this.$hud.removeClass('has-footer');\n                this.$footer.remove();\n                this.$footer = null;\n            }\n\n            // Append the new body contents\n            this.$main.append(bodyContents);\n\n            // Look for a header and footer\n            var $header = this.$main.find('.' + this.settings.headerClass + ':first'),\n                $footer = this.$main.find('.' + this.settings.footerClass + ':first');\n\n            if ($header.length) {\n                this.$header = $header.insertBefore(this.$mainContainer);\n                this.$hud.addClass('has-header');\n            }\n\n            if ($footer.length) {\n                this.$footer = $footer.insertAfter(this.$mainContainer);\n                this.$hud.addClass('has-footer');\n            }\n        },\n\n        /**\n         * Show\n         */\n        show: function(ev) {\n            if (ev && ev.stopPropagation) {\n                ev.stopPropagation();\n            }\n\n            if (this.showing) {\n                return;\n            }\n\n            if (this.settings.closeOtherHUDs) {\n                for (var hudID in Garnish.HUD.activeHUDs) {\n                    if (!Garnish.HUD.activeHUDs.hasOwnProperty(hudID)) {\n                        continue;\n                    }\n                    Garnish.HUD.activeHUDs[hudID].hide();\n                }\n            }\n\n            // Move it to the end of <body> so it gets the highest sub-z-index\n            this.$shade.appendTo(Garnish.$bod);\n            this.$hud.appendTo(Garnish.$bod);\n\n            this.$hud.show();\n            this.$shade.show();\n            this.showing = true;\n            Garnish.HUD.activeHUDs[this._namespace] = this;\n            Garnish.escManager.register(this, 'hide');\n\n            this.onShow();\n            this.enable();\n\n            if (this.updateRecords()) {\n                // Prevent the browser from jumping\n                this.$hud.css('top', Garnish.$scrollContainer.scrollTop());\n\n                this.updateSizeAndPosition(true);\n            }\n        },\n\n        onShow: function() {\n            this.trigger('show');\n        },\n\n        updateRecords: function() {\n            var changed = false;\n            changed = (this.windowWidth !== (this.windowWidth = Garnish.$win.width())) || changed;\n            changed = (this.windowHeight !== (this.windowHeight = Garnish.$win.height())) || changed;\n            changed = (this.scrollTop !== (this.scrollTop = Garnish.$scrollContainer.scrollTop())) || changed;\n            changed = (this.scrollLeft !== (this.scrollLeft = Garnish.$scrollContainer.scrollLeft())) || changed;\n            changed = (this.mainWidth !== (this.mainWidth = this.$main.outerWidth())) || changed;\n            changed = (this.mainHeight !== (this.mainHeight = this.$main.outerHeight())) || changed;\n            return changed;\n        },\n\n        updateSizeAndPosition: function(force) {\n            if (force === true || (this.updateRecords() && !this.updatingSizeAndPosition)) {\n                this.updatingSizeAndPosition = true;\n                Garnish.requestAnimationFrame($.proxy(this, 'updateSizeAndPositionInternal'));\n            }\n        },\n\n        updateSizeAndPositionInternal: function() {\n            var triggerWidth,\n                triggerHeight,\n                triggerOffset,\n                windowScrollLeft,\n                windowScrollTop,\n                scrollContainerTriggerOffset,\n                scrollContainerScrollLeft,\n                scrollContainerScrollTop,\n                hudBodyWidth,\n                hudBodyHeight;\n\n            // Get the window sizes and trigger offset\n\n            windowScrollLeft = Garnish.$win.scrollLeft();\n            windowScrollTop = Garnish.$win.scrollTop();\n\n            // Get the trigger's dimensions\n            triggerWidth = this.$trigger.outerWidth();\n            triggerHeight = this.$trigger.outerHeight();\n\n            // Get the offsets for each side of the trigger element\n            triggerOffset = this.$trigger.offset();\n\n            if (this.$fixedTriggerParent) {\n                triggerOffset.left -= windowScrollLeft;\n                triggerOffset.top -= windowScrollTop;\n\n                scrollContainerTriggerOffset = triggerOffset;\n\n                windowScrollLeft = 0;\n                windowScrollTop = 0;\n                scrollContainerScrollLeft = 0;\n                scrollContainerScrollTop = 0;\n            }\n            else {\n                scrollContainerTriggerOffset = Garnish.getOffset(this.$trigger);\n\n                scrollContainerScrollLeft = Garnish.$scrollContainer.scrollLeft();\n                scrollContainerScrollTop = Garnish.$scrollContainer.scrollTop();\n            }\n\n            triggerOffset.right = triggerOffset.left + triggerWidth;\n            triggerOffset.bottom = triggerOffset.top + triggerHeight;\n\n            scrollContainerTriggerOffset.right = scrollContainerTriggerOffset.left + triggerWidth;\n            scrollContainerTriggerOffset.bottom = scrollContainerTriggerOffset.top + triggerHeight;\n\n            // Get the HUD dimensions\n            this.$hud.css({\n                width: ''\n            });\n\n            this.$mainContainer.css({\n                height: '',\n                'overflow-x': '',\n                'overflow-y': ''\n            });\n\n            hudBodyWidth = this.$body.width();\n            hudBodyHeight = this.$body.height();\n\n            // Determine the best orientation for the HUD\n\n            // Find the actual available top/right/bottom/left clearances\n            var clearances = {\n                bottom: this.windowHeight + scrollContainerScrollTop - scrollContainerTriggerOffset.bottom,\n                top: scrollContainerTriggerOffset.top - scrollContainerScrollTop,\n                right: this.windowWidth + scrollContainerScrollLeft - scrollContainerTriggerOffset.right,\n                left: scrollContainerTriggerOffset.left - scrollContainerScrollLeft\n            };\n\n            // Find the first position that has enough room\n            this.orientation = null;\n\n            for (var i = 0; i < this.settings.orientations.length; i++) {\n                var orientation = this.settings.orientations[i],\n                    relevantSize = (orientation === 'top' || orientation === 'bottom' ? hudBodyHeight : hudBodyWidth);\n\n                if (clearances[orientation] - (this.settings.windowSpacing + this.settings.triggerSpacing) >= relevantSize) {\n                    // This is the first orientation that has enough room in order of preference, so we'll go with this\n                    this.orientation = orientation;\n                    break;\n                }\n\n                if (!this.orientation || clearances[orientation] > clearances[this.orientation]) {\n                    // Use this as a fallback as it's the orientation with the most clearance so far\n                    this.orientation = orientation;\n                }\n            }\n\n            // Just in case...\n            if (!this.orientation || $.inArray(this.orientation, ['bottom', 'top', 'right', 'left']) === -1) {\n                this.orientation = 'bottom'\n            }\n\n            // Update the tip class\n            if (this.tipClass) {\n                this.$tip.removeClass(this.tipClass);\n            }\n\n            this.tipClass = this.settings.tipClass + '-' + Garnish.HUD.tipClasses[this.orientation];\n            this.$tip.addClass(this.tipClass);\n\n            // Make sure the HUD body is within the allowed size\n\n            var maxHudBodyWidth,\n                maxHudBodyHeight;\n\n            if (this.orientation === 'top' || this.orientation === 'bottom') {\n                maxHudBodyWidth = this.windowWidth - this.settings.windowSpacing * 2;\n                maxHudBodyHeight = clearances[this.orientation] - this.settings.windowSpacing - this.settings.triggerSpacing;\n            }\n            else {\n                maxHudBodyWidth = clearances[this.orientation] - this.settings.windowSpacing - this.settings.triggerSpacing;\n                maxHudBodyHeight = this.windowHeight - this.settings.windowSpacing * 2;\n            }\n\n            if (maxHudBodyWidth < this.settings.minBodyWidth) {\n                maxHudBodyWidth = this.settings.minBodyWidth;\n            }\n\n            if (maxHudBodyHeight < this.settings.minBodyHeight) {\n                maxHudBodyHeight = this.settings.minBodyHeight;\n            }\n\n            if (hudBodyWidth > maxHudBodyWidth || hudBodyWidth < this.settings.minBodyWidth) {\n                if (hudBodyWidth > maxHudBodyWidth) {\n                    hudBodyWidth = maxHudBodyWidth;\n                }\n                else {\n                    hudBodyWidth = this.settings.minBodyWidth;\n                }\n\n                this.$hud.width(hudBodyWidth);\n\n                // Is there any overflow now?\n                if (this.mainWidth > maxHudBodyWidth) {\n                    this.$mainContainer.css('overflow-x', 'scroll');\n                }\n\n                // The height may have just changed\n                hudBodyHeight = this.$body.height();\n            }\n\n            if (hudBodyHeight > maxHudBodyHeight || hudBodyHeight < this.settings.minBodyHeight) {\n                if (hudBodyHeight > maxHudBodyHeight) {\n                    hudBodyHeight = maxHudBodyHeight;\n                }\n                else {\n                    hudBodyHeight = this.settings.minBodyHeight;\n                }\n\n                var mainHeight = hudBodyHeight;\n\n                if (this.$header) {\n                    mainHeight -= this.$header.outerHeight();\n                }\n\n                if (this.$footer) {\n                    mainHeight -= this.$footer.outerHeight();\n                }\n\n                this.$mainContainer.height(mainHeight);\n\n                // Is there any overflow now?\n                if (this.mainHeight > mainHeight) {\n                    this.$mainContainer.css('overflow-y', 'scroll');\n                }\n            }\n\n            // Set the HUD/tip positions\n            var triggerCenter, left, top;\n\n            if (this.orientation === 'top' || this.orientation === 'bottom') {\n                // Center the HUD horizontally\n                var maxLeft = (this.windowWidth + windowScrollLeft) - (hudBodyWidth + this.settings.windowSpacing);\n                var minLeft = (windowScrollLeft + this.settings.windowSpacing);\n                triggerCenter = triggerOffset.left + Math.round(triggerWidth / 2);\n                left = triggerCenter - Math.round(hudBodyWidth / 2);\n\n                if (left > maxLeft) {\n                    left = maxLeft;\n                }\n                if (left < minLeft) {\n                    left = minLeft;\n                }\n\n                this.$hud.css('left', left);\n\n                var tipLeft = (triggerCenter - left) - (this.settings.tipWidth / 2);\n                this.$tip.css({left: tipLeft, top: ''});\n\n                if (this.orientation === 'top') {\n                    top = triggerOffset.top - (hudBodyHeight + this.settings.triggerSpacing);\n                    this.$hud.css('top', top);\n                }\n                else {\n                    top = triggerOffset.bottom + this.settings.triggerSpacing;\n                    this.$hud.css('top', top);\n                }\n            }\n            else {\n                // Center the HUD vertically\n                var maxTop = (this.windowHeight + windowScrollTop) - (hudBodyHeight + this.settings.windowSpacing);\n                var minTop = (windowScrollTop + this.settings.windowSpacing);\n                triggerCenter = triggerOffset.top + Math.round(triggerHeight / 2);\n                top = triggerCenter - Math.round(hudBodyHeight / 2);\n\n                if (top > maxTop) {\n                    top = maxTop;\n                }\n                if (top < minTop) {\n                    top = minTop;\n                }\n\n                this.$hud.css('top', top);\n\n                var tipTop = (triggerCenter - top) - (this.settings.tipWidth / 2);\n                this.$tip.css({top: tipTop, left: ''});\n\n\n                if (this.orientation === 'left') {\n                    left = triggerOffset.left - (hudBodyWidth + this.settings.triggerSpacing);\n                    this.$hud.css('left', left);\n                }\n                else {\n                    left = triggerOffset.right + this.settings.triggerSpacing;\n                    this.$hud.css('left', left);\n                }\n            }\n\n            this.updatingSizeAndPosition = false;\n            this.trigger('updateSizeAndPosition');\n        },\n\n        /**\n         * Hide\n         */\n        hide: function() {\n            this.disable();\n\n            this.$hud.hide();\n            this.$shade.hide();\n\n            this.showing = false;\n            //this.windowWidth = null;\n            //this.windowHeight = null;\n            //this.scrollTop = null;\n            //this.scrollLeft = null;\n            //this.mainWidth = null;\n            //this.mainHeight = null;\n\n            delete Garnish.HUD.activeHUDs[this._namespace];\n\n            Garnish.escManager.unregister(this);\n\n            this.onHide();\n        },\n\n        onHide: function() {\n            this.trigger('hide');\n        },\n\n        toggle: function() {\n            if (this.showing) {\n                this.hide();\n            }\n            else {\n                this.show();\n            }\n        },\n\n        submit: function() {\n            this.onSubmit();\n        },\n\n        onSubmit: function() {\n            this.trigger('submit');\n        },\n\n        _handleSubmit: function(ev) {\n            ev.preventDefault();\n            this.submit();\n        }\n    },\n    {\n        tipClasses: {bottom: 'top', top: 'bottom', right: 'left', left: 'right'},\n\n        defaults: {\n            shadeClass: 'hud-shade',\n            hudClass: 'hud',\n            tipClass: 'tip',\n            bodyClass: 'body',\n            headerClass: 'hud-header',\n            footerClass: 'hud-footer',\n            mainContainerClass: 'main-container',\n            mainClass: 'main',\n            orientations: ['bottom', 'top', 'right', 'left'],\n            triggerSpacing: 10,\n            windowSpacing: 10,\n            tipWidth: 30,\n            minBodyWidth: 200,\n            minBodyHeight: 0,\n            onShow: $.noop,\n            onHide: $.noop,\n            onSubmit: $.noop,\n            closeBtn: null,\n            closeOtherHUDs: true\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Menu\n */\nGarnish.Menu = Garnish.Base.extend(\n    {\n        settings: null,\n\n        $container: null,\n        $options: null,\n        $anchor: null,\n\n        menuId: null,\n\n        _windowWidth: null,\n        _windowHeight: null,\n        _windowScrollLeft: null,\n        _windowScrollTop: null,\n\n        _anchorOffset: null,\n        _anchorWidth: null,\n        _anchorHeight: null,\n        _anchorOffsetRight: null,\n        _anchorOffsetBottom: null,\n\n        _menuWidth: null,\n        _menuHeight: null,\n\n        /**\n         * Constructor\n         */\n        init: function(container, settings) {\n            this.setSettings(settings, Garnish.Menu.defaults);\n\n            this.$container = $(container);\n\n            this.$options = $();\n            this.addOptions(this.$container.find('a'));\n\n            // Menu List\n            this.menuId = 'menu' + this._namespace;\n            this.$menuList = $('ul', this.$container);\n            this.$menuList.attr({\n                'role': 'listbox',\n                'id': this.menuId,\n                'aria-hidden': 'true'\n            });\n\n            // Deprecated\n            if (this.settings.attachToElement) {\n                this.settings.anchor = this.settings.attachToElement;\n                Garnish.log('The \\'attachToElement\\' setting is deprecated. Use \\'anchor\\' instead.');\n            }\n\n            if (this.settings.anchor) {\n                this.$anchor = $(this.settings.anchor);\n            }\n\n            // Prevent clicking on the container from hiding the menu\n            this.addListener(this.$container, 'mousedown', function(ev) {\n                ev.stopPropagation();\n\n                // Prevent this from causing the menu button to blur\n                ev.preventDefault();\n            });\n        },\n\n        addOptions: function($options) {\n            this.$options = this.$options.add($options);\n            $options.data('menu', this);\n\n            $options.each($.proxy(function(optionKey, option) {\n                $(option).attr({\n                    'role': 'option',\n                    'tabindex': '-1',\n                    'id': this.menuId + '-option-' + optionKey\n                });\n            }, this));\n\n            this.addListener($options, 'click', 'selectOption');\n        },\n\n        setPositionRelativeToAnchor: function() {\n            this._windowWidth = Garnish.$win.width();\n            this._windowHeight = Garnish.$win.height();\n            this._windowScrollLeft = Garnish.$win.scrollLeft();\n            this._windowScrollTop = Garnish.$win.scrollTop();\n\n            this._anchorOffset = this.$anchor.offset();\n            this._anchorWidth = this.$anchor.outerWidth();\n            this._anchorHeight = this.$anchor.outerHeight();\n            this._anchorOffsetRight = this._anchorOffset.left + this._anchorHeight;\n            this._anchorOffsetBottom = this._anchorOffset.top + this._anchorHeight;\n\n            this.$container.css('minWidth', 0);\n            this.$container.css('minWidth', this._anchorWidth - (this.$container.outerWidth() - this.$container.width()));\n\n            this._menuWidth = this.$container.outerWidth();\n            this._menuHeight = this.$container.outerHeight();\n\n            // Is there room for the menu below the anchor?\n            var topClearance = this._anchorOffset.top - this._windowScrollTop,\n                bottomClearance = this._windowHeight + this._windowScrollTop - this._anchorOffsetBottom;\n\n            if (bottomClearance >= this._menuHeight || (topClearance < this._menuHeight && bottomClearance >= topClearance)) {\n                this.$container.css({\n                    top: this._anchorOffsetBottom,\n                    maxHeight: bottomClearance - this.settings.windowSpacing\n                });\n            } else {\n                this.$container.css({\n                    top: this._anchorOffset.top - Math.min(this._menuHeight, topClearance - this.settings.windowSpacing),\n                    maxHeight: topClearance - this.settings.windowSpacing\n                });\n            }\n\n            // Figure out how we're aliging it\n            var align = this.$container.data('align');\n\n            if (align !== 'left' && align !== 'center' && align !== 'right') {\n                align = 'left';\n            }\n\n            if (align === 'center') {\n                this._alignCenter();\n            }\n            else {\n                // Figure out which options are actually possible\n                var rightClearance = this._windowWidth + this._windowScrollLeft - (this._anchorOffset.left + this._menuWidth),\n                    leftClearance = this._anchorOffsetRight - this._menuWidth;\n\n                if (align === 'right' && leftClearance >= 0 || rightClearance < 0) {\n                    this._alignRight();\n                }\n                else {\n                    this._alignLeft();\n                }\n            }\n\n            delete this._windowWidth;\n            delete this._windowHeight;\n            delete this._windowScrollLeft;\n            delete this._windowScrollTop;\n            delete this._anchorOffset;\n            delete this._anchorWidth;\n            delete this._anchorHeight;\n            delete this._anchorOffsetRight;\n            delete this._anchorOffsetBottom;\n            delete this._menuWidth;\n            delete this._menuHeight;\n        },\n\n        show: function() {\n            // Move the menu to the end of the DOM\n            this.$container.appendTo(Garnish.$bod);\n\n            if (this.$anchor) {\n                this.setPositionRelativeToAnchor();\n            }\n\n            this.$container.velocity('stop');\n            this.$container.css({\n                opacity: 1,\n                display: 'block'\n            });\n\n            this.$menuList.attr('aria-hidden', 'false');\n\n            Garnish.escManager.register(this, 'hide');\n            this.addListener(Garnish.$scrollContainer, 'scroll', 'setPositionRelativeToAnchor');\n        },\n\n        hide: function() {\n            this.$menuList.attr('aria-hidden', 'true');\n\n            this.$container.velocity('fadeOut', {duration: Garnish.FX_DURATION}, $.proxy(function() {\n                this.$container.detach();\n            }, this));\n\n            Garnish.escManager.unregister(this);\n            this.removeListener(Garnish.$scrollContainer, 'scroll');\n\n            this.trigger('hide');\n        },\n\n        selectOption: function(ev) {\n            this.settings.onOptionSelect(ev.currentTarget);\n            this.trigger('optionselect', {selectedOption: ev.currentTarget});\n            this.hide();\n        },\n\n        _alignLeft: function() {\n            this.$container.css({\n                left: this._anchorOffset.left,\n                right: 'auto'\n            });\n        },\n\n        _alignRight: function() {\n            this.$container.css({\n                right: this._windowWidth - (this._anchorOffset.left + this._anchorWidth),\n                left: 'auto'\n            });\n        },\n\n        _alignCenter: function() {\n            var left = Math.round((this._anchorOffset.left + this._anchorWidth / 2) - (this._menuWidth / 2));\n\n            if (left < 0) {\n                left = 0;\n            }\n\n            this.$container.css('left', left);\n        }\n\n    },\n    {\n        defaults: {\n            anchor: null,\n            windowSpacing: 5,\n            onOptionSelect: $.noop\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Menu Button\n */\nGarnish.MenuBtn = Garnish.Base.extend(\n    {\n        $btn: null,\n        menu: null,\n        showingMenu: false,\n        disabled: true,\n\n        /**\n         * Constructor\n         */\n        init: function(btn, settings) {\n            this.$btn = $(btn);\n\n            // Is this already a menu button?\n            if (this.$btn.data('menubtn')) {\n                // Grab the old MenuBtn's menu container\n                var $menu = this.$btn.data('menubtn').menu.$container;\n\n                Garnish.log('Double-instantiating a menu button on an element');\n                this.$btn.data('menubtn').destroy();\n            }\n            else {\n                var $menu = this.$btn.next('.menu').detach();\n            }\n\n            this.$btn.data('menubtn', this);\n\n            this.setSettings(settings, Garnish.MenuBtn.defaults);\n\n            this.menu = new Garnish.Menu($menu, {\n                anchor: (this.settings.menuAnchor || this.$btn),\n                onOptionSelect: $.proxy(this, 'onOptionSelect')\n            });\n\n            this.$btn.attr({\n                'tabindex': 0,\n                'role': 'combobox',\n                'aria-owns': this.menu.menuId,\n                'aria-haspopup': 'true',\n                'aria-expanded': 'false'\n            });\n\n            this.menu.on('hide', $.proxy(this, 'onMenuHide'));\n            this.addListener(this.$btn, 'mousedown', 'onMouseDown');\n            this.addListener(this.$btn, 'keydown', 'onKeyDown');\n            this.addListener(this.$btn, 'blur', 'onBlur');\n            this.enable();\n        },\n\n        onBlur: function(ev) {\n            if (this.showingMenu) {\n                this.hideMenu();\n            }\n        },\n\n        onKeyDown: function(ev) {\n            var $option;\n\n            switch (ev.keyCode) {\n                case Garnish.RETURN_KEY: {\n                    ev.preventDefault();\n\n                    var $currentOption = this.menu.$options.filter('.hover');\n\n                    if ($currentOption.length > 0) {\n                        $currentOption.get(0).click();\n                    }\n\n                    break;\n                }\n\n                case Garnish.SPACE_KEY: {\n                    ev.preventDefault();\n\n                    if (!this.showingMenu) {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.first();\n                        }\n\n                        this.focusOption($option);\n                    }\n\n                    break;\n                }\n\n                case Garnish.DOWN_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        $.each(this.menu.$options, $.proxy(function(index, value) {\n                            if (!$option) {\n                                if ($(value).hasClass('hover')) {\n                                    if ((index + 1) < this.menu.$options.length) {\n                                        $option = $(this.menu.$options[(index + 1)]);\n                                    }\n                                }\n                            }\n                        }, this));\n\n                        if (!$option) {\n                            $option = $(this.menu.$options[0]);\n                        }\n                    }\n                    else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.first();\n                        }\n                    }\n\n                    this.focusOption($option);\n\n                    break;\n                }\n\n                case Garnish.UP_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        $.each(this.menu.$options, $.proxy(function(index, value) {\n                            if (!$option) {\n                                if ($(value).hasClass('hover')) {\n                                    if ((index - 1) >= 0) {\n                                        $option = $(this.menu.$options[(index - 1)]);\n                                    }\n                                }\n                            }\n                        }, this));\n\n                        if (!$option) {\n                            $option = $(this.menu.$options[(this.menu.$options.length - 1)]);\n                        }\n                    }\n                    else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.last();\n                        }\n                    }\n\n                    this.focusOption($option);\n\n                    break;\n                }\n            }\n        },\n\n        focusOption: function($option) {\n            this.menu.$options.removeClass('hover');\n\n            $option.addClass('hover');\n\n            this.menu.$menuList.attr('aria-activedescendant', $option.attr('id'));\n            this.$btn.attr('aria-activedescendant', $option.attr('id'));\n        },\n\n        onMouseDown: function(ev) {\n            if (ev.which !== Garnish.PRIMARY_CLICK || Garnish.isCtrlKeyPressed(ev)) {\n                return;\n            }\n\n            ev.preventDefault();\n\n            if (this.showingMenu) {\n                this.hideMenu();\n            }\n            else {\n                this.showMenu();\n            }\n        },\n\n        showMenu: function() {\n            if (this.disabled) {\n                return;\n            }\n\n            this.menu.show();\n            this.$btn.addClass('active');\n            this.$btn.trigger('focus');\n            this.$btn.attr('aria-expanded', 'true');\n\n            this.showingMenu = true;\n\n            setTimeout($.proxy(function() {\n                this.addListener(Garnish.$doc, 'mousedown', 'onMouseDown');\n            }, this), 1);\n        },\n\n        hideMenu: function() {\n            this.menu.hide();\n            this.$btn.attr('aria-expanded', 'false');\n        },\n\n        onMenuHide: function() {\n            this.$btn.removeClass('active');\n            this.showingMenu = false;\n\n            this.removeListener(Garnish.$doc, 'mousedown');\n        },\n\n        onOptionSelect: function(option) {\n            this.settings.onOptionSelect(option);\n            this.trigger('optionSelect', {option: option});\n        },\n\n        enable: function() {\n            this.disabled = false;\n        },\n\n        disable: function() {\n            this.disabled = true;\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$btn.removeData('menubtn');\n            this.base();\n        }\n    },\n    {\n        defaults: {\n            menuAnchor: null,\n            onOptionSelect: $.noop\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Mixed input\n *\n * @todo RTL support, in the event that the input doesn't have dir=\"ltr\".\n */\nGarnish.MixedInput = Garnish.Base.extend(\n    {\n        $container: null,\n        elements: null,\n        focussedElement: null,\n        blurTimeout: null,\n\n        init: function(container, settings) {\n            this.$container = $(container);\n            this.setSettings(settings, Garnish.MixedInput.defaults);\n\n            this.elements = [];\n\n            // Allow the container to receive focus\n            this.$container.attr('tabindex', 0);\n            this.addListener(this.$container, 'focus', 'onFocus');\n        },\n\n        getElementIndex: function($elem) {\n            return $.inArray($elem, this.elements);\n        },\n\n        isText: function($elem) {\n            return ($elem.prop('nodeName') === 'INPUT');\n        },\n\n        onFocus: function() {\n            // Set focus to the first element\n            if (this.elements.length) {\n                var $elem = this.elements[0];\n                this.setFocus($elem);\n                this.setCarotPos($elem, 0);\n            }\n            else {\n                this.addTextElement();\n            }\n        },\n\n        addTextElement: function(index) {\n            var text = new TextElement(this);\n            this.addElement(text.$input, index);\n            return text;\n        },\n\n        addElement: function($elem, index) {\n            // Was a target index passed, and is it valid?\n            if (typeof index === 'undefined') {\n                if (this.focussedElement) {\n                    var focussedElement = this.focussedElement,\n                        focussedElementIndex = this.getElementIndex(focussedElement);\n\n                    // Is the focus on a text element?\n                    if (this.isText(focussedElement)) {\n                        var selectionStart = focussedElement.prop('selectionStart'),\n                            selectionEnd = focussedElement.prop('selectionEnd'),\n                            val = focussedElement.val(),\n                            preVal = val.substring(0, selectionStart),\n                            postVal = val.substr(selectionEnd);\n\n                        if (preVal && postVal) {\n                            // Split the input into two\n                            focussedElement.val(preVal).trigger('change');\n                            var newText = new TextElement(this);\n                            newText.$input.val(postVal).trigger('change');\n                            this.addElement(newText.$input, focussedElementIndex + 1);\n\n                            // Insert the new element in between them\n                            index = focussedElementIndex + 1;\n                        }\n                        else if (!preVal) {\n                            // Insert the new element before this one\n                            index = focussedElementIndex;\n                        }\n                        else {\n                            // Insert it after this one\n                            index = focussedElementIndex + 1;\n                        }\n                    }\n                    else {\n                        // Just insert the new one after this one\n                        index = focussedElementIndex + 1;\n                    }\n                }\n                else {\n                    // Insert the new element at the end\n                    index = this.elements.length;\n                }\n            }\n\n            // Add the element\n            if (typeof this.elements[index] !== 'undefined') {\n                $elem.insertBefore(this.elements[index]);\n                this.elements.splice(index, 0, $elem);\n            }\n            else {\n                // Just for safe measure, set the index to what it really will be\n                index = this.elements.length;\n\n                this.$container.append($elem);\n                this.elements.push($elem);\n            }\n\n            // Make sure that there are text elements surrounding all non-text elements\n            if (!this.isText($elem)) {\n                // Add a text element before?\n                if (index === 0 || !this.isText(this.elements[index - 1])) {\n                    this.addTextElement(index);\n                    index++;\n                }\n\n                // Add a text element after?\n                if (index === this.elements.length - 1 || !this.isText(this.elements[index + 1])) {\n                    this.addTextElement(index + 1);\n                }\n            }\n\n            // Add event listeners\n            this.addListener($elem, 'click', function() {\n                this.setFocus($elem);\n            });\n\n            // Set focus to the new element\n            setTimeout($.proxy(function() {\n                this.setFocus($elem);\n            }, this), 1);\n        },\n\n        removeElement: function($elem) {\n            var index = this.getElementIndex($elem);\n            if (index !== -1) {\n                this.elements.splice(index, 1);\n\n                if (!this.isText($elem)) {\n                    // Combine the two now-adjacent text elements\n                    var $prevElem = this.elements[index - 1],\n                        $nextElem = this.elements[index];\n\n                    if (this.isText($prevElem) && this.isText($nextElem)) {\n                        var prevElemVal = $prevElem.val(),\n                            newVal = prevElemVal + $nextElem.val();\n                        $prevElem.val(newVal).trigger('change');\n                        this.removeElement($nextElem);\n                        this.setFocus($prevElem);\n                        this.setCarotPos($prevElem, prevElemVal.length);\n                    }\n                }\n\n                $elem.remove();\n            }\n        },\n\n        setFocus: function($elem) {\n            this.$container.addClass('focus');\n\n            if (!this.focussedElement) {\n                // Prevent the container from receiving focus\n                // as long as one of its elements has focus\n                this.$container.attr('tabindex', '-1');\n            }\n            else {\n                // Blur the previously-focussed element\n                this.blurFocussedElement();\n            }\n\n            $elem.attr('tabindex', '0');\n            $elem.focus();\n            this.focussedElement = $elem;\n\n            this.addListener($elem, 'blur', function() {\n                this.blurTimeout = setTimeout($.proxy(function() {\n                    if (this.focussedElement === $elem) {\n                        this.blurFocussedElement();\n                        this.focussedElement = null;\n                        this.$container.removeClass('focus');\n\n                        // Get ready for future focus\n                        this.$container.attr('tabindex', '0');\n                    }\n                }, this), 1);\n            });\n        },\n\n        blurFocussedElement: function() {\n            this.removeListener(this.focussedElement, 'blur');\n            this.focussedElement.attr('tabindex', '-1');\n        },\n\n        focusPreviousElement: function($from) {\n            var index = this.getElementIndex($from);\n\n            if (index > 0) {\n                var $elem = this.elements[index - 1];\n                this.setFocus($elem);\n\n                // If it's a text element, put the carot at the end\n                if (this.isText($elem)) {\n                    var length = $elem.val().length;\n                    this.setCarotPos($elem, length);\n                }\n            }\n        },\n\n        focusNextElement: function($from) {\n            var index = this.getElementIndex($from);\n\n            if (index < this.elements.length - 1) {\n                var $elem = this.elements[index + 1];\n                this.setFocus($elem);\n\n                // If it's a text element, put the carot at the beginning\n                if (this.isText($elem)) {\n                    this.setCarotPos($elem, 0)\n                }\n            }\n        },\n\n        setCarotPos: function($elem, pos) {\n            $elem.prop('selectionStart', pos);\n            $elem.prop('selectionEnd', pos);\n        }\n\n    });\n\n\nvar TextElement = Garnish.Base.extend({\n\n        parentInput: null,\n        $input: null,\n        $stage: null,\n        val: null,\n        focussed: false,\n        interval: null,\n\n        init: function(parentInput) {\n            this.parentInput = parentInput;\n\n            this.$input = $('<input type=\"text\"/>').appendTo(this.parentInput.$container);\n            this.$input.css('margin-right', (2 - TextElement.padding) + 'px');\n\n            this.setWidth();\n\n            this.addListener(this.$input, 'focus', 'onFocus');\n            this.addListener(this.$input, 'blur', 'onBlur');\n            this.addListener(this.$input, 'keydown', 'onKeyDown');\n            this.addListener(this.$input, 'change', 'checkInput');\n        },\n\n        getIndex: function() {\n            return this.parentInput.getElementIndex(this.$input);\n        },\n\n        buildStage: function() {\n            this.$stage = $('<stage/>').appendTo(Garnish.$bod);\n\n            // replicate the textarea's text styles\n            this.$stage.css({\n                position: 'absolute',\n                top: -9999,\n                left: -9999,\n                wordWrap: 'nowrap'\n            });\n\n            Garnish.copyTextStyles(this.$input, this.$stage);\n        },\n\n        getTextWidth: function(val) {\n            if (!this.$stage) {\n                this.buildStage();\n            }\n\n            if (val) {\n                // Ampersand entities\n                val = val.replace(/&/g, '&amp;');\n\n                // < and >\n                val = val.replace(/</g, '&lt;');\n                val = val.replace(/>/g, '&gt;');\n\n                // Spaces\n                val = val.replace(/ /g, '&nbsp;');\n            }\n\n            this.$stage.html(val);\n            this.stageWidth = this.$stage.width();\n            return this.stageWidth;\n        },\n\n        onFocus: function() {\n            this.focussed = true;\n            this.interval = setInterval($.proxy(this, 'checkInput'), Garnish.NiceText.interval);\n            this.checkInput();\n        },\n\n        onBlur: function() {\n            this.focussed = false;\n            clearInterval(this.interval);\n            this.checkInput();\n        },\n\n        onKeyDown: function(ev) {\n            setTimeout($.proxy(this, 'checkInput'), 1);\n\n            switch (ev.keyCode) {\n                case Garnish.LEFT_KEY: {\n                    if (this.$input.prop('selectionStart') === 0 && this.$input.prop('selectionEnd') === 0) {\n                        // Set focus to the previous element\n                        this.parentInput.focusPreviousElement(this.$input);\n                    }\n                    break;\n                }\n\n                case Garnish.RIGHT_KEY: {\n                    if (this.$input.prop('selectionStart') === this.val.length && this.$input.prop('selectionEnd') === this.val.length) {\n                        // Set focus to the next element\n                        this.parentInput.focusNextElement(this.$input);\n                    }\n                    break;\n                }\n\n                case Garnish.DELETE_KEY: {\n                    if (this.$input.prop('selectionStart') === 0 && this.$input.prop('selectionEnd') === 0) {\n                        // Set focus to the previous element\n                        this.parentInput.focusPreviousElement(this.$input);\n                        ev.preventDefault();\n                    }\n                }\n            }\n        },\n\n        getVal: function() {\n            this.val = this.$input.val();\n            return this.val;\n        },\n\n        setVal: function(val) {\n            this.$input.val(val);\n            this.checkInput();\n        },\n\n        checkInput: function() {\n            // Has the value changed?\n            var changed = (this.val !== this.getVal());\n            if (changed) {\n                this.setWidth();\n                this.onChange();\n            }\n\n            return changed;\n        },\n\n        setWidth: function() {\n            // has the width changed?\n            if (this.stageWidth !== this.getTextWidth(this.val)) {\n                // update the textarea width\n                var width = this.stageWidth + TextElement.padding;\n                this.$input.width(width);\n            }\n        },\n\n        onChange: $.noop\n    },\n    {\n        padding: 20\n    }\n);\n","/** global: Garnish */\n/**\n * Modal\n */\nGarnish.Modal = Garnish.Base.extend(\n    {\n        $container: null,\n        $shade: null,\n\n        visible: false,\n\n        dragger: null,\n\n        desiredWidth: null,\n        desiredHeight: null,\n        resizeDragger: null,\n        resizeStartWidth: null,\n        resizeStartHeight: null,\n\n        init: function(container, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(container)) {\n                // (settings)\n                settings = container;\n                container = null;\n            }\n\n            this.setSettings(settings, Garnish.Modal.defaults);\n\n            // Create the shade\n            this.$shade = $('<div class=\"' + this.settings.shadeClass + '\"/>');\n\n            // If the container is already set, drop the shade below it.\n            if (container) {\n                this.$shade.insertBefore(container);\n            }\n            else {\n                this.$shade.appendTo(Garnish.$bod);\n            }\n\n            if (container) {\n                this.setContainer(container);\n\n                if (this.settings.autoShow) {\n                    this.show();\n                }\n            }\n\n            Garnish.Modal.instances.push(this);\n        },\n\n        setContainer: function(container) {\n            this.$container = $(container);\n\n            // Is this already a modal?\n            if (this.$container.data('modal')) {\n                Garnish.log('Double-instantiating a modal on an element');\n                this.$container.data('modal').destroy();\n            }\n\n            this.$container.data('modal', this);\n\n            if (this.settings.draggable) {\n                this.dragger = new Garnish.DragMove(this.$container, {\n                    handle: (this.settings.dragHandleSelector ? this.$container.find(this.settings.dragHandleSelector) : this.$container)\n                });\n            }\n\n            if (this.settings.resizable) {\n                var $resizeDragHandle = $('<div class=\"resizehandle\"/>').appendTo(this.$container);\n\n                this.resizeDragger = new Garnish.BaseDrag($resizeDragHandle, {\n                    onDragStart: $.proxy(this, '_handleResizeStart'),\n                    onDrag: $.proxy(this, '_handleResize')\n                });\n            }\n\n            this.addListener(this.$container, 'click', function(ev) {\n                ev.stopPropagation();\n            });\n\n            // Show it if we're late to the party\n            if (this.visible) {\n                this.show();\n            }\n        },\n\n        show: function() {\n            // Close other modals as needed\n            if (this.settings.closeOtherModals && Garnish.Modal.visibleModal && Garnish.Modal.visibleModal !== this) {\n                Garnish.Modal.visibleModal.hide();\n            }\n\n            if (this.$container) {\n                // Move it to the end of <body> so it gets the highest sub-z-index\n                this.$shade.appendTo(Garnish.$bod);\n                this.$container.appendTo(Garnish.$bod);\n\n                this.$container.show();\n                this.updateSizeAndPosition();\n\n                this.$shade.velocity('fadeIn', {\n                    duration: 50,\n                    complete: $.proxy(function() {\n                        this.$container.velocity('fadeIn', {\n                            complete: $.proxy(function() {\n                                this.updateSizeAndPosition();\n                                this.onFadeIn();\n                            }, this)\n                        });\n                    }, this)\n                });\n\n                if (this.settings.hideOnShadeClick) {\n                    this.addListener(this.$shade, 'click', 'hide');\n                }\n\n                this.addListener(Garnish.$win, 'resize', '_handleWindowResize');\n            }\n\n            this.enable();\n\n            if (this.settings.hideOnEsc) {\n                Garnish.escManager.register(this, 'hide');\n            }\n\n            if (!this.visible) {\n                this.visible = true;\n                Garnish.Modal.visibleModal = this;\n\n                this.trigger('show');\n                this.settings.onShow();\n            }\n        },\n\n        quickShow: function() {\n            this.show();\n\n            if (this.$container) {\n                this.$container.velocity('stop');\n                this.$container.show().css('opacity', 1);\n\n                this.$shade.velocity('stop');\n                this.$shade.show().css('opacity', 1);\n            }\n        },\n\n        hide: function(ev) {\n            this.disable();\n\n            if (ev) {\n                ev.stopPropagation();\n            }\n\n            if (this.$container) {\n                this.$container.velocity('fadeOut', {duration: Garnish.FX_DURATION});\n                this.$shade.velocity('fadeOut', {\n                    duration: Garnish.FX_DURATION,\n                    complete: $.proxy(this, 'onFadeOut')\n                });\n\n                if (this.settings.hideOnShadeClick) {\n                    this.removeListener(this.$shade, 'click');\n                }\n\n                this.removeListener(Garnish.$win, 'resize');\n            }\n\n            this.visible = false;\n            Garnish.Modal.visibleModal = null;\n\n            if (this.settings.hideOnEsc) {\n                Garnish.escManager.unregister(this);\n            }\n\n            this.trigger('hide');\n            this.settings.onHide();\n        },\n\n        quickHide: function() {\n            this.hide();\n\n            if (this.$container) {\n                this.$container.velocity('stop');\n                this.$container.css('opacity', 0).hide();\n\n                this.$shade.velocity('stop');\n                this.$shade.css('opacity', 0).hide();\n            }\n        },\n\n        updateSizeAndPosition: function() {\n            if (!this.$container) {\n                return;\n            }\n\n            this.$container.css({\n                'width': (this.desiredWidth ? Math.max(this.desiredWidth, 200) : ''),\n                'height': (this.desiredHeight ? Math.max(this.desiredHeight, 200) : ''),\n                'min-width': '',\n                'min-height': ''\n            });\n\n            // Set the width first so that the height can adjust for the width\n            this.updateSizeAndPosition._windowWidth = Garnish.$win.width();\n            this.updateSizeAndPosition._width = Math.min(this.getWidth(), this.updateSizeAndPosition._windowWidth - this.settings.minGutter * 2);\n\n            this.$container.css({\n                'width': this.updateSizeAndPosition._width,\n                'min-width': this.updateSizeAndPosition._width,\n                'left': Math.round((this.updateSizeAndPosition._windowWidth - this.updateSizeAndPosition._width) / 2)\n            });\n\n            // Now set the height\n            this.updateSizeAndPosition._windowHeight = Garnish.$win.height();\n            this.updateSizeAndPosition._height = Math.min(this.getHeight(), this.updateSizeAndPosition._windowHeight - this.settings.minGutter * 2);\n\n            this.$container.css({\n                'height': this.updateSizeAndPosition._height,\n                'min-height': this.updateSizeAndPosition._height,\n                'top': Math.round((this.updateSizeAndPosition._windowHeight - this.updateSizeAndPosition._height) / 2)\n            });\n\n            this.trigger('updateSizeAndPosition');\n        },\n\n        onFadeIn: function() {\n            this.trigger('fadeIn');\n            this.settings.onFadeIn();\n        },\n\n        onFadeOut: function() {\n            this.trigger('fadeOut');\n            this.settings.onFadeOut();\n        },\n\n        getHeight: function() {\n            if (!this.$container) {\n                throw 'Attempted to get the height of a modal whose container has not been set.';\n            }\n\n            if (!this.visible) {\n                this.$container.show();\n            }\n\n            this.getHeight._height = this.$container.outerHeight();\n\n            if (!this.visible) {\n                this.$container.hide();\n            }\n\n            return this.getHeight._height;\n        },\n\n        getWidth: function() {\n            if (!this.$container) {\n                throw 'Attempted to get the width of a modal whose container has not been set.';\n            }\n\n            if (!this.visible) {\n                this.$container.show();\n            }\n\n            // Chrome might be 1px shy here for some reason\n            this.getWidth._width = this.$container.outerWidth() + 1;\n\n            if (!this.visible) {\n                this.$container.hide();\n            }\n\n            return this.getWidth._width;\n        },\n\n        _handleWindowResize: function(ev) {\n            // ignore propagated resize events\n            if (ev.target === window) {\n                this.updateSizeAndPosition();\n            }\n        },\n\n        _handleResizeStart: function() {\n            this.resizeStartWidth = this.getWidth();\n            this.resizeStartHeight = this.getHeight();\n        },\n\n        _handleResize: function() {\n            if (Garnish.ltr) {\n                this.desiredWidth = this.resizeStartWidth + (this.resizeDragger.mouseDistX * 2);\n            }\n            else {\n                this.desiredWidth = this.resizeStartWidth - (this.resizeDragger.mouseDistX * 2);\n            }\n\n            this.desiredHeight = this.resizeStartHeight + (this.resizeDragger.mouseDistY * 2);\n\n            this.updateSizeAndPosition();\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            if (this.$container) {\n                this.$container.removeData('modal').remove();\n            }\n\n            if (this.dragger) {\n                this.dragger.destroy();\n            }\n\n            if (this.resizeDragger) {\n                this.resizeDragger.destroy();\n            }\n\n            this.base();\n        }\n    },\n    {\n        relativeElemPadding: 8,\n        defaults: {\n            autoShow: true,\n            draggable: false,\n            dragHandleSelector: null,\n            resizable: false,\n            minGutter: 10,\n            onShow: $.noop,\n            onHide: $.noop,\n            onFadeIn: $.noop,\n            onFadeOut: $.noop,\n            closeOtherModals: false,\n            hideOnEsc: true,\n            hideOnShadeClick: true,\n            shadeClass: 'modal-shade'\n        },\n        instances: [],\n        visibleModal: null\n    }\n);\n","/** global: Garnish */\n/**\n * Nice Text\n */\nGarnish.NiceText = Garnish.Base.extend(\n    {\n        $input: null,\n        $hint: null,\n        $stage: null,\n        $charsLeft: null,\n        autoHeight: null,\n        maxLength: null,\n        showCharsLeft: false,\n        showingHint: false,\n        val: null,\n        inputBoxSizing: 'content-box',\n        width: null,\n        height: null,\n        minHeight: null,\n        initialized: false,\n\n        init: function(input, settings) {\n            this.$input = $(input);\n            this.settings = $.extend({}, Garnish.NiceText.defaults, settings);\n\n            if (this.isVisible()) {\n                this.initialize();\n            }\n            else {\n                this.addListener(Garnish.$win, 'resize', 'initializeIfVisible');\n            }\n        },\n\n        isVisible: function() {\n            return (this.$input.height() > 0);\n        },\n\n        initialize: function() {\n            if (this.initialized) {\n                return;\n            }\n\n            this.initialized = true;\n            this.removeListener(Garnish.$win, 'resize');\n\n            this.maxLength = this.$input.attr('maxlength');\n\n            if (this.maxLength) {\n                this.maxLength = parseInt(this.maxLength);\n            }\n\n            if (this.maxLength && (this.settings.showCharsLeft || Garnish.hasAttr(this.$input, 'data-show-chars-left'))) {\n                this.showCharsLeft = true;\n\n                // Remove the maxlength attribute\n                this.$input.removeAttr('maxlength');\n            }\n\n            // Is this already a transparent text input?\n            if (this.$input.data('nicetext')) {\n                Garnish.log('Double-instantiating a transparent text input on an element');\n                this.$input.data('nicetext').destroy();\n            }\n\n            this.$input.data('nicetext', this);\n\n            this.getVal();\n\n            this.autoHeight = (this.settings.autoHeight && this.$input.prop('nodeName') === 'TEXTAREA');\n\n            if (this.autoHeight) {\n                this.minHeight = this.getHeightForValue('');\n                this.updateHeight();\n\n                // Update height when the window resizes\n                this.width = this.$input.width();\n                this.addListener(Garnish.$win, 'resize', 'updateHeightIfWidthChanged');\n            }\n\n            if (this.settings.hint) {\n                this.$hintContainer = $('<div class=\"texthint-container\"/>').insertBefore(this.$input);\n                this.$hint = $('<div class=\"texthint\">' + this.settings.hint + '</div>').appendTo(this.$hintContainer);\n                this.$hint.css({\n                    top: (parseInt(this.$input.css('borderTopWidth')) + parseInt(this.$input.css('paddingTop'))),\n                    left: (parseInt(this.$input.css('borderLeftWidth')) + parseInt(this.$input.css('paddingLeft')) + 1)\n                });\n                Garnish.copyTextStyles(this.$input, this.$hint);\n\n                if (this.val) {\n                    this.$hint.hide();\n                }\n                else {\n                    this.showingHint = true;\n                }\n\n                // Focus the input when clicking on the hint\n                this.addListener(this.$hint, 'mousedown', function(ev) {\n                    ev.preventDefault();\n                    this.$input.focus();\n                });\n            }\n\n            if (this.showCharsLeft) {\n                this.$charsLeft = $('<div class=\"' + this.settings.charsLeftClass + '\"/>').insertAfter(this.$input);\n                this.updateCharsLeft();\n            }\n\n            this.addListener(this.$input, 'textchange', 'onTextChange');\n        },\n\n        initializeIfVisible: function() {\n            if (this.isVisible()) {\n                this.initialize();\n            }\n        },\n\n        getVal: function() {\n            this.val = this.$input.val();\n            return this.val;\n        },\n\n        showHint: function() {\n            this.$hint.velocity('fadeIn', {\n                complete: Garnish.NiceText.hintFadeDuration\n            });\n\n            this.showingHint = true;\n        },\n\n        hideHint: function() {\n            this.$hint.velocity('fadeOut', {\n                complete: Garnish.NiceText.hintFadeDuration\n            });\n\n            this.showingHint = false;\n        },\n\n        onTextChange: function() {\n            this.getVal();\n\n            if (this.$hint) {\n                if (this.showingHint && this.val) {\n                    this.hideHint();\n                }\n                else if (!this.showingHint && !this.val) {\n                    this.showHint();\n                }\n            }\n\n            if (this.autoHeight) {\n                this.updateHeight();\n            }\n\n            if (this.showCharsLeft) {\n                this.updateCharsLeft();\n            }\n        },\n\n        buildStage: function() {\n            this.$stage = $('<stage/>').appendTo(Garnish.$bod);\n\n            // replicate the textarea's text styles\n            this.$stage.css({\n                display: 'block',\n                position: 'absolute',\n                top: -9999,\n                left: -9999\n            });\n\n            this.inputBoxSizing = this.$input.css('box-sizing');\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.$stage.css({\n                    'border-top': this.$input.css('border-top'),\n                    'border-right': this.$input.css('border-right'),\n                    'border-bottom': this.$input.css('border-bottom'),\n                    'border-left': this.$input.css('border-left'),\n                    'padding-top': this.$input.css('padding-top'),\n                    'padding-right': this.$input.css('padding-right'),\n                    'padding-bottom': this.$input.css('padding-bottom'),\n                    'padding-left': this.$input.css('padding-left'),\n                    '-webkit-box-sizing': this.inputBoxSizing,\n                    '-moz-box-sizing': this.inputBoxSizing,\n                    'box-sizing': this.inputBoxSizing\n                });\n            }\n\n            Garnish.copyTextStyles(this.$input, this.$stage);\n        },\n\n        getHeightForValue: function(val) {\n            if (!this.$stage) {\n                this.buildStage();\n            }\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.$stage.css('width', this.$input.outerWidth());\n            }\n            else {\n                this.$stage.css('width', this.$input.width());\n            }\n\n            if (!val) {\n                val = '&nbsp;';\n                for (var i = 1; i < this.$input.prop('rows'); i++) {\n                    val += '<br/>&nbsp;';\n                }\n            }\n            else {\n                // Ampersand entities\n                val = val.replace(/&/g, '&amp;');\n\n                // < and >\n                val = val.replace(/</g, '&lt;');\n                val = val.replace(/>/g, '&gt;');\n\n                // Multiple spaces\n                val = val.replace(/ {2,}/g, function(spaces) {\n                    // TODO: replace with String.repeat() when more broadly available?\n                    var replace = '';\n                    for (var i = 0; i < spaces.length - 1; i++) {\n                        replace += '&nbsp;';\n                    }\n                    return replace + ' ';\n                });\n\n                // Line breaks\n                val = val.replace(/[\\n\\r]$/g, '<br/>&nbsp;');\n                val = val.replace(/[\\n\\r]/g, '<br/>');\n            }\n\n            this.$stage.html(val);\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.getHeightForValue._height = this.$stage.outerHeight();\n            }\n            else {\n                this.getHeightForValue._height = this.$stage.height();\n            }\n\n            if (this.minHeight && this.getHeightForValue._height < this.minHeight) {\n                this.getHeightForValue._height = this.minHeight;\n            }\n\n            return this.getHeightForValue._height;\n        },\n\n        updateHeight: function() {\n            // has the height changed?\n            if (this.height !== (this.height = this.getHeightForValue(this.val))) {\n                this.$input.css('min-height', this.height);\n\n                if (this.initialized) {\n                    this.onHeightChange();\n                }\n            }\n        },\n\n        updateHeightIfWidthChanged: function() {\n            if (this.isVisible() && this.width !== (this.width = this.$input.width()) && this.width) {\n                this.updateHeight();\n            }\n        },\n\n        onHeightChange: function() {\n            this.settings.onHeightChange();\n        },\n\n        updateCharsLeft: function() {\n            this.updateCharsLeft._charsLeft = this.maxLength - this.val.length;\n            this.$charsLeft.text(this.updateCharsLeft._charsLeft);\n\n            if (this.updateCharsLeft._charsLeft >= 0) {\n                this.$charsLeft.removeClass(this.settings.negativeCharsLeftClass);\n            }\n            else {\n                this.$charsLeft.addClass(this.settings.negativeCharsLeftClass);\n            }\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$input.removeData('nicetext');\n\n            if (this.$hint) {\n                this.$hint.remove();\n            }\n\n            if (this.$stage) {\n                this.$stage.remove();\n            }\n\n            this.base();\n        }\n    },\n    {\n        interval: 100,\n        hintFadeDuration: 50,\n        defaults: {\n            autoHeight: true,\n            showCharsLeft: false,\n            charsLeftClass: 'chars-left',\n            negativeCharsLeftClass: 'negative-chars-left',\n            onHeightChange: $.noop\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Pill\n */\nGarnish.Pill = Garnish.Base.extend(\n    {\n        $outerContainer: null,\n        $innerContainer: null,\n        $btns: null,\n        $selectedBtn: null,\n        $input: null,\n\n        init: function(outerContainer) {\n            this.$outerContainer = $(outerContainer);\n\n            // Is this already a pill?\n            if (this.$outerContainer.data('pill')) {\n                Garnish.log('Double-instantiating a pill on an element');\n                this.$outerContainer.data('pill').destroy();\n            }\n\n            this.$outerContainer.data('pill', this);\n\n            this.$innerContainer = this.$outerContainer.find('.btngroup:first');\n            this.$btns = this.$innerContainer.find('.btn');\n            this.$selectedBtn = this.$btns.filter('.active:first');\n            this.$input = this.$outerContainer.find('input:first');\n\n            Garnish.preventOutlineOnMouseFocus(this.$innerContainer);\n            this.addListener(this.$btns, 'mousedown', 'onMouseDown');\n            this.addListener(this.$innerContainer, 'keydown', 'onKeyDown');\n        },\n\n        select: function(btn) {\n            this.$selectedBtn.removeClass('active');\n            var $btn = $(btn);\n            $btn.addClass('active');\n            this.$input.val($btn.attr('data-value'));\n            this.$selectedBtn = $btn;\n        },\n\n        selectNext: function() {\n            if (!this.$selectedBtn.length) {\n                this.select(this.$btns[this.$btns.length - 1]);\n            }\n            else {\n                var nextIndex = this._getSelectedBtnIndex() + 1;\n\n                if (typeof this.$btns[nextIndex] !== 'undefined') {\n                    this.select(this.$btns[nextIndex]);\n                }\n            }\n        },\n\n        selectPrev: function() {\n            if (!this.$selectedBtn.length) {\n                this.select(this.$btns[0]);\n            }\n            else {\n                var prevIndex = this._getSelectedBtnIndex() - 1;\n\n                if (typeof this.$btns[prevIndex] !== 'undefined') {\n                    this.select(this.$btns[prevIndex]);\n                }\n            }\n        },\n\n        onMouseDown: function(ev) {\n            this.select(ev.currentTarget);\n        },\n\n        _getSelectedBtnIndex: function() {\n            if (typeof this.$selectedBtn[0] !== 'undefined') {\n                return $.inArray(this.$selectedBtn[0], this.$btns);\n            }\n            else {\n                return -1;\n            }\n        },\n\n        onKeyDown: function(ev) {\n            switch (ev.keyCode) {\n                case Garnish.RIGHT_KEY: {\n                    if (Garnish.ltr) {\n                        this.selectNext();\n                    }\n                    else {\n                        this.selectPrev();\n                    }\n\n                    ev.preventDefault();\n                    break;\n                }\n\n                case Garnish.LEFT_KEY: {\n                    if (Garnish.ltr) {\n                        this.selectPrev();\n                    }\n                    else {\n                        this.selectNext();\n                    }\n\n                    ev.preventDefault();\n                    break;\n                }\n            }\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$outerContainer.removeData('pill');\n            this.base();\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Select\n */\nGarnish.Select = Garnish.Base.extend(\n    {\n        $container: null,\n        $items: null,\n        $selectedItems: null,\n        $focusedItem: null,\n\n        mousedownTarget: null,\n        mouseUpTimeout: null,\n        callbackFrame: null,\n\n        $focusable: null,\n        $first: null,\n        first: null,\n        $last: null,\n        last: null,\n\n        /**\n         * Constructor\n         */\n        init: function(container, items, settings) {\n            this.$container = $(container);\n\n            // Param mapping\n            if (typeof items === 'undefined' && $.isPlainObject(container)) {\n                // (settings)\n                settings = container;\n                container = null;\n                items = null;\n            }\n            else if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (container, settings)\n                settings = items;\n                items = null;\n            }\n\n            // Is this already a select?\n            if (this.$container.data('select')) {\n                Garnish.log('Double-instantiating a select on an element');\n                this.$container.data('select').destroy();\n            }\n\n            this.$container.data('select', this);\n\n            this.setSettings(settings, Garnish.Select.defaults);\n\n            this.$items = $();\n            this.$selectedItems = $();\n\n            this.addItems(items);\n\n            // --------------------------------------------------------------------\n\n            if (this.settings.allowEmpty && !this.settings.checkboxMode) {\n                this.addListener(this.$container, 'click', function() {\n                    if (this.ignoreClick) {\n                        this.ignoreClick = false;\n                    }\n                    else {\n                        // Deselect all items on container click\n                        this.deselectAll(true);\n                    }\n                });\n            }\n        },\n\n        /**\n         * Get Item Index\n         */\n        getItemIndex: function($item) {\n            return this.$items.index($item[0]);\n        },\n\n        /**\n         * Is Selected?\n         */\n        isSelected: function(item) {\n            if (Garnish.isJquery(item)) {\n                if (!item[0]) {\n                    return false;\n                }\n\n                item = item[0];\n            }\n\n            return ($.inArray(item, this.$selectedItems) !== -1);\n        },\n\n        /**\n         * Select Item\n         */\n        selectItem: function($item, focus, preventScroll) {\n            if (!this.settings.multi) {\n                this.deselectAll();\n            }\n\n            this.$first = this.$last = $item;\n            this.first = this.last = this.getItemIndex($item);\n\n            if (focus) {\n                this.setFocusableItem($item);\n                this.focusItem($item, preventScroll);\n            }\n\n            this._selectItems($item);\n        },\n\n        selectAll: function() {\n            if (!this.settings.multi || !this.$items.length) {\n                return;\n            }\n\n            this.first = 0;\n            this.last = this.$items.length - 1;\n            this.$first = this.$items.eq(this.first);\n            this.$last = this.$items.eq(this.last);\n\n            this._selectItems(this.$items);\n        },\n\n        /**\n         * Select Range\n         */\n        selectRange: function($item, preventScroll) {\n            if (!this.settings.multi) {\n                return this.selectItem($item, true);\n            }\n\n            this.deselectAll();\n\n            this.$last = $item;\n            this.last = this.getItemIndex($item);\n\n            this.setFocusableItem($item);\n            this.focusItem($item, preventScroll);\n\n            // prepare params for $.slice()\n            var sliceFrom, sliceTo;\n\n            if (this.first < this.last) {\n                sliceFrom = this.first;\n                sliceTo = this.last + 1;\n            }\n            else {\n                sliceFrom = this.last;\n                sliceTo = this.first + 1;\n            }\n\n            this._selectItems(this.$items.slice(sliceFrom, sliceTo));\n        },\n\n        /**\n         * Deselect Item\n         */\n        deselectItem: function($item) {\n            var index = this.getItemIndex($item);\n            if (this.first === index) {\n                this.$first = this.first = null;\n            }\n            if (this.last === index) {\n                this.$last = this.last = null;\n            }\n\n            this._deselectItems($item);\n        },\n\n        /**\n         * Deselect All\n         */\n        deselectAll: function(clearFirst) {\n            if (clearFirst) {\n                this.$first = this.first = this.$last = this.last = null;\n            }\n\n            this._deselectItems(this.$items);\n        },\n\n        /**\n         * Deselect Others\n         */\n        deselectOthers: function($item) {\n            this.deselectAll();\n            this.selectItem($item, true);\n        },\n\n        /**\n         * Toggle Item\n         */\n        toggleItem: function($item, preventScroll) {\n            if (!this.isSelected($item)) {\n                this.selectItem($item, true, preventScroll);\n            }\n            else {\n                if (this._canDeselect($item)) {\n                    this.deselectItem($item, true);\n                }\n            }\n        },\n\n        clearMouseUpTimeout: function() {\n            clearTimeout(this.mouseUpTimeout);\n        },\n\n        getFirstItem: function() {\n            if (this.$items.length) {\n                return this.$items.first();\n            }\n        },\n\n        getLastItem: function() {\n            if (this.$items.length) {\n                return this.$items.last();\n            }\n        },\n\n        isPreviousItem: function(index) {\n            return (index > 0);\n        },\n\n        isNextItem: function(index) {\n            return (index < this.$items.length - 1);\n        },\n\n        getPreviousItem: function(index) {\n            if (this.isPreviousItem(index)) {\n                return this.$items.eq(index - 1);\n            }\n        },\n\n        getNextItem: function(index) {\n            if (this.isNextItem(index)) {\n                return this.$items.eq(index + 1);\n            }\n        },\n\n        getItemToTheLeft: function(index) {\n            var func = (Garnish.ltr ? 'Previous' : 'Next');\n\n            if (this['is' + func + 'Item'](index)) {\n                if (this.settings.horizontal) {\n                    return this['get' + func + 'Item'](index);\n                }\n                if (!this.settings.vertical) {\n                    return this.getClosestItem(index, Garnish.X_AXIS, '<');\n                }\n            }\n        },\n\n        getItemToTheRight: function(index) {\n            var func = (Garnish.ltr ? 'Next' : 'Previous');\n\n            if (this['is' + func + 'Item'](index)) {\n                if (this.settings.horizontal) {\n                    return this['get' + func + 'Item'](index);\n                }\n                else if (!this.settings.vertical) {\n                    return this.getClosestItem(index, Garnish.X_AXIS, '>');\n                }\n            }\n        },\n\n        getItemAbove: function(index) {\n            if (this.isPreviousItem(index)) {\n                if (this.settings.vertical) {\n                    return this.getPreviousItem(index);\n                }\n                else if (!this.settings.horizontal) {\n                    return this.getClosestItem(index, Garnish.Y_AXIS, '<');\n                }\n            }\n        },\n\n        getItemBelow: function(index) {\n            if (this.isNextItem(index)) {\n                if (this.settings.vertical) {\n                    return this.getNextItem(index);\n                }\n                else if (!this.settings.horizontal) {\n                    return this.getClosestItem(index, Garnish.Y_AXIS, '>');\n                }\n            }\n        },\n\n        getClosestItem: function(index, axis, dir) {\n            var axisProps = Garnish.Select.closestItemAxisProps[axis],\n                dirProps = Garnish.Select.closestItemDirectionProps[dir];\n\n            var $thisItem = this.$items.eq(index),\n                thisOffset = $thisItem.offset(),\n                thisMidpoint = thisOffset[axisProps.midpointOffset] + Math.round($thisItem[axisProps.midpointSizeFunc]() / 2),\n                otherRowPos = null,\n                smallestMidpointDiff = null,\n                $closestItem = null;\n\n            // Go the other way if this is the X axis and a RTL page\n            var step;\n\n            if (Garnish.rtl && axis === Garnish.X_AXIS) {\n                step = dirProps.step * -1;\n            }\n            else {\n                step = dirProps.step;\n            }\n\n            for (var i = index + step; (typeof this.$items[i] !== 'undefined'); i += step) {\n                var $otherItem = this.$items.eq(i),\n                    otherOffset = $otherItem.offset();\n\n                // Are we on the next row yet?\n                if (dirProps.isNextRow(otherOffset[axisProps.rowOffset], thisOffset[axisProps.rowOffset])) {\n                    // Is this the first time we've seen this row?\n                    if (otherRowPos === null) {\n                        otherRowPos = otherOffset[axisProps.rowOffset];\n                    }\n                    // Have we gone too far?\n                    else if (otherOffset[axisProps.rowOffset] !== otherRowPos) {\n                        break;\n                    }\n\n                    var otherMidpoint = otherOffset[axisProps.midpointOffset] + Math.round($otherItem[axisProps.midpointSizeFunc]() / 2),\n                        midpointDiff = Math.abs(thisMidpoint - otherMidpoint);\n\n                    // Are we getting warmer?\n                    if (smallestMidpointDiff === null || midpointDiff < smallestMidpointDiff) {\n                        smallestMidpointDiff = midpointDiff;\n                        $closestItem = $otherItem;\n                    }\n                    // Getting colder?\n                    else {\n                        break;\n                    }\n                }\n                // Getting colder?\n                else if (dirProps.isWrongDirection(otherOffset[axisProps.rowOffset], thisOffset[axisProps.rowOffset])) {\n                    break;\n                }\n            }\n\n            return $closestItem;\n        },\n\n        getFurthestItemToTheLeft: function(index) {\n            return this.getFurthestItem(index, 'ToTheLeft');\n        },\n\n        getFurthestItemToTheRight: function(index) {\n            return this.getFurthestItem(index, 'ToTheRight');\n        },\n\n        getFurthestItemAbove: function(index) {\n            return this.getFurthestItem(index, 'Above');\n        },\n\n        getFurthestItemBelow: function(index) {\n            return this.getFurthestItem(index, 'Below');\n        },\n\n        getFurthestItem: function(index, dir) {\n            var $item, $testItem;\n\n            while ($testItem = this['getItem' + dir](index)) {\n                $item = $testItem;\n                index = this.getItemIndex($item);\n            }\n\n            return $item;\n        },\n\n        /**\n         * totalSelected getter\n         */\n        get totalSelected() {\n            return this.getTotalSelected();\n        },\n\n        /**\n         * Get Total Selected\n         */\n        getTotalSelected: function() {\n            return this.$selectedItems.length;\n        },\n\n        /**\n         * Add Items\n         */\n        addItems: function(items) {\n            var $items = $(items);\n\n            for (var i = 0; i < $items.length; i++) {\n                var item = $items[i];\n\n                // Make sure this element doesn't belong to another selector\n                if ($.data(item, 'select')) {\n                    Garnish.log('Element was added to more than one selector');\n                    $.data(item, 'select').removeItems(item);\n                }\n\n                // Add the item\n                $.data(item, 'select', this);\n\n                // Get the handle\n                var $handle;\n\n                if (this.settings.handle) {\n                    if (typeof this.settings.handle === 'object') {\n                        $handle = $(this.settings.handle);\n                    }\n                    else if (typeof this.settings.handle === 'string') {\n                        $handle = $(item).find(this.settings.handle);\n                    }\n                    else if (typeof this.settings.handle === 'function') {\n                        $handle = $(this.settings.handle(item));\n                    }\n                }\n                else {\n                    $handle = $(item);\n                }\n\n                $.data(item, 'select-handle', $handle);\n                $handle.data('select-item', item);\n\n                this.addListener($handle, 'mousedown', 'onMouseDown');\n                this.addListener($handle, 'mouseup', 'onMouseUp');\n                this.addListener($handle, 'click', function() {\n                    this.ignoreClick = true;\n                });\n\n                this.addListener(item, 'keydown', 'onKeyDown');\n            }\n\n            this.$items = this.$items.add($items);\n            this.updateIndexes();\n        },\n\n        /**\n         * Remove Items\n         */\n        removeItems: function(items) {\n            items = $.makeArray(items);\n\n            var itemsChanged = false,\n                selectionChanged = false;\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure we actually know about this item\n                var index = $.inArray(item, this.$items);\n                if (index !== -1) {\n                    this._deinitItem(item);\n                    this.$items.splice(index, 1);\n                    itemsChanged = true;\n\n                    var selectedIndex = $.inArray(item, this.$selectedItems);\n                    if (selectedIndex !== -1) {\n                        this.$selectedItems.splice(selectedIndex, 1);\n                        selectionChanged = true;\n                    }\n                }\n            }\n\n            if (itemsChanged) {\n                this.updateIndexes();\n\n                if (selectionChanged) {\n                    $(items).removeClass(this.settings.selectedClass);\n                    this.onSelectionChange();\n                }\n            }\n        },\n\n        /**\n         * Remove All Items\n         */\n        removeAllItems: function() {\n            for (var i = 0; i < this.$items.length; i++) {\n                this._deinitItem(this.$items[i]);\n            }\n\n            this.$items = $();\n            this.$selectedItems = $();\n            this.updateIndexes();\n        },\n\n        /**\n         * Update First/Last indexes\n         */\n        updateIndexes: function() {\n            if (this.first !== null) {\n                this.first = this.getItemIndex(this.$first);\n                this.setFocusableItem(this.$first);\n            }\n            else if (this.$items.length) {\n                this.setFocusableItem($(this.$items[0]));\n            }\n\n            if (this.$focusedItem) {\n                this.setFocusableItem(this.$focusedItem);\n                this.focusItem(this.$focusedItem);\n            }\n\n            if (this.last !== null) {\n                this.last = this.getItemIndex(this.$last);\n            }\n        },\n\n        /**\n         * Reset Item Order\n         */\n        resetItemOrder: function() {\n            this.$items = $().add(this.$items);\n            this.$selectedItems = $().add(this.$selectedItems);\n            this.updateIndexes();\n        },\n\n        /**\n         * Sets the focusable item.\n         *\n         * We only want to have one focusable item per selection list, so that the user\n         * doesn't have to tab through a million items.\n         *\n         * @param {object} $item\n         */\n        setFocusableItem: function($item) {\n            if (this.$focusable) {\n                this.$focusable.removeAttr('tabindex');\n            }\n\n            this.$focusable = $item.attr('tabindex', '0');\n        },\n\n        /**\n         * Sets the focus on an item.\n         */\n        focusItem: function($item, preventScroll) {\n            if (preventScroll) {\n                var scrollLeft = Garnish.$doc.scrollLeft(),\n                    scrollTop = Garnish.$doc.scrollTop();\n                $item.focus();\n                window.scrollTo(scrollLeft, scrollTop);\n            }\n            else {\n                $item.focus();\n            }\n\n            this.$focusedItem = $item;\n            this.trigger('focusItem', {item: $item});\n        },\n\n        /**\n         * Get Selected Items\n         */\n        getSelectedItems: function() {\n            return this.$selectedItems;\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$container.removeData('select');\n            this.removeAllItems();\n            this.base();\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Mouse Down\n         */\n        onMouseDown: function(ev) {\n            // ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Enforce the filter\n            if (this.settings.filter && !$(ev.target).is(this.settings.filter)) {\n                return;\n            }\n\n            this.mousedownTarget = ev.currentTarget;\n\n            var $item = $($.data(ev.currentTarget, 'select-item'));\n\n            if (this.first !== null && ev.shiftKey) {\n                // Shift key is consistent for both selection modes\n                this.selectRange($item, true);\n            }\n            else if (this._actAsCheckbox(ev)) {\n                this.toggleItem($item, true);\n            }\n        },\n\n        /**\n         * On Mouse Up\n         */\n        onMouseUp: function(ev) {\n            // ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Enfore the filter\n            if (this.settings.filter && !$(ev.target).is(this.settings.filter)) {\n                return;\n            }\n\n            var $item = $($.data(ev.currentTarget, 'select-item'));\n\n            // was this a click?\n            if (\n                !this._actAsCheckbox(ev) && !ev.shiftKey &&\n                ev.currentTarget === this.mousedownTarget\n            ) {\n                // If this is already selected, wait a moment to see if this is a double click before making any rash decisions\n                if (this.isSelected($item)) {\n                    this.clearMouseUpTimeout();\n\n                    this.mouseUpTimeout = setTimeout($.proxy(function() {\n                        this.deselectOthers($item);\n                    }, this), 300);\n                }\n                else {\n                    this.deselectAll();\n                    this.selectItem($item, true, true);\n                }\n            }\n        },\n\n        /**\n         * On Key Down\n         */\n        onKeyDown: function(ev) {\n            // Ignore if the focus isn't on one of our items\n            if (ev.target !== ev.currentTarget) {\n                return;\n            }\n\n            var ctrlKey = Garnish.isCtrlKeyPressed(ev);\n            var shiftKey = ev.shiftKey;\n\n            var anchor, $item;\n\n            if (!this.settings.checkboxMode || !this.$focusable.length) {\n                anchor = ev.shiftKey ? this.last : this.first;\n            }\n            else {\n                anchor = $.inArray(this.$focusable[0], this.$items);\n\n                if (anchor === -1) {\n                    anchor = 0;\n                }\n            }\n\n            // Ok, what are we doing here?\n            switch (ev.keyCode) {\n                case Garnish.LEFT_KEY: {\n                    ev.preventDefault();\n\n                    // Select the last item if none are selected\n                    if (this.first === null) {\n                        if (Garnish.ltr) {\n                            $item = this.getLastItem();\n                        }\n                        else {\n                            $item = this.getFirstItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemToTheLeft(anchor);\n                        }\n                        else {\n                            $item = this.getItemToTheLeft(anchor);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.RIGHT_KEY: {\n                    ev.preventDefault();\n\n                    // Select the first item if none are selected\n                    if (this.first === null) {\n                        if (Garnish.ltr) {\n                            $item = this.getFirstItem();\n                        }\n                        else {\n                            $item = this.getLastItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemToTheRight(anchor);\n                        }\n                        else {\n                            $item = this.getItemToTheRight(anchor);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.UP_KEY: {\n                    ev.preventDefault();\n\n                    // Select the last item if none are selected\n                    if (this.first === null) {\n                        if (this.$focusable) {\n                            $item = this.$focusable.prev();\n                        }\n\n                        if (!this.$focusable || !$item.length) {\n                            $item = this.getLastItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemAbove(anchor);\n                        }\n                        else {\n                            $item = this.getItemAbove(anchor);\n                        }\n\n                        if (!$item) {\n                            $item = this.getFirstItem();\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.DOWN_KEY: {\n                    ev.preventDefault();\n\n                    // Select the first item if none are selected\n                    if (this.first === null) {\n                        if (this.$focusable) {\n                            $item = this.$focusable.next();\n                        }\n\n                        if (!this.$focusable || !$item.length) {\n                            $item = this.getFirstItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemBelow(anchor);\n                        }\n                        else {\n                            $item = this.getItemBelow(anchor);\n                        }\n\n                        if (!$item) {\n                            $item = this.getLastItem();\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.SPACE_KEY: {\n                    if (!ctrlKey && !shiftKey) {\n                        ev.preventDefault();\n\n                        if (this.isSelected(this.$focusable)) {\n                            if (this._canDeselect(this.$focusable)) {\n                                this.deselectItem(this.$focusable);\n                            }\n                        }\n                        else {\n                            this.selectItem(this.$focusable, true);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.A_KEY: {\n                    if (ctrlKey) {\n                        ev.preventDefault();\n                        this.selectAll();\n                    }\n\n                    break;\n                }\n            }\n\n            // Is there an item queued up for focus/selection?\n            if ($item && $item.length) {\n                if (!this.settings.checkboxMode) {\n                    // select it\n                    if (this.first !== null && ev.shiftKey) {\n                        this.selectRange($item);\n                    }\n                    else {\n                        this.deselectAll();\n                        this.selectItem($item, true);\n                    }\n                }\n                else {\n                    // just set the new item to be focusable\n                    this.setFocusableItem($item);\n                    $item.focus();\n                    this.$focusedItem = $item;\n                    this.trigger('focusItem', {item: $item});\n                }\n            }\n        },\n\n        /**\n         * Set Callback Timeout\n         */\n        onSelectionChange: function() {\n            if (this.callbackFrame) {\n                Garnish.cancelAnimationFrame(this.callbackFrame);\n                this.callbackFrame = null;\n            }\n\n            this.callbackFrame = Garnish.requestAnimationFrame($.proxy(function() {\n                this.callbackFrame = null;\n                this.trigger('selectionChange');\n                this.settings.onSelectionChange();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        _actAsCheckbox: function(ev) {\n            if (Garnish.isCtrlKeyPressed(ev)) {\n                return !this.settings.checkboxMode;\n            }\n            else {\n                return this.settings.checkboxMode;\n            }\n        },\n\n        _canDeselect: function($items) {\n            return (this.settings.allowEmpty || this.totalSelected > $items.length);\n        },\n\n        _selectItems: function($items) {\n            $items.addClass(this.settings.selectedClass);\n            this.$selectedItems = this.$selectedItems.add($items);\n            this.onSelectionChange();\n        },\n\n        _deselectItems: function($items) {\n            $items.removeClass(this.settings.selectedClass);\n            this.$selectedItems = this.$selectedItems.not($items);\n            this.onSelectionChange();\n        },\n\n        /**\n         * Deinitialize an item.\n         */\n        _deinitItem: function(item) {\n            var $handle = $.data(item, 'select-handle');\n\n            if ($handle) {\n                $handle.removeData('select-item');\n                this.removeAllListeners($handle);\n            }\n\n            $.removeData(item, 'select');\n            $.removeData(item, 'select-handle');\n\n            if (this.$focusedItem && this.$focusedItem[0] === item) {\n                this.$focusedItem = null;\n            }\n        }\n    },\n    {\n        defaults: {\n            selectedClass: 'sel',\n            multi: false,\n            allowEmpty: true,\n            vertical: false,\n            horizontal: false,\n            handle: null,\n            filter: null,\n            checkboxMode: false,\n            onSelectionChange: $.noop\n        },\n\n        closestItemAxisProps: {\n            x: {\n                midpointOffset: 'top',\n                midpointSizeFunc: 'outerHeight',\n                rowOffset: 'left'\n            },\n            y: {\n                midpointOffset: 'left',\n                midpointSizeFunc: 'outerWidth',\n                rowOffset: 'top'\n            }\n        },\n\n        closestItemDirectionProps: {\n            '<': {\n                step: -1,\n                isNextRow: function(a, b) {\n                    return (a < b);\n                },\n                isWrongDirection: function(a, b) {\n                    return (a > b);\n                }\n            },\n            '>': {\n                step: 1,\n                isNextRow: function(a, b) {\n                    return (a > b);\n                },\n                isWrongDirection: function(a, b) {\n                    return (a < b);\n                }\n            }\n        }\n    }\n);\n","/** global: Garnish */\n/**\n * Select Menu\n */\nGarnish.SelectMenu = Garnish.Menu.extend(\n    {\n        /**\n         * Constructor\n         */\n        init: function(btn, options, settings, callback) {\n            // argument mapping\n            if (typeof settings === 'function') {\n                // (btn, options, callback)\n                callback = settings;\n                settings = {};\n            }\n\n            settings = $.extend({}, Garnish.SelectMenu.defaults, settings);\n\n            this.base(btn, options, settings, callback);\n\n            this.selected = -1;\n        },\n\n        /**\n         * Build\n         */\n        build: function() {\n            this.base();\n\n            if (this.selected !== -1) {\n                this._addSelectedOptionClass(this.selected);\n            }\n        },\n\n        /**\n         * Select\n         */\n        select: function(option) {\n            // ignore if it's already selected\n            if (option === this.selected) {\n                return;\n            }\n\n            if (this.dom.ul) {\n                if (this.selected !== -1) {\n                    this.dom.options[this.selected].className = '';\n                }\n\n                this._addSelectedOptionClass(option);\n            }\n\n            this.selected = option;\n\n            // set the button text to the selected option\n            this.setBtnText($(this.options[option].label).text());\n\n            this.base(option);\n        },\n\n        /**\n         * Add Selected Option Class\n         */\n        _addSelectedOptionClass: function(option) {\n            this.dom.options[option].className = 'sel';\n        },\n\n        /**\n         * Set Button Text\n         */\n        setBtnText: function(text) {\n            this.dom.$btnLabel.text(text);\n        }\n\n    },\n    {\n        defaults: {\n            ulClass: 'menu select'\n        }\n    }\n);\n","/**\n * Garnish UI toolkit\n *\n * @copyright 2013 Pixel & Tonic, Inc.. All rights reserved.\n * @author    Brandon Kelly <brandon@pixelandtonic.com>\n * @version   0.1.29\n * @license   MIT\n */\n(function($){\n\n/*!\r\n\tBase.js, version 1.1a\r\n\tCopyright 2006-2010, Dean Edwards\r\n\tLicense: http://www.opensource.org/licenses/mit-license.php\r\n*/\r\n\r\nvar Base = function() {\r\n\t// dummy\r\n};\r\n\r\nBase.extend = function(_instance, _static) { // subclass\r\n\tvar extend = Base.prototype.extend;\r\n\r\n\t// build the prototype\r\n\tBase._prototyping = true;\r\n\tvar proto = new this;\r\n\textend.call(proto, _instance);\r\n\tproto.base = function() {\r\n\t\t// call this method from any other method to invoke that method's ancestor\r\n\t};\r\n\tdelete Base._prototyping;\r\n\r\n\t// create the wrapper for the constructor function\r\n\t//var constructor = proto.constructor.valueOf(); //-dean\r\n\tvar constructor = proto.constructor;\r\n\tvar klass = proto.constructor = function() {\r\n\t\tif (!Base._prototyping) {\r\n\t\t\tif (this._constructing || this.constructor == klass) { // instantiation\r\n\t\t\t\tthis._constructing = true;\r\n\t\t\t\tconstructor.apply(this, arguments);\r\n\t\t\t\tdelete this._constructing;\r\n\t\t\t} else if (arguments[0] != null) { // casting\r\n\t\t\t\treturn (arguments[0].extend || extend).call(arguments[0], proto);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\t// build the class interface\r\n\tklass.ancestor = this;\r\n\tklass.extend = this.extend;\r\n\tklass.forEach = this.forEach;\r\n\tklass.implement = this.implement;\r\n\tklass.prototype = proto;\r\n\tklass.toString = this.toString;\r\n\tklass.valueOf = function(type) {\r\n\t\t//return (type == \"object\") ? klass : constructor; //-dean\r\n\t\treturn (type == \"object\") ? klass : constructor.valueOf();\r\n\t};\r\n\textend.call(klass, _static);\r\n\t// class initialisation\r\n\tif (typeof klass.init == \"function\") klass.init();\r\n\treturn klass;\r\n};\r\n\r\nBase.prototype = {\r\n\textend: function(source, value) {\r\n\t\tif (arguments.length > 1) { // extending with a name/value pair\r\n\t\t\tvar ancestor = this[source];\r\n\t\t\tif (ancestor && (typeof value == \"function\") && // overriding a method?\r\n\t\t\t\t// the valueOf() comparison is to avoid circular references\r\n\t\t\t\t(!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) &&\r\n\t\t\t\t/\\bbase\\b/.test(value)) {\r\n\t\t\t\t// get the underlying method\r\n\t\t\t\tvar method = value.valueOf();\r\n\t\t\t\t// override\r\n\t\t\t\tvalue = function() {\r\n\t\t\t\t\tvar previous = this.base || Base.prototype.base;\r\n\t\t\t\t\tthis.base = ancestor;\r\n\t\t\t\t\tvar returnValue = method.apply(this, arguments);\r\n\t\t\t\t\tthis.base = previous;\r\n\t\t\t\t\treturn returnValue;\r\n\t\t\t\t};\r\n\t\t\t\t// point to the underlying method\r\n\t\t\t\tvalue.valueOf = function(type) {\r\n\t\t\t\t\treturn (type == \"object\") ? value : method;\r\n\t\t\t\t};\r\n\t\t\t\tvalue.toString = Base.toString;\r\n\t\t\t}\r\n\t\t\tthis[source] = value;\r\n\t\t} else if (source) { // extending with an object literal\r\n\t\t\tvar extend = Base.prototype.extend;\r\n\t\t\t// if this object has a customised extend method then use it\r\n\t\t\tif (!Base._prototyping && typeof this != \"function\") {\r\n\t\t\t\textend = this.extend || extend;\r\n\t\t\t}\r\n\t\t\tvar proto = {toSource: null};\r\n\t\t\t// do the \"toString\" and other methods manually\r\n\t\t\tvar hidden = [\"constructor\", \"toString\", \"valueOf\"];\r\n\t\t\t// if we are prototyping then include the constructor\r\n\t\t\tvar i = Base._prototyping ? 0 : 1;\r\n\t\t\twhile (key = hidden[i++]) {\r\n\t\t\t\tif (source[key] != proto[key]) {\r\n\t\t\t\t\textend.call(this, key, source[key]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// copy each of the source object's properties to this object\r\n\t\t\tfor (var key in source) {\r\n\t\t\t\tif (!proto[key]) {\r\n\t\t\t\t\tvar desc = Object.getOwnPropertyDescriptor(source, key);\r\n\t\t\t\t\tif (typeof desc.value != typeof undefined) {\r\n\t\t\t\t\t\t// set the value normally in case it's a function that needs to be overwritten\r\n\t\t\t\t\t\textend.call(this, key, desc.value);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// set it while maintaining the original descriptor settings\r\n\t\t\t\t\t\tObject.defineProperty(this, key, desc);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n};\r\n\r\n// initialise\r\nBase = Base.extend({\r\n\tconstructor: function() {\r\n\t\tthis.extend(arguments[0]);\r\n\t}\r\n}, {\r\n\tancestor: Object,\r\n\tversion: \"1.1\",\r\n\r\n\tforEach: function(object, block, context) {\r\n\t\tfor (var key in object) {\r\n\t\t\tif (this.prototype[key] === undefined) {\r\n\t\t\t\tblock.call(context, object[key], key, object);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\timplement: function() {\r\n\t\tfor (var i = 0; i < arguments.length; i++) {\r\n\t\t\tif (typeof arguments[i] == \"function\") {\r\n\t\t\t\t// if it's a function, call it\r\n\t\t\t\targuments[i](this.prototype);\r\n\t\t\t} else {\r\n\t\t\t\t// add the interface using the extend method\r\n\t\t\t\tthis.prototype.extend(arguments[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\ttoString: function() {\r\n\t\treturn String(this.valueOf());\r\n\t}\r\n});\r\n\n/**\n * @namespace Garnish\n */\n\n// Bail if Garnish is already defined\nif (typeof Garnish !== 'undefined') {\n    throw 'Garnish is already defined!';\n}\n\nGarnish = {\n\n    // jQuery objects for common elements\n    $win: $(window),\n    $doc: $(document),\n    $bod: $(document.body)\n\n};\n\nGarnish.rtl = Garnish.$bod.hasClass('rtl');\nGarnish.ltr = !Garnish.rtl;\n\nGarnish = $.extend(Garnish, {\n\n    $scrollContainer: Garnish.$win,\n\n    // Key code constants\n    DELETE_KEY: 8,\n    SHIFT_KEY: 16,\n    CTRL_KEY: 17,\n    ALT_KEY: 18,\n    RETURN_KEY: 13,\n    ESC_KEY: 27,\n    SPACE_KEY: 32,\n    LEFT_KEY: 37,\n    UP_KEY: 38,\n    RIGHT_KEY: 39,\n    DOWN_KEY: 40,\n    A_KEY: 65,\n    S_KEY: 83,\n    CMD_KEY: 91,\n\n    // Mouse button constants\n    PRIMARY_CLICK: 1,\n    SECONDARY_CLICK: 3,\n\n    // Axis constants\n    X_AXIS: 'x',\n    Y_AXIS: 'y',\n\n    FX_DURATION: 100,\n\n    // Node types\n    TEXT_NODE: 3,\n\n    /**\n     * Logs a message to the browser's console, if the browser has one.\n     *\n     * @param {string} msg\n     */\n    log: function(msg) {\n        if (typeof console !== 'undefined' && typeof console.log === 'function') {\n            console.log(msg);\n        }\n    },\n\n    _isMobileBrowser: null,\n    _isMobileOrTabletBrowser: null,\n\n    /**\n     * Returns whether this is a mobile browser.\n     * Detection script courtesy of http://detectmobilebrowsers.com\n     *\n     * Last updated: 2014-11-24\n     *\n     * @param {boolean} detectTablets\n     * @return {boolean}\n     */\n    isMobileBrowser: function(detectTablets) {\n        var key = detectTablets ? '_isMobileOrTabletBrowser' : '_isMobileBrowser';\n\n        if (Garnish[key] === null) {\n            var a = navigator.userAgent || navigator.vendor || window.opera;\n            Garnish[key] = ((new RegExp('(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino' + (detectTablets ? '|android|ipad|playbook|silk' : ''), 'i')).test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-/i.test(a.substr(0, 4)));\n        }\n\n        return Garnish[key];\n    },\n\n    /**\n     * Returns whether a variable is an array.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isArray: function(val) {\n        return (val instanceof Array);\n    },\n\n    /**\n     * Returns whether a variable is a jQuery collection.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isJquery: function(val) {\n        return (val instanceof jQuery);\n    },\n\n    /**\n     * Returns whether a variable is a string.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isString: function(val) {\n        return (typeof val === 'string');\n    },\n\n    /**\n     * Returns whether an element has an attribute.\n     *\n     * @see http://stackoverflow.com/questions/1318076/jquery-hasattr-checking-to-see-if-there-is-an-attribute-on-an-element/1318091#1318091\n     */\n    hasAttr: function(elem, attr) {\n        var val = $(elem).attr(attr);\n        return (typeof val !== 'undefined' && val !== false);\n    },\n\n    /**\n     * Returns whether something is a text node.\n     *\n     * @param {object} elem\n     * @return {boolean}\n     */\n    isTextNode: function(elem) {\n        return (elem.nodeType === Garnish.TEXT_NODE);\n    },\n\n    /**\n     * Returns the offset of an element within the scroll container, whether that's the window or something else\n     */\n    getOffset: function(elem) {\n        this.getOffset._offset = $(elem).offset();\n\n        if (Garnish.$scrollContainer[0] !== Garnish.$win[0]) {\n            this.getOffset._offset.top += Garnish.$scrollContainer.scrollTop();\n            this.getOffset._offset.left += Garnish.$scrollContainer.scrollLeft();\n        }\n\n        return this.getOffset._offset;\n    },\n\n    /**\n     * Returns the distance between two coordinates.\n     *\n     * @param {number} x1 The first coordinate's X position.\n     * @param {number} y1 The first coordinate's Y position.\n     * @param {number} x2 The second coordinate's X position.\n     * @param {number} y2 The second coordinate's Y position.\n     * @return {number}\n     */\n    getDist: function(x1, y1, x2, y2) {\n        return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));\n    },\n\n    /**\n     * Returns whether an element is touching an x/y coordinate.\n     *\n     * @param {number}    x    The coordinate's X position.\n     * @param {number}    y    The coordinate's Y position.\n     * @param {object} elem Either an actual element or a jQuery collection.\n     * @return {boolean}\n     */\n    hitTest: function(x, y, elem) {\n        Garnish.hitTest._$elem = $(elem);\n        Garnish.hitTest._offset = Garnish.hitTest._$elem.offset();\n        Garnish.hitTest._x1 = Garnish.hitTest._offset.left;\n        Garnish.hitTest._y1 = Garnish.hitTest._offset.top;\n        Garnish.hitTest._x2 = Garnish.hitTest._x1 + Garnish.hitTest._$elem.outerWidth();\n        Garnish.hitTest._y2 = Garnish.hitTest._y1 + Garnish.hitTest._$elem.outerHeight();\n\n        return (x >= Garnish.hitTest._x1 && x < Garnish.hitTest._x2 && y >= Garnish.hitTest._y1 && y < Garnish.hitTest._y2);\n    },\n\n    /**\n     * Returns whether the cursor is touching an element.\n     *\n     * @param {object} ev   The mouse event object containing pageX and pageY properties.\n     * @param {object} elem Either an actual element or a jQuery collection.\n     * @return {boolean}\n     */\n    isCursorOver: function(ev, elem) {\n        return Garnish.hitTest(ev.pageX, ev.pageY, elem);\n    },\n\n    /**\n     * Copies text styles from one element to another.\n     *\n     * @param {object} source The source element. Can be either an actual element or a jQuery collection.\n     * @param {object} target The target element. Can be either an actual element or a jQuery collection.\n     */\n    copyTextStyles: function(source, target) {\n        var $source = $(source),\n            $target = $(target);\n\n        $target.css({\n            fontFamily: $source.css('fontFamily'),\n            fontSize: $source.css('fontSize'),\n            fontWeight: $source.css('fontWeight'),\n            letterSpacing: $source.css('letterSpacing'),\n            lineHeight: $source.css('lineHeight'),\n            textAlign: $source.css('textAlign'),\n            textIndent: $source.css('textIndent'),\n            whiteSpace: $source.css('whiteSpace'),\n            wordSpacing: $source.css('wordSpacing'),\n            wordWrap: $source.css('wordWrap')\n        });\n    },\n\n    /**\n     * Returns the body's real scrollTop, discarding any window banding in Safari.\n     *\n     * @return {number}\n     */\n    getBodyScrollTop: function() {\n        Garnish.getBodyScrollTop._scrollTop = document.body.scrollTop;\n\n        if (Garnish.getBodyScrollTop._scrollTop < 0) {\n            Garnish.getBodyScrollTop._scrollTop = 0;\n        }\n        else {\n            Garnish.getBodyScrollTop._maxScrollTop = Garnish.$bod.outerHeight() - Garnish.$win.height();\n\n            if (Garnish.getBodyScrollTop._scrollTop > Garnish.getBodyScrollTop._maxScrollTop) {\n                Garnish.getBodyScrollTop._scrollTop = Garnish.getBodyScrollTop._maxScrollTop;\n            }\n        }\n\n        return Garnish.getBodyScrollTop._scrollTop;\n    },\n\n    requestAnimationFrame: (function() {\n            var raf = (\n                window.requestAnimationFrame ||\n                window.mozRequestAnimationFrame ||\n                window.webkitRequestAnimationFrame ||\n                function(fn) {\n                    return window.setTimeout(fn, 20);\n                }\n            );\n\n            return function(fn) {\n                return raf(fn);\n            };\n        })(),\n\n    cancelAnimationFrame: (function() {\n            var cancel = (\n                window.cancelAnimationFrame ||\n                window.mozCancelAnimationFrame ||\n                window.webkitCancelAnimationFrame ||\n                window.clearTimeout\n            );\n\n            return function(id) {\n                return cancel(id);\n            };\n        })(),\n\n    /**\n     * Scrolls a container element to an element within it.\n     *\n     * @param {object} container Either an actual element or a jQuery collection.\n     * @param {object} elem      Either an actual element or a jQuery collection.\n     */\n    scrollContainerToElement: function(container, elem) {\n        var $elem;\n\n        if (typeof elem === 'undefined') {\n            $elem = $(container);\n            $container = $elem.scrollParent();\n        }\n        else {\n            var $container = $(container);\n            $elem = $(elem);\n        }\n\n        if ($container.prop('nodeName') === 'HTML' || $container[0] === Garnish.$doc[0]) {\n            $container = Garnish.$win;\n        }\n\n        var scrollTop = $container.scrollTop(),\n            elemOffset = $elem.offset().top;\n\n        var elemScrollOffset;\n\n        if ($container[0] === window) {\n            elemScrollOffset = elemOffset - scrollTop;\n        }\n        else {\n            elemScrollOffset = elemOffset - $container.offset().top;\n        }\n\n        var targetScrollTop = false;\n\n        // Is the element above the fold?\n        if (elemScrollOffset < 0) {\n            targetScrollTop = scrollTop + elemScrollOffset - 10;\n        }\n        else {\n            var elemHeight = $elem.outerHeight(),\n                containerHeight = ($container[0] === window ? window.innerHeight : $container[0].clientHeight);\n\n            // Is it below the fold?\n            if (elemScrollOffset + elemHeight > containerHeight) {\n                targetScrollTop = scrollTop + (elemScrollOffset - (containerHeight - elemHeight)) + 10;\n            }\n        }\n\n        if (targetScrollTop !== false) {\n            // Velocity only allows you to scroll to an arbitrary position if you're scrolling the main window\n            if ($container[0] === window) {\n                $('html').velocity('scroll', {\n                    offset: targetScrollTop + 'px',\n                    mobileHA: false\n                });\n            }\n            else {\n                $container.scrollTop(targetScrollTop);\n            }\n        }\n    },\n\n    SHAKE_STEPS: 10,\n    SHAKE_STEP_DURATION: 25,\n\n    /**\n     * Shakes an element.\n     *\n     * @param {object}  elem Either an actual element or a jQuery collection.\n     * @param {string} prop The property that should be adjusted (default is 'margin-left').\n     */\n    shake: function(elem, prop) {\n        var $elem = $(elem);\n\n        if (!prop) {\n            prop = 'margin-left';\n        }\n\n        var startingPoint = parseInt($elem.css(prop));\n        if (isNaN(startingPoint)) {\n            startingPoint = 0;\n        }\n\n        for (var i = 0; i <= Garnish.SHAKE_STEPS; i++) {\n            (function(i) {\n                setTimeout(function() {\n                    Garnish.shake._properties = {};\n                    Garnish.shake._properties[prop] = startingPoint + (i % 2 ? -1 : 1) * (10 - i);\n                    $elem.velocity(Garnish.shake._properties, Garnish.SHAKE_STEP_DURATION);\n                }, (Garnish.SHAKE_STEP_DURATION * i));\n            })(i);\n        }\n    },\n\n    /**\n     * Returns the first element in an array or jQuery collection.\n     *\n     * @param {object} elem\n     * @return mixed\n     */\n    getElement: function(elem) {\n        return $.makeArray(elem)[0];\n    },\n\n    /**\n     * Returns the beginning of an input's name= attribute value with any [bracktes] stripped out.\n     *\n     * @param {object} elem\n     * @return string|null\n     */\n    getInputBasename: function(elem) {\n        var name = $(elem).attr('name');\n\n        if (name) {\n            return name.replace(/\\[.*/, '');\n        }\n        else {\n            return null;\n        }\n    },\n\n    /**\n     * Returns an input's value as it would be POSTed.\n     * So unchecked checkboxes and radio buttons return null,\n     * and multi-selects whose name don't end in \"[]\" only return the last selection\n     *\n     * @param {object} $input\n     * @return {(string|string[])}\n     */\n    getInputPostVal: function($input) {\n        var type = $input.attr('type'),\n            val = $input.val();\n\n        // Is this an unchecked checkbox or radio button?\n        if ((type === 'checkbox' || type === 'radio')) {\n            if ($input.prop('checked')) {\n                return val;\n            }\n            else {\n                return null;\n            }\n        }\n\n        // Flatten any array values whose input name doesn't end in \"[]\"\n        //  - e.g. a multi-select\n        else if (Garnish.isArray(val) && $input.attr('name').substr(-2) !== '[]') {\n            if (val.length) {\n                return val[val.length - 1];\n            }\n            else {\n                return null;\n            }\n        }\n\n        // Just return the value\n        else {\n            return val;\n        }\n    },\n\n    /**\n     * Returns the inputs within a container\n     *\n     * @param {object} container The container element. Can be either an actual element or a jQuery collection.\n     * @return {object}\n     */\n    findInputs: function(container) {\n        return $(container).find('input,text,textarea,select,button');\n    },\n\n    /**\n     * Returns the post data within a container.\n     *\n     * @param {object} container\n     * @return {array}\n     */\n    getPostData: function(container) {\n        var postData = {},\n            arrayInputCounters = {},\n            $inputs = Garnish.findInputs(container);\n\n        var inputName;\n\n        for (var i = 0; i < $inputs.length; i++) {\n            var $input = $inputs.eq(i);\n\n            if ($input.prop('disabled')) {\n                continue;\n            }\n\n            inputName = $input.attr('name');\n            if (!inputName) {\n                continue;\n            }\n\n            var inputVal = Garnish.getInputPostVal($input);\n            if (inputVal === null) {\n                continue;\n            }\n\n            var isArrayInput = (inputName.substr(-2) === '[]');\n\n            if (isArrayInput) {\n                // Get the cropped input name\n                var croppedName = inputName.substring(0, inputName.length - 2);\n\n                // Prep the input counter\n                if (typeof arrayInputCounters[croppedName] === 'undefined') {\n                    arrayInputCounters[croppedName] = 0;\n                }\n            }\n\n            if (!Garnish.isArray(inputVal)) {\n                inputVal = [inputVal];\n            }\n\n            for (var j = 0; j < inputVal.length; j++) {\n                if (isArrayInput) {\n                    inputName = croppedName + '[' + arrayInputCounters[croppedName] + ']';\n                    arrayInputCounters[croppedName]++;\n                }\n\n                postData[inputName] = inputVal[j];\n            }\n        }\n\n        return postData;\n    },\n\n    copyInputValues: function(source, target) {\n        var $sourceInputs = Garnish.findInputs(source),\n            $targetInputs = Garnish.findInputs(target);\n\n        for (var i = 0; i < $sourceInputs.length; i++) {\n            if (typeof $targetInputs[i] === 'undefined') {\n                break;\n            }\n\n            $targetInputs.eq(i).val(\n                $sourceInputs.eq(i).val()\n            );\n        }\n    },\n\n    /**\n     * Returns whether the \"Ctrl\" key is pressed (or ⌘ if this is a Mac) for a given keyboard event\n     *\n     * @param ev The keyboard event\n     *\n     * @return {boolean} Whether the \"Ctrl\" key is pressed\n     */\n    isCtrlKeyPressed: function(ev) {\n        if (window.navigator.platform.match(/Mac/)) {\n            // metaKey maps to ⌘ on Macs\n            return ev.metaKey;\n        }\n        else {\n            // Both altKey and ctrlKey == true on some Windows keyboards when the right-hand ALT key is pressed\n            // so just be safe and make sure altKey == false\n            return (ev.ctrlKey && !ev.altKey);\n        }\n    },\n\n    _eventHandlers: [],\n\n    _normalizeEvents: function(events) {\n        if (typeof events === 'string') {\n            events = events.split(' ');\n        }\n\n        for (var i = 0; i < events.length; i++) {\n            if (typeof events[i] === 'string') {\n                events[i] = events[i].split('.');\n            }\n        }\n\n        return events;\n    },\n\n    on: function(target, events, data, handler) {\n        if (typeof data === 'function') {\n            handler = data;\n            data = {};\n        }\n\n        events = this._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n            this._eventHandlers.push({\n                target: target,\n                type: ev[0],\n                namespace: ev[1],\n                data: data,\n                handler: handler\n            });\n        }\n    },\n\n    off: function(target, events, handler) {\n        events = this._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n\n            for (var j = this._eventHandlers.length - 1; j >= 0; j--) {\n                var eventHandler = this._eventHandlers[j];\n\n                if (\n                    eventHandler.target === target &&\n                    eventHandler.type === ev[0] &&\n                    (!ev[1] || eventHandler.namespace === ev[1]) &&\n                    eventHandler.handler === handler\n                ) {\n                    this._eventHandlers.splice(j, 1);\n                }\n            }\n        }\n    }\n});\n\n\n/**\n * Garnish base class\n */\nGarnish.Base = Base.extend({\n\n    settings: null,\n\n    _eventHandlers: null,\n    _namespace: null,\n    _$listeners: null,\n    _disabled: false,\n\n    constructor: function() {\n        this._eventHandlers = [];\n        this._namespace = '.Garnish' + Math.floor(Math.random() * 1000000000);\n        this._listeners = [];\n        this.init.apply(this, arguments);\n    },\n\n    init: $.noop,\n\n    setSettings: function(settings, defaults) {\n        var baseSettings = (typeof this.settings === 'undefined' ? {} : this.settings);\n        this.settings = $.extend({}, baseSettings, defaults, settings);\n    },\n\n    on: function(events, data, handler) {\n        if (typeof data === 'function') {\n            handler = data;\n            data = {};\n        }\n\n        events = Garnish._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n            this._eventHandlers.push({\n                type: ev[0],\n                namespace: ev[1],\n                data: data,\n                handler: handler\n            });\n        }\n    },\n\n    off: function(events, handler) {\n        events = Garnish._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n\n            for (var j = this._eventHandlers.length - 1; j >= 0; j--) {\n                var eventHandler = this._eventHandlers[j];\n\n                if (\n                    eventHandler.type === ev[0] &&\n                    (!ev[1] || eventHandler.namespace === ev[1]) &&\n                    eventHandler.handler === handler\n                ) {\n                    this._eventHandlers.splice(j, 1);\n                }\n            }\n        }\n    },\n\n    trigger: function(type, data) {\n        var ev = {\n            type: type,\n            target: this\n        };\n\n        // instance level event handlers\n        var i, handler, _ev;\n        for (i = 0; i < this._eventHandlers.length; i++) {\n            handler = this._eventHandlers[i];\n\n            if (handler.type === type) {\n                _ev = $.extend({data: handler.data}, data, ev);\n                handler.handler(_ev);\n            }\n        }\n\n        // class level event handlers\n        for (i = 0; i < Garnish._eventHandlers.length; i++) {\n            handler = Garnish._eventHandlers[i];\n\n            if (this instanceof handler.target && handler.type === type) {\n                _ev = $.extend({data: handler.data}, data, ev);\n                handler.handler(_ev);\n            }\n        }\n    },\n\n    _splitEvents: function(events) {\n        if (typeof events === 'string') {\n            events = events.split(',');\n\n            for (var i = 0; i < events.length; i++) {\n                events[i] = $.trim(events[i]);\n            }\n        }\n\n        return events;\n    },\n\n    _formatEvents: function(events) {\n        events = this._splitEvents(events).slice(0);\n\n        for (var i = 0; i < events.length; i++) {\n            events[i] += this._namespace;\n        }\n\n        return events.join(' ');\n    },\n\n    addListener: function(elem, events, data, func) {\n        var $elem = $(elem);\n\n        // Ignore if there aren't any elements\n        if (!$elem.length) {\n            return;\n        }\n\n        events = this._splitEvents(events);\n\n        // Param mapping\n        if (typeof func === 'undefined' && typeof data !== 'object') {\n            // (elem, events, func)\n            func = data;\n            data = {};\n        }\n\n        if (typeof func === 'function') {\n            func = $.proxy(func, this);\n        }\n        else {\n            func = $.proxy(this, func);\n        }\n\n        $elem.on(this._formatEvents(events), data, $.proxy(function() {\n            if (!this._disabled) {\n                return func.apply(this, arguments);\n            }\n        }, this));\n\n        // Remember that we're listening to this element\n        if ($.inArray(elem, this._listeners) === -1) {\n            this._listeners.push(elem);\n        }\n    },\n\n    removeListener: function(elem, events) {\n        $(elem).off(this._formatEvents(events));\n    },\n\n    removeAllListeners: function(elem) {\n        $(elem).off(this._namespace);\n    },\n\n    disable: function() {\n        this._disabled = true;\n    },\n\n    enable: function() {\n        this._disabled = false;\n    },\n\n    destroy: function() {\n        this.trigger('destroy');\n        this.removeAllListeners(this._listeners);\n    }\n});\n\n// Custom events\n// -----------------------------------------------------------------------------\n\nvar erd;\n\nfunction getErd() {\n    if (typeof erd === 'undefined') {\n        erd = elementResizeDetectorMaker({\n            callOnAdd: false\n        });\n    }\n\n    return erd;\n}\n\nfunction triggerResizeEvent(elem) {\n    $(elem).trigger('resize');\n}\n\n// Work them into jQuery's event system\n$.extend(jQuery.event.special, {\n    activate: {\n        setup: function(data, namespaces, eventHandle) {\n            var activateNamespace = this._namespace + '-activate';\n            var $elem = $(this);\n\n            $elem.on({\n                'mousedown.garnish-activate': function(e) {\n                    // Prevent buttons from getting focus on click\n                    e.preventDefault();\n                },\n                'click.garnish-activate': function(e) {\n                    e.preventDefault();\n\n                    if (!$elem.hasClass('disabled')) {\n                        $elem.trigger('activate');\n                    }\n                },\n                'keydown.garnish-activate': function(e) {\n                    // Ignore if the event was bubbled up, or if it wasn't the space key\n                    if (this !== $elem[0] || e.keyCode !== Garnish.SPACE_KEY) {\n                        return;\n                    }\n\n                    e.preventDefault();\n\n                    if (!$elem.hasClass('disabled')) {\n                        $elem.addClass('active');\n\n                        Garnish.$doc.on('keyup.garnish-activate', function(e) {\n                            $elem.removeClass('active');\n\n                            if (e.keyCode === Garnish.SPACE_KEY) {\n                                e.preventDefault();\n                                $elem.trigger('activate');\n                            }\n\n                            Garnish.$doc.off('keyup.garnish-activate');\n                        });\n                    }\n                }\n            });\n\n            if (!$elem.hasClass('disabled')) {\n                $elem.attr('tabindex', '0');\n            } else {\n                $elem.removeAttr('tabindex');\n            }\n        },\n        teardown: function() {\n            $(this).off('.garnish-activate');\n        }\n    },\n\n    textchange: {\n        setup: function(data, namespaces, eventHandle) {\n            var $elem = $(this);\n            $elem.data('garnish-textchange-value', $elem.val());\n            $elem.on('keypress.garnish-textchange keyup.garnish-textchange change.garnish-textchange blur.garnish-textchange', function(e) {\n                var val = $elem.val();\n                if (val !== $elem.data('garnish-textchange-value')) {\n                    $elem.data('garnish-textchange-value', val);\n                    $elem.trigger('textchange');\n                }\n            });\n        },\n        teardown: function() {\n            $(this).off('.garnish-textchange');\n        },\n        handle: function(ev, data) {\n            var el = this;\n            var args = arguments;\n            var delay = data && typeof data.delay !== 'undefined' ? data.delay : (ev.data && ev.data.delay !== undefined ? ev.data.delay : null);\n            var handleObj = ev.handleObj;\n            var targetData = $.data(ev.target);\n\n            // Was this event configured with a delay?\n            if (delay) {\n                if (targetData.delayTimeout) {\n                    clearTimeout(targetData.delayTimeout);\n                }\n\n                targetData.delayTimeout = setTimeout(function() {\n                    handleObj.handler.apply(el, args);\n                }, delay);\n            } else {\n                return handleObj.handler.apply(el, args);\n            }\n        }\n    },\n\n    resize: {\n        setup: function(data, namespaces, eventHandle) {\n            // window is the only element that natively supports a resize event\n            if (this === window) {\n                return false;\n            }\n\n            $('> :last-child', this).addClass('last');\n            getErd().listenTo(this, triggerResizeEvent)\n        },\n        teardown: function() {\n            if (this === window) {\n                return false;\n            }\n\n            getErd().removeListener(this, triggerResizeEvent);\n        }\n    }\n});\n\n// Give them their own element collection chaining methods\njQuery.each(['activate', 'textchange', 'resize'], function(i, name) {\n    jQuery.fn[name] = function(data, fn) {\n        return arguments.length > 0 ?\n            this.on(name, null, data, fn) :\n            this.trigger(name);\n    };\n});\n\n/** global: Garnish */\n/**\n * Base drag class\n *\n * Does all the grunt work for manipulating elements via click-and-drag,\n * while leaving the actual element manipulation up to a subclass.\n */\nGarnish.BaseDrag = Garnish.Base.extend(\n    {\n        $items: null,\n\n        dragging: false,\n\n        mousedownX: null,\n        mousedownY: null,\n        realMouseX: null,\n        realMouseY: null,\n        mouseX: null,\n        mouseY: null,\n        mouseDistX: null,\n        mouseDistY: null,\n        mouseOffsetX: null,\n        mouseOffsetY: null,\n\n        $targetItem: null,\n\n        scrollProperty: null,\n        scrollAxis: null,\n        scrollDist: null,\n        scrollProxy: null,\n        scrollFrame: null,\n\n        _: null,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            this.settings = $.extend({}, Garnish.BaseDrag.defaults, settings);\n\n            this.$items = $();\n            this._ = {};\n\n            if (items) {\n                this.addItems(items);\n            }\n        },\n\n        /**\n         * Returns whether dragging is allowed right now.\n         */\n        allowDragging: function() {\n            return true;\n        },\n\n        /**\n         * Start Dragging\n         */\n        startDragging: function() {\n            this.dragging = true;\n            this.onDragStart();\n        },\n\n        /**\n         * Drag\n         */\n        drag: function(didMouseMove) {\n            if (didMouseMove) {\n                // Is the mouse up against one of the window edges?\n                this.drag._scrollProperty = null;\n\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    // Scrolling up?\n                    this.drag._winScrollTop = Garnish.$win.scrollTop();\n                    this.drag._minMouseScrollY = this.drag._winScrollTop + Garnish.BaseDrag.windowScrollTargetSize;\n\n                    if (this.mouseY < this.drag._minMouseScrollY) {\n                        this.drag._scrollProperty = 'scrollTop';\n                        this.drag._scrollAxis = 'Y';\n                        this.drag._scrollDist = Math.round((this.mouseY - this.drag._minMouseScrollY) / 2);\n                    }\n                    else {\n                        // Scrolling down?\n                        this.drag._maxMouseScrollY = this.drag._winScrollTop + Garnish.$win.height() - Garnish.BaseDrag.windowScrollTargetSize;\n\n                        if (this.mouseY > this.drag._maxMouseScrollY) {\n                            this.drag._scrollProperty = 'scrollTop';\n                            this.drag._scrollAxis = 'Y';\n                            this.drag._scrollDist = Math.round((this.mouseY - this.drag._maxMouseScrollY) / 2);\n                        }\n                    }\n                }\n\n                if (!this.drag._scrollProperty && this.settings.axis !== Garnish.Y_AXIS) {\n                    // Scrolling left?\n                    this.drag._winScrollLeft = Garnish.$win.scrollLeft();\n                    this.drag._minMouseScrollX = this.drag._winScrollLeft + Garnish.BaseDrag.windowScrollTargetSize;\n\n                    if (this.mouseX < this.drag._minMouseScrollX) {\n                        this.drag._scrollProperty = 'scrollLeft';\n                        this.drag._scrollAxis = 'X';\n                        this.drag._scrollDist = Math.round((this.mouseX - this.drag._minMouseScrollX) / 2);\n                    }\n                    else {\n                        // Scrolling right?\n                        this.drag._maxMouseScrollX = this.drag._winScrollLeft + Garnish.$win.width() - Garnish.BaseDrag.windowScrollTargetSize;\n\n                        if (this.mouseX > this.drag._maxMouseScrollX) {\n                            this.drag._scrollProperty = 'scrollLeft';\n                            this.drag._scrollAxis = 'X';\n                            this.drag._scrollDist = Math.round((this.mouseX - this.drag._maxMouseScrollX) / 2);\n                        }\n                    }\n                }\n\n                if (this.drag._scrollProperty) {\n                    // Are we starting to scroll now?\n                    if (!this.scrollProperty) {\n                        if (!this.scrollProxy) {\n                            this.scrollProxy = $.proxy(this, '_scrollWindow');\n                        }\n\n                        if (this.scrollFrame) {\n                            Garnish.cancelAnimationFrame(this.scrollFrame);\n                            this.scrollFrame = null;\n                        }\n\n                        this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);\n                    }\n\n                    this.scrollProperty = this.drag._scrollProperty;\n                    this.scrollAxis = this.drag._scrollAxis;\n                    this.scrollDist = this.drag._scrollDist;\n                }\n                else {\n                    this._cancelWindowScroll();\n                }\n            }\n\n            this.onDrag();\n        },\n\n        /**\n         * Stop Dragging\n         */\n        stopDragging: function() {\n            this.dragging = false;\n            this.onDragStop();\n\n            // Clear the scroll animation\n            this._cancelWindowScroll();\n        },\n\n        /**\n         * Add Items\n         *\n         * @param {object} items Elements that should be draggable.\n         */\n        addItems: function(items) {\n            items = $.makeArray(items);\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure this element doesn't belong to another dragger\n                if ($.data(item, 'drag')) {\n                    Garnish.log('Element was added to more than one dragger');\n                    $.data(item, 'drag').removeItems(item);\n                }\n\n                // Add the item\n                $.data(item, 'drag', this);\n\n                // Add the listener\n                this.addListener(item, 'mousedown', '_handleMouseDown');\n            }\n\n            this.$items = this.$items.add(items);\n        },\n\n        /**\n         * Remove Items\n         *\n         * @param {object} items Elements that should no longer be draggable.\n         */\n        removeItems: function(items) {\n            items = $.makeArray(items);\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure we actually know about this item\n                var index = $.inArray(item, this.$items);\n                if (index !== -1) {\n                    this._deinitItem(item);\n                    this.$items.splice(index, 1);\n                }\n            }\n        },\n\n        /**\n         * Remove All Items\n         */\n        removeAllItems: function() {\n            for (var i = 0; i < this.$items.length; i++) {\n                this._deinitItem(this.$items[i]);\n            }\n\n            this.$items = $();\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.removeAllItems();\n            this.base();\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('dragStart');\n                this.settings.onDragStart();\n            }, this));\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('drag');\n                this.settings.onDrag();\n            }, this));\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('dragStop');\n                this.settings.onDragStop();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        /**\n         * Handle Mouse Down\n         */\n        _handleMouseDown: function(ev) {\n            // Ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Ignore if we already have a target\n            if (this.$targetItem) {\n                return;\n            }\n\n            // Ignore if they didn't actually click on the handle\n            var $target = $(ev.target),\n                $handle = this._getItemHandle(ev.currentTarget);\n\n            if (!$target.is($handle) && !$target.closest($handle).length) {\n                return;\n            }\n\n            // Make sure the target isn't a button (unless the button is the handle)\n            if (ev.currentTarget !== ev.target && this.settings.ignoreHandleSelector) {\n                if (\n                    $target.is(this.settings.ignoreHandleSelector) ||\n                    $target.closest(this.settings.ignoreHandleSelector).length\n                ) {\n                    return;\n                }\n            }\n\n            ev.preventDefault();\n\n            // Make sure that dragging is allowed right now\n            if (!this.allowDragging()) {\n                return;\n            }\n\n            // Capture the target\n            this.$targetItem = $(ev.currentTarget);\n\n            // Capture the current mouse position\n            this.mousedownX = this.mouseX = ev.pageX;\n            this.mousedownY = this.mouseY = ev.pageY;\n\n            // Capture the difference between the mouse position and the target item's offset\n            var offset = this.$targetItem.offset();\n            this.mouseOffsetX = ev.pageX - offset.left;\n            this.mouseOffsetY = ev.pageY - offset.top;\n\n            // Listen for mousemove, mouseup\n            this.addListener(Garnish.$doc, 'mousemove', '_handleMouseMove');\n            this.addListener(Garnish.$doc, 'mouseup', '_handleMouseUp');\n        },\n\n        _getItemHandle: function(item) {\n            if (this.settings.handle) {\n                if (typeof this.settings.handle === 'object') {\n                    return $(this.settings.handle);\n                }\n\n                if (typeof this.settings.handle === 'string') {\n                    return $(this.settings.handle, item);\n                }\n\n                if (typeof this.settings.handle === 'function') {\n                    return $(this.settings.handle(item));\n                }\n            }\n\n            return $(item);\n        },\n\n        /**\n         * Handle Mouse Move\n         */\n        _handleMouseMove: function(ev) {\n            ev.preventDefault();\n\n            this.realMouseX = ev.pageX;\n            this.realMouseY = ev.pageY;\n\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this.mouseX = ev.pageX;\n            }\n\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this.mouseY = ev.pageY;\n            }\n\n            this.mouseDistX = this.mouseX - this.mousedownX;\n            this.mouseDistY = this.mouseY - this.mousedownY;\n\n            if (!this.dragging) {\n                // Has the mouse moved far enough to initiate dragging yet?\n                this._handleMouseMove._mouseDist = Garnish.getDist(this.mousedownX, this.mousedownY, this.realMouseX, this.realMouseY);\n\n                if (this._handleMouseMove._mouseDist >= Garnish.BaseDrag.minMouseDist) {\n                    this.startDragging();\n                }\n            }\n\n            if (this.dragging) {\n                this.drag(true);\n            }\n        },\n\n        /**\n         * Handle Moues Up\n         */\n        _handleMouseUp: function(ev) {\n            // Unbind the document events\n            this.removeAllListeners(Garnish.$doc);\n\n            if (this.dragging) {\n                this.stopDragging();\n            }\n\n            this.$targetItem = null;\n        },\n\n        /**\n         * Scroll Window\n         */\n        _scrollWindow: function() {\n            this._.scrollPos = Garnish.$scrollContainer[this.scrollProperty]();\n            Garnish.$scrollContainer[this.scrollProperty](this._.scrollPos + this.scrollDist);\n\n            this['mouse' + this.scrollAxis] -= this._.scrollPos - Garnish.$scrollContainer[this.scrollProperty]();\n            this['realMouse' + this.scrollAxis] = this['mouse' + this.scrollAxis];\n\n            this.drag();\n\n            this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);\n        },\n\n        /**\n         * Cancel Window Scroll\n         */\n        _cancelWindowScroll: function() {\n            if (this.scrollFrame) {\n                Garnish.cancelAnimationFrame(this.scrollFrame);\n                this.scrollFrame = null;\n            }\n\n            this.scrollProperty = null;\n            this.scrollAxis = null;\n            this.scrollDist = null;\n        },\n\n        /**\n         * Deinitialize an item.\n         */\n        _deinitItem: function(item) {\n            this.removeAllListeners(item);\n            $.removeData(item, 'drag');\n        }\n    },\n    {\n        minMouseDist: 1,\n        windowScrollTargetSize: 25,\n\n        defaults: {\n            handle: null,\n            axis: null,\n            ignoreHandleSelector: 'input, textarea, button, select, .btn',\n\n            onDragStart: $.noop,\n            onDrag: $.noop,\n            onDragStop: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Checkbox select class\n */\nGarnish.CheckboxSelect = Garnish.Base.extend(\n    {\n        $container: null,\n        $all: null,\n        $options: null,\n\n        init: function(container) {\n            this.$container = $(container);\n\n            // Is this already a checkbox select?\n            if (this.$container.data('checkboxSelect')) {\n                Garnish.log('Double-instantiating a checkbox select on an element');\n                this.$container.data('checkbox-select').destroy();\n            }\n\n            this.$container.data('checkboxSelect', this);\n\n            var $checkboxes = this.$container.find('input');\n            this.$all = $checkboxes.filter('.all:first');\n            this.$options = $checkboxes.not(this.$all);\n\n            this.addListener(this.$all, 'change', 'onAllChange');\n        },\n\n        onAllChange: function() {\n            var isAllChecked = this.$all.prop('checked');\n\n            this.$options.prop({\n                checked: isAllChecked,\n                disabled: isAllChecked\n            });\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$container.removeData('checkboxSelect');\n            this.base();\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Context Menu\n */\nGarnish.ContextMenu = Garnish.Base.extend(\n    {\n        $target: null,\n        options: null,\n        $menu: null,\n        showingMenu: false,\n\n        /**\n         * Constructor\n         */\n        init: function(target, options, settings) {\n            this.$target = $(target);\n\n            // Is this already a context menu target?\n            if (this.$target.data('contextmenu')) {\n                Garnish.log('Double-instantiating a context menu on an element');\n                this.$target.data('contextmenu').destroy();\n            }\n\n            this.$target.data('contextmenu', this);\n\n            this.options = options;\n            this.setSettings(settings, Garnish.ContextMenu.defaults);\n\n            Garnish.ContextMenu.counter++;\n\n            this.enable();\n        },\n\n        /**\n         * Build Menu\n         */\n        buildMenu: function() {\n            this.$menu = $('<div class=\"' + this.settings.menuClass + '\" style=\"display: none\" />');\n\n            var $ul = $('<ul/>').appendTo(this.$menu);\n\n            for (var i in this.options) {\n                if (!this.options.hasOwnProperty(i)) {\n                    continue;\n                }\n\n                var option = this.options[i];\n\n                if (option === '-') {\n                    // Create a new <ul>\n                    $('<hr/>').appendTo(this.$menu);\n                    $ul = $('<ul/>').appendTo(this.$menu);\n                }\n                else {\n                    var $li = $('<li></li>').appendTo($ul),\n                        $a = $('<a>' + option.label + '</a>').appendTo($li);\n\n                    if (typeof option.onClick === 'function') {\n                        // maintain the current $a and options.onClick variables\n                        (function($a, onClick) {\n                            setTimeout($.proxy(function() {\n                                $a.mousedown($.proxy(function(ev) {\n                                    this.hideMenu();\n                                    // call the onClick callback, with the scope set to the item,\n                                    // and pass it the event with currentTarget set to the item as well\n                                    onClick.call(this.currentTarget, $.extend(ev, {currentTarget: this.currentTarget}));\n                                }, this));\n                            }, this), 1);\n                        }).call(this, $a, option.onClick);\n                    }\n                }\n            }\n        },\n\n        /**\n         * Show Menu\n         */\n        showMenu: function(ev) {\n            // Ignore left mouse clicks\n            if (ev.type === 'mousedown' && ev.which !== Garnish.SECONDARY_CLICK) {\n                return;\n            }\n\n            if (ev.type === 'contextmenu') {\n                // Prevent the real context menu from showing\n                ev.preventDefault();\n            }\n\n            // Ignore if already showing\n            if (this.showing && ev.currentTarget === this.currentTarget) {\n                return;\n            }\n\n            this.currentTarget = ev.currentTarget;\n\n            if (!this.$menu) {\n                this.buildMenu();\n            }\n\n            this.$menu.appendTo(document.body);\n            this.$menu.show();\n            this.$menu.css({left: ev.pageX + 1, top: ev.pageY - 4});\n\n            this.showing = true;\n\n            setTimeout($.proxy(function() {\n                this.addListener(Garnish.$doc, 'mousedown', 'hideMenu');\n            }, this), 0);\n        },\n\n        /**\n         * Hide Menu\n         */\n        hideMenu: function() {\n            this.removeListener(Garnish.$doc, 'mousedown');\n            this.$menu.hide();\n            this.showing = false;\n        },\n\n        /**\n         * Enable\n         */\n        enable: function() {\n            this.addListener(this.$target, 'contextmenu,mousedown', 'showMenu');\n        },\n\n        /**\n         * Disable\n         */\n        disable: function() {\n            this.removeListener(this.$target, 'contextmenu,mousedown');\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$target.removeData('contextmenu');\n            this.base();\n        }\n    },\n    {\n        defaults: {\n            menuClass: 'menu'\n        },\n        counter: 0\n    }\n);\n\n/** global: Garnish */\n/**\n * Drag class\n *\n * Builds on the BaseDrag class by \"picking up\" the selceted element(s),\n * without worrying about what to do when an element is being dragged.\n */\nGarnish.Drag = Garnish.BaseDrag.extend(\n    {\n        targetItemWidth: null,\n        targetItemHeight: null,\n        targetItemPositionInDraggee: null,\n\n        $draggee: null,\n\n        otherItems: null,\n        totalOtherItems: null,\n\n        helpers: null,\n        helperTargets: null,\n        helperPositions: null,\n        helperLagIncrement: null,\n        updateHelperPosProxy: null,\n        updateHelperPosFrame: null,\n\n        lastMouseX: null,\n        lastMouseY: null,\n\n        _returningHelpersToDraggees: false,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            settings = $.extend({}, Garnish.Drag.defaults, settings);\n            this.base(items, settings);\n        },\n\n        /**\n         * Returns whether dragging is allowed right now.\n         */\n        allowDragging: function() {\n            // Don't allow dragging if we're in the middle of animating the helpers back to the draggees\n            return !this._returningHelpersToDraggees;\n        },\n\n        /**\n         * Start Dragging\n         */\n        startDragging: function() {\n            // Reset some things\n            this.helpers = [];\n            this.helperTargets = [];\n            this.helperPositions = [];\n            this.lastMouseX = this.lastMouseY = null;\n\n            // Capture the target item's width/height\n            this.targetItemWidth = this.$targetItem.outerWidth();\n            this.targetItemHeight = this.$targetItem.outerHeight();\n\n            // Save the draggee's display style (block/table-row) so we can re-apply it later\n            this.draggeeDisplay = this.$targetItem.css('display');\n\n            // Set the $draggee\n            this.setDraggee(this.findDraggee());\n\n            // Create an array of all the other items\n            this.otherItems = [];\n\n            for (var i = 0; i < this.$items.length; i++) {\n                var item = this.$items[i];\n\n                if ($.inArray(item, this.$draggee) === -1) {\n                    this.otherItems.push(item);\n                }\n            }\n\n            this.totalOtherItems = this.otherItems.length;\n\n            // Keep the helpers following the cursor, with a little lag to smooth it out\n            if (!this.updateHelperPosProxy) {\n                this.updateHelperPosProxy = $.proxy(this, '_updateHelperPos');\n            }\n\n            this.helperLagIncrement = this.helpers.length === 1 ? 0 : this.settings.helperLagIncrementDividend / (this.helpers.length - 1);\n            this.updateHelperPosFrame = Garnish.requestAnimationFrame(this.updateHelperPosProxy);\n\n            this.base();\n        },\n\n        /**\n         * Sets the draggee.\n         */\n        setDraggee: function($draggee) {\n            // Record the target item's position in the draggee\n            this.targetItemPositionInDraggee = $.inArray(this.$targetItem[0], $draggee.add(this.$targetItem[0]));\n\n            // Keep the target item at the front of the list\n            this.$draggee = $([this.$targetItem[0]].concat($draggee.not(this.$targetItem).toArray()));\n\n            // Create the helper(s)\n            if (this.settings.singleHelper) {\n                this._createHelper(0);\n            }\n            else {\n                for (var i = 0; i < this.$draggee.length; i++) {\n                    this._createHelper(i);\n                }\n            }\n\n            if (this.settings.removeDraggee) {\n                this.$draggee.hide();\n            }\n            else if (this.settings.collapseDraggees) {\n                this.$targetItem.css('visibility', 'hidden');\n                this.$draggee.not(this.$targetItem).hide();\n            }\n            else {\n                this.$draggee.css('visibility', 'hidden');\n            }\n        },\n\n        /**\n         * Appends additional items to the draggee.\n         */\n        appendDraggee: function($newDraggee) {\n            if (!$newDraggee.length) {\n                return;\n            }\n\n            if (!this.settings.collapseDraggees) {\n                var oldLength = this.$draggee.length;\n            }\n\n            this.$draggee = $(this.$draggee.toArray().concat($newDraggee.toArray()));\n\n            // Create new helpers?\n            if (!this.settings.collapseDraggees) {\n                var newLength = this.$draggee.length;\n\n                for (var i = oldLength; i < newLength; i++) {\n                    this._createHelper(i);\n                }\n            }\n\n            if (this.settings.removeDraggee || this.settings.collapseDraggees) {\n                $newDraggee.hide();\n            }\n            else {\n                $newDraggee.css('visibility', 'hidden');\n            }\n        },\n\n        /**\n         * Drag\n         */\n        drag: function(didMouseMove) {\n            // Update the draggee's virtual midpoint\n            this.draggeeVirtualMidpointX = this.mouseX - this.mouseOffsetX + (this.targetItemWidth / 2);\n            this.draggeeVirtualMidpointY = this.mouseY - this.mouseOffsetY + (this.targetItemHeight / 2);\n\n            this.base(didMouseMove);\n        },\n\n        /**\n         * Stop Dragging\n         */\n        stopDragging: function() {\n            // Clear the helper animation\n            Garnish.cancelAnimationFrame(this.updateHelperPosFrame);\n\n            this.base();\n        },\n\n        /**\n         * Identifies the item(s) that are being dragged.\n         */\n        findDraggee: function() {\n            switch (typeof this.settings.filter) {\n                case 'function': {\n                    return this.settings.filter();\n                }\n\n                case 'string': {\n                    return this.$items.filter(this.settings.filter);\n                }\n\n                default: {\n                    return this.$targetItem;\n                }\n            }\n        },\n\n        /**\n         * Returns the helper’s target X position\n         */\n        getHelperTargetX: function() {\n            return this.mouseX - this.mouseOffsetX;\n        },\n\n        /**\n         * Returns the helper’s target Y position\n         */\n        getHelperTargetY: function() {\n            return this.mouseY - this.mouseOffsetY;\n        },\n\n        /**\n         * Return Helpers to Draggees\n         */\n        returnHelpersToDraggees: function() {\n            this._returningHelpersToDraggees = true;\n\n            for (var i = 0; i < this.helpers.length; i++) {\n                var $draggee = this.$draggee.eq(i),\n                    $helper = this.helpers[i];\n\n                $draggee.css({\n                    display: this.draggeeDisplay,\n                    visibility: 'hidden'\n                });\n\n                var draggeeOffset = $draggee.offset();\n                var callback;\n\n                if (i === 0) {\n                    callback = $.proxy(this, '_showDraggee');\n                }\n                else {\n                    callback = null;\n                }\n\n                $helper.velocity({left: draggeeOffset.left, top: draggeeOffset.top}, Garnish.FX_DURATION, callback);\n            }\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        onReturnHelpersToDraggees: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('returnHelpersToDraggees');\n                this.settings.onReturnHelpersToDraggees();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        /**\n         * Creates a helper.\n         */\n        _createHelper: function(i) {\n            var $draggee = this.$draggee.eq(i),\n                $draggeeHelper = $draggee.clone().addClass('draghelper');\n\n            if (this.settings.copyDraggeeInputValuesToHelper) {\n                Garnish.copyInputValues($draggee, $draggeeHelper);\n            }\n\n            // Remove any name= attributes so radio buttons don't lose their values\n            $draggeeHelper.find('[name]').attr('name', '');\n\n            $draggeeHelper.css({\n                width: $draggee.width() + 1, // Prevent the brower from wrapping text if the width was actually a fraction of a pixel larger\n                height: $draggee.height(),\n                margin: 0,\n                'pointer-events': 'none'\n            });\n\n            if (this.settings.helper) {\n                if (typeof this.settings.helper === 'function') {\n                    $draggeeHelper = this.settings.helper($draggeeHelper);\n                }\n                else {\n                    $draggeeHelper = $(this.settings.helper).append($draggeeHelper);\n                }\n            }\n\n            $draggeeHelper.appendTo(Garnish.$bod);\n\n            var helperPos = this._getHelperTarget(i);\n\n            $draggeeHelper.css({\n                position: 'absolute',\n                top: helperPos.top,\n                left: helperPos.left,\n                zIndex: this.settings.helperBaseZindex + this.$draggee.length - i,\n                opacity: this.settings.helperOpacity\n            });\n\n            this.helperPositions[i] = {\n                top: helperPos.top,\n                left: helperPos.left\n            };\n\n            this.helpers.push($draggeeHelper);\n        },\n\n        /**\n         * Update Helper Position\n         */\n        _updateHelperPos: function() {\n            // Has the mouse moved?\n            if (this.mouseX !== this.lastMouseX || this.mouseY !== this.lastMouseY) {\n                // Get the new target helper positions\n                for (this._updateHelperPos._i = 0; this._updateHelperPos._i < this.helpers.length; this._updateHelperPos._i++) {\n                    this.helperTargets[this._updateHelperPos._i] = this._getHelperTarget(this._updateHelperPos._i);\n                }\n\n                this.lastMouseX = this.mouseX;\n                this.lastMouseY = this.mouseY;\n            }\n\n            // Gravitate helpers toward their target positions\n            for (this._updateHelperPos._j = 0; this._updateHelperPos._j < this.helpers.length; this._updateHelperPos._j++) {\n                this._updateHelperPos._lag = this.settings.helperLagBase + (this.helperLagIncrement * this._updateHelperPos._j);\n\n                this.helperPositions[this._updateHelperPos._j] = {\n                    left: this.helperPositions[this._updateHelperPos._j].left + ((this.helperTargets[this._updateHelperPos._j].left - this.helperPositions[this._updateHelperPos._j].left) / this._updateHelperPos._lag),\n                    top: this.helperPositions[this._updateHelperPos._j].top + ((this.helperTargets[this._updateHelperPos._j].top - this.helperPositions[this._updateHelperPos._j].top) / this._updateHelperPos._lag)\n                };\n\n                this.helpers[this._updateHelperPos._j].css(this.helperPositions[this._updateHelperPos._j]);\n            }\n\n            // Let's do this again on the next frame!\n            this.updateHelperPosFrame = Garnish.requestAnimationFrame(this.updateHelperPosProxy);\n        },\n\n        /**\n         * Get the helper position for a draggee helper\n         */\n        _getHelperTarget: function(i) {\n            return {\n                left: this.getHelperTargetX() + (this.settings.helperSpacingX * i),\n                top: this.getHelperTargetY() + (this.settings.helperSpacingY * i)\n            };\n        },\n\n        _showDraggee: function() {\n            // Remove the helpers\n            for (var i = 0; i < this.helpers.length; i++) {\n                this.helpers[i].remove();\n            }\n\n            this.helpers = null;\n\n            this.$draggee.show().css('visibility', 'inherit');\n\n            this.onReturnHelpersToDraggees();\n\n            this._returningHelpersToDraggees = false;\n        }\n    },\n    {\n        defaults: {\n            filter: null,\n            singleHelper: false,\n            collapseDraggees: false,\n            removeDraggee: false,\n            copyDraggeeInputValuesToHelper: false,\n            helperOpacity: 1,\n            helper: null,\n            helperBaseZindex: 1000,\n            helperLagBase: 1,\n            helperLagIncrementDividend: 1.5,\n            helperSpacingX: 5,\n            helperSpacingY: 5,\n            onReturnHelpersToDraggees: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Drag-and-drop class\n *\n * Builds on the Drag class by allowing you to set up \"drop targets\"\n * which the dragged elemements can be dropped onto.\n */\nGarnish.DragDrop = Garnish.Drag.extend({\n\n        $dropTargets: null,\n        $activeDropTarget: null,\n\n        /**\n         * Constructor\n         */\n        init: function(settings) {\n            settings = $.extend({}, Garnish.DragDrop.defaults, settings);\n            this.base(settings);\n        },\n\n        updateDropTargets: function() {\n            if (this.settings.dropTargets) {\n                if (typeof this.settings.dropTargets === 'function') {\n                    this.$dropTargets = $(this.settings.dropTargets());\n                }\n                else {\n                    this.$dropTargets = $(this.settings.dropTargets);\n                }\n\n                // Discard if it's an empty array\n                if (!this.$dropTargets.length) {\n                    this.$dropTargets = null;\n                }\n            }\n        },\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            this.updateDropTargets();\n            this.$activeDropTarget = null;\n            this.base();\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            if (this.$dropTargets) {\n                this.onDrag._activeDropTarget = null;\n\n                // is the cursor over any of the drop target?\n                for (this.onDrag._i = 0; this.onDrag._i < this.$dropTargets.length; this.onDrag._i++) {\n                    this.onDrag._elem = this.$dropTargets[this.onDrag._i];\n\n                    if (Garnish.hitTest(this.mouseX, this.mouseY, this.onDrag._elem)) {\n                        this.onDrag._activeDropTarget = this.onDrag._elem;\n                        break;\n                    }\n                }\n\n                // has the drop target changed?\n                if (\n                    (this.$activeDropTarget && this.onDrag._activeDropTarget !== this.$activeDropTarget[0]) ||\n                    (!this.$activeDropTarget && this.onDrag._activeDropTarget !== null)\n                ) {\n                    // was there a previous one?\n                    if (this.$activeDropTarget) {\n                        this.$activeDropTarget.removeClass(this.settings.activeDropTargetClass);\n                    }\n\n                    // remember the new one\n                    if (this.onDrag._activeDropTarget) {\n                        this.$activeDropTarget = $(this.onDrag._activeDropTarget).addClass(this.settings.activeDropTargetClass);\n                    }\n                    else {\n                        this.$activeDropTarget = null;\n                    }\n\n                    this.settings.onDropTargetChange(this.$activeDropTarget);\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            if (this.$dropTargets && this.$activeDropTarget) {\n                this.$activeDropTarget.removeClass(this.settings.activeDropTargetClass);\n            }\n\n            this.base();\n        },\n\n        /**\n         * Fade Out Helpers\n         */\n        fadeOutHelpers: function() {\n            for (var i = 0; i < this.helpers.length; i++) {\n                (function($draggeeHelper) {\n                    $draggeeHelper.velocity('fadeOut', {\n                        duration: Garnish.FX_DURATION,\n                        complete: function() {\n                            $draggeeHelper.remove();\n                        }\n                    });\n                })(this.helpers[i]);\n            }\n        }\n    },\n    {\n        defaults: {\n            dropTargets: null,\n            onDropTargetChange: $.noop,\n            activeDropTargetClass: 'active'\n        }\n    });\n\n/** global: Garnish */\n/**\n * Drag-to-move clas\n *\n * Builds on the BaseDrag class by simply moving the dragged element(s) along with the mouse.\n */\nGarnish.DragMove = Garnish.BaseDrag.extend(\n    {\n        onDrag: function(items, settings) {\n            this.$targetItem.css({\n                left: this.mouseX - this.mouseOffsetX,\n                top: this.mouseY - this.mouseOffsetY\n            });\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Drag-to-sort class\n *\n * Builds on the Drag class by allowing you to sort the elements amongst themselves.\n */\nGarnish.DragSort = Garnish.Drag.extend(\n    {\n        $heightedContainer: null,\n        $insertion: null,\n        insertionVisible: false,\n        oldDraggeeIndexes: null,\n        newDraggeeIndexes: null,\n        closestItem: null,\n\n        _midpointVersion: 0,\n        _$prevItem: null,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            settings = $.extend({}, Garnish.DragSort.defaults, settings);\n            this.base(items, settings);\n        },\n\n        /**\n         * Creates the insertion element.\n         */\n        createInsertion: function() {\n            if (this.settings.insertion) {\n                if (typeof this.settings.insertion === 'function') {\n                    return $(this.settings.insertion(this.$draggee));\n                }\n                else {\n                    return $(this.settings.insertion);\n                }\n            }\n        },\n\n        /**\n         * Returns the helper’s target X position\n         */\n        getHelperTargetX: function() {\n            if (this.settings.magnetStrength !== 1) {\n                this.getHelperTargetX._draggeeOffsetX = this.$draggee.offset().left;\n                return this.getHelperTargetX._draggeeOffsetX + ((this.mouseX - this.mouseOffsetX - this.getHelperTargetX._draggeeOffsetX) / this.settings.magnetStrength);\n            }\n            else {\n                return this.base();\n            }\n        },\n\n        /**\n         * Returns the helper’s target Y position\n         */\n        getHelperTargetY: function() {\n            if (this.settings.magnetStrength !== 1) {\n                this.getHelperTargetY._draggeeOffsetY = this.$draggee.offset().top;\n                return this.getHelperTargetY._draggeeOffsetY + ((this.mouseY - this.mouseOffsetY - this.getHelperTargetY._draggeeOffsetY) / this.settings.magnetStrength);\n            }\n            else {\n                return this.base();\n            }\n        },\n\n        /**\n         * Returns whether the draggee can be inserted before a given item.\n         */\n        canInsertBefore: function($item) {\n            return true;\n        },\n\n        /**\n         * Returns whether the draggee can be inserted after a given item.\n         */\n        canInsertAfter: function($item) {\n            return true;\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            this.oldDraggeeIndexes = this._getDraggeeIndexes();\n\n            // Are we supposed to be moving the target item to the front, and is it not already there?\n            if (\n                this.settings.moveTargetItemToFront &&\n                this.$draggee.length > 1 &&\n                this._getItemIndex(this.$draggee[0]) > this._getItemIndex(this.$draggee[1])\n            ) {\n                // Reposition the target item before the other draggee items in the DOM\n                this.$draggee.first().insertBefore(this.$draggee[1]);\n            }\n\n            // Create the insertion\n            this.$insertion = this.createInsertion();\n            this._placeInsertionWithDraggee();\n\n            this.closestItem = null;\n            this._clearMidpoints();\n\n            //  Get the closest container that has a height\n            if (this.settings.container) {\n                this.$heightedContainer = $(this.settings.container);\n\n                while (!this.$heightedContainer.height()) {\n                    this.$heightedContainer = this.$heightedContainer.parent();\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            // If there's a container set, make sure that we're hovering over it\n            if (this.$heightedContainer && !Garnish.hitTest(this.mouseX, this.mouseY, this.$heightedContainer)) {\n                if (this.closestItem) {\n                    this.closestItem = null;\n                    this._removeInsertion();\n                }\n            }\n            else {\n                // Is there a new closest item?\n                if (\n                    this.closestItem !== (this.closestItem = this._getClosestItem()) &&\n                    this.closestItem !== null\n                ) {\n                    this._updateInsertion();\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            this._removeInsertion();\n\n            // Should we keep the target item where it was?\n            if (!this.settings.moveTargetItemToFront && this.targetItemPositionInDraggee !== 0) {\n                this.$targetItem.insertAfter(this.$draggee.eq(this.targetItemPositionInDraggee));\n            }\n\n            // Return the helpers to the draggees\n            this.returnHelpersToDraggees();\n\n            this.base();\n\n            // Has the item actually moved?\n            this.$items = $().add(this.$items);\n            this.newDraggeeIndexes = this._getDraggeeIndexes();\n\n            if (this.newDraggeeIndexes.join(',') !== this.oldDraggeeIndexes.join(',')) {\n                this.onSortChange();\n            }\n        },\n\n        /**\n         * On Insertion Point Change event\n         */\n        onInsertionPointChange: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('insertionPointChange');\n                this.settings.onInsertionPointChange();\n            }, this));\n        },\n\n        /**\n         * On Sort Change event\n         */\n        onSortChange: function() {\n            Garnish.requestAnimationFrame($.proxy(function() {\n                this.trigger('sortChange');\n                this.settings.onSortChange();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        _getItemIndex: function(item) {\n            return $.inArray(item, this.$items);\n        },\n\n        _getDraggeeIndexes: function() {\n            var indexes = [];\n\n            for (var i = 0; i < this.$draggee.length; i++) {\n                indexes.push(this._getItemIndex(this.$draggee[i]))\n            }\n\n            return indexes;\n        },\n\n        /**\n         * Returns the closest item to the cursor.\n         */\n        _getClosestItem: function() {\n            this._getClosestItem._closestItem = null;\n\n            // Start by checking the draggee/insertion, if either are visible\n            if (!this.settings.removeDraggee) {\n                this._testForClosestItem(this.$draggee[0]);\n            }\n            else if (this.insertionVisible) {\n                this._testForClosestItem(this.$insertion[0]);\n            }\n\n            // Check items before the draggee\n            if (this._getClosestItem._closestItem) {\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._closestItem)\n            }\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this._getClosestItem._startXDist = this._getClosestItem._lastXDist = this._getClosestItem._closestItem ? Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX) : null;\n            }\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this._getClosestItem._startYDist = this._getClosestItem._lastYDist = this._getClosestItem._closestItem ? Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY) : null;\n            }\n\n            this._getClosestItem._$otherItem = this.$draggee.first().prev();\n\n            while (this._getClosestItem._$otherItem.length) {\n                // See if we're just getting further away\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._$otherItem[0]);\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._xDist = Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._yDist = Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n                }\n\n                if (\n                    (this.settings.axis === Garnish.Y_AXIS || (this._getClosestItem._lastXDist !== null && this._getClosestItem._xDist > this._getClosestItem._lastXDist)) &&\n                    (this.settings.axis === Garnish.X_AXIS || (this._getClosestItem._lastYDist !== null && this._getClosestItem._yDist > this._getClosestItem._lastYDist))\n                ) {\n                    break;\n                }\n\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._lastXDist = this._getClosestItem._xDist;\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._lastYDist = this._getClosestItem._yDist;\n                }\n\n                // Give the extending class a chance to allow/disallow this item\n                if (this.canInsertBefore(this._getClosestItem._$otherItem)) {\n                    this._testForClosestItem(this._getClosestItem._$otherItem[0]);\n                }\n\n                // Prep the next item\n                this._getClosestItem._$otherItem = this._getClosestItem._$otherItem.prev();\n            }\n\n            // Check items after the draggee\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this._getClosestItem._lastXDist = this._getClosestItem._startXDist;\n            }\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this._getClosestItem._lastYDist = this._getClosestItem._startYDist;\n            }\n\n            this._getClosestItem._$otherItem = this.$draggee.last().next();\n\n            while (this._getClosestItem._$otherItem.length) {\n                // See if we're just getting further away\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._$otherItem[0]);\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._xDist = Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._yDist = Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n                }\n\n                if (\n                    (this.settings.axis === Garnish.Y_AXIS || (this._getClosestItem._lastXDist !== null && this._getClosestItem._xDist > this._getClosestItem._lastXDist)) &&\n                    (this.settings.axis === Garnish.X_AXIS || (this._getClosestItem._lastYDist !== null && this._getClosestItem._yDist > this._getClosestItem._lastYDist))\n                ) {\n                    break;\n                }\n\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._lastXDist = this._getClosestItem._xDist;\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._lastYDist = this._getClosestItem._yDist;\n                }\n\n                // Give the extending class a chance to allow/disallow this item\n                if (this.canInsertAfter(this._getClosestItem._$otherItem)) {\n                    this._testForClosestItem(this._getClosestItem._$otherItem[0]);\n                }\n\n                // Prep the next item\n                this._getClosestItem._$otherItem = this._getClosestItem._$otherItem.next();\n            }\n\n            // Return the result\n\n            // Ignore if it's the draggee or insertion\n            if (\n                this._getClosestItem._closestItem !== this.$draggee[0] &&\n                (!this.insertionVisible || this._getClosestItem._closestItem !== this.$insertion[0])\n            ) {\n                return this._getClosestItem._closestItem;\n            }\n            else {\n                return null;\n            }\n        },\n\n        _clearMidpoints: function() {\n            this._midpointVersion++;\n            this._$prevItem = null;\n        },\n\n        _getItemMidpoint: function(item) {\n            if ($.data(item, 'midpointVersion') !== this._midpointVersion) {\n                // If this isn't the draggee, temporarily move the draggee to this item\n                this._getItemMidpoint._repositionDraggee = (\n                    !this.settings.axis &&\n                    (!this.settings.removeDraggee || this.insertionVisible) &&\n                    item !== this.$draggee[0] &&\n                    (!this.$insertion || item !== this.$insertion.get(0))\n                );\n\n                if (this._getItemMidpoint._repositionDraggee) {\n                    // Is this the first time we've had to temporarily reposition the draggee since the last midpoint clearing?\n                    if (!this._$prevItem) {\n                        this._$prevItem = (this.insertionVisible ? this.$insertion : this.$draggee).first().prev();\n                    }\n\n                    this._moveDraggeeToItem(item);\n\n                    // Now figure out which element we're actually getting the midpoint of\n                    if (!this.settings.removeDraggee) {\n                        this._getItemMidpoint._$item = this.$draggee;\n                    }\n                    else {\n                        this._getItemMidpoint._$item = this.$insertion;\n                    }\n                }\n                else {\n                    // We're actually getting the midpoint of this item\n                    this._getItemMidpoint._$item = $(item);\n                }\n\n                this._getItemMidpoint._offset = this._getItemMidpoint._$item.offset();\n\n                $.data(item, 'midpoint', {\n                    x: this._getItemMidpoint._offset.left + this._getItemMidpoint._$item.outerWidth() / 2,\n                    y: this._getItemMidpoint._offset.top + this._getItemMidpoint._$item.outerHeight() / 2\n                });\n\n                $.data(item, 'midpointVersion', this._midpointVersion);\n\n                delete this._getItemMidpoint._$item;\n                delete this._getItemMidpoint._offset;\n\n                if (this._getItemMidpoint._repositionDraggee) {\n                    // Move the draggee back\n                    if (this._$prevItem.length) {\n                        this.$draggee.insertAfter(this._$prevItem);\n                    }\n                    else {\n                        this.$draggee.prependTo(this.$draggee.parent());\n                    }\n\n                    this._placeInsertionWithDraggee();\n                }\n            }\n\n            return $.data(item, 'midpoint');\n        },\n\n        _testForClosestItem: function(item) {\n            this._testForClosestItem._midpoint = this._getItemMidpoint(item);\n            this._testForClosestItem._mouseDistX = Math.abs(this._testForClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n            this._testForClosestItem._mouseDistY = Math.abs(this._testForClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n\n            // Don't even consider items that are further away on the Y axis\n            if (\n                this._getClosestItem._closestItem === null ||\n                this._testForClosestItem._mouseDistY < this._getClosestItem._closestItemMouseDistY ||\n                (\n                    this._testForClosestItem._mouseDistY === this._getClosestItem._closestItemMouseDistY &&\n                    this._testForClosestItem._mouseDistX <= this._getClosestItem._closestItemMouseDistX\n                )\n            ) {\n                this._getClosestItem._closestItem = item;\n                this._getClosestItem._closestItemMouseDistX = this._testForClosestItem._mouseDistX;\n                this._getClosestItem._closestItemMouseDistY = this._testForClosestItem._mouseDistY;\n            }\n        },\n\n        /**\n         * Updates the position of the insertion point.\n         */\n        _updateInsertion: function() {\n            if (this.closestItem) {\n                this._moveDraggeeToItem(this.closestItem);\n            }\n\n            // Now that things have shifted around, invalidate the midpoints\n            this._clearMidpoints();\n\n            this.onInsertionPointChange();\n        },\n\n        _moveDraggeeToItem: function(item) {\n            // Going down?\n            if (this.$draggee.index() < $(item).index()) {\n                this.$draggee.insertAfter(item);\n            }\n            else {\n                this.$draggee.insertBefore(item);\n            }\n\n            this._placeInsertionWithDraggee();\n        },\n\n        _placeInsertionWithDraggee: function() {\n            if (this.$insertion) {\n                this.$insertion.insertBefore(this.$draggee.first());\n                this.insertionVisible = true;\n            }\n        },\n\n        /**\n         * Removes the insertion, if it's visible.\n         */\n        _removeInsertion: function() {\n            if (this.insertionVisible) {\n                this.$insertion.remove();\n                this.insertionVisible = false;\n            }\n        }\n    },\n    {\n        defaults: {\n            container: null,\n            insertion: null,\n            moveTargetItemToFront: false,\n            magnetStrength: 1,\n            onInsertionPointChange: $.noop,\n            onSortChange: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * ESC key manager class\n */\nGarnish.EscManager = Garnish.Base.extend(\n    {\n        handlers: null,\n\n        init: function() {\n            this.handlers = [];\n\n            this.addListener(Garnish.$bod, 'keyup', function(ev) {\n                if (ev.keyCode === Garnish.ESC_KEY) {\n                    this.escapeLatest(ev);\n                }\n            });\n        },\n\n        register: function(obj, func) {\n            this.handlers.push({\n                obj: obj,\n                func: func\n            });\n        },\n\n        unregister: function(obj) {\n            for (var i = this.handlers.length - 1; i >= 0; i--) {\n                if (this.handlers[i].obj === obj) {\n                    this.handlers.splice(i, 1);\n                }\n            }\n        },\n\n        escapeLatest: function(ev) {\n            if (this.handlers.length) {\n                var handler = this.handlers.pop();\n\n                var func;\n\n                if (typeof handler.func === 'function') {\n                    func = handler.func;\n                }\n                else {\n                    func = handler.obj[handler.func];\n                }\n\n                func.call(handler.obj, ev);\n\n                if (typeof handler.obj.trigger === 'function') {\n                    handler.obj.trigger('escape');\n                }\n            }\n        }\n    }\n);\n\nGarnish.escManager = new Garnish.EscManager();\n\n/** global: Garnish */\n/**\n * HUD\n */\nGarnish.HUD = Garnish.Base.extend(\n    {\n        $trigger: null,\n        $fixedTriggerParent: null,\n        $hud: null,\n        $tip: null,\n        $body: null,\n        $header: null,\n        $footer: null,\n        $mainContainer: null,\n        $main: null,\n        $shade: null,\n\n        showing: false,\n        orientation: null,\n\n        updatingSizeAndPosition: false,\n        windowWidth: null,\n        windowHeight: null,\n        scrollTop: null,\n        scrollLeft: null,\n        mainWidth: null,\n        mainHeight: null,\n\n        /**\n         * Constructor\n         */\n        init: function(trigger, bodyContents, settings) {\n\n            this.$trigger = $(trigger);\n\n            this.setSettings(settings, Garnish.HUD.defaults);\n            this.on('show', this.settings.onShow);\n            this.on('hide', this.settings.onHide);\n            this.on('submit', this.settings.onSubmit);\n\n            if (typeof Garnish.HUD.activeHUDs === 'undefined') {\n                Garnish.HUD.activeHUDs = {};\n            }\n\n            this.$shade = $('<div/>', {'class': this.settings.shadeClass});\n            this.$hud = $('<div/>', {'class': this.settings.hudClass}).data('hud', this);\n            this.$tip = $('<div/>', {'class': this.settings.tipClass}).appendTo(this.$hud);\n            this.$body = $('<form/>', {'class': this.settings.bodyClass}).appendTo(this.$hud);\n            this.$mainContainer = $('<div/>', {'class': this.settings.mainContainerClass}).appendTo(this.$body);\n            this.$main = $('<div/>', {'class': this.settings.mainClass}).appendTo(this.$mainContainer);\n\n            this.updateBody(bodyContents);\n\n            // See if the trigger is fixed\n            var $parent = this.$trigger;\n\n            do {\n                if ($parent.css('position') === 'fixed') {\n                    this.$fixedTriggerParent = $parent;\n                    break;\n                }\n\n                $parent = $parent.offsetParent();\n            }\n            while ($parent.length && $parent.prop('nodeName') !== 'HTML');\n\n            if (this.$fixedTriggerParent) {\n                this.$hud.css('position', 'fixed');\n            }\n            else {\n                this.$hud.css('position', 'absolute');\n            }\n\n            // Hide the HUD until it gets positioned\n\t\t\tvar windowWidth = Garnish.$win.width();\n\n\t\t\tthis.$hud.css({\n                left: '-' + windowWidth + 'px',\n\t\t\t});\n\n            this.show();\n\n            this.addListener(this.$body, 'submit', '_handleSubmit');\n            this.addListener(this.$shade, 'tap,click', 'hide');\n\n            if (this.settings.closeBtn) {\n                this.addListener(this.settings.closeBtn, 'activate', 'hide');\n            }\n\n            this.addListener(Garnish.$win, 'resize', 'updateSizeAndPosition');\n            this.addListener(this.$main, 'resize', 'updateSizeAndPosition');\n            if (!this.$fixedTriggerParent && Garnish.$scrollContainer[0] !== Garnish.$win[0]) {\n                this.addListener(Garnish.$scrollContainer, 'scroll', 'updateSizeAndPosition');\n            }\n        },\n\n        /**\n         * Update the body contents\n         */\n        updateBody: function(bodyContents) {\n            // Cleanup\n            this.$main.html('');\n\n            if (this.$header) {\n                this.$hud.removeClass('has-header');\n                this.$header.remove();\n                this.$header = null;\n            }\n\n            if (this.$footer) {\n                this.$hud.removeClass('has-footer');\n                this.$footer.remove();\n                this.$footer = null;\n            }\n\n            // Append the new body contents\n            this.$main.append(bodyContents);\n\n            // Look for a header and footer\n            var $header = this.$main.find('.' + this.settings.headerClass + ':first'),\n                $footer = this.$main.find('.' + this.settings.footerClass + ':first');\n\n            if ($header.length) {\n                this.$header = $header.insertBefore(this.$mainContainer);\n                this.$hud.addClass('has-header');\n            }\n\n            if ($footer.length) {\n                this.$footer = $footer.insertAfter(this.$mainContainer);\n                this.$hud.addClass('has-footer');\n            }\n        },\n\n        /**\n         * Show\n         */\n        show: function(ev) {\n            if (ev && ev.stopPropagation) {\n                ev.stopPropagation();\n            }\n\n            if (this.showing) {\n                return;\n            }\n\n            if (this.settings.closeOtherHUDs) {\n                for (var hudID in Garnish.HUD.activeHUDs) {\n                    if (!Garnish.HUD.activeHUDs.hasOwnProperty(hudID)) {\n                        continue;\n                    }\n                    Garnish.HUD.activeHUDs[hudID].hide();\n                }\n            }\n\n            // Move it to the end of <body> so it gets the highest sub-z-index\n            this.$shade.appendTo(Garnish.$bod);\n            this.$hud.appendTo(Garnish.$bod);\n\n            this.$hud.show();\n            this.$shade.show();\n            this.showing = true;\n            Garnish.HUD.activeHUDs[this._namespace] = this;\n            Garnish.escManager.register(this, 'hide');\n\n            this.onShow();\n            this.enable();\n\n            if (this.updateRecords()) {\n                // Prevent the browser from jumping\n                this.$hud.css('top', Garnish.$scrollContainer.scrollTop());\n\n                this.updateSizeAndPosition(true);\n            }\n        },\n\n        onShow: function() {\n            this.trigger('show');\n        },\n\n        updateRecords: function() {\n            var changed = false;\n            changed = (this.windowWidth !== (this.windowWidth = Garnish.$win.width())) || changed;\n            changed = (this.windowHeight !== (this.windowHeight = Garnish.$win.height())) || changed;\n            changed = (this.scrollTop !== (this.scrollTop = Garnish.$scrollContainer.scrollTop())) || changed;\n            changed = (this.scrollLeft !== (this.scrollLeft = Garnish.$scrollContainer.scrollLeft())) || changed;\n            changed = (this.mainWidth !== (this.mainWidth = this.$main.outerWidth())) || changed;\n            changed = (this.mainHeight !== (this.mainHeight = this.$main.outerHeight())) || changed;\n            return changed;\n        },\n\n        updateSizeAndPosition: function(force) {\n            if (force === true || (this.updateRecords() && !this.updatingSizeAndPosition)) {\n                this.updatingSizeAndPosition = true;\n                Garnish.requestAnimationFrame($.proxy(this, 'updateSizeAndPositionInternal'));\n            }\n        },\n\n        updateSizeAndPositionInternal: function() {\n            var triggerWidth,\n                triggerHeight,\n                triggerOffset,\n                windowScrollLeft,\n                windowScrollTop,\n                scrollContainerTriggerOffset,\n                scrollContainerScrollLeft,\n                scrollContainerScrollTop,\n                hudBodyWidth,\n                hudBodyHeight;\n\n            // Get the window sizes and trigger offset\n\n            windowScrollLeft = Garnish.$win.scrollLeft();\n            windowScrollTop = Garnish.$win.scrollTop();\n\n            // Get the trigger's dimensions\n            triggerWidth = this.$trigger.outerWidth();\n            triggerHeight = this.$trigger.outerHeight();\n\n            // Get the offsets for each side of the trigger element\n            triggerOffset = this.$trigger.offset();\n\n            if (this.$fixedTriggerParent) {\n                triggerOffset.left -= windowScrollLeft;\n                triggerOffset.top -= windowScrollTop;\n\n                scrollContainerTriggerOffset = triggerOffset;\n\n                windowScrollLeft = 0;\n                windowScrollTop = 0;\n                scrollContainerScrollLeft = 0;\n                scrollContainerScrollTop = 0;\n            }\n            else {\n                scrollContainerTriggerOffset = Garnish.getOffset(this.$trigger);\n\n                scrollContainerScrollLeft = Garnish.$scrollContainer.scrollLeft();\n                scrollContainerScrollTop = Garnish.$scrollContainer.scrollTop();\n            }\n\n            triggerOffset.right = triggerOffset.left + triggerWidth;\n            triggerOffset.bottom = triggerOffset.top + triggerHeight;\n\n            scrollContainerTriggerOffset.right = scrollContainerTriggerOffset.left + triggerWidth;\n            scrollContainerTriggerOffset.bottom = scrollContainerTriggerOffset.top + triggerHeight;\n\n            // Get the HUD dimensions\n            this.$hud.css({\n                width: ''\n            });\n\n            this.$mainContainer.css({\n                height: '',\n                'overflow-x': '',\n                'overflow-y': ''\n            });\n\n            hudBodyWidth = this.$body.width();\n            hudBodyHeight = this.$body.height();\n\n            // Determine the best orientation for the HUD\n\n            // Find the actual available top/right/bottom/left clearances\n            var clearances = {\n                bottom: this.windowHeight + scrollContainerScrollTop - scrollContainerTriggerOffset.bottom,\n                top: scrollContainerTriggerOffset.top - scrollContainerScrollTop,\n                right: this.windowWidth + scrollContainerScrollLeft - scrollContainerTriggerOffset.right,\n                left: scrollContainerTriggerOffset.left - scrollContainerScrollLeft\n            };\n\n            // Find the first position that has enough room\n            this.orientation = null;\n\n            for (var i = 0; i < this.settings.orientations.length; i++) {\n                var orientation = this.settings.orientations[i],\n                    relevantSize = (orientation === 'top' || orientation === 'bottom' ? hudBodyHeight : hudBodyWidth);\n\n                if (clearances[orientation] - (this.settings.windowSpacing + this.settings.triggerSpacing) >= relevantSize) {\n                    // This is the first orientation that has enough room in order of preference, so we'll go with this\n                    this.orientation = orientation;\n                    break;\n                }\n\n                if (!this.orientation || clearances[orientation] > clearances[this.orientation]) {\n                    // Use this as a fallback as it's the orientation with the most clearance so far\n                    this.orientation = orientation;\n                }\n            }\n\n            // Just in case...\n            if (!this.orientation || $.inArray(this.orientation, ['bottom', 'top', 'right', 'left']) === -1) {\n                this.orientation = 'bottom'\n            }\n\n            // Update the tip class\n            if (this.tipClass) {\n                this.$tip.removeClass(this.tipClass);\n            }\n\n            this.tipClass = this.settings.tipClass + '-' + Garnish.HUD.tipClasses[this.orientation];\n            this.$tip.addClass(this.tipClass);\n\n            // Make sure the HUD body is within the allowed size\n\n            var maxHudBodyWidth,\n                maxHudBodyHeight;\n\n            if (this.orientation === 'top' || this.orientation === 'bottom') {\n                maxHudBodyWidth = this.windowWidth - this.settings.windowSpacing * 2;\n                maxHudBodyHeight = clearances[this.orientation] - this.settings.windowSpacing - this.settings.triggerSpacing;\n            }\n            else {\n                maxHudBodyWidth = clearances[this.orientation] - this.settings.windowSpacing - this.settings.triggerSpacing;\n                maxHudBodyHeight = this.windowHeight - this.settings.windowSpacing * 2;\n            }\n\n            if (maxHudBodyWidth < this.settings.minBodyWidth) {\n                maxHudBodyWidth = this.settings.minBodyWidth;\n            }\n\n            if (maxHudBodyHeight < this.settings.minBodyHeight) {\n                maxHudBodyHeight = this.settings.minBodyHeight;\n            }\n\n            if (hudBodyWidth > maxHudBodyWidth || hudBodyWidth < this.settings.minBodyWidth) {\n                if (hudBodyWidth > maxHudBodyWidth) {\n                    hudBodyWidth = maxHudBodyWidth;\n                }\n                else {\n                    hudBodyWidth = this.settings.minBodyWidth;\n                }\n\n                this.$hud.width(hudBodyWidth);\n\n                // Is there any overflow now?\n                if (this.mainWidth > maxHudBodyWidth) {\n                    this.$mainContainer.css('overflow-x', 'scroll');\n                }\n\n                // The height may have just changed\n                hudBodyHeight = this.$body.height();\n            }\n\n            if (hudBodyHeight > maxHudBodyHeight || hudBodyHeight < this.settings.minBodyHeight) {\n                if (hudBodyHeight > maxHudBodyHeight) {\n                    hudBodyHeight = maxHudBodyHeight;\n                }\n                else {\n                    hudBodyHeight = this.settings.minBodyHeight;\n                }\n\n                var mainHeight = hudBodyHeight;\n\n                if (this.$header) {\n                    mainHeight -= this.$header.outerHeight();\n                }\n\n                if (this.$footer) {\n                    mainHeight -= this.$footer.outerHeight();\n                }\n\n                this.$mainContainer.height(mainHeight);\n\n                // Is there any overflow now?\n                if (this.mainHeight > mainHeight) {\n                    this.$mainContainer.css('overflow-y', 'scroll');\n                }\n            }\n\n            // Set the HUD/tip positions\n            var triggerCenter, left, top;\n\n            if (this.orientation === 'top' || this.orientation === 'bottom') {\n                // Center the HUD horizontally\n                var maxLeft = (this.windowWidth + windowScrollLeft) - (hudBodyWidth + this.settings.windowSpacing);\n                var minLeft = (windowScrollLeft + this.settings.windowSpacing);\n                triggerCenter = triggerOffset.left + Math.round(triggerWidth / 2);\n                left = triggerCenter - Math.round(hudBodyWidth / 2);\n\n                if (left > maxLeft) {\n                    left = maxLeft;\n                }\n                if (left < minLeft) {\n                    left = minLeft;\n                }\n\n                this.$hud.css('left', left);\n\n                var tipLeft = (triggerCenter - left) - (this.settings.tipWidth / 2);\n                this.$tip.css({left: tipLeft, top: ''});\n\n                if (this.orientation === 'top') {\n                    top = triggerOffset.top - (hudBodyHeight + this.settings.triggerSpacing);\n                    this.$hud.css('top', top);\n                }\n                else {\n                    top = triggerOffset.bottom + this.settings.triggerSpacing;\n                    this.$hud.css('top', top);\n                }\n            }\n            else {\n                // Center the HUD vertically\n                var maxTop = (this.windowHeight + windowScrollTop) - (hudBodyHeight + this.settings.windowSpacing);\n                var minTop = (windowScrollTop + this.settings.windowSpacing);\n                triggerCenter = triggerOffset.top + Math.round(triggerHeight / 2);\n                top = triggerCenter - Math.round(hudBodyHeight / 2);\n\n                if (top > maxTop) {\n                    top = maxTop;\n                }\n                if (top < minTop) {\n                    top = minTop;\n                }\n\n                this.$hud.css('top', top);\n\n                var tipTop = (triggerCenter - top) - (this.settings.tipWidth / 2);\n                this.$tip.css({top: tipTop, left: ''});\n\n\n                if (this.orientation === 'left') {\n                    left = triggerOffset.left - (hudBodyWidth + this.settings.triggerSpacing);\n                    this.$hud.css('left', left);\n                }\n                else {\n                    left = triggerOffset.right + this.settings.triggerSpacing;\n                    this.$hud.css('left', left);\n                }\n            }\n\n            this.updatingSizeAndPosition = false;\n            this.trigger('updateSizeAndPosition');\n        },\n\n        /**\n         * Hide\n         */\n        hide: function() {\n            this.disable();\n\n            this.$hud.hide();\n            this.$shade.hide();\n\n            this.showing = false;\n            //this.windowWidth = null;\n            //this.windowHeight = null;\n            //this.scrollTop = null;\n            //this.scrollLeft = null;\n            //this.mainWidth = null;\n            //this.mainHeight = null;\n\n            delete Garnish.HUD.activeHUDs[this._namespace];\n\n            Garnish.escManager.unregister(this);\n\n            this.onHide();\n        },\n\n        onHide: function() {\n            this.trigger('hide');\n        },\n\n        toggle: function() {\n            if (this.showing) {\n                this.hide();\n            }\n            else {\n                this.show();\n            }\n        },\n\n        submit: function() {\n            this.onSubmit();\n        },\n\n        onSubmit: function() {\n            this.trigger('submit');\n        },\n\n        _handleSubmit: function(ev) {\n            ev.preventDefault();\n            this.submit();\n        }\n    },\n    {\n        tipClasses: {bottom: 'top', top: 'bottom', right: 'left', left: 'right'},\n\n        defaults: {\n            shadeClass: 'hud-shade',\n            hudClass: 'hud',\n            tipClass: 'tip',\n            bodyClass: 'body',\n            headerClass: 'hud-header',\n            footerClass: 'hud-footer',\n            mainContainerClass: 'main-container',\n            mainClass: 'main',\n            orientations: ['bottom', 'top', 'right', 'left'],\n            triggerSpacing: 10,\n            windowSpacing: 10,\n            tipWidth: 30,\n            minBodyWidth: 200,\n            minBodyHeight: 0,\n            onShow: $.noop,\n            onHide: $.noop,\n            onSubmit: $.noop,\n            closeBtn: null,\n            closeOtherHUDs: true\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Menu\n */\nGarnish.Menu = Garnish.Base.extend(\n    {\n        settings: null,\n\n        $container: null,\n        $options: null,\n        $anchor: null,\n\n        menuId: null,\n\n        _windowWidth: null,\n        _windowHeight: null,\n        _windowScrollLeft: null,\n        _windowScrollTop: null,\n\n        _anchorOffset: null,\n        _anchorWidth: null,\n        _anchorHeight: null,\n        _anchorOffsetRight: null,\n        _anchorOffsetBottom: null,\n\n        _menuWidth: null,\n        _menuHeight: null,\n\n        /**\n         * Constructor\n         */\n        init: function(container, settings) {\n            this.setSettings(settings, Garnish.Menu.defaults);\n\n            this.$container = $(container);\n\n            this.$options = $();\n            this.addOptions(this.$container.find('a'));\n\n            // Menu List\n            this.menuId = 'menu' + this._namespace;\n            this.$menuList = $('ul', this.$container);\n            this.$menuList.attr({\n                'role': 'listbox',\n                'id': this.menuId,\n                'aria-hidden': 'true'\n            });\n\n            // Deprecated\n            if (this.settings.attachToElement) {\n                this.settings.anchor = this.settings.attachToElement;\n                Garnish.log('The \\'attachToElement\\' setting is deprecated. Use \\'anchor\\' instead.');\n            }\n\n            if (this.settings.anchor) {\n                this.$anchor = $(this.settings.anchor);\n            }\n\n            // Prevent clicking on the container from hiding the menu\n            this.addListener(this.$container, 'mousedown', function(ev) {\n                ev.stopPropagation();\n\n                // Prevent this from causing the menu button to blur\n                ev.preventDefault();\n            });\n        },\n\n        addOptions: function($options) {\n            this.$options = this.$options.add($options);\n            $options.data('menu', this);\n\n            $options.each($.proxy(function(optionKey, option) {\n                $(option).attr({\n                    'role': 'option',\n                    'tabindex': '-1',\n                    'id': this.menuId + '-option-' + optionKey\n                });\n            }, this));\n\n            this.addListener($options, 'click', 'selectOption');\n        },\n\n        setPositionRelativeToAnchor: function() {\n            this._windowWidth = Garnish.$win.width();\n            this._windowHeight = Garnish.$win.height();\n            this._windowScrollLeft = Garnish.$win.scrollLeft();\n            this._windowScrollTop = Garnish.$win.scrollTop();\n\n            this._anchorOffset = this.$anchor.offset();\n            this._anchorWidth = this.$anchor.outerWidth();\n            this._anchorHeight = this.$anchor.outerHeight();\n            this._anchorOffsetRight = this._anchorOffset.left + this._anchorHeight;\n            this._anchorOffsetBottom = this._anchorOffset.top + this._anchorHeight;\n\n            this.$container.css('minWidth', 0);\n            this.$container.css('minWidth', this._anchorWidth - (this.$container.outerWidth() - this.$container.width()));\n\n            this._menuWidth = this.$container.outerWidth();\n            this._menuHeight = this.$container.outerHeight();\n\n            // Is there room for the menu below the anchor?\n            var topClearance = this._anchorOffset.top - this._windowScrollTop,\n                bottomClearance = this._windowHeight + this._windowScrollTop - this._anchorOffsetBottom;\n\n            if (bottomClearance >= this._menuHeight || (topClearance < this._menuHeight && bottomClearance >= topClearance)) {\n                this.$container.css({\n                    top: this._anchorOffsetBottom,\n                    maxHeight: bottomClearance - this.settings.windowSpacing\n                });\n            } else {\n                this.$container.css({\n                    top: this._anchorOffset.top - Math.min(this._menuHeight, topClearance - this.settings.windowSpacing),\n                    maxHeight: topClearance - this.settings.windowSpacing\n                });\n            }\n\n            // Figure out how we're aliging it\n            var align = this.$container.data('align');\n\n            if (align !== 'left' && align !== 'center' && align !== 'right') {\n                align = 'left';\n            }\n\n            if (align === 'center') {\n                this._alignCenter();\n            }\n            else {\n                // Figure out which options are actually possible\n                var rightClearance = this._windowWidth + this._windowScrollLeft - (this._anchorOffset.left + this._menuWidth),\n                    leftClearance = this._anchorOffsetRight - this._menuWidth;\n\n                if (align === 'right' && leftClearance >= 0 || rightClearance < 0) {\n                    this._alignRight();\n                }\n                else {\n                    this._alignLeft();\n                }\n            }\n\n            delete this._windowWidth;\n            delete this._windowHeight;\n            delete this._windowScrollLeft;\n            delete this._windowScrollTop;\n            delete this._anchorOffset;\n            delete this._anchorWidth;\n            delete this._anchorHeight;\n            delete this._anchorOffsetRight;\n            delete this._anchorOffsetBottom;\n            delete this._menuWidth;\n            delete this._menuHeight;\n        },\n\n        show: function() {\n            // Move the menu to the end of the DOM\n            this.$container.appendTo(Garnish.$bod);\n\n            if (this.$anchor) {\n                this.setPositionRelativeToAnchor();\n            }\n\n            this.$container.velocity('stop');\n            this.$container.css({\n                opacity: 1,\n                display: 'block'\n            });\n\n            this.$menuList.attr('aria-hidden', 'false');\n\n            Garnish.escManager.register(this, 'hide');\n            this.addListener(Garnish.$scrollContainer, 'scroll', 'setPositionRelativeToAnchor');\n        },\n\n        hide: function() {\n            this.$menuList.attr('aria-hidden', 'true');\n\n            this.$container.velocity('fadeOut', {duration: Garnish.FX_DURATION}, $.proxy(function() {\n                this.$container.detach();\n            }, this));\n\n            Garnish.escManager.unregister(this);\n            this.removeListener(Garnish.$scrollContainer, 'scroll');\n\n            this.trigger('hide');\n        },\n\n        selectOption: function(ev) {\n            this.settings.onOptionSelect(ev.currentTarget);\n            this.trigger('optionselect', {selectedOption: ev.currentTarget});\n            this.hide();\n        },\n\n        _alignLeft: function() {\n            this.$container.css({\n                left: this._anchorOffset.left,\n                right: 'auto'\n            });\n        },\n\n        _alignRight: function() {\n            this.$container.css({\n                right: this._windowWidth - (this._anchorOffset.left + this._anchorWidth),\n                left: 'auto'\n            });\n        },\n\n        _alignCenter: function() {\n            var left = Math.round((this._anchorOffset.left + this._anchorWidth / 2) - (this._menuWidth / 2));\n\n            if (left < 0) {\n                left = 0;\n            }\n\n            this.$container.css('left', left);\n        }\n\n    },\n    {\n        defaults: {\n            anchor: null,\n            windowSpacing: 5,\n            onOptionSelect: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Menu Button\n */\nGarnish.MenuBtn = Garnish.Base.extend(\n    {\n        $btn: null,\n        menu: null,\n        showingMenu: false,\n        disabled: true,\n\n        /**\n         * Constructor\n         */\n        init: function(btn, settings) {\n            this.$btn = $(btn);\n\n            // Is this already a menu button?\n            if (this.$btn.data('menubtn')) {\n                // Grab the old MenuBtn's menu container\n                var $menu = this.$btn.data('menubtn').menu.$container;\n\n                Garnish.log('Double-instantiating a menu button on an element');\n                this.$btn.data('menubtn').destroy();\n            }\n            else {\n                var $menu = this.$btn.next('.menu').detach();\n            }\n\n            this.$btn.data('menubtn', this);\n\n            this.setSettings(settings, Garnish.MenuBtn.defaults);\n\n            this.menu = new Garnish.Menu($menu, {\n                anchor: (this.settings.menuAnchor || this.$btn),\n                onOptionSelect: $.proxy(this, 'onOptionSelect')\n            });\n\n            this.$btn.attr({\n                'tabindex': 0,\n                'role': 'combobox',\n                'aria-owns': this.menu.menuId,\n                'aria-haspopup': 'true',\n                'aria-expanded': 'false'\n            });\n\n            this.menu.on('hide', $.proxy(this, 'onMenuHide'));\n            this.addListener(this.$btn, 'mousedown', 'onMouseDown');\n            this.addListener(this.$btn, 'keydown', 'onKeyDown');\n            this.addListener(this.$btn, 'blur', 'onBlur');\n            this.enable();\n        },\n\n        onBlur: function(ev) {\n            if (this.showingMenu) {\n                this.hideMenu();\n            }\n        },\n\n        onKeyDown: function(ev) {\n            var $option;\n\n            switch (ev.keyCode) {\n                case Garnish.RETURN_KEY: {\n                    ev.preventDefault();\n\n                    var $currentOption = this.menu.$options.filter('.hover');\n\n                    if ($currentOption.length > 0) {\n                        $currentOption.get(0).click();\n                    }\n\n                    break;\n                }\n\n                case Garnish.SPACE_KEY: {\n                    ev.preventDefault();\n\n                    if (!this.showingMenu) {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.first();\n                        }\n\n                        this.focusOption($option);\n                    }\n\n                    break;\n                }\n\n                case Garnish.DOWN_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        $.each(this.menu.$options, $.proxy(function(index, value) {\n                            if (!$option) {\n                                if ($(value).hasClass('hover')) {\n                                    if ((index + 1) < this.menu.$options.length) {\n                                        $option = $(this.menu.$options[(index + 1)]);\n                                    }\n                                }\n                            }\n                        }, this));\n\n                        if (!$option) {\n                            $option = $(this.menu.$options[0]);\n                        }\n                    }\n                    else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.first();\n                        }\n                    }\n\n                    this.focusOption($option);\n\n                    break;\n                }\n\n                case Garnish.UP_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        $.each(this.menu.$options, $.proxy(function(index, value) {\n                            if (!$option) {\n                                if ($(value).hasClass('hover')) {\n                                    if ((index - 1) >= 0) {\n                                        $option = $(this.menu.$options[(index - 1)]);\n                                    }\n                                }\n                            }\n                        }, this));\n\n                        if (!$option) {\n                            $option = $(this.menu.$options[(this.menu.$options.length - 1)]);\n                        }\n                    }\n                    else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.last();\n                        }\n                    }\n\n                    this.focusOption($option);\n\n                    break;\n                }\n            }\n        },\n\n        focusOption: function($option) {\n            this.menu.$options.removeClass('hover');\n\n            $option.addClass('hover');\n\n            this.menu.$menuList.attr('aria-activedescendant', $option.attr('id'));\n            this.$btn.attr('aria-activedescendant', $option.attr('id'));\n        },\n\n        onMouseDown: function(ev) {\n            if (ev.which !== Garnish.PRIMARY_CLICK || Garnish.isCtrlKeyPressed(ev)) {\n                return;\n            }\n\n            ev.preventDefault();\n\n            if (this.showingMenu) {\n                this.hideMenu();\n            }\n            else {\n                this.showMenu();\n            }\n        },\n\n        showMenu: function() {\n            if (this.disabled) {\n                return;\n            }\n\n            this.menu.show();\n            this.$btn.addClass('active');\n            this.$btn.trigger('focus');\n            this.$btn.attr('aria-expanded', 'true');\n\n            this.showingMenu = true;\n\n            setTimeout($.proxy(function() {\n                this.addListener(Garnish.$doc, 'mousedown', 'onMouseDown');\n            }, this), 1);\n        },\n\n        hideMenu: function() {\n            this.menu.hide();\n            this.$btn.attr('aria-expanded', 'false');\n        },\n\n        onMenuHide: function() {\n            this.$btn.removeClass('active');\n            this.showingMenu = false;\n\n            this.removeListener(Garnish.$doc, 'mousedown');\n        },\n\n        onOptionSelect: function(option) {\n            this.settings.onOptionSelect(option);\n            this.trigger('optionSelect', {option: option});\n        },\n\n        enable: function() {\n            this.disabled = false;\n        },\n\n        disable: function() {\n            this.disabled = true;\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$btn.removeData('menubtn');\n            this.base();\n        }\n    },\n    {\n        defaults: {\n            menuAnchor: null,\n            onOptionSelect: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Mixed input\n *\n * @todo RTL support, in the event that the input doesn't have dir=\"ltr\".\n */\nGarnish.MixedInput = Garnish.Base.extend(\n    {\n        $container: null,\n        elements: null,\n        focussedElement: null,\n        blurTimeout: null,\n\n        init: function(container, settings) {\n            this.$container = $(container);\n            this.setSettings(settings, Garnish.MixedInput.defaults);\n\n            this.elements = [];\n\n            // Allow the container to receive focus\n            this.$container.attr('tabindex', 0);\n            this.addListener(this.$container, 'focus', 'onFocus');\n        },\n\n        getElementIndex: function($elem) {\n            return $.inArray($elem, this.elements);\n        },\n\n        isText: function($elem) {\n            return ($elem.prop('nodeName') === 'INPUT');\n        },\n\n        onFocus: function() {\n            // Set focus to the first element\n            if (this.elements.length) {\n                var $elem = this.elements[0];\n                this.setFocus($elem);\n                this.setCarotPos($elem, 0);\n            }\n            else {\n                this.addTextElement();\n            }\n        },\n\n        addTextElement: function(index) {\n            var text = new TextElement(this);\n            this.addElement(text.$input, index);\n            return text;\n        },\n\n        addElement: function($elem, index) {\n            // Was a target index passed, and is it valid?\n            if (typeof index === 'undefined') {\n                if (this.focussedElement) {\n                    var focussedElement = this.focussedElement,\n                        focussedElementIndex = this.getElementIndex(focussedElement);\n\n                    // Is the focus on a text element?\n                    if (this.isText(focussedElement)) {\n                        var selectionStart = focussedElement.prop('selectionStart'),\n                            selectionEnd = focussedElement.prop('selectionEnd'),\n                            val = focussedElement.val(),\n                            preVal = val.substring(0, selectionStart),\n                            postVal = val.substr(selectionEnd);\n\n                        if (preVal && postVal) {\n                            // Split the input into two\n                            focussedElement.val(preVal).trigger('change');\n                            var newText = new TextElement(this);\n                            newText.$input.val(postVal).trigger('change');\n                            this.addElement(newText.$input, focussedElementIndex + 1);\n\n                            // Insert the new element in between them\n                            index = focussedElementIndex + 1;\n                        }\n                        else if (!preVal) {\n                            // Insert the new element before this one\n                            index = focussedElementIndex;\n                        }\n                        else {\n                            // Insert it after this one\n                            index = focussedElementIndex + 1;\n                        }\n                    }\n                    else {\n                        // Just insert the new one after this one\n                        index = focussedElementIndex + 1;\n                    }\n                }\n                else {\n                    // Insert the new element at the end\n                    index = this.elements.length;\n                }\n            }\n\n            // Add the element\n            if (typeof this.elements[index] !== 'undefined') {\n                $elem.insertBefore(this.elements[index]);\n                this.elements.splice(index, 0, $elem);\n            }\n            else {\n                // Just for safe measure, set the index to what it really will be\n                index = this.elements.length;\n\n                this.$container.append($elem);\n                this.elements.push($elem);\n            }\n\n            // Make sure that there are text elements surrounding all non-text elements\n            if (!this.isText($elem)) {\n                // Add a text element before?\n                if (index === 0 || !this.isText(this.elements[index - 1])) {\n                    this.addTextElement(index);\n                    index++;\n                }\n\n                // Add a text element after?\n                if (index === this.elements.length - 1 || !this.isText(this.elements[index + 1])) {\n                    this.addTextElement(index + 1);\n                }\n            }\n\n            // Add event listeners\n            this.addListener($elem, 'click', function() {\n                this.setFocus($elem);\n            });\n\n            // Set focus to the new element\n            setTimeout($.proxy(function() {\n                this.setFocus($elem);\n            }, this), 1);\n        },\n\n        removeElement: function($elem) {\n            var index = this.getElementIndex($elem);\n            if (index !== -1) {\n                this.elements.splice(index, 1);\n\n                if (!this.isText($elem)) {\n                    // Combine the two now-adjacent text elements\n                    var $prevElem = this.elements[index - 1],\n                        $nextElem = this.elements[index];\n\n                    if (this.isText($prevElem) && this.isText($nextElem)) {\n                        var prevElemVal = $prevElem.val(),\n                            newVal = prevElemVal + $nextElem.val();\n                        $prevElem.val(newVal).trigger('change');\n                        this.removeElement($nextElem);\n                        this.setFocus($prevElem);\n                        this.setCarotPos($prevElem, prevElemVal.length);\n                    }\n                }\n\n                $elem.remove();\n            }\n        },\n\n        setFocus: function($elem) {\n            this.$container.addClass('focus');\n\n            if (!this.focussedElement) {\n                // Prevent the container from receiving focus\n                // as long as one of its elements has focus\n                this.$container.attr('tabindex', '-1');\n            }\n            else {\n                // Blur the previously-focussed element\n                this.blurFocussedElement();\n            }\n\n            $elem.attr('tabindex', '0');\n            $elem.focus();\n            this.focussedElement = $elem;\n\n            this.addListener($elem, 'blur', function() {\n                this.blurTimeout = setTimeout($.proxy(function() {\n                    if (this.focussedElement === $elem) {\n                        this.blurFocussedElement();\n                        this.focussedElement = null;\n                        this.$container.removeClass('focus');\n\n                        // Get ready for future focus\n                        this.$container.attr('tabindex', '0');\n                    }\n                }, this), 1);\n            });\n        },\n\n        blurFocussedElement: function() {\n            this.removeListener(this.focussedElement, 'blur');\n            this.focussedElement.attr('tabindex', '-1');\n        },\n\n        focusPreviousElement: function($from) {\n            var index = this.getElementIndex($from);\n\n            if (index > 0) {\n                var $elem = this.elements[index - 1];\n                this.setFocus($elem);\n\n                // If it's a text element, put the carot at the end\n                if (this.isText($elem)) {\n                    var length = $elem.val().length;\n                    this.setCarotPos($elem, length);\n                }\n            }\n        },\n\n        focusNextElement: function($from) {\n            var index = this.getElementIndex($from);\n\n            if (index < this.elements.length - 1) {\n                var $elem = this.elements[index + 1];\n                this.setFocus($elem);\n\n                // If it's a text element, put the carot at the beginning\n                if (this.isText($elem)) {\n                    this.setCarotPos($elem, 0)\n                }\n            }\n        },\n\n        setCarotPos: function($elem, pos) {\n            $elem.prop('selectionStart', pos);\n            $elem.prop('selectionEnd', pos);\n        }\n\n    });\n\n\nvar TextElement = Garnish.Base.extend({\n\n        parentInput: null,\n        $input: null,\n        $stage: null,\n        val: null,\n        focussed: false,\n        interval: null,\n\n        init: function(parentInput) {\n            this.parentInput = parentInput;\n\n            this.$input = $('<input type=\"text\"/>').appendTo(this.parentInput.$container);\n            this.$input.css('margin-right', (2 - TextElement.padding) + 'px');\n\n            this.setWidth();\n\n            this.addListener(this.$input, 'focus', 'onFocus');\n            this.addListener(this.$input, 'blur', 'onBlur');\n            this.addListener(this.$input, 'keydown', 'onKeyDown');\n            this.addListener(this.$input, 'change', 'checkInput');\n        },\n\n        getIndex: function() {\n            return this.parentInput.getElementIndex(this.$input);\n        },\n\n        buildStage: function() {\n            this.$stage = $('<stage/>').appendTo(Garnish.$bod);\n\n            // replicate the textarea's text styles\n            this.$stage.css({\n                position: 'absolute',\n                top: -9999,\n                left: -9999,\n                wordWrap: 'nowrap'\n            });\n\n            Garnish.copyTextStyles(this.$input, this.$stage);\n        },\n\n        getTextWidth: function(val) {\n            if (!this.$stage) {\n                this.buildStage();\n            }\n\n            if (val) {\n                // Ampersand entities\n                val = val.replace(/&/g, '&amp;');\n\n                // < and >\n                val = val.replace(/</g, '&lt;');\n                val = val.replace(/>/g, '&gt;');\n\n                // Spaces\n                val = val.replace(/ /g, '&nbsp;');\n            }\n\n            this.$stage.html(val);\n            this.stageWidth = this.$stage.width();\n            return this.stageWidth;\n        },\n\n        onFocus: function() {\n            this.focussed = true;\n            this.interval = setInterval($.proxy(this, 'checkInput'), Garnish.NiceText.interval);\n            this.checkInput();\n        },\n\n        onBlur: function() {\n            this.focussed = false;\n            clearInterval(this.interval);\n            this.checkInput();\n        },\n\n        onKeyDown: function(ev) {\n            setTimeout($.proxy(this, 'checkInput'), 1);\n\n            switch (ev.keyCode) {\n                case Garnish.LEFT_KEY: {\n                    if (this.$input.prop('selectionStart') === 0 && this.$input.prop('selectionEnd') === 0) {\n                        // Set focus to the previous element\n                        this.parentInput.focusPreviousElement(this.$input);\n                    }\n                    break;\n                }\n\n                case Garnish.RIGHT_KEY: {\n                    if (this.$input.prop('selectionStart') === this.val.length && this.$input.prop('selectionEnd') === this.val.length) {\n                        // Set focus to the next element\n                        this.parentInput.focusNextElement(this.$input);\n                    }\n                    break;\n                }\n\n                case Garnish.DELETE_KEY: {\n                    if (this.$input.prop('selectionStart') === 0 && this.$input.prop('selectionEnd') === 0) {\n                        // Set focus to the previous element\n                        this.parentInput.focusPreviousElement(this.$input);\n                        ev.preventDefault();\n                    }\n                }\n            }\n        },\n\n        getVal: function() {\n            this.val = this.$input.val();\n            return this.val;\n        },\n\n        setVal: function(val) {\n            this.$input.val(val);\n            this.checkInput();\n        },\n\n        checkInput: function() {\n            // Has the value changed?\n            var changed = (this.val !== this.getVal());\n            if (changed) {\n                this.setWidth();\n                this.onChange();\n            }\n\n            return changed;\n        },\n\n        setWidth: function() {\n            // has the width changed?\n            if (this.stageWidth !== this.getTextWidth(this.val)) {\n                // update the textarea width\n                var width = this.stageWidth + TextElement.padding;\n                this.$input.width(width);\n            }\n        },\n\n        onChange: $.noop\n    },\n    {\n        padding: 20\n    }\n);\n\n/** global: Garnish */\n/**\n * Modal\n */\nGarnish.Modal = Garnish.Base.extend(\n    {\n        $container: null,\n        $shade: null,\n\n        visible: false,\n\n        dragger: null,\n\n        desiredWidth: null,\n        desiredHeight: null,\n        resizeDragger: null,\n        resizeStartWidth: null,\n        resizeStartHeight: null,\n\n        init: function(container, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(container)) {\n                // (settings)\n                settings = container;\n                container = null;\n            }\n\n            this.setSettings(settings, Garnish.Modal.defaults);\n\n            // Create the shade\n            this.$shade = $('<div class=\"' + this.settings.shadeClass + '\"/>');\n\n            // If the container is already set, drop the shade below it.\n            if (container) {\n                this.$shade.insertBefore(container);\n            }\n            else {\n                this.$shade.appendTo(Garnish.$bod);\n            }\n\n            if (container) {\n                this.setContainer(container);\n\n                if (this.settings.autoShow) {\n                    this.show();\n                }\n            }\n\n            Garnish.Modal.instances.push(this);\n        },\n\n        setContainer: function(container) {\n            this.$container = $(container);\n\n            // Is this already a modal?\n            if (this.$container.data('modal')) {\n                Garnish.log('Double-instantiating a modal on an element');\n                this.$container.data('modal').destroy();\n            }\n\n            this.$container.data('modal', this);\n\n            if (this.settings.draggable) {\n                this.dragger = new Garnish.DragMove(this.$container, {\n                    handle: (this.settings.dragHandleSelector ? this.$container.find(this.settings.dragHandleSelector) : this.$container)\n                });\n            }\n\n            if (this.settings.resizable) {\n                var $resizeDragHandle = $('<div class=\"resizehandle\"/>').appendTo(this.$container);\n\n                this.resizeDragger = new Garnish.BaseDrag($resizeDragHandle, {\n                    onDragStart: $.proxy(this, '_handleResizeStart'),\n                    onDrag: $.proxy(this, '_handleResize')\n                });\n            }\n\n            this.addListener(this.$container, 'click', function(ev) {\n                ev.stopPropagation();\n            });\n\n            // Show it if we're late to the party\n            if (this.visible) {\n                this.show();\n            }\n        },\n\n        show: function() {\n            // Close other modals as needed\n            if (this.settings.closeOtherModals && Garnish.Modal.visibleModal && Garnish.Modal.visibleModal !== this) {\n                Garnish.Modal.visibleModal.hide();\n            }\n\n            if (this.$container) {\n                // Move it to the end of <body> so it gets the highest sub-z-index\n                this.$shade.appendTo(Garnish.$bod);\n                this.$container.appendTo(Garnish.$bod);\n\n                this.$container.show();\n                this.updateSizeAndPosition();\n\n                this.$shade.velocity('fadeIn', {\n                    duration: 50,\n                    complete: $.proxy(function() {\n                        this.$container.velocity('fadeIn', {\n                            complete: $.proxy(function() {\n                                this.updateSizeAndPosition();\n                                this.onFadeIn();\n                            }, this)\n                        });\n                    }, this)\n                });\n\n                if (this.settings.hideOnShadeClick) {\n                    this.addListener(this.$shade, 'click', 'hide');\n                }\n\n                this.addListener(Garnish.$win, 'resize', '_handleWindowResize');\n            }\n\n            this.enable();\n\n            if (this.settings.hideOnEsc) {\n                Garnish.escManager.register(this, 'hide');\n            }\n\n            if (!this.visible) {\n                this.visible = true;\n                Garnish.Modal.visibleModal = this;\n\n                this.trigger('show');\n                this.settings.onShow();\n            }\n        },\n\n        quickShow: function() {\n            this.show();\n\n            if (this.$container) {\n                this.$container.velocity('stop');\n                this.$container.show().css('opacity', 1);\n\n                this.$shade.velocity('stop');\n                this.$shade.show().css('opacity', 1);\n            }\n        },\n\n        hide: function(ev) {\n            this.disable();\n\n            if (ev) {\n                ev.stopPropagation();\n            }\n\n            if (this.$container) {\n                this.$container.velocity('fadeOut', {duration: Garnish.FX_DURATION});\n                this.$shade.velocity('fadeOut', {\n                    duration: Garnish.FX_DURATION,\n                    complete: $.proxy(this, 'onFadeOut')\n                });\n\n                if (this.settings.hideOnShadeClick) {\n                    this.removeListener(this.$shade, 'click');\n                }\n\n                this.removeListener(Garnish.$win, 'resize');\n            }\n\n            this.visible = false;\n            Garnish.Modal.visibleModal = null;\n\n            if (this.settings.hideOnEsc) {\n                Garnish.escManager.unregister(this);\n            }\n\n            this.trigger('hide');\n            this.settings.onHide();\n        },\n\n        quickHide: function() {\n            this.hide();\n\n            if (this.$container) {\n                this.$container.velocity('stop');\n                this.$container.css('opacity', 0).hide();\n\n                this.$shade.velocity('stop');\n                this.$shade.css('opacity', 0).hide();\n            }\n        },\n\n        updateSizeAndPosition: function() {\n            if (!this.$container) {\n                return;\n            }\n\n            this.$container.css({\n                'width': (this.desiredWidth ? Math.max(this.desiredWidth, 200) : ''),\n                'height': (this.desiredHeight ? Math.max(this.desiredHeight, 200) : ''),\n                'min-width': '',\n                'min-height': ''\n            });\n\n            // Set the width first so that the height can adjust for the width\n            this.updateSizeAndPosition._windowWidth = Garnish.$win.width();\n            this.updateSizeAndPosition._width = Math.min(this.getWidth(), this.updateSizeAndPosition._windowWidth - this.settings.minGutter * 2);\n\n            this.$container.css({\n                'width': this.updateSizeAndPosition._width,\n                'min-width': this.updateSizeAndPosition._width,\n                'left': Math.round((this.updateSizeAndPosition._windowWidth - this.updateSizeAndPosition._width) / 2)\n            });\n\n            // Now set the height\n            this.updateSizeAndPosition._windowHeight = Garnish.$win.height();\n            this.updateSizeAndPosition._height = Math.min(this.getHeight(), this.updateSizeAndPosition._windowHeight - this.settings.minGutter * 2);\n\n            this.$container.css({\n                'height': this.updateSizeAndPosition._height,\n                'min-height': this.updateSizeAndPosition._height,\n                'top': Math.round((this.updateSizeAndPosition._windowHeight - this.updateSizeAndPosition._height) / 2)\n            });\n\n            this.trigger('updateSizeAndPosition');\n        },\n\n        onFadeIn: function() {\n            this.trigger('fadeIn');\n            this.settings.onFadeIn();\n        },\n\n        onFadeOut: function() {\n            this.trigger('fadeOut');\n            this.settings.onFadeOut();\n        },\n\n        getHeight: function() {\n            if (!this.$container) {\n                throw 'Attempted to get the height of a modal whose container has not been set.';\n            }\n\n            if (!this.visible) {\n                this.$container.show();\n            }\n\n            this.getHeight._height = this.$container.outerHeight();\n\n            if (!this.visible) {\n                this.$container.hide();\n            }\n\n            return this.getHeight._height;\n        },\n\n        getWidth: function() {\n            if (!this.$container) {\n                throw 'Attempted to get the width of a modal whose container has not been set.';\n            }\n\n            if (!this.visible) {\n                this.$container.show();\n            }\n\n            // Chrome might be 1px shy here for some reason\n            this.getWidth._width = this.$container.outerWidth() + 1;\n\n            if (!this.visible) {\n                this.$container.hide();\n            }\n\n            return this.getWidth._width;\n        },\n\n        _handleWindowResize: function(ev) {\n            // ignore propagated resize events\n            if (ev.target === window) {\n                this.updateSizeAndPosition();\n            }\n        },\n\n        _handleResizeStart: function() {\n            this.resizeStartWidth = this.getWidth();\n            this.resizeStartHeight = this.getHeight();\n        },\n\n        _handleResize: function() {\n            if (Garnish.ltr) {\n                this.desiredWidth = this.resizeStartWidth + (this.resizeDragger.mouseDistX * 2);\n            }\n            else {\n                this.desiredWidth = this.resizeStartWidth - (this.resizeDragger.mouseDistX * 2);\n            }\n\n            this.desiredHeight = this.resizeStartHeight + (this.resizeDragger.mouseDistY * 2);\n\n            this.updateSizeAndPosition();\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            if (this.$container) {\n                this.$container.removeData('modal').remove();\n            }\n\n            if (this.dragger) {\n                this.dragger.destroy();\n            }\n\n            if (this.resizeDragger) {\n                this.resizeDragger.destroy();\n            }\n\n            this.base();\n        }\n    },\n    {\n        relativeElemPadding: 8,\n        defaults: {\n            autoShow: true,\n            draggable: false,\n            dragHandleSelector: null,\n            resizable: false,\n            minGutter: 10,\n            onShow: $.noop,\n            onHide: $.noop,\n            onFadeIn: $.noop,\n            onFadeOut: $.noop,\n            closeOtherModals: false,\n            hideOnEsc: true,\n            hideOnShadeClick: true,\n            shadeClass: 'modal-shade'\n        },\n        instances: [],\n        visibleModal: null\n    }\n);\n\n/** global: Garnish */\n/**\n * Nice Text\n */\nGarnish.NiceText = Garnish.Base.extend(\n    {\n        $input: null,\n        $hint: null,\n        $stage: null,\n        $charsLeft: null,\n        autoHeight: null,\n        maxLength: null,\n        showCharsLeft: false,\n        showingHint: false,\n        val: null,\n        inputBoxSizing: 'content-box',\n        width: null,\n        height: null,\n        minHeight: null,\n        initialized: false,\n\n        init: function(input, settings) {\n            this.$input = $(input);\n            this.settings = $.extend({}, Garnish.NiceText.defaults, settings);\n\n            if (this.isVisible()) {\n                this.initialize();\n            }\n            else {\n                this.addListener(Garnish.$win, 'resize', 'initializeIfVisible');\n            }\n        },\n\n        isVisible: function() {\n            return (this.$input.height() > 0);\n        },\n\n        initialize: function() {\n            if (this.initialized) {\n                return;\n            }\n\n            this.initialized = true;\n            this.removeListener(Garnish.$win, 'resize');\n\n            this.maxLength = this.$input.attr('maxlength');\n\n            if (this.maxLength) {\n                this.maxLength = parseInt(this.maxLength);\n            }\n\n            if (this.maxLength && (this.settings.showCharsLeft || Garnish.hasAttr(this.$input, 'data-show-chars-left'))) {\n                this.showCharsLeft = true;\n\n                // Remove the maxlength attribute\n                this.$input.removeAttr('maxlength');\n            }\n\n            // Is this already a transparent text input?\n            if (this.$input.data('nicetext')) {\n                Garnish.log('Double-instantiating a transparent text input on an element');\n                this.$input.data('nicetext').destroy();\n            }\n\n            this.$input.data('nicetext', this);\n\n            this.getVal();\n\n            this.autoHeight = (this.settings.autoHeight && this.$input.prop('nodeName') === 'TEXTAREA');\n\n            if (this.autoHeight) {\n                this.minHeight = this.getHeightForValue('');\n                this.updateHeight();\n\n                // Update height when the window resizes\n                this.width = this.$input.width();\n                this.addListener(Garnish.$win, 'resize', 'updateHeightIfWidthChanged');\n            }\n\n            if (this.settings.hint) {\n                this.$hintContainer = $('<div class=\"texthint-container\"/>').insertBefore(this.$input);\n                this.$hint = $('<div class=\"texthint\">' + this.settings.hint + '</div>').appendTo(this.$hintContainer);\n                this.$hint.css({\n                    top: (parseInt(this.$input.css('borderTopWidth')) + parseInt(this.$input.css('paddingTop'))),\n                    left: (parseInt(this.$input.css('borderLeftWidth')) + parseInt(this.$input.css('paddingLeft')) + 1)\n                });\n                Garnish.copyTextStyles(this.$input, this.$hint);\n\n                if (this.val) {\n                    this.$hint.hide();\n                }\n                else {\n                    this.showingHint = true;\n                }\n\n                // Focus the input when clicking on the hint\n                this.addListener(this.$hint, 'mousedown', function(ev) {\n                    ev.preventDefault();\n                    this.$input.focus();\n                });\n            }\n\n            if (this.showCharsLeft) {\n                this.$charsLeft = $('<div class=\"' + this.settings.charsLeftClass + '\"/>').insertAfter(this.$input);\n                this.updateCharsLeft();\n            }\n\n            this.addListener(this.$input, 'textchange', 'onTextChange');\n        },\n\n        initializeIfVisible: function() {\n            if (this.isVisible()) {\n                this.initialize();\n            }\n        },\n\n        getVal: function() {\n            this.val = this.$input.val();\n            return this.val;\n        },\n\n        showHint: function() {\n            this.$hint.velocity('fadeIn', {\n                complete: Garnish.NiceText.hintFadeDuration\n            });\n\n            this.showingHint = true;\n        },\n\n        hideHint: function() {\n            this.$hint.velocity('fadeOut', {\n                complete: Garnish.NiceText.hintFadeDuration\n            });\n\n            this.showingHint = false;\n        },\n\n        onTextChange: function() {\n            this.getVal();\n\n            if (this.$hint) {\n                if (this.showingHint && this.val) {\n                    this.hideHint();\n                }\n                else if (!this.showingHint && !this.val) {\n                    this.showHint();\n                }\n            }\n\n            if (this.autoHeight) {\n                this.updateHeight();\n            }\n\n            if (this.showCharsLeft) {\n                this.updateCharsLeft();\n            }\n        },\n\n        buildStage: function() {\n            this.$stage = $('<stage/>').appendTo(Garnish.$bod);\n\n            // replicate the textarea's text styles\n            this.$stage.css({\n                display: 'block',\n                position: 'absolute',\n                top: -9999,\n                left: -9999\n            });\n\n            this.inputBoxSizing = this.$input.css('box-sizing');\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.$stage.css({\n                    'border-top': this.$input.css('border-top'),\n                    'border-right': this.$input.css('border-right'),\n                    'border-bottom': this.$input.css('border-bottom'),\n                    'border-left': this.$input.css('border-left'),\n                    'padding-top': this.$input.css('padding-top'),\n                    'padding-right': this.$input.css('padding-right'),\n                    'padding-bottom': this.$input.css('padding-bottom'),\n                    'padding-left': this.$input.css('padding-left'),\n                    '-webkit-box-sizing': this.inputBoxSizing,\n                    '-moz-box-sizing': this.inputBoxSizing,\n                    'box-sizing': this.inputBoxSizing\n                });\n            }\n\n            Garnish.copyTextStyles(this.$input, this.$stage);\n        },\n\n        getHeightForValue: function(val) {\n            if (!this.$stage) {\n                this.buildStage();\n            }\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.$stage.css('width', this.$input.outerWidth());\n            }\n            else {\n                this.$stage.css('width', this.$input.width());\n            }\n\n            if (!val) {\n                val = '&nbsp;';\n                for (var i = 1; i < this.$input.prop('rows'); i++) {\n                    val += '<br/>&nbsp;';\n                }\n            }\n            else {\n                // Ampersand entities\n                val = val.replace(/&/g, '&amp;');\n\n                // < and >\n                val = val.replace(/</g, '&lt;');\n                val = val.replace(/>/g, '&gt;');\n\n                // Multiple spaces\n                val = val.replace(/ {2,}/g, function(spaces) {\n                    // TODO: replace with String.repeat() when more broadly available?\n                    var replace = '';\n                    for (var i = 0; i < spaces.length - 1; i++) {\n                        replace += '&nbsp;';\n                    }\n                    return replace + ' ';\n                });\n\n                // Line breaks\n                val = val.replace(/[\\n\\r]$/g, '<br/>&nbsp;');\n                val = val.replace(/[\\n\\r]/g, '<br/>');\n            }\n\n            this.$stage.html(val);\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.getHeightForValue._height = this.$stage.outerHeight();\n            }\n            else {\n                this.getHeightForValue._height = this.$stage.height();\n            }\n\n            if (this.minHeight && this.getHeightForValue._height < this.minHeight) {\n                this.getHeightForValue._height = this.minHeight;\n            }\n\n            return this.getHeightForValue._height;\n        },\n\n        updateHeight: function() {\n            // has the height changed?\n            if (this.height !== (this.height = this.getHeightForValue(this.val))) {\n                this.$input.css('min-height', this.height);\n\n                if (this.initialized) {\n                    this.onHeightChange();\n                }\n            }\n        },\n\n        updateHeightIfWidthChanged: function() {\n            if (this.isVisible() && this.width !== (this.width = this.$input.width()) && this.width) {\n                this.updateHeight();\n            }\n        },\n\n        onHeightChange: function() {\n            this.settings.onHeightChange();\n        },\n\n        updateCharsLeft: function() {\n            this.updateCharsLeft._charsLeft = this.maxLength - this.val.length;\n            this.$charsLeft.text(this.updateCharsLeft._charsLeft);\n\n            if (this.updateCharsLeft._charsLeft >= 0) {\n                this.$charsLeft.removeClass(this.settings.negativeCharsLeftClass);\n            }\n            else {\n                this.$charsLeft.addClass(this.settings.negativeCharsLeftClass);\n            }\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$input.removeData('nicetext');\n\n            if (this.$hint) {\n                this.$hint.remove();\n            }\n\n            if (this.$stage) {\n                this.$stage.remove();\n            }\n\n            this.base();\n        }\n    },\n    {\n        interval: 100,\n        hintFadeDuration: 50,\n        defaults: {\n            autoHeight: true,\n            showCharsLeft: false,\n            charsLeftClass: 'chars-left',\n            negativeCharsLeftClass: 'negative-chars-left',\n            onHeightChange: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Pill\n */\nGarnish.Pill = Garnish.Base.extend(\n    {\n        $outerContainer: null,\n        $innerContainer: null,\n        $btns: null,\n        $selectedBtn: null,\n        $input: null,\n\n        init: function(outerContainer) {\n            this.$outerContainer = $(outerContainer);\n\n            // Is this already a pill?\n            if (this.$outerContainer.data('pill')) {\n                Garnish.log('Double-instantiating a pill on an element');\n                this.$outerContainer.data('pill').destroy();\n            }\n\n            this.$outerContainer.data('pill', this);\n\n            this.$innerContainer = this.$outerContainer.find('.btngroup:first');\n            this.$btns = this.$innerContainer.find('.btn');\n            this.$selectedBtn = this.$btns.filter('.active:first');\n            this.$input = this.$outerContainer.find('input:first');\n\n            Garnish.preventOutlineOnMouseFocus(this.$innerContainer);\n            this.addListener(this.$btns, 'mousedown', 'onMouseDown');\n            this.addListener(this.$innerContainer, 'keydown', 'onKeyDown');\n        },\n\n        select: function(btn) {\n            this.$selectedBtn.removeClass('active');\n            var $btn = $(btn);\n            $btn.addClass('active');\n            this.$input.val($btn.attr('data-value'));\n            this.$selectedBtn = $btn;\n        },\n\n        selectNext: function() {\n            if (!this.$selectedBtn.length) {\n                this.select(this.$btns[this.$btns.length - 1]);\n            }\n            else {\n                var nextIndex = this._getSelectedBtnIndex() + 1;\n\n                if (typeof this.$btns[nextIndex] !== 'undefined') {\n                    this.select(this.$btns[nextIndex]);\n                }\n            }\n        },\n\n        selectPrev: function() {\n            if (!this.$selectedBtn.length) {\n                this.select(this.$btns[0]);\n            }\n            else {\n                var prevIndex = this._getSelectedBtnIndex() - 1;\n\n                if (typeof this.$btns[prevIndex] !== 'undefined') {\n                    this.select(this.$btns[prevIndex]);\n                }\n            }\n        },\n\n        onMouseDown: function(ev) {\n            this.select(ev.currentTarget);\n        },\n\n        _getSelectedBtnIndex: function() {\n            if (typeof this.$selectedBtn[0] !== 'undefined') {\n                return $.inArray(this.$selectedBtn[0], this.$btns);\n            }\n            else {\n                return -1;\n            }\n        },\n\n        onKeyDown: function(ev) {\n            switch (ev.keyCode) {\n                case Garnish.RIGHT_KEY: {\n                    if (Garnish.ltr) {\n                        this.selectNext();\n                    }\n                    else {\n                        this.selectPrev();\n                    }\n\n                    ev.preventDefault();\n                    break;\n                }\n\n                case Garnish.LEFT_KEY: {\n                    if (Garnish.ltr) {\n                        this.selectPrev();\n                    }\n                    else {\n                        this.selectNext();\n                    }\n\n                    ev.preventDefault();\n                    break;\n                }\n            }\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$outerContainer.removeData('pill');\n            this.base();\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Select\n */\nGarnish.Select = Garnish.Base.extend(\n    {\n        $container: null,\n        $items: null,\n        $selectedItems: null,\n        $focusedItem: null,\n\n        mousedownTarget: null,\n        mouseUpTimeout: null,\n        callbackFrame: null,\n\n        $focusable: null,\n        $first: null,\n        first: null,\n        $last: null,\n        last: null,\n\n        /**\n         * Constructor\n         */\n        init: function(container, items, settings) {\n            this.$container = $(container);\n\n            // Param mapping\n            if (typeof items === 'undefined' && $.isPlainObject(container)) {\n                // (settings)\n                settings = container;\n                container = null;\n                items = null;\n            }\n            else if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (container, settings)\n                settings = items;\n                items = null;\n            }\n\n            // Is this already a select?\n            if (this.$container.data('select')) {\n                Garnish.log('Double-instantiating a select on an element');\n                this.$container.data('select').destroy();\n            }\n\n            this.$container.data('select', this);\n\n            this.setSettings(settings, Garnish.Select.defaults);\n\n            this.$items = $();\n            this.$selectedItems = $();\n\n            this.addItems(items);\n\n            // --------------------------------------------------------------------\n\n            if (this.settings.allowEmpty && !this.settings.checkboxMode) {\n                this.addListener(this.$container, 'click', function() {\n                    if (this.ignoreClick) {\n                        this.ignoreClick = false;\n                    }\n                    else {\n                        // Deselect all items on container click\n                        this.deselectAll(true);\n                    }\n                });\n            }\n        },\n\n        /**\n         * Get Item Index\n         */\n        getItemIndex: function($item) {\n            return this.$items.index($item[0]);\n        },\n\n        /**\n         * Is Selected?\n         */\n        isSelected: function(item) {\n            if (Garnish.isJquery(item)) {\n                if (!item[0]) {\n                    return false;\n                }\n\n                item = item[0];\n            }\n\n            return ($.inArray(item, this.$selectedItems) !== -1);\n        },\n\n        /**\n         * Select Item\n         */\n        selectItem: function($item, focus, preventScroll) {\n            if (!this.settings.multi) {\n                this.deselectAll();\n            }\n\n            this.$first = this.$last = $item;\n            this.first = this.last = this.getItemIndex($item);\n\n            if (focus) {\n                this.setFocusableItem($item);\n                this.focusItem($item, preventScroll);\n            }\n\n            this._selectItems($item);\n        },\n\n        selectAll: function() {\n            if (!this.settings.multi || !this.$items.length) {\n                return;\n            }\n\n            this.first = 0;\n            this.last = this.$items.length - 1;\n            this.$first = this.$items.eq(this.first);\n            this.$last = this.$items.eq(this.last);\n\n            this._selectItems(this.$items);\n        },\n\n        /**\n         * Select Range\n         */\n        selectRange: function($item, preventScroll) {\n            if (!this.settings.multi) {\n                return this.selectItem($item, true);\n            }\n\n            this.deselectAll();\n\n            this.$last = $item;\n            this.last = this.getItemIndex($item);\n\n            this.setFocusableItem($item);\n            this.focusItem($item, preventScroll);\n\n            // prepare params for $.slice()\n            var sliceFrom, sliceTo;\n\n            if (this.first < this.last) {\n                sliceFrom = this.first;\n                sliceTo = this.last + 1;\n            }\n            else {\n                sliceFrom = this.last;\n                sliceTo = this.first + 1;\n            }\n\n            this._selectItems(this.$items.slice(sliceFrom, sliceTo));\n        },\n\n        /**\n         * Deselect Item\n         */\n        deselectItem: function($item) {\n            var index = this.getItemIndex($item);\n            if (this.first === index) {\n                this.$first = this.first = null;\n            }\n            if (this.last === index) {\n                this.$last = this.last = null;\n            }\n\n            this._deselectItems($item);\n        },\n\n        /**\n         * Deselect All\n         */\n        deselectAll: function(clearFirst) {\n            if (clearFirst) {\n                this.$first = this.first = this.$last = this.last = null;\n            }\n\n            this._deselectItems(this.$items);\n        },\n\n        /**\n         * Deselect Others\n         */\n        deselectOthers: function($item) {\n            this.deselectAll();\n            this.selectItem($item, true);\n        },\n\n        /**\n         * Toggle Item\n         */\n        toggleItem: function($item, preventScroll) {\n            if (!this.isSelected($item)) {\n                this.selectItem($item, true, preventScroll);\n            }\n            else {\n                if (this._canDeselect($item)) {\n                    this.deselectItem($item, true);\n                }\n            }\n        },\n\n        clearMouseUpTimeout: function() {\n            clearTimeout(this.mouseUpTimeout);\n        },\n\n        getFirstItem: function() {\n            if (this.$items.length) {\n                return this.$items.first();\n            }\n        },\n\n        getLastItem: function() {\n            if (this.$items.length) {\n                return this.$items.last();\n            }\n        },\n\n        isPreviousItem: function(index) {\n            return (index > 0);\n        },\n\n        isNextItem: function(index) {\n            return (index < this.$items.length - 1);\n        },\n\n        getPreviousItem: function(index) {\n            if (this.isPreviousItem(index)) {\n                return this.$items.eq(index - 1);\n            }\n        },\n\n        getNextItem: function(index) {\n            if (this.isNextItem(index)) {\n                return this.$items.eq(index + 1);\n            }\n        },\n\n        getItemToTheLeft: function(index) {\n            var func = (Garnish.ltr ? 'Previous' : 'Next');\n\n            if (this['is' + func + 'Item'](index)) {\n                if (this.settings.horizontal) {\n                    return this['get' + func + 'Item'](index);\n                }\n                if (!this.settings.vertical) {\n                    return this.getClosestItem(index, Garnish.X_AXIS, '<');\n                }\n            }\n        },\n\n        getItemToTheRight: function(index) {\n            var func = (Garnish.ltr ? 'Next' : 'Previous');\n\n            if (this['is' + func + 'Item'](index)) {\n                if (this.settings.horizontal) {\n                    return this['get' + func + 'Item'](index);\n                }\n                else if (!this.settings.vertical) {\n                    return this.getClosestItem(index, Garnish.X_AXIS, '>');\n                }\n            }\n        },\n\n        getItemAbove: function(index) {\n            if (this.isPreviousItem(index)) {\n                if (this.settings.vertical) {\n                    return this.getPreviousItem(index);\n                }\n                else if (!this.settings.horizontal) {\n                    return this.getClosestItem(index, Garnish.Y_AXIS, '<');\n                }\n            }\n        },\n\n        getItemBelow: function(index) {\n            if (this.isNextItem(index)) {\n                if (this.settings.vertical) {\n                    return this.getNextItem(index);\n                }\n                else if (!this.settings.horizontal) {\n                    return this.getClosestItem(index, Garnish.Y_AXIS, '>');\n                }\n            }\n        },\n\n        getClosestItem: function(index, axis, dir) {\n            var axisProps = Garnish.Select.closestItemAxisProps[axis],\n                dirProps = Garnish.Select.closestItemDirectionProps[dir];\n\n            var $thisItem = this.$items.eq(index),\n                thisOffset = $thisItem.offset(),\n                thisMidpoint = thisOffset[axisProps.midpointOffset] + Math.round($thisItem[axisProps.midpointSizeFunc]() / 2),\n                otherRowPos = null,\n                smallestMidpointDiff = null,\n                $closestItem = null;\n\n            // Go the other way if this is the X axis and a RTL page\n            var step;\n\n            if (Garnish.rtl && axis === Garnish.X_AXIS) {\n                step = dirProps.step * -1;\n            }\n            else {\n                step = dirProps.step;\n            }\n\n            for (var i = index + step; (typeof this.$items[i] !== 'undefined'); i += step) {\n                var $otherItem = this.$items.eq(i),\n                    otherOffset = $otherItem.offset();\n\n                // Are we on the next row yet?\n                if (dirProps.isNextRow(otherOffset[axisProps.rowOffset], thisOffset[axisProps.rowOffset])) {\n                    // Is this the first time we've seen this row?\n                    if (otherRowPos === null) {\n                        otherRowPos = otherOffset[axisProps.rowOffset];\n                    }\n                    // Have we gone too far?\n                    else if (otherOffset[axisProps.rowOffset] !== otherRowPos) {\n                        break;\n                    }\n\n                    var otherMidpoint = otherOffset[axisProps.midpointOffset] + Math.round($otherItem[axisProps.midpointSizeFunc]() / 2),\n                        midpointDiff = Math.abs(thisMidpoint - otherMidpoint);\n\n                    // Are we getting warmer?\n                    if (smallestMidpointDiff === null || midpointDiff < smallestMidpointDiff) {\n                        smallestMidpointDiff = midpointDiff;\n                        $closestItem = $otherItem;\n                    }\n                    // Getting colder?\n                    else {\n                        break;\n                    }\n                }\n                // Getting colder?\n                else if (dirProps.isWrongDirection(otherOffset[axisProps.rowOffset], thisOffset[axisProps.rowOffset])) {\n                    break;\n                }\n            }\n\n            return $closestItem;\n        },\n\n        getFurthestItemToTheLeft: function(index) {\n            return this.getFurthestItem(index, 'ToTheLeft');\n        },\n\n        getFurthestItemToTheRight: function(index) {\n            return this.getFurthestItem(index, 'ToTheRight');\n        },\n\n        getFurthestItemAbove: function(index) {\n            return this.getFurthestItem(index, 'Above');\n        },\n\n        getFurthestItemBelow: function(index) {\n            return this.getFurthestItem(index, 'Below');\n        },\n\n        getFurthestItem: function(index, dir) {\n            var $item, $testItem;\n\n            while ($testItem = this['getItem' + dir](index)) {\n                $item = $testItem;\n                index = this.getItemIndex($item);\n            }\n\n            return $item;\n        },\n\n        /**\n         * totalSelected getter\n         */\n        get totalSelected() {\n            return this.getTotalSelected();\n        },\n\n        /**\n         * Get Total Selected\n         */\n        getTotalSelected: function() {\n            return this.$selectedItems.length;\n        },\n\n        /**\n         * Add Items\n         */\n        addItems: function(items) {\n            var $items = $(items);\n\n            for (var i = 0; i < $items.length; i++) {\n                var item = $items[i];\n\n                // Make sure this element doesn't belong to another selector\n                if ($.data(item, 'select')) {\n                    Garnish.log('Element was added to more than one selector');\n                    $.data(item, 'select').removeItems(item);\n                }\n\n                // Add the item\n                $.data(item, 'select', this);\n\n                // Get the handle\n                var $handle;\n\n                if (this.settings.handle) {\n                    if (typeof this.settings.handle === 'object') {\n                        $handle = $(this.settings.handle);\n                    }\n                    else if (typeof this.settings.handle === 'string') {\n                        $handle = $(item).find(this.settings.handle);\n                    }\n                    else if (typeof this.settings.handle === 'function') {\n                        $handle = $(this.settings.handle(item));\n                    }\n                }\n                else {\n                    $handle = $(item);\n                }\n\n                $.data(item, 'select-handle', $handle);\n                $handle.data('select-item', item);\n\n                this.addListener($handle, 'mousedown', 'onMouseDown');\n                this.addListener($handle, 'mouseup', 'onMouseUp');\n                this.addListener($handle, 'click', function() {\n                    this.ignoreClick = true;\n                });\n\n                this.addListener(item, 'keydown', 'onKeyDown');\n            }\n\n            this.$items = this.$items.add($items);\n            this.updateIndexes();\n        },\n\n        /**\n         * Remove Items\n         */\n        removeItems: function(items) {\n            items = $.makeArray(items);\n\n            var itemsChanged = false,\n                selectionChanged = false;\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure we actually know about this item\n                var index = $.inArray(item, this.$items);\n                if (index !== -1) {\n                    this._deinitItem(item);\n                    this.$items.splice(index, 1);\n                    itemsChanged = true;\n\n                    var selectedIndex = $.inArray(item, this.$selectedItems);\n                    if (selectedIndex !== -1) {\n                        this.$selectedItems.splice(selectedIndex, 1);\n                        selectionChanged = true;\n                    }\n                }\n            }\n\n            if (itemsChanged) {\n                this.updateIndexes();\n\n                if (selectionChanged) {\n                    $(items).removeClass(this.settings.selectedClass);\n                    this.onSelectionChange();\n                }\n            }\n        },\n\n        /**\n         * Remove All Items\n         */\n        removeAllItems: function() {\n            for (var i = 0; i < this.$items.length; i++) {\n                this._deinitItem(this.$items[i]);\n            }\n\n            this.$items = $();\n            this.$selectedItems = $();\n            this.updateIndexes();\n        },\n\n        /**\n         * Update First/Last indexes\n         */\n        updateIndexes: function() {\n            if (this.first !== null) {\n                this.first = this.getItemIndex(this.$first);\n                this.setFocusableItem(this.$first);\n            }\n            else if (this.$items.length) {\n                this.setFocusableItem($(this.$items[0]));\n            }\n\n            if (this.$focusedItem) {\n                this.setFocusableItem(this.$focusedItem);\n                this.focusItem(this.$focusedItem);\n            }\n\n            if (this.last !== null) {\n                this.last = this.getItemIndex(this.$last);\n            }\n        },\n\n        /**\n         * Reset Item Order\n         */\n        resetItemOrder: function() {\n            this.$items = $().add(this.$items);\n            this.$selectedItems = $().add(this.$selectedItems);\n            this.updateIndexes();\n        },\n\n        /**\n         * Sets the focusable item.\n         *\n         * We only want to have one focusable item per selection list, so that the user\n         * doesn't have to tab through a million items.\n         *\n         * @param {object} $item\n         */\n        setFocusableItem: function($item) {\n            if (this.$focusable) {\n                this.$focusable.removeAttr('tabindex');\n            }\n\n            this.$focusable = $item.attr('tabindex', '0');\n        },\n\n        /**\n         * Sets the focus on an item.\n         */\n        focusItem: function($item, preventScroll) {\n            if (preventScroll) {\n                var scrollLeft = Garnish.$doc.scrollLeft(),\n                    scrollTop = Garnish.$doc.scrollTop();\n                $item.focus();\n                window.scrollTo(scrollLeft, scrollTop);\n            }\n            else {\n                $item.focus();\n            }\n\n            this.$focusedItem = $item;\n            this.trigger('focusItem', {item: $item});\n        },\n\n        /**\n         * Get Selected Items\n         */\n        getSelectedItems: function() {\n            return this.$selectedItems;\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$container.removeData('select');\n            this.removeAllItems();\n            this.base();\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Mouse Down\n         */\n        onMouseDown: function(ev) {\n            // ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Enforce the filter\n            if (this.settings.filter && !$(ev.target).is(this.settings.filter)) {\n                return;\n            }\n\n            this.mousedownTarget = ev.currentTarget;\n\n            var $item = $($.data(ev.currentTarget, 'select-item'));\n\n            if (this.first !== null && ev.shiftKey) {\n                // Shift key is consistent for both selection modes\n                this.selectRange($item, true);\n            }\n            else if (this._actAsCheckbox(ev)) {\n                this.toggleItem($item, true);\n            }\n        },\n\n        /**\n         * On Mouse Up\n         */\n        onMouseUp: function(ev) {\n            // ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Enfore the filter\n            if (this.settings.filter && !$(ev.target).is(this.settings.filter)) {\n                return;\n            }\n\n            var $item = $($.data(ev.currentTarget, 'select-item'));\n\n            // was this a click?\n            if (\n                !this._actAsCheckbox(ev) && !ev.shiftKey &&\n                ev.currentTarget === this.mousedownTarget\n            ) {\n                // If this is already selected, wait a moment to see if this is a double click before making any rash decisions\n                if (this.isSelected($item)) {\n                    this.clearMouseUpTimeout();\n\n                    this.mouseUpTimeout = setTimeout($.proxy(function() {\n                        this.deselectOthers($item);\n                    }, this), 300);\n                }\n                else {\n                    this.deselectAll();\n                    this.selectItem($item, true, true);\n                }\n            }\n        },\n\n        /**\n         * On Key Down\n         */\n        onKeyDown: function(ev) {\n            // Ignore if the focus isn't on one of our items\n            if (ev.target !== ev.currentTarget) {\n                return;\n            }\n\n            var ctrlKey = Garnish.isCtrlKeyPressed(ev);\n            var shiftKey = ev.shiftKey;\n\n            var anchor, $item;\n\n            if (!this.settings.checkboxMode || !this.$focusable.length) {\n                anchor = ev.shiftKey ? this.last : this.first;\n            }\n            else {\n                anchor = $.inArray(this.$focusable[0], this.$items);\n\n                if (anchor === -1) {\n                    anchor = 0;\n                }\n            }\n\n            // Ok, what are we doing here?\n            switch (ev.keyCode) {\n                case Garnish.LEFT_KEY: {\n                    ev.preventDefault();\n\n                    // Select the last item if none are selected\n                    if (this.first === null) {\n                        if (Garnish.ltr) {\n                            $item = this.getLastItem();\n                        }\n                        else {\n                            $item = this.getFirstItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemToTheLeft(anchor);\n                        }\n                        else {\n                            $item = this.getItemToTheLeft(anchor);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.RIGHT_KEY: {\n                    ev.preventDefault();\n\n                    // Select the first item if none are selected\n                    if (this.first === null) {\n                        if (Garnish.ltr) {\n                            $item = this.getFirstItem();\n                        }\n                        else {\n                            $item = this.getLastItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemToTheRight(anchor);\n                        }\n                        else {\n                            $item = this.getItemToTheRight(anchor);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.UP_KEY: {\n                    ev.preventDefault();\n\n                    // Select the last item if none are selected\n                    if (this.first === null) {\n                        if (this.$focusable) {\n                            $item = this.$focusable.prev();\n                        }\n\n                        if (!this.$focusable || !$item.length) {\n                            $item = this.getLastItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemAbove(anchor);\n                        }\n                        else {\n                            $item = this.getItemAbove(anchor);\n                        }\n\n                        if (!$item) {\n                            $item = this.getFirstItem();\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.DOWN_KEY: {\n                    ev.preventDefault();\n\n                    // Select the first item if none are selected\n                    if (this.first === null) {\n                        if (this.$focusable) {\n                            $item = this.$focusable.next();\n                        }\n\n                        if (!this.$focusable || !$item.length) {\n                            $item = this.getFirstItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemBelow(anchor);\n                        }\n                        else {\n                            $item = this.getItemBelow(anchor);\n                        }\n\n                        if (!$item) {\n                            $item = this.getLastItem();\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.SPACE_KEY: {\n                    if (!ctrlKey && !shiftKey) {\n                        ev.preventDefault();\n\n                        if (this.isSelected(this.$focusable)) {\n                            if (this._canDeselect(this.$focusable)) {\n                                this.deselectItem(this.$focusable);\n                            }\n                        }\n                        else {\n                            this.selectItem(this.$focusable, true);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.A_KEY: {\n                    if (ctrlKey) {\n                        ev.preventDefault();\n                        this.selectAll();\n                    }\n\n                    break;\n                }\n            }\n\n            // Is there an item queued up for focus/selection?\n            if ($item && $item.length) {\n                if (!this.settings.checkboxMode) {\n                    // select it\n                    if (this.first !== null && ev.shiftKey) {\n                        this.selectRange($item);\n                    }\n                    else {\n                        this.deselectAll();\n                        this.selectItem($item, true);\n                    }\n                }\n                else {\n                    // just set the new item to be focusable\n                    this.setFocusableItem($item);\n                    $item.focus();\n                    this.$focusedItem = $item;\n                    this.trigger('focusItem', {item: $item});\n                }\n            }\n        },\n\n        /**\n         * Set Callback Timeout\n         */\n        onSelectionChange: function() {\n            if (this.callbackFrame) {\n                Garnish.cancelAnimationFrame(this.callbackFrame);\n                this.callbackFrame = null;\n            }\n\n            this.callbackFrame = Garnish.requestAnimationFrame($.proxy(function() {\n                this.callbackFrame = null;\n                this.trigger('selectionChange');\n                this.settings.onSelectionChange();\n            }, this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        _actAsCheckbox: function(ev) {\n            if (Garnish.isCtrlKeyPressed(ev)) {\n                return !this.settings.checkboxMode;\n            }\n            else {\n                return this.settings.checkboxMode;\n            }\n        },\n\n        _canDeselect: function($items) {\n            return (this.settings.allowEmpty || this.totalSelected > $items.length);\n        },\n\n        _selectItems: function($items) {\n            $items.addClass(this.settings.selectedClass);\n            this.$selectedItems = this.$selectedItems.add($items);\n            this.onSelectionChange();\n        },\n\n        _deselectItems: function($items) {\n            $items.removeClass(this.settings.selectedClass);\n            this.$selectedItems = this.$selectedItems.not($items);\n            this.onSelectionChange();\n        },\n\n        /**\n         * Deinitialize an item.\n         */\n        _deinitItem: function(item) {\n            var $handle = $.data(item, 'select-handle');\n\n            if ($handle) {\n                $handle.removeData('select-item');\n                this.removeAllListeners($handle);\n            }\n\n            $.removeData(item, 'select');\n            $.removeData(item, 'select-handle');\n\n            if (this.$focusedItem && this.$focusedItem[0] === item) {\n                this.$focusedItem = null;\n            }\n        }\n    },\n    {\n        defaults: {\n            selectedClass: 'sel',\n            multi: false,\n            allowEmpty: true,\n            vertical: false,\n            horizontal: false,\n            handle: null,\n            filter: null,\n            checkboxMode: false,\n            onSelectionChange: $.noop\n        },\n\n        closestItemAxisProps: {\n            x: {\n                midpointOffset: 'top',\n                midpointSizeFunc: 'outerHeight',\n                rowOffset: 'left'\n            },\n            y: {\n                midpointOffset: 'left',\n                midpointSizeFunc: 'outerWidth',\n                rowOffset: 'top'\n            }\n        },\n\n        closestItemDirectionProps: {\n            '<': {\n                step: -1,\n                isNextRow: function(a, b) {\n                    return (a < b);\n                },\n                isWrongDirection: function(a, b) {\n                    return (a > b);\n                }\n            },\n            '>': {\n                step: 1,\n                isNextRow: function(a, b) {\n                    return (a > b);\n                },\n                isWrongDirection: function(a, b) {\n                    return (a < b);\n                }\n            }\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Select Menu\n */\nGarnish.SelectMenu = Garnish.Menu.extend(\n    {\n        /**\n         * Constructor\n         */\n        init: function(btn, options, settings, callback) {\n            // argument mapping\n            if (typeof settings === 'function') {\n                // (btn, options, callback)\n                callback = settings;\n                settings = {};\n            }\n\n            settings = $.extend({}, Garnish.SelectMenu.defaults, settings);\n\n            this.base(btn, options, settings, callback);\n\n            this.selected = -1;\n        },\n\n        /**\n         * Build\n         */\n        build: function() {\n            this.base();\n\n            if (this.selected !== -1) {\n                this._addSelectedOptionClass(this.selected);\n            }\n        },\n\n        /**\n         * Select\n         */\n        select: function(option) {\n            // ignore if it's already selected\n            if (option === this.selected) {\n                return;\n            }\n\n            if (this.dom.ul) {\n                if (this.selected !== -1) {\n                    this.dom.options[this.selected].className = '';\n                }\n\n                this._addSelectedOptionClass(option);\n            }\n\n            this.selected = option;\n\n            // set the button text to the selected option\n            this.setBtnText($(this.options[option].label).text());\n\n            this.base(option);\n        },\n\n        /**\n         * Add Selected Option Class\n         */\n        _addSelectedOptionClass: function(option) {\n            this.dom.options[option].className = 'sel';\n        },\n\n        /**\n         * Set Button Text\n         */\n        setBtnText: function(text) {\n            this.dom.$btnLabel.text(text);\n        }\n\n    },\n    {\n        defaults: {\n            ulClass: 'menu select'\n        }\n    }\n);\n\n})(jQuery);\n"]}