diff --git a/contrib/externs/jquery-3.3.js b/contrib/externs/jquery-3.3.js
new file mode 100644
index 00000000000..04c8a3dceed
--- /dev/null
+++ b/contrib/externs/jquery-3.3.js
@@ -0,0 +1,2083 @@
+/*
+ * Copyright 2017 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Externs for jQuery 3.1
+ *
+ * Note that some functions use different return types depending on the number
+ * of parameters passed in. In these cases, you may need to annotate the type
+ * of the result in your code, so the JSCompiler understands which type you're
+ * expecting. For example:
+ * var elt = /** @type {Element} * / (foo.get(0));
+ *
+ * @see http://api.jquery.com/
+ * @externs
+ */
+
+/**
+ * @typedef {(Window|Document|Element|Array|string|jQuery|
+ * NodeList)}
+ */
+var jQuerySelector;
+
+/** @typedef {function(...)|Array} */
+var jQueryCallback;
+
+/**
+ * @record
+ */
+function jQueryAjaxSettings() {};
+
+/** @type {(Object|undefined)} */
+jQueryAjaxSettings.prototype.accepts;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.async;
+
+/** @type {(function(jQuery.jqXHR, (jQueryAjaxSettings|Object))|undefined)} */
+jQueryAjaxSettings.prototype.beforeSend;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.cache;
+
+/** @type {(function(jQuery.jqXHR, string)|undefined)} */
+jQueryAjaxSettings.prototype.complete;
+
+/** @type {(Object|undefined)} */
+jQueryAjaxSettings.prototype.contents;
+
+/** @type {(?string|boolean|undefined)} */
+jQueryAjaxSettings.prototype.contentType;
+
+/** @type {(Object, ?>|jQueryAjaxSettings|undefined)} */
+jQueryAjaxSettings.prototype.context;
+
+/** @type {(Object|undefined)} */
+jQueryAjaxSettings.prototype.converters;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.crossDomain;
+
+/** @type {(Object, ?>|?string|Array>|undefined)} */
+jQueryAjaxSettings.prototype.data;
+
+/** @type {(function(string, string):?|undefined)} */
+jQueryAjaxSettings.prototype.dataFilter;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.dataType;
+
+/** @type {(function(jQuery.jqXHR, string, string)|undefined)} */
+jQueryAjaxSettings.prototype.error;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.global;
+
+/** @type {(Object, ?>|undefined)} */
+jQueryAjaxSettings.prototype.headers;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.ifModified;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.isLocal;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.jsonp;
+
+/** @type {(?string|function()|undefined)} */
+jQueryAjaxSettings.prototype.jsonpCallback;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.mimeType;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.password;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.processData;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.scriptCharset;
+
+/** @type {(Object|undefined)} */
+jQueryAjaxSettings.prototype.statusCode;
+
+/** @type {(function(?, string, jQuery.jqXHR)|undefined)} */
+jQueryAjaxSettings.prototype.success;
+
+/** @type {(?number|undefined)} */
+jQueryAjaxSettings.prototype.timeout;
+
+/** @type {(?boolean|undefined)} */
+jQueryAjaxSettings.prototype.traditional;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.type;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.url;
+
+/** @type {(?string|undefined)} */
+jQueryAjaxSettings.prototype.username;
+
+/** @type {(function():(ActiveXObject|XMLHttpRequest)|undefined)} */
+jQueryAjaxSettings.prototype.xhr;
+
+/** @type {(Object, ?>|undefined)} */
+jQueryAjaxSettings.prototype.xhrFields;
+
+/**
+ * @record
+ * @extends {jQueryAjaxSettings}
+ */
+function jQueryAjaxSettingsExtra() {};
+
+/** @type {Object} */
+jQueryAjaxSettingsExtra.prototype.flatOptions;
+
+/** @type {Object} */
+jQueryAjaxSettingsExtra.prototype.responseFields;
+
+
+/**
+ * @record
+ */
+function jQueryAjaxTransport(){};
+
+/** @return {undefined} */
+jQueryAjaxTransport.abort = function() {};
+
+/**
+ * @param {!IObject} headers
+ * @param {function(number, string, !IObject=, string=):undefined} completeCallback
+ * @return {undefined}
+ */
+jQueryAjaxTransport.send = function(headers, completeCallback) {};
+
+/**
+ * @constructor
+ * @param {(jQuerySelector|Object|function())=} arg1
+ * @param {(Element|jQuery|Document|
+ * Object)=} arg2
+ * @throws {Error} on invalid selector
+ * @return {!jQuery}
+ * @implements {Iterable}
+ */
+function jQuery(arg1, arg2) {};
+
+/**
+ * @const
+ */
+var $ = jQuery;
+
+/**
+ * @param {jQuerySelector} arg1
+ * @param {Element=} context
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.add = function(arg1, context) {};
+
+/**
+ * @param {jQuerySelector=} arg1
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.addBack = function(arg1) {};
+
+/**
+ * @param {(string|Array|function(number,String))} arg1
+ * @return {!jQuery}
+ */
+jQuery.prototype.addClass = function(arg1) {};
+
+/**
+ * @param {(string|Element|Array|jQuery|function(this:Element,number,string):(string|!Element|!jQuery))} arg1
+ * @param {...(string|Element|Array|jQuery)} content
+ * @return {!jQuery}
+ */
+jQuery.prototype.after = function(arg1, content) {};
+
+/**
+ * @param {(string|jQueryAjaxSettings|Object)} arg1
+ * @param {(jQueryAjaxSettings|Object)=} settings
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.ajax = function(arg1, settings) {};
+
+/**
+ * @param {function(!jQuery.Event,XMLHttpRequest,(jQueryAjaxSettings|Object))} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.ajaxComplete = function(handler) {};
+
+/**
+ * @param {function(!jQuery.Event,jQuery.jqXHR,(jQueryAjaxSettings|Object),*)} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.ajaxError = function(handler) {};
+
+/**
+ * @param {(string|function((jQueryAjaxSettings|Object),(jQueryAjaxSettings|Object),jQuery.jqXHR))} dataTypes
+ * @param {function((jQueryAjaxSettings|Object),(jQueryAjaxSettings|Object),jQuery.jqXHR)=} handler
+ * @return {undefined}
+ */
+jQuery.ajaxPrefilter = function(dataTypes, handler) {};
+
+/**
+ * @param {function(!jQuery.Event,jQuery.jqXHR,(jQueryAjaxSettings|Object))} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.ajaxSend = function(handler) {};
+
+/** @const {jQueryAjaxSettingsExtra|Object} */
+jQuery.ajaxSettings;
+
+/** @param {jQueryAjaxSettings|Object} options */
+jQuery.ajaxSetup = function(options) {};
+
+/**
+ * @param {function()} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.ajaxStart = function(handler) {};
+
+/**
+ * @param {function()} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.ajaxStop = function(handler) {};
+
+/**
+ * @param {function(!jQuery.Event,XMLHttpRequest,(jQueryAjaxSettings|Object), ?)} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.ajaxSuccess = function(handler) {};
+
+/**
+ * @param {string} dataType
+ * @param {function(!jQueryAjaxSettingsExtra, !jQueryAjaxSettings, !jQuery.jqXHR):(!jQueryAjaxTransport|undefined)} handler
+ * @return {undefined}
+ */
+jQuery.ajaxTransport = function(dataType, handler) {};
+
+/**
+ * @deprecated Please use .addBack(selector) instead.
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.andSelf = function() {};
+
+/**
+ * @param {Object} properties
+ * @param {(string|number|function()|Object)=} arg2
+ * @param {(string|function())=} easing
+ * @param {function()=} complete
+ * @return {!jQuery}
+ */
+jQuery.prototype.animate = function(properties, arg2, easing, complete) {};
+
+/**
+ * @param {(string|Element|Array|jQuery|function(number,string))} arg1
+ * @param {...(string|Element|Array|jQuery)} content
+ * @return {!jQuery}
+ */
+jQuery.prototype.append = function(arg1, content) {};
+
+/**
+ * @param {jQuerySelector} target
+ * @return {!jQuery}
+ */
+jQuery.prototype.appendTo = function(target) {};
+
+/**
+ * @param {(string|Object)} arg1
+ * @param {(string|number|boolean|function(number,string))=} arg2
+ * @return {(string|!jQuery)}
+ */
+jQuery.prototype.attr = function(arg1, arg2) {};
+
+/**
+ * @param {(string|Element|Array|jQuery|function(this:Element,number,string=):(string|!Element|!jQuery))} arg1
+ * @param {...(string|Element|Array|jQuery)} content
+ * @return {!jQuery}
+ */
+jQuery.prototype.before = function(arg1, content) {};
+
+/**
+ * @param {(string|Object)} arg1
+ * @param {(Object|function(!jQuery.Event)|boolean)=} eventData
+ * @param {(function(!jQuery.Event)|boolean)=} arg3
+ * @return {!jQuery}
+ * @deprecated Please use .on instead.
+ */
+jQuery.prototype.bind = function(arg1, eventData, arg3) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "blur", handler ) instead.
+ */
+jQuery.prototype.blur = function(arg1, handler) {};
+
+/**
+ * @constructor
+ * @private
+ */
+jQuery.callbacks = function () {};
+
+/**
+ * @param {string=} flags
+ * @return {!jQuery.callbacks}
+ */
+jQuery.Callbacks = function (flags) {};
+
+/**
+ * @param {jQueryCallback} callbacks
+ * @return {!jQuery.callbacks}
+ */
+jQuery.callbacks.prototype.add = function(callbacks) {};
+
+/** @return {!jQuery.callbacks} */
+jQuery.callbacks.prototype.disable = function() {};
+
+/**
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.callbacks.prototype.disabled = function() {};
+
+/** @return {!jQuery.callbacks} */
+jQuery.callbacks.prototype.empty = function() {};
+
+/**
+ * @param {...*} var_args
+ * @return {!jQuery.callbacks}
+ */
+jQuery.callbacks.prototype.fire = function(var_args) {};
+
+/**
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.callbacks.prototype.fired = function() {};
+
+/**
+ * @param {...*} var_args
+ * @return {!jQuery.callbacks}
+ */
+jQuery.callbacks.prototype.fireWith = function(var_args) {};
+
+/**
+ * @param {function()=} callback
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.callbacks.prototype.has = function(callback) {};
+
+/** @return {!jQuery.callbacks} */
+jQuery.callbacks.prototype.lock = function() {};
+
+/**
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.callbacks.prototype.locked = function() {};
+
+/**
+ * @param {(function()|Array)} callbacks
+ * @return {!jQuery.callbacks}
+ */
+jQuery.callbacks.prototype.remove = function(callbacks) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "change", handler ) instead.
+ */
+jQuery.prototype.change = function(arg1, handler) {};
+
+/**
+ * @param {jQuerySelector=} selector
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.children = function(selector) {};
+
+/**
+ * @param {string=} queueName
+ * @return {!jQuery}
+ */
+jQuery.prototype.clearQueue = function(queueName) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "click", handler ) instead.
+ */
+jQuery.prototype.click = function(arg1, handler) {};
+
+/**
+ * @param {boolean=} withDataAndEvents
+ * @param {boolean=} deepWithDataAndEvents
+ * @return {!jQuery}
+ * @suppress {checkTypes} see https://code.google.com/p/closure-compiler/issues/detail?id=583
+ */
+jQuery.prototype.clone = function(withDataAndEvents, deepWithDataAndEvents) {};
+
+/**
+ * @param {jQuerySelector} arg1
+ * @param {Element=} context
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.closest = function(arg1, context) {};
+
+/**
+ * @param {Element} container
+ * @param {Element} contained
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.contains = function(container, contained) {};
+
+/**
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.contents = function() {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "contextmenu", handler ) instead.
+ */
+jQuery.prototype.contextmenu = function(arg1, handler) {};
+
+/**
+ * @param {(string|Object)} arg1
+ * @param {(string|number|function(number,*))=} arg2
+ * @return {(string|!jQuery)}
+ * @throws {Error}
+ */
+jQuery.prototype.css = function(arg1, arg2) {};
+
+/** @type {Object} */
+jQuery.cssHooks;
+
+/**
+ * @param {Element} elem
+ * @param {string=} key
+ * @param {*=} value
+ * @return {*}
+ */
+jQuery.data = function(elem, key, value) {};
+
+/**
+ * @param {(string|Object)=} arg1
+ * @param {*=} value
+ * @return {*}
+ */
+jQuery.prototype.data = function(arg1, value) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "dblclick", handler ) instead.
+ */
+jQuery.prototype.dblclick = function(arg1, handler) {};
+
+/**
+ * @constructor
+ * @implements {jQuery.Promise}
+ * @param {function()=} opt_fn
+ * @see http://api.jquery.com/category/deferred-object/
+ */
+jQuery.deferred = function(opt_fn) {};
+
+/**
+ * @constructor
+ * @extends {jQuery.deferred}
+ * @param {function()=} opt_fn
+ * @return {!jQuery.Deferred}
+ */
+jQuery.Deferred = function(opt_fn) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} alwaysCallbacks
+ * @param {...jQueryCallback} alwaysCallbacks2
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.always
+ = function(alwaysCallbacks, alwaysCallbacks2) {};
+
+/**
+ * @override
+ * @param {function()} failCallback
+ * @return {!jQuery.Promise}
+ */
+jQuery.deferred.prototype.catch = function(failCallback) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} doneCallbacks
+ * @param {...jQueryCallback} doneCallbacks2
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.done = function(doneCallbacks, doneCallbacks2) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} failCallbacks
+ * @param {...jQueryCallback} failCallbacks2
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.fail = function(failCallbacks, failCallbacks2) {};
+
+/**
+ * @param {...*} var_args
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.notify = function(var_args) {};
+
+/**
+ * @param {Object} context
+ * @param {...*} var_args
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.notifyWith = function(context, var_args) {};
+
+/**
+ * @deprecated Please use deferred.then() instead.
+ * @override
+ * @param {function()=} doneFilter
+ * @param {function()=} failFilter
+ * @param {function()=} progressFilter
+ * @return {!jQuery.Promise}
+ */
+jQuery.deferred.prototype.pipe =
+ function(doneFilter, failFilter, progressFilter) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} progressCallbacks
+ * @param {...jQueryCallback} progressCallbacks2
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.progress = function(progressCallbacks,progressCallbacks2) {};
+
+/**
+ * @override
+ * @param {Object=} target
+ * @return {!jQuery.Promise}
+ */
+jQuery.deferred.prototype.promise = function(target) {};
+
+/**
+ * @param {...*} var_args
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.reject = function(var_args) {};
+
+/**
+ * @param {Object} context
+ * @param {Array<*>=} args
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.rejectWith = function(context, args) {};
+
+/**
+ * @param {...*} var_args
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.resolve = function(var_args) {};
+
+/**
+ * @param {Object} context
+ * @param {Array<*>=} args
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.resolveWith = function(context, args) {};
+
+/**
+ * @override
+ * @return {string}
+ * @nosideeffects
+ */
+jQuery.deferred.prototype.state = function() {};
+
+/**
+ * @override
+ * @param {function()} doneCallbacks
+ * @param {function()=} failCallbacks
+ * @param {function()=} progressFilter
+ * @return {!jQuery.deferred}
+ */
+jQuery.deferred.prototype.then
+ = function(doneCallbacks, failCallbacks, progressFilter) {};
+
+/**
+ * @param {number} duration
+ * @param {string=} queueName
+ * @return {!jQuery}
+ */
+jQuery.prototype.delay = function(duration, queueName) {};
+
+/**
+ * @param {string} selector
+ * @param {(string|Object)} arg2
+ * @param {(function(!jQuery.Event)|Object)=} arg3
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on instead.
+ */
+jQuery.prototype.delegate = function(selector, arg2, arg3, handler) {};
+
+/**
+ * @param {Element} elem
+ * @param {string=} queueName
+ * @return {undefined}
+ */
+jQuery.dequeue = function(elem, queueName) {};
+
+/**
+ * @param {string=} queueName
+ * @return {!jQuery}
+ */
+jQuery.prototype.dequeue = function(queueName) {};
+
+/**
+ * @param {jQuerySelector=} selector
+ * @return {!jQuery}
+ */
+jQuery.prototype.detach = function(selector) {};
+
+/**
+ * @param {Object} collection
+ * @param {function((number|string),?)} callback
+ * @return {Object}
+ */
+jQuery.each = function(collection, callback) {};
+
+/**
+ * @param {function(number,Element)} fnc
+ * @return {!jQuery}
+ */
+jQuery.prototype.each = function(fnc) {};
+
+
+/** @return {!jQuery} */
+jQuery.prototype.empty = function() {};
+
+/**
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.end = function() {};
+
+/**
+ * @param {number} arg1
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.eq = function(arg1) {};
+
+/**
+ * @param {string} message
+ * @throws {Error}
+ */
+jQuery.error = function(message) {};
+
+/**
+ * @param {string} arg1
+ * @return {string}
+ */
+jQuery.escapeSelector = function(arg1) {};
+
+/** @const */
+jQuery.event = {};
+
+/** @type {Object} */
+jQuery.event.special;
+
+/**
+ * @constructor
+ * @param {string} eventType
+ * @param {Object=} properties
+ * @return {!jQuery.Event}
+ */
+jQuery.Event = function(eventType, properties) {};
+
+/** @type {boolean} */
+jQuery.Event.prototype.altKey;
+
+/** @type {boolean} */
+jQuery.Event.prototype.bubbles;
+
+/** @type {number} */
+jQuery.Event.prototype.button;
+
+/** @type {number} */
+jQuery.Event.prototype.buttons;
+
+/** @type {boolean} */
+jQuery.Event.prototype.cancelable;
+
+/** @type {number} */
+jQuery.Event.prototype.charCode;
+
+/** @type {number} */
+jQuery.Event.prototype.clientX;
+
+/** @type {number} */
+jQuery.Event.prototype.clientY;
+
+/** @type {boolean} */
+jQuery.Event.prototype.ctrlKey;
+
+/** @type {Element} */
+jQuery.Event.prototype.currentTarget;
+
+/** @type {Object} */
+jQuery.Event.prototype.data;
+
+/** @type {Element} */
+jQuery.Event.prototype.delegateTarget;
+
+/** @type {number} */
+jQuery.Event.prototype.detail;
+
+/** @type {number} */
+jQuery.Event.prototype.eventPhase;
+
+/**
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.Event.prototype.isDefaultPrevented = function() {};
+
+/**
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.Event.prototype.isImmediatePropagationStopped = function() {};
+
+/**
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.Event.prototype.isPropagationStopped = function() {};
+
+/** @type {number} */
+jQuery.Event.prototype.keyCode;
+
+/** @type {boolean} */
+jQuery.Event.prototype.metaKey;
+
+/** @type {string} */
+jQuery.Event.prototype.namespace;
+
+/** @type {number} */
+jQuery.Event.prototype.offsetX;
+
+/** @type {number} */
+jQuery.Event.prototype.offsetY;
+
+/** @type {Event} */
+jQuery.Event.prototype.originalEvent;
+
+/** @type {Element} */
+jQuery.Event.prototype.originalTarget;
+
+/** @type {number} */
+jQuery.Event.prototype.pageX;
+
+/** @type {number} */
+jQuery.Event.prototype.pageY;
+
+/** @return {undefined} */
+jQuery.Event.prototype.preventDefault = function() {};
+
+/** @type {Object} */
+jQuery.Event.prototype.props;
+
+/** @type {Element} */
+jQuery.Event.prototype.relatedTarget;
+
+/** @type {*} */
+jQuery.Event.prototype.result;
+
+/** @type {number} */
+jQuery.Event.prototype.screenX;
+
+/** @type {number} */
+jQuery.Event.prototype.screenY;
+
+/** @type {boolean} */
+jQuery.Event.prototype.shiftKey;
+
+/** @return {undefined} */
+jQuery.Event.prototype.stopImmediatePropagation = function() {};
+
+/** @return {undefined} */
+jQuery.Event.prototype.stopPropagation = function() {};
+
+/** @type {Element} */
+jQuery.Event.prototype.target;
+
+/** @type {number} */
+jQuery.Event.prototype.timeStamp;
+
+/** @type {Element} */
+jQuery.Event.prototype.toElement;
+
+/** @type {string} */
+jQuery.Event.prototype.type;
+
+/** @type {Window} */
+jQuery.Event.prototype.view;
+
+/** @type {number} @deprecated */
+jQuery.Event.prototype.which;
+
+/**
+ * @param {(Object|boolean)} arg1
+ * @param {...*} var_args
+ * @return {Object}
+ */
+jQuery.extend = function(arg1, var_args) {};
+
+/**
+ * @param {(Object|boolean)} arg1
+ * @param {...*} var_args
+ * @return {Object}
+ */
+jQuery.prototype.extend = function(arg1, var_args) {};
+
+/**
+ * @param {(string|number|function())=} duration
+ * @param {(function()|string)=} arg2
+ * @param {function()=} callback
+ * @return {!jQuery}
+ */
+jQuery.prototype.fadeIn = function(duration, arg2, callback) {};
+
+/**
+ * @param {(string|number|function())=} duration
+ * @param {(function()|string)=} arg2
+ * @param {function()=} callback
+ * @return {!jQuery}
+ */
+jQuery.prototype.fadeOut = function(duration, arg2, callback) {};
+
+/**
+ * @param {(string|number)} duration
+ * @param {number} opacity
+ * @param {(function()|string)=} arg3
+ * @param {function()=} callback
+ * @return {!jQuery}
+ */
+jQuery.prototype.fadeTo = function(duration, opacity, arg3, callback) {};
+
+/**
+ * @param {(string|number|function())=} duration
+ * @param {(string|function())=} easing
+ * @param {function()=} callback
+ * @return {!jQuery}
+ */
+jQuery.prototype.fadeToggle = function(duration, easing, callback) {};
+
+/**
+ * @param {(jQuerySelector|function(number,Element))} arg1
+ * @return {!jQuery}
+ * @see http://api.jquery.com/filter/
+ */
+jQuery.prototype.filter = function(arg1) {};
+
+/**
+ * @param {jQuerySelector} arg1
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.find = function(arg1) {};
+
+/**
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.first = function() {};
+
+/** @see http://docs.jquery.com/Plugins/Authoring */
+jQuery.fn = jQuery.prototype;
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "focus", handler ) instead.
+ */
+jQuery.prototype.focus = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "focusin", handler ) instead.
+ */
+jQuery.prototype.focusin = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "focusout", handler ) instead.
+ */
+jQuery.prototype.focusout = function(arg1, handler) {};
+
+/** @const */
+jQuery.fx = {};
+
+/** @type {number} */
+jQuery.fx.interval;
+
+/** @type {boolean} */
+jQuery.fx.off;
+
+/**
+ * @param {(string|jQueryAjaxSettings|Object)} url
+ * @param {(Object|string|
+ * function(string,string,jQuery.jqXHR))=} data
+ * @param {(function(string,string,jQuery.jqXHR)|string|null)=} success
+ * @param {string=} dataType
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.get = function(url, data, success, dataType) {};
+
+/**
+ * @param {number=} index
+ * @return {(Element|Array)}
+ * @nosideeffects
+ */
+jQuery.prototype.get = function(index) {};
+
+/**
+ * @param {string} url
+ * @param {(Object|
+ * function(Object,string,jQuery.jqXHR))=} data
+ * @param {function(Object,string,jQuery.jqXHR)=} success
+ * @return {!jQuery.jqXHR}
+ * @see http://api.jquery.com/jquery.getjson/#jQuery-getJSON-url-data-success
+ */
+jQuery.getJSON = function(url, data, success) {};
+
+/**
+ * @param {string} url
+ * @param {function(Node,string,jQuery.jqXHR)=} success
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.getScript = function(url, success) {};
+
+/** @param {string} code */
+jQuery.globalEval = function(code) {};
+
+/**
+ * @template T
+ * @param {!Array} arr
+ * @param {function(*,number)} fnc
+ * @param {boolean=} invert
+ * @return {!Array}
+ */
+jQuery.grep = function(arr, fnc, invert) {};
+
+/**
+ * @param {(string|Element)} arg1
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.has = function(arg1) {};
+
+/**
+ * @param {string} className
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.prototype.hasClass = function(className) {};
+
+/**
+ * @param {!Element} elem
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.hasData = function(elem) {};
+
+/**
+ * @param {(string|number|function(number,number))=} arg1
+ * @return {(number|undefined|!jQuery)}
+ */
+jQuery.prototype.height = function(arg1) {};
+
+/**
+ * @param {(string|number|function())=} duration
+ * @param {(function()|string)=} arg2
+ * @param {function()=} callback
+ * @return {!jQuery}
+ */
+jQuery.prototype.hide = function(duration, arg2, callback) {};
+
+/**
+ * @param {boolean} hold
+ * @return {undefined}
+ * @deprecated
+ */
+jQuery.holdReady = function(hold) {};
+
+/**
+ * @param {function(!jQuery.Event)} arg1
+ * @param {function(!jQuery.Event)=} handlerOut
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mouseenter", handler ) and .on( "mouseleave", handler ) instead.
+ */
+jQuery.prototype.hover = function(arg1, handlerOut) {};
+
+/**
+ * @param {(string|function(number,string))=} arg1
+ * @return {(string|!jQuery)}
+ */
+jQuery.prototype.html = function(arg1) {};
+
+/**
+ * @param {string} html
+ * @nosideeffects
+ * @return {string}
+ */
+jQuery.htmlPrefilter = function(html) {};
+
+/**
+ * @param {*} value
+ * @param {Array<*>} arr
+ * @param {number=} fromIndex
+ * @return {number}
+ * @nosideeffects
+ */
+jQuery.inArray = function(value, arr, fromIndex) {};
+
+/**
+ * @param {jQuerySelector=} arg1
+ * @return {number}
+ * @nosideeffects
+ */
+jQuery.prototype.index = function(arg1) {};
+
+/**
+ * @param {(number|string|function(number,number):(number|string))=} value
+ * @return {(number|undefined|jQuery)}
+ */
+jQuery.prototype.innerHeight = function(value) {};
+
+/**
+ * @param {(number|string|function(number,number):(number|string))=} value
+ * @return {(number|undefined|jQuery)}
+ */
+jQuery.prototype.innerWidth = function(value) {};
+
+/**
+ * @param {jQuerySelector} target
+ * @return {!jQuery}
+ */
+jQuery.prototype.insertAfter = function(target) {};
+
+/**
+ * @param {jQuerySelector} target
+ * @return {!jQuery}
+ */
+jQuery.prototype.insertBefore = function(target) {};
+
+/**
+ * @param {jQuerySelector|function(number,Element):boolean} arg1
+ * @return {boolean}
+ */
+jQuery.prototype.is = function(arg1) {};
+
+/**
+ * @param {*} obj
+ * @return {boolean}
+ * @nosideeffects
+ * @deprecated Please use Array.isArray(obj) instead.
+ */
+jQuery.isArray = function(obj) {};
+
+/**
+ * @param {Object} obj
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.isEmptyObject = function(obj) {};
+
+/**
+ * @param {*} obj
+ * @return {boolean}
+ * @nosideeffects
+ * @deprecated
+ */
+jQuery.isFunction = function(obj) {};
+
+/**
+ * @param {*} value
+ * @return {boolean}
+ * @nosideeffects
+ * @deprecated
+ */
+jQuery.isNumeric = function(value) {};
+
+/**
+ * @param {*} obj
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.isPlainObject = function(obj) {};
+
+/**
+ * @param {*} obj
+ * @return {boolean}
+ * @nosideeffects
+ * @deprecated
+ */
+jQuery.isWindow = function(obj) {};
+
+/**
+ * @param {Element} node
+ * @return {boolean}
+ * @nosideeffects
+ */
+jQuery.isXMLDoc = function(node) {};
+
+/** @type {string} */
+jQuery.prototype.jquery;
+
+/**
+ * @constructor
+ * @extends {XMLHttpRequest}
+ * @implements {jQuery.Promise}
+ * @private
+ * @see http://api.jquery.com/jQuery.ajax/#jqXHR
+ */
+jQuery.jqXHR = function () {};
+
+/**
+ * @override
+ * @param {string=} statusText
+ * @return {!jQuery.jqXHR}
+ * @suppress {checkTypes} to avoid warning about XMLHttpRequest abort method missmatch
+ */
+jQuery.jqXHR.prototype.abort = function(statusText) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} alwaysCallbacks
+ * @param {...jQueryCallback} alwaysCallbacks2
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.always =
+ function(alwaysCallbacks, alwaysCallbacks2) {};
+
+/**
+ * @override
+ * @param {function()} failCallback
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.catch = function(failCallback) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} doneCallbacks
+ * @param {...jQueryCallback} doneCallbacks2
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.done = function(doneCallbacks,doneCallbacks2) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} failCallbacks
+ * @param {...jQueryCallback} failCallbacks2
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.fail = function(failCallbacks,failCallbacks2) {};
+
+/**
+ * @deprecated
+ * @override
+ */
+jQuery.jqXHR.prototype.onreadystatechange = function (callback) {};
+
+/**
+ * @override
+ * @param {function()=} doneFilter
+ * @param {function()=} failFilter
+ * @param {function()=} progressFilter
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.pipe =
+ function(doneFilter, failFilter, progressFilter) {};
+
+/**
+ * @override
+ * @param {jQueryCallback} progressCallbacks
+ * @param {...jQueryCallback} progressCallbacks2
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.progress = function(progressCallbacks,progressCallbacks2) {};
+
+/**
+ * @override
+ * @param {Object=} target
+ * @return {!jQuery.Promise}
+ */
+jQuery.jqXHR.prototype.promise = function(target) {};
+
+/**
+ * @override
+ * @return {string}
+ * @nosideeffects
+ */
+jQuery.jqXHR.prototype.state = function() {};
+
+/**
+ * @param {Object} map
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.statusCode = function(map) {};
+
+/**
+ * @override
+ * @param {function()} doneCallback
+ * @param {function()=} failCallback
+ * @param {function()=} progressCallback
+ * @return {!jQuery.jqXHR}
+ */
+jQuery.jqXHR.prototype.then =
+ function(doneCallback, failCallback, progressCallback) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "keydown", handler ) instead.
+ */
+jQuery.prototype.keydown = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "keypress", handler ) instead.
+ */
+jQuery.prototype.keypress = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "keyup", handler ) instead.
+ */
+jQuery.prototype.keyup = function(arg1, handler) {};
+
+/**
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.last = function() {};
+
+/** @type {number} */
+jQuery.prototype.length;
+
+/**
+ * @param {*} obj
+ * @return {Array<*>}
+ * @nosideeffects
+ */
+jQuery.makeArray = function(obj) {};
+
+/**
+ * @template T
+ * @param {(Array|Object)} arg1
+ * @param {(function(T,number)|function(T,(string|number)))} callback
+ * @return {Array}
+ */
+jQuery.map = function(arg1, callback) {};
+
+/**
+ * @param {function(number,Element)} callback
+ * @return {!jQuery}
+ */
+jQuery.prototype.map = function(callback) {};
+
+/**
+ * @param {Array<*>} first
+ * @param {Array<*>} second
+ * @return {Array<*>}
+ */
+jQuery.merge = function(first, second) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mousedown", handler ) instead.
+ */
+jQuery.prototype.mousedown = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mousenter", handler ) instead.
+ */
+jQuery.prototype.mouseenter = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mouseleave", handler ) instead.
+ */
+jQuery.prototype.mouseleave = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mousemove", handler ) instead.
+ */
+jQuery.prototype.mousemove = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mouseout", handler ) instead.
+ */
+jQuery.prototype.mouseout = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mouseover", handler ) instead.
+ */
+jQuery.prototype.mouseover = function(arg1, handler) {};
+
+/**
+ * @param {(function(!jQuery.Event)|Object)=} arg1
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ * @deprecated Please use .on( "mouseup", handler ) instead.
+ */
+jQuery.prototype.mouseup = function(arg1, handler) {};
+
+/**
+ * @param {jQuerySelector=} selector
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.next = function(selector) {};
+
+/**
+ * @param {string=} selector
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.nextAll = function(selector) {};
+
+/**
+ * @param {jQuerySelector=} arg1
+ * @param {jQuerySelector=} filter
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.nextUntil = function(arg1, filter) {};
+
+/**
+ * @param {boolean=} removeAll
+ * @return {Object}
+ */
+jQuery.noConflict = function(removeAll) {};
+
+/**
+ * @return {undefined}
+ * @nosideeffects
+ */
+jQuery.noop = function() {};
+
+/**
+ * @param {(jQuerySelector|function(this:Element,number,Element=):boolean)} arg1
+ * @return {!jQuery}
+ */
+jQuery.prototype.not = function(arg1) {};
+
+/**
+ * @return {number}
+ * @nosideeffects
+ * @deprecated
+ */
+jQuery.now = function() {};
+
+/**
+ * @param {(string|Object)=} arg1
+ * @param {(string|function(!jQuery.Event))=} selector
+ * @param {function(!jQuery.Event)=} handler
+ * @return {!jQuery}
+ */
+jQuery.prototype.off = function(arg1, selector, handler) {};
+
+/**
+ * @param {({left:number,top:number}|
+ * function(number,{top:number,left:number}))=} arg1
+ * @return {({left:number,top:number}|undefined|!jQuery)}
+ * @throws {Error}
+ */
+jQuery.prototype.offset = function(arg1) {};
+
+/**
+ * @return {!jQuery}
+ * @nosideeffects
+ */
+jQuery.prototype.offsetParent = function() {};
+
+/**
+ * @param {(string|Object)} events
+ * @param {*=} selector or data or handler
+ * @param {*=} data or handler
+ * @param {function(!jQuery.Event)=} handler
+ * @throws {Error}
+ * @return {!jQuery}
+ */
+jQuery.prototype.on = function(events, selector, data, handler) {};
+
+/**
+ * @param {(string|Object)} events
+ * @param {*=} selector or data or handler
+ * @param {*=} data or handler
+ * @param {function(!jQuery.Event)=} handler
+ * @throws {Error}
+ * @return {!jQuery}
+ */
+jQuery.prototype.one = function(events, selector, data, handler) {};
+
+/**
+ * @param {boolean|number|string|function(number,number):(number|string)=} includeMargin
+ * @return {number|undefined|jQuery}
+ */
+jQuery.prototype.outerHeight = function(includeMargin) {};
+
+/**
+ * @param {boolean|number|string|function(number,number):(number|string)=} includeMargin
+ * @return {number|undefined|jQuery}
+ */
+jQuery.prototype.outerWidth = function(includeMargin) {};
+
+/**
+ * @param {(Object|Array