mirror of
https://github.com/moparisthebest/kaiwa
synced 2024-11-17 14:55:05 -05:00
33927 lines
1.0 MiB
33927 lines
1.0 MiB
/*!
|
|
* jQuery JavaScript Library v2.0.0
|
|
* http://jquery.com/
|
|
*
|
|
* Includes Sizzle.js
|
|
* http://sizzlejs.com/
|
|
*
|
|
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
|
|
* Released under the MIT license
|
|
* http://jquery.org/license
|
|
*
|
|
* Date: 2013-04-18
|
|
*/
|
|
(function( window, undefined ) {
|
|
|
|
// Can't do this because several apps including ASP.NET trace
|
|
// the stack via arguments.caller.callee and Firefox dies if
|
|
// you try to trace through "use strict" call chains. (#13335)
|
|
// Support: Firefox 18+
|
|
//"use strict";
|
|
var
|
|
// A central reference to the root jQuery(document)
|
|
rootjQuery,
|
|
|
|
// The deferred used on DOM ready
|
|
readyList,
|
|
|
|
// Support: IE9
|
|
// For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
|
|
core_strundefined = typeof undefined,
|
|
|
|
// Use the correct document accordingly with window argument (sandbox)
|
|
location = window.location,
|
|
document = window.document,
|
|
docElem = document.documentElement,
|
|
|
|
// Map over jQuery in case of overwrite
|
|
_jQuery = window.jQuery,
|
|
|
|
// Map over the $ in case of overwrite
|
|
_$ = window.$,
|
|
|
|
// [[Class]] -> type pairs
|
|
class2type = {},
|
|
|
|
// List of deleted data cache ids, so we can reuse them
|
|
core_deletedIds = [],
|
|
|
|
core_version = "2.0.0",
|
|
|
|
// Save a reference to some core methods
|
|
core_concat = core_deletedIds.concat,
|
|
core_push = core_deletedIds.push,
|
|
core_slice = core_deletedIds.slice,
|
|
core_indexOf = core_deletedIds.indexOf,
|
|
core_toString = class2type.toString,
|
|
core_hasOwn = class2type.hasOwnProperty,
|
|
core_trim = core_version.trim,
|
|
|
|
// Define a local copy of jQuery
|
|
jQuery = function( selector, context ) {
|
|
// The jQuery object is actually just the init constructor 'enhanced'
|
|
return new jQuery.fn.init( selector, context, rootjQuery );
|
|
},
|
|
|
|
// Used for matching numbers
|
|
core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
|
|
|
|
// Used for splitting on whitespace
|
|
core_rnotwhite = /\S+/g,
|
|
|
|
// A simple way to check for HTML strings
|
|
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
|
|
// Strict HTML recognition (#11290: must start with <)
|
|
rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
|
|
|
|
// Match a standalone tag
|
|
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
|
|
|
|
// Matches dashed string for camelizing
|
|
rmsPrefix = /^-ms-/,
|
|
rdashAlpha = /-([\da-z])/gi,
|
|
|
|
// Used by jQuery.camelCase as callback to replace()
|
|
fcamelCase = function( all, letter ) {
|
|
return letter.toUpperCase();
|
|
},
|
|
|
|
// The ready event handler and self cleanup method
|
|
completed = function() {
|
|
document.removeEventListener( "DOMContentLoaded", completed, false );
|
|
window.removeEventListener( "load", completed, false );
|
|
jQuery.ready();
|
|
};
|
|
|
|
jQuery.fn = jQuery.prototype = {
|
|
// The current version of jQuery being used
|
|
jquery: core_version,
|
|
|
|
constructor: jQuery,
|
|
init: function( selector, context, rootjQuery ) {
|
|
var match, elem;
|
|
|
|
// HANDLE: $(""), $(null), $(undefined), $(false)
|
|
if ( !selector ) {
|
|
return this;
|
|
}
|
|
|
|
// Handle HTML strings
|
|
if ( typeof selector === "string" ) {
|
|
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
|
|
// Assume that strings that start and end with <> are HTML and skip the regex check
|
|
match = [ null, selector, null ];
|
|
|
|
} else {
|
|
match = rquickExpr.exec( selector );
|
|
}
|
|
|
|
// Match html or make sure no context is specified for #id
|
|
if ( match && (match[1] || !context) ) {
|
|
|
|
// HANDLE: $(html) -> $(array)
|
|
if ( match[1] ) {
|
|
context = context instanceof jQuery ? context[0] : context;
|
|
|
|
// scripts is true for back-compat
|
|
jQuery.merge( this, jQuery.parseHTML(
|
|
match[1],
|
|
context && context.nodeType ? context.ownerDocument || context : document,
|
|
true
|
|
) );
|
|
|
|
// HANDLE: $(html, props)
|
|
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
|
|
for ( match in context ) {
|
|
// Properties of context are called as methods if possible
|
|
if ( jQuery.isFunction( this[ match ] ) ) {
|
|
this[ match ]( context[ match ] );
|
|
|
|
// ...and otherwise set as attributes
|
|
} else {
|
|
this.attr( match, context[ match ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
|
|
// HANDLE: $(#id)
|
|
} else {
|
|
elem = document.getElementById( match[2] );
|
|
|
|
// Check parentNode to catch when Blackberry 4.6 returns
|
|
// nodes that are no longer in the document #6963
|
|
if ( elem && elem.parentNode ) {
|
|
// Inject the element directly into the jQuery object
|
|
this.length = 1;
|
|
this[0] = elem;
|
|
}
|
|
|
|
this.context = document;
|
|
this.selector = selector;
|
|
return this;
|
|
}
|
|
|
|
// HANDLE: $(expr, $(...))
|
|
} else if ( !context || context.jquery ) {
|
|
return ( context || rootjQuery ).find( selector );
|
|
|
|
// HANDLE: $(expr, context)
|
|
// (which is just equivalent to: $(context).find(expr)
|
|
} else {
|
|
return this.constructor( context ).find( selector );
|
|
}
|
|
|
|
// HANDLE: $(DOMElement)
|
|
} else if ( selector.nodeType ) {
|
|
this.context = this[0] = selector;
|
|
this.length = 1;
|
|
return this;
|
|
|
|
// HANDLE: $(function)
|
|
// Shortcut for document ready
|
|
} else if ( jQuery.isFunction( selector ) ) {
|
|
return rootjQuery.ready( selector );
|
|
}
|
|
|
|
if ( selector.selector !== undefined ) {
|
|
this.selector = selector.selector;
|
|
this.context = selector.context;
|
|
}
|
|
|
|
return jQuery.makeArray( selector, this );
|
|
},
|
|
|
|
// Start with an empty selector
|
|
selector: "",
|
|
|
|
// The default length of a jQuery object is 0
|
|
length: 0,
|
|
|
|
toArray: function() {
|
|
return core_slice.call( this );
|
|
},
|
|
|
|
// Get the Nth element in the matched element set OR
|
|
// Get the whole matched element set as a clean array
|
|
get: function( num ) {
|
|
return num == null ?
|
|
|
|
// Return a 'clean' array
|
|
this.toArray() :
|
|
|
|
// Return just the object
|
|
( num < 0 ? this[ this.length + num ] : this[ num ] );
|
|
},
|
|
|
|
// Take an array of elements and push it onto the stack
|
|
// (returning the new matched element set)
|
|
pushStack: function( elems ) {
|
|
|
|
// Build a new jQuery matched element set
|
|
var ret = jQuery.merge( this.constructor(), elems );
|
|
|
|
// Add the old object onto the stack (as a reference)
|
|
ret.prevObject = this;
|
|
ret.context = this.context;
|
|
|
|
// Return the newly-formed element set
|
|
return ret;
|
|
},
|
|
|
|
// Execute a callback for every element in the matched set.
|
|
// (You can seed the arguments with an array of args, but this is
|
|
// only used internally.)
|
|
each: function( callback, args ) {
|
|
return jQuery.each( this, callback, args );
|
|
},
|
|
|
|
ready: function( fn ) {
|
|
// Add the callback
|
|
jQuery.ready.promise().done( fn );
|
|
|
|
return this;
|
|
},
|
|
|
|
slice: function() {
|
|
return this.pushStack( core_slice.apply( this, arguments ) );
|
|
},
|
|
|
|
first: function() {
|
|
return this.eq( 0 );
|
|
},
|
|
|
|
last: function() {
|
|
return this.eq( -1 );
|
|
},
|
|
|
|
eq: function( i ) {
|
|
var len = this.length,
|
|
j = +i + ( i < 0 ? len : 0 );
|
|
return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
|
|
},
|
|
|
|
map: function( callback ) {
|
|
return this.pushStack( jQuery.map(this, function( elem, i ) {
|
|
return callback.call( elem, i, elem );
|
|
}));
|
|
},
|
|
|
|
end: function() {
|
|
return this.prevObject || this.constructor(null);
|
|
},
|
|
|
|
// For internal use only.
|
|
// Behaves like an Array's method, not like a jQuery method.
|
|
push: core_push,
|
|
sort: [].sort,
|
|
splice: [].splice
|
|
};
|
|
|
|
// Give the init function the jQuery prototype for later instantiation
|
|
jQuery.fn.init.prototype = jQuery.fn;
|
|
|
|
jQuery.extend = jQuery.fn.extend = function() {
|
|
var options, name, src, copy, copyIsArray, clone,
|
|
target = arguments[0] || {},
|
|
i = 1,
|
|
length = arguments.length,
|
|
deep = false;
|
|
|
|
// Handle a deep copy situation
|
|
if ( typeof target === "boolean" ) {
|
|
deep = target;
|
|
target = arguments[1] || {};
|
|
// skip the boolean and the target
|
|
i = 2;
|
|
}
|
|
|
|
// Handle case when target is a string or something (possible in deep copy)
|
|
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
|
|
target = {};
|
|
}
|
|
|
|
// extend jQuery itself if only one argument is passed
|
|
if ( length === i ) {
|
|
target = this;
|
|
--i;
|
|
}
|
|
|
|
for ( ; i < length; i++ ) {
|
|
// Only deal with non-null/undefined values
|
|
if ( (options = arguments[ i ]) != null ) {
|
|
// Extend the base object
|
|
for ( name in options ) {
|
|
src = target[ name ];
|
|
copy = options[ name ];
|
|
|
|
// Prevent never-ending loop
|
|
if ( target === copy ) {
|
|
continue;
|
|
}
|
|
|
|
// Recurse if we're merging plain objects or arrays
|
|
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
|
|
if ( copyIsArray ) {
|
|
copyIsArray = false;
|
|
clone = src && jQuery.isArray(src) ? src : [];
|
|
|
|
} else {
|
|
clone = src && jQuery.isPlainObject(src) ? src : {};
|
|
}
|
|
|
|
// Never move original objects, clone them
|
|
target[ name ] = jQuery.extend( deep, clone, copy );
|
|
|
|
// Don't bring in undefined values
|
|
} else if ( copy !== undefined ) {
|
|
target[ name ] = copy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the modified object
|
|
return target;
|
|
};
|
|
|
|
jQuery.extend({
|
|
// Unique for each copy of jQuery on the page
|
|
expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
|
|
|
|
noConflict: function( deep ) {
|
|
if ( window.$ === jQuery ) {
|
|
window.$ = _$;
|
|
}
|
|
|
|
if ( deep && window.jQuery === jQuery ) {
|
|
window.jQuery = _jQuery;
|
|
}
|
|
|
|
return jQuery;
|
|
},
|
|
|
|
// Is the DOM ready to be used? Set to true once it occurs.
|
|
isReady: false,
|
|
|
|
// A counter to track how many items to wait for before
|
|
// the ready event fires. See #6781
|
|
readyWait: 1,
|
|
|
|
// Hold (or release) the ready event
|
|
holdReady: function( hold ) {
|
|
if ( hold ) {
|
|
jQuery.readyWait++;
|
|
} else {
|
|
jQuery.ready( true );
|
|
}
|
|
},
|
|
|
|
// Handle when the DOM is ready
|
|
ready: function( wait ) {
|
|
|
|
// Abort if there are pending holds or we're already ready
|
|
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
|
|
return;
|
|
}
|
|
|
|
// Remember that the DOM is ready
|
|
jQuery.isReady = true;
|
|
|
|
// If a normal DOM Ready event fired, decrement, and wait if need be
|
|
if ( wait !== true && --jQuery.readyWait > 0 ) {
|
|
return;
|
|
}
|
|
|
|
// If there are functions bound, to execute
|
|
readyList.resolveWith( document, [ jQuery ] );
|
|
|
|
// Trigger any bound ready events
|
|
if ( jQuery.fn.trigger ) {
|
|
jQuery( document ).trigger("ready").off("ready");
|
|
}
|
|
},
|
|
|
|
// See test/unit/core.js for details concerning isFunction.
|
|
// Since version 1.3, DOM methods and functions like alert
|
|
// aren't supported. They return false on IE (#2968).
|
|
isFunction: function( obj ) {
|
|
return jQuery.type(obj) === "function";
|
|
},
|
|
|
|
isArray: Array.isArray,
|
|
|
|
isWindow: function( obj ) {
|
|
return obj != null && obj === obj.window;
|
|
},
|
|
|
|
isNumeric: function( obj ) {
|
|
return !isNaN( parseFloat(obj) ) && isFinite( obj );
|
|
},
|
|
|
|
type: function( obj ) {
|
|
if ( obj == null ) {
|
|
return String( obj );
|
|
}
|
|
// Support: Safari <= 5.1 (functionish RegExp)
|
|
return typeof obj === "object" || typeof obj === "function" ?
|
|
class2type[ core_toString.call(obj) ] || "object" :
|
|
typeof obj;
|
|
},
|
|
|
|
isPlainObject: function( obj ) {
|
|
// Not plain objects:
|
|
// - Any object or value whose internal [[Class]] property is not "[object Object]"
|
|
// - DOM nodes
|
|
// - window
|
|
if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
|
|
return false;
|
|
}
|
|
|
|
// Support: Firefox <20
|
|
// The try/catch suppresses exceptions thrown when attempting to access
|
|
// the "constructor" property of certain host objects, ie. |window.location|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=814622
|
|
try {
|
|
if ( obj.constructor &&
|
|
!core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
|
|
return false;
|
|
}
|
|
} catch ( e ) {
|
|
return false;
|
|
}
|
|
|
|
// If the function hasn't returned already, we're confident that
|
|
// |obj| is a plain object, created by {} or constructed with new Object
|
|
return true;
|
|
},
|
|
|
|
isEmptyObject: function( obj ) {
|
|
var name;
|
|
for ( name in obj ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
error: function( msg ) {
|
|
throw new Error( msg );
|
|
},
|
|
|
|
// data: string of html
|
|
// context (optional): If specified, the fragment will be created in this context, defaults to document
|
|
// keepScripts (optional): If true, will include scripts passed in the html string
|
|
parseHTML: function( data, context, keepScripts ) {
|
|
if ( !data || typeof data !== "string" ) {
|
|
return null;
|
|
}
|
|
if ( typeof context === "boolean" ) {
|
|
keepScripts = context;
|
|
context = false;
|
|
}
|
|
context = context || document;
|
|
|
|
var parsed = rsingleTag.exec( data ),
|
|
scripts = !keepScripts && [];
|
|
|
|
// Single tag
|
|
if ( parsed ) {
|
|
return [ context.createElement( parsed[1] ) ];
|
|
}
|
|
|
|
parsed = jQuery.buildFragment( [ data ], context, scripts );
|
|
|
|
if ( scripts ) {
|
|
jQuery( scripts ).remove();
|
|
}
|
|
|
|
return jQuery.merge( [], parsed.childNodes );
|
|
},
|
|
|
|
parseJSON: JSON.parse,
|
|
|
|
// Cross-browser xml parsing
|
|
parseXML: function( data ) {
|
|
var xml, tmp;
|
|
if ( !data || typeof data !== "string" ) {
|
|
return null;
|
|
}
|
|
|
|
// Support: IE9
|
|
try {
|
|
tmp = new DOMParser();
|
|
xml = tmp.parseFromString( data , "text/xml" );
|
|
} catch ( e ) {
|
|
xml = undefined;
|
|
}
|
|
|
|
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
|
|
jQuery.error( "Invalid XML: " + data );
|
|
}
|
|
return xml;
|
|
},
|
|
|
|
noop: function() {},
|
|
|
|
// Evaluates a script in a global context
|
|
globalEval: function( code ) {
|
|
var script,
|
|
indirect = eval;
|
|
|
|
code = jQuery.trim( code );
|
|
|
|
if ( code ) {
|
|
// If the code includes a valid, prologue position
|
|
// strict mode pragma, execute code by injecting a
|
|
// script tag into the document.
|
|
if ( code.indexOf("use strict") === 1 ) {
|
|
script = document.createElement("script");
|
|
script.text = code;
|
|
document.head.appendChild( script ).parentNode.removeChild( script );
|
|
} else {
|
|
// Otherwise, avoid the DOM node creation, insertion
|
|
// and removal by using an indirect global eval
|
|
indirect( code );
|
|
}
|
|
}
|
|
},
|
|
|
|
// Convert dashed to camelCase; used by the css and data modules
|
|
// Microsoft forgot to hump their vendor prefix (#9572)
|
|
camelCase: function( string ) {
|
|
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
|
},
|
|
|
|
nodeName: function( elem, name ) {
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
|
|
},
|
|
|
|
// args is for internal usage only
|
|
each: function( obj, callback, args ) {
|
|
var value,
|
|
i = 0,
|
|
length = obj.length,
|
|
isArray = isArraylike( obj );
|
|
|
|
if ( args ) {
|
|
if ( isArray ) {
|
|
for ( ; i < length; i++ ) {
|
|
value = callback.apply( obj[ i ], args );
|
|
|
|
if ( value === false ) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for ( i in obj ) {
|
|
value = callback.apply( obj[ i ], args );
|
|
|
|
if ( value === false ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// A special, fast, case for the most common use of each
|
|
} else {
|
|
if ( isArray ) {
|
|
for ( ; i < length; i++ ) {
|
|
value = callback.call( obj[ i ], i, obj[ i ] );
|
|
|
|
if ( value === false ) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for ( i in obj ) {
|
|
value = callback.call( obj[ i ], i, obj[ i ] );
|
|
|
|
if ( value === false ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
},
|
|
|
|
trim: function( text ) {
|
|
return text == null ? "" : core_trim.call( text );
|
|
},
|
|
|
|
// results is for internal usage only
|
|
makeArray: function( arr, results ) {
|
|
var ret = results || [];
|
|
|
|
if ( arr != null ) {
|
|
if ( isArraylike( Object(arr) ) ) {
|
|
jQuery.merge( ret,
|
|
typeof arr === "string" ?
|
|
[ arr ] : arr
|
|
);
|
|
} else {
|
|
core_push.call( ret, arr );
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
|
|
inArray: function( elem, arr, i ) {
|
|
return arr == null ? -1 : core_indexOf.call( arr, elem, i );
|
|
},
|
|
|
|
merge: function( first, second ) {
|
|
var l = second.length,
|
|
i = first.length,
|
|
j = 0;
|
|
|
|
if ( typeof l === "number" ) {
|
|
for ( ; j < l; j++ ) {
|
|
first[ i++ ] = second[ j ];
|
|
}
|
|
} else {
|
|
while ( second[j] !== undefined ) {
|
|
first[ i++ ] = second[ j++ ];
|
|
}
|
|
}
|
|
|
|
first.length = i;
|
|
|
|
return first;
|
|
},
|
|
|
|
grep: function( elems, callback, inv ) {
|
|
var retVal,
|
|
ret = [],
|
|
i = 0,
|
|
length = elems.length;
|
|
inv = !!inv;
|
|
|
|
// Go through the array, only saving the items
|
|
// that pass the validator function
|
|
for ( ; i < length; i++ ) {
|
|
retVal = !!callback( elems[ i ], i );
|
|
if ( inv !== retVal ) {
|
|
ret.push( elems[ i ] );
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
|
|
// arg is for internal usage only
|
|
map: function( elems, callback, arg ) {
|
|
var value,
|
|
i = 0,
|
|
length = elems.length,
|
|
isArray = isArraylike( elems ),
|
|
ret = [];
|
|
|
|
// Go through the array, translating each of the items to their
|
|
if ( isArray ) {
|
|
for ( ; i < length; i++ ) {
|
|
value = callback( elems[ i ], i, arg );
|
|
|
|
if ( value != null ) {
|
|
ret[ ret.length ] = value;
|
|
}
|
|
}
|
|
|
|
// Go through every key on the object,
|
|
} else {
|
|
for ( i in elems ) {
|
|
value = callback( elems[ i ], i, arg );
|
|
|
|
if ( value != null ) {
|
|
ret[ ret.length ] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Flatten any nested arrays
|
|
return core_concat.apply( [], ret );
|
|
},
|
|
|
|
// A global GUID counter for objects
|
|
guid: 1,
|
|
|
|
// Bind a function to a context, optionally partially applying any
|
|
// arguments.
|
|
proxy: function( fn, context ) {
|
|
var tmp, args, proxy;
|
|
|
|
if ( typeof context === "string" ) {
|
|
tmp = fn[ context ];
|
|
context = fn;
|
|
fn = tmp;
|
|
}
|
|
|
|
// Quick check to determine if target is callable, in the spec
|
|
// this throws a TypeError, but we will just return undefined.
|
|
if ( !jQuery.isFunction( fn ) ) {
|
|
return undefined;
|
|
}
|
|
|
|
// Simulated bind
|
|
args = core_slice.call( arguments, 2 );
|
|
proxy = function() {
|
|
return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
|
|
};
|
|
|
|
// Set the guid of unique handler to the same of original handler, so it can be removed
|
|
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
|
|
|
|
return proxy;
|
|
},
|
|
|
|
// Multifunctional method to get and set values of a collection
|
|
// The value/s can optionally be executed if it's a function
|
|
access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
|
|
var i = 0,
|
|
length = elems.length,
|
|
bulk = key == null;
|
|
|
|
// Sets many values
|
|
if ( jQuery.type( key ) === "object" ) {
|
|
chainable = true;
|
|
for ( i in key ) {
|
|
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
|
|
}
|
|
|
|
// Sets one value
|
|
} else if ( value !== undefined ) {
|
|
chainable = true;
|
|
|
|
if ( !jQuery.isFunction( value ) ) {
|
|
raw = true;
|
|
}
|
|
|
|
if ( bulk ) {
|
|
// Bulk operations run against the entire set
|
|
if ( raw ) {
|
|
fn.call( elems, value );
|
|
fn = null;
|
|
|
|
// ...except when executing function values
|
|
} else {
|
|
bulk = fn;
|
|
fn = function( elem, key, value ) {
|
|
return bulk.call( jQuery( elem ), value );
|
|
};
|
|
}
|
|
}
|
|
|
|
if ( fn ) {
|
|
for ( ; i < length; i++ ) {
|
|
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return chainable ?
|
|
elems :
|
|
|
|
// Gets
|
|
bulk ?
|
|
fn.call( elems ) :
|
|
length ? fn( elems[0], key ) : emptyGet;
|
|
},
|
|
|
|
now: Date.now,
|
|
|
|
// A method for quickly swapping in/out CSS properties to get correct calculations.
|
|
// Note: this method belongs to the css module but it's needed here for the support module.
|
|
// If support gets modularized, this method should be moved back to the css module.
|
|
swap: function( elem, options, callback, args ) {
|
|
var ret, name,
|
|
old = {};
|
|
|
|
// Remember the old values, and insert the new ones
|
|
for ( name in options ) {
|
|
old[ name ] = elem.style[ name ];
|
|
elem.style[ name ] = options[ name ];
|
|
}
|
|
|
|
ret = callback.apply( elem, args || [] );
|
|
|
|
// Revert the old values
|
|
for ( name in options ) {
|
|
elem.style[ name ] = old[ name ];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
});
|
|
|
|
jQuery.ready.promise = function( obj ) {
|
|
if ( !readyList ) {
|
|
|
|
readyList = jQuery.Deferred();
|
|
|
|
// Catch cases where $(document).ready() is called after the browser event has already occurred.
|
|
// we once tried to use readyState "interactive" here, but it caused issues like the one
|
|
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
|
|
if ( document.readyState === "complete" ) {
|
|
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
|
setTimeout( jQuery.ready );
|
|
|
|
} else {
|
|
|
|
// Use the handy event callback
|
|
document.addEventListener( "DOMContentLoaded", completed, false );
|
|
|
|
// A fallback to window.onload, that will always work
|
|
window.addEventListener( "load", completed, false );
|
|
}
|
|
}
|
|
return readyList.promise( obj );
|
|
};
|
|
|
|
// Populate the class2type map
|
|
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
|
|
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
|
});
|
|
|
|
function isArraylike( obj ) {
|
|
var length = obj.length,
|
|
type = jQuery.type( obj );
|
|
|
|
if ( jQuery.isWindow( obj ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( obj.nodeType === 1 && length ) {
|
|
return true;
|
|
}
|
|
|
|
return type === "array" || type !== "function" &&
|
|
( length === 0 ||
|
|
typeof length === "number" && length > 0 && ( length - 1 ) in obj );
|
|
}
|
|
|
|
// All jQuery objects should point back to these
|
|
rootjQuery = jQuery(document);
|
|
/*!
|
|
* Sizzle CSS Selector Engine v1.9.2-pre
|
|
* http://sizzlejs.com/
|
|
*
|
|
* Copyright 2013 jQuery Foundation, Inc. and other contributors
|
|
* Released under the MIT license
|
|
* http://jquery.org/license
|
|
*
|
|
* Date: 2013-04-16
|
|
*/
|
|
(function( window, undefined ) {
|
|
|
|
var i,
|
|
cachedruns,
|
|
Expr,
|
|
getText,
|
|
isXML,
|
|
compile,
|
|
outermostContext,
|
|
sortInput,
|
|
|
|
// Local document vars
|
|
setDocument,
|
|
document,
|
|
docElem,
|
|
documentIsHTML,
|
|
rbuggyQSA,
|
|
rbuggyMatches,
|
|
matches,
|
|
contains,
|
|
|
|
// Instance-specific data
|
|
expando = "sizzle" + -(new Date()),
|
|
preferredDoc = window.document,
|
|
support = {},
|
|
dirruns = 0,
|
|
done = 0,
|
|
classCache = createCache(),
|
|
tokenCache = createCache(),
|
|
compilerCache = createCache(),
|
|
hasDuplicate = false,
|
|
sortOrder = function() { return 0; },
|
|
|
|
// General-purpose constants
|
|
strundefined = typeof undefined,
|
|
MAX_NEGATIVE = 1 << 31,
|
|
|
|
// Array methods
|
|
arr = [],
|
|
pop = arr.pop,
|
|
push_native = arr.push,
|
|
push = arr.push,
|
|
slice = arr.slice,
|
|
// Use a stripped-down indexOf if we can't use a native one
|
|
indexOf = arr.indexOf || function( elem ) {
|
|
var i = 0,
|
|
len = this.length;
|
|
for ( ; i < len; i++ ) {
|
|
if ( this[i] === elem ) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
|
|
|
|
// Regular expressions
|
|
|
|
// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
|
|
whitespace = "[\\x20\\t\\r\\n\\f]",
|
|
// http://www.w3.org/TR/css3-syntax/#characters
|
|
characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
|
|
|
|
// Loosely modeled on CSS identifier characters
|
|
// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
|
|
// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
|
|
identifier = characterEncoding.replace( "w", "w#" ),
|
|
|
|
// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
|
|
attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
|
|
"*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
|
|
|
|
// Prefer arguments quoted,
|
|
// then not containing pseudos/brackets,
|
|
// then attribute selectors/non-parenthetical expressions,
|
|
// then anything else
|
|
// These preferences are here to reduce the number of selectors
|
|
// needing tokenize in the PSEUDO preFilter
|
|
pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
|
|
|
|
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
|
|
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
|
|
|
|
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
|
|
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
|
|
|
|
rsibling = new RegExp( whitespace + "*[+~]" ),
|
|
rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
|
|
|
|
rpseudo = new RegExp( pseudos ),
|
|
ridentifier = new RegExp( "^" + identifier + "$" ),
|
|
|
|
matchExpr = {
|
|
"ID": new RegExp( "^#(" + characterEncoding + ")" ),
|
|
"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
|
|
"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
|
|
"ATTR": new RegExp( "^" + attributes ),
|
|
"PSEUDO": new RegExp( "^" + pseudos ),
|
|
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
|
|
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
|
|
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
|
|
"boolean": new RegExp( "^(?:" + booleans + ")$", "i" ),
|
|
// For use in libraries implementing .is()
|
|
// We use this for POS matching in `select`
|
|
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
|
|
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
|
|
},
|
|
|
|
rnative = /^[^{]+\{\s*\[native \w/,
|
|
|
|
// Easily-parseable/retrievable ID or TAG or CLASS selectors
|
|
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
|
|
|
|
rinputs = /^(?:input|select|textarea|button)$/i,
|
|
rheader = /^h\d$/i,
|
|
|
|
rescape = /'|\\/g,
|
|
|
|
// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
|
|
runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
|
|
funescape = function( _, escaped ) {
|
|
var high = "0x" + escaped - 0x10000;
|
|
// NaN means non-codepoint
|
|
return high !== high ?
|
|
escaped :
|
|
// BMP codepoint
|
|
high < 0 ?
|
|
String.fromCharCode( high + 0x10000 ) :
|
|
// Supplemental Plane codepoint (surrogate pair)
|
|
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
|
|
};
|
|
|
|
// Optimize for push.apply( _, NodeList )
|
|
try {
|
|
push.apply(
|
|
(arr = slice.call( preferredDoc.childNodes )),
|
|
preferredDoc.childNodes
|
|
);
|
|
// Support: Android<4.0
|
|
// Detect silently failing push.apply
|
|
arr[ preferredDoc.childNodes.length ].nodeType;
|
|
} catch ( e ) {
|
|
push = { apply: arr.length ?
|
|
|
|
// Leverage slice if possible
|
|
function( target, els ) {
|
|
push_native.apply( target, slice.call(els) );
|
|
} :
|
|
|
|
// Support: IE<9
|
|
// Otherwise append directly
|
|
function( target, els ) {
|
|
var j = target.length,
|
|
i = 0;
|
|
// Can't trust NodeList.length
|
|
while ( (target[j++] = els[i++]) ) {}
|
|
target.length = j - 1;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* For feature detection
|
|
* @param {Function} fn The function to test for native support
|
|
*/
|
|
function isNative( fn ) {
|
|
return rnative.test( fn + "" );
|
|
}
|
|
|
|
/**
|
|
* Create key-value caches of limited size
|
|
* @returns {Function(string, Object)} Returns the Object data after storing it on itself with
|
|
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
|
|
* deleting the oldest entry
|
|
*/
|
|
function createCache() {
|
|
var cache,
|
|
keys = [];
|
|
|
|
return (cache = function( key, value ) {
|
|
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
|
|
if ( keys.push( key += " " ) > Expr.cacheLength ) {
|
|
// Only keep the most recent entries
|
|
delete cache[ keys.shift() ];
|
|
}
|
|
return (cache[ key ] = value);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mark a function for special use by Sizzle
|
|
* @param {Function} fn The function to mark
|
|
*/
|
|
function markFunction( fn ) {
|
|
fn[ expando ] = true;
|
|
return fn;
|
|
}
|
|
|
|
/**
|
|
* Support testing using an element
|
|
* @param {Function} fn Passed the created div and expects a boolean result
|
|
*/
|
|
function assert( fn ) {
|
|
var div = document.createElement("div");
|
|
|
|
try {
|
|
return !!fn( div );
|
|
} catch (e) {
|
|
return false;
|
|
} finally {
|
|
if ( div.parentNode ) {
|
|
div.parentNode.removeChild( div );
|
|
}
|
|
// release memory in IE
|
|
div = null;
|
|
}
|
|
}
|
|
|
|
function Sizzle( selector, context, results, seed ) {
|
|
var match, elem, m, nodeType,
|
|
// QSA vars
|
|
i, groups, old, nid, newContext, newSelector;
|
|
|
|
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
|
|
setDocument( context );
|
|
}
|
|
|
|
context = context || document;
|
|
results = results || [];
|
|
|
|
if ( !selector || typeof selector !== "string" ) {
|
|
return results;
|
|
}
|
|
|
|
if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
|
|
return [];
|
|
}
|
|
|
|
if ( documentIsHTML && !seed ) {
|
|
|
|
// Shortcuts
|
|
if ( (match = rquickExpr.exec( selector )) ) {
|
|
// Speed-up: Sizzle("#ID")
|
|
if ( (m = match[1]) ) {
|
|
if ( nodeType === 9 ) {
|
|
elem = context.getElementById( m );
|
|
// Check parentNode to catch when Blackberry 4.6 returns
|
|
// nodes that are no longer in the document #6963
|
|
if ( elem && elem.parentNode ) {
|
|
// Handle the case where IE, Opera, and Webkit return items
|
|
// by name instead of ID
|
|
if ( elem.id === m ) {
|
|
results.push( elem );
|
|
return results;
|
|
}
|
|
} else {
|
|
return results;
|
|
}
|
|
} else {
|
|
// Context is not a document
|
|
if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
|
|
contains( context, elem ) && elem.id === m ) {
|
|
results.push( elem );
|
|
return results;
|
|
}
|
|
}
|
|
|
|
// Speed-up: Sizzle("TAG")
|
|
} else if ( match[2] ) {
|
|
push.apply( results, context.getElementsByTagName( selector ) );
|
|
return results;
|
|
|
|
// Speed-up: Sizzle(".CLASS")
|
|
} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
|
|
push.apply( results, context.getElementsByClassName( m ) );
|
|
return results;
|
|
}
|
|
}
|
|
|
|
// QSA path
|
|
if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
|
|
nid = old = expando;
|
|
newContext = context;
|
|
newSelector = nodeType === 9 && selector;
|
|
|
|
// qSA works strangely on Element-rooted queries
|
|
// We can work around this by specifying an extra ID on the root
|
|
// and working up from there (Thanks to Andrew Dupont for the technique)
|
|
// IE 8 doesn't work on object elements
|
|
if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
|
|
groups = tokenize( selector );
|
|
|
|
if ( (old = context.getAttribute("id")) ) {
|
|
nid = old.replace( rescape, "\\$&" );
|
|
} else {
|
|
context.setAttribute( "id", nid );
|
|
}
|
|
nid = "[id='" + nid + "'] ";
|
|
|
|
i = groups.length;
|
|
while ( i-- ) {
|
|
groups[i] = nid + toSelector( groups[i] );
|
|
}
|
|
newContext = rsibling.test( selector ) && context.parentNode || context;
|
|
newSelector = groups.join(",");
|
|
}
|
|
|
|
if ( newSelector ) {
|
|
try {
|
|
push.apply( results,
|
|
newContext.querySelectorAll( newSelector )
|
|
);
|
|
return results;
|
|
} catch(qsaError) {
|
|
} finally {
|
|
if ( !old ) {
|
|
context.removeAttribute("id");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// All others
|
|
return select( selector.replace( rtrim, "$1" ), context, results, seed );
|
|
}
|
|
|
|
/**
|
|
* Detect xml
|
|
* @param {Element|Object} elem An element or a document
|
|
*/
|
|
isXML = Sizzle.isXML = function( elem ) {
|
|
// documentElement is verified for cases where it doesn't yet exist
|
|
// (such as loading iframes in IE - #4833)
|
|
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
|
|
return documentElement ? documentElement.nodeName !== "HTML" : false;
|
|
};
|
|
|
|
/**
|
|
* Sets document-related variables once based on the current document
|
|
* @param {Element|Object} [doc] An element or document object to use to set the document
|
|
* @returns {Object} Returns the current document
|
|
*/
|
|
setDocument = Sizzle.setDocument = function( node ) {
|
|
var doc = node ? node.ownerDocument || node : preferredDoc;
|
|
|
|
// If no document and documentElement is available, return
|
|
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
|
|
return document;
|
|
}
|
|
|
|
// Set our document
|
|
document = doc;
|
|
docElem = doc.documentElement;
|
|
|
|
// Support tests
|
|
documentIsHTML = !isXML( doc );
|
|
|
|
// Check if getElementsByTagName("*") returns only elements
|
|
support.getElementsByTagName = assert(function( div ) {
|
|
div.appendChild( doc.createComment("") );
|
|
return !div.getElementsByTagName("*").length;
|
|
});
|
|
|
|
// Support: IE<8
|
|
// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
|
|
support.attributes = assert(function( div ) {
|
|
div.className = "i";
|
|
return !div.getAttribute("className");
|
|
});
|
|
|
|
// Check if getElementsByClassName can be trusted
|
|
support.getElementsByClassName = assert(function( div ) {
|
|
div.innerHTML = "<div class='a'></div><div class='a i'></div>";
|
|
|
|
// Support: Safari<4
|
|
// Catch class over-caching
|
|
div.firstChild.className = "i";
|
|
// Support: Opera<10
|
|
// Catch gEBCN failure to find non-leading classes
|
|
return div.getElementsByClassName("i").length === 2;
|
|
});
|
|
|
|
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
|
|
// Detached nodes confoundingly follow *each other*
|
|
support.sortDetached = assert(function( div1 ) {
|
|
// Should return 1, but returns 4 (following)
|
|
return div1.compareDocumentPosition( document.createElement("div") ) & 1;
|
|
});
|
|
|
|
// Support: IE<10
|
|
// Check if getElementById returns elements by name
|
|
// Support: Windows 8 Native Apps
|
|
// Assigning innerHTML with "name" attributes throws uncatchable exceptions
|
|
// (http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx)
|
|
// and the broken getElementById methods don't pick up programatically-set names,
|
|
// so use a roundabout getElementsByName test
|
|
support.getById = assert(function( div ) {
|
|
docElem.appendChild( div ).id = expando;
|
|
return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
|
|
});
|
|
|
|
// ID find and filter
|
|
if ( support.getById ) {
|
|
Expr.find["ID"] = function( id, context ) {
|
|
if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
|
|
var m = context.getElementById( id );
|
|
// Check parentNode to catch when Blackberry 4.6 returns
|
|
// nodes that are no longer in the document #6963
|
|
return m && m.parentNode ? [m] : [];
|
|
}
|
|
};
|
|
Expr.filter["ID"] = function( id ) {
|
|
var attrId = id.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
return elem.getAttribute("id") === attrId;
|
|
};
|
|
};
|
|
} else {
|
|
Expr.find["ID"] = function( id, context ) {
|
|
if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
|
|
var m = context.getElementById( id );
|
|
|
|
return m ?
|
|
m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
|
|
[m] :
|
|
undefined :
|
|
[];
|
|
}
|
|
};
|
|
Expr.filter["ID"] = function( id ) {
|
|
var attrId = id.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
|
|
return node && node.value === attrId;
|
|
};
|
|
};
|
|
}
|
|
|
|
// Tag
|
|
Expr.find["TAG"] = support.getElementsByTagName ?
|
|
function( tag, context ) {
|
|
if ( typeof context.getElementsByTagName !== strundefined ) {
|
|
return context.getElementsByTagName( tag );
|
|
}
|
|
} :
|
|
function( tag, context ) {
|
|
var elem,
|
|
tmp = [],
|
|
i = 0,
|
|
results = context.getElementsByTagName( tag );
|
|
|
|
// Filter out possible comments
|
|
if ( tag === "*" ) {
|
|
while ( (elem = results[i++]) ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
tmp.push( elem );
|
|
}
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
return results;
|
|
};
|
|
|
|
// Class
|
|
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
|
|
if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
|
|
return context.getElementsByClassName( className );
|
|
}
|
|
};
|
|
|
|
// QSA and matchesSelector support
|
|
|
|
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
|
|
rbuggyMatches = [];
|
|
|
|
// qSa(:focus) reports false when true (Chrome 21)
|
|
// We allow this because of a bug in IE8/9 that throws an error
|
|
// whenever `document.activeElement` is accessed on an iframe
|
|
// So, we allow :focus to pass through QSA all the time to avoid the IE error
|
|
// See http://bugs.jquery.com/ticket/13378
|
|
rbuggyQSA = [];
|
|
|
|
if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
|
|
// Build QSA regex
|
|
// Regex strategy adopted from Diego Perini
|
|
assert(function( div ) {
|
|
// Select is set to empty string on purpose
|
|
// This is to test IE's treatment of not explicitly
|
|
// setting a boolean content attribute,
|
|
// since its presence should be enough
|
|
// http://bugs.jquery.com/ticket/12359
|
|
div.innerHTML = "<select><option selected=''></option></select>";
|
|
|
|
// Support: IE8
|
|
// Boolean attributes and "value" are not treated correctly
|
|
if ( !div.querySelectorAll("[selected]").length ) {
|
|
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
|
|
}
|
|
|
|
// Webkit/Opera - :checked should return selected option elements
|
|
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
|
// IE8 throws error here and will not see later tests
|
|
if ( !div.querySelectorAll(":checked").length ) {
|
|
rbuggyQSA.push(":checked");
|
|
}
|
|
});
|
|
|
|
assert(function( div ) {
|
|
|
|
// Support: Opera 10-12/IE8
|
|
// ^= $= *= and empty values
|
|
// Should not select anything
|
|
// Support: Windows 8 Native Apps
|
|
// The type attribute is restricted during .innerHTML assignment
|
|
var input = document.createElement("input");
|
|
input.setAttribute( "type", "hidden" );
|
|
div.appendChild( input ).setAttribute( "t", "" );
|
|
|
|
if ( div.querySelectorAll("[t^='']").length ) {
|
|
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
|
|
}
|
|
|
|
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
|
|
// IE8 throws error here and will not see later tests
|
|
if ( !div.querySelectorAll(":enabled").length ) {
|
|
rbuggyQSA.push( ":enabled", ":disabled" );
|
|
}
|
|
|
|
// Opera 10-11 does not throw on post-comma invalid pseudos
|
|
div.querySelectorAll("*,:x");
|
|
rbuggyQSA.push(",.*:");
|
|
});
|
|
}
|
|
|
|
if ( (support.matchesSelector = isNative( (matches = docElem.webkitMatchesSelector ||
|
|
docElem.mozMatchesSelector ||
|
|
docElem.oMatchesSelector ||
|
|
docElem.msMatchesSelector) )) ) {
|
|
|
|
assert(function( div ) {
|
|
// Check to see if it's possible to do matchesSelector
|
|
// on a disconnected node (IE 9)
|
|
support.disconnectedMatch = matches.call( div, "div" );
|
|
|
|
// This should fail with an exception
|
|
// Gecko does not error, returns false instead
|
|
matches.call( div, "[s!='']:x" );
|
|
rbuggyMatches.push( "!=", pseudos );
|
|
});
|
|
}
|
|
|
|
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
|
|
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
|
|
|
|
// Element contains another
|
|
// Purposefully does not implement inclusive descendent
|
|
// As in, an element does not contain itself
|
|
contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
|
|
function( a, b ) {
|
|
var adown = a.nodeType === 9 ? a.documentElement : a,
|
|
bup = b && b.parentNode;
|
|
return a === bup || !!( bup && bup.nodeType === 1 && (
|
|
adown.contains ?
|
|
adown.contains( bup ) :
|
|
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
|
));
|
|
} :
|
|
function( a, b ) {
|
|
if ( b ) {
|
|
while ( (b = b.parentNode) ) {
|
|
if ( b === a ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// Document order sorting
|
|
sortOrder = docElem.compareDocumentPosition ?
|
|
function( a, b ) {
|
|
|
|
// Flag for duplicate removal
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
|
|
var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
|
|
|
|
if ( compare ) {
|
|
// Disconnected nodes
|
|
if ( compare & 1 ||
|
|
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
|
|
|
|
// Choose the first element that is related to our preferred document
|
|
if ( a === doc || contains(preferredDoc, a) ) {
|
|
return -1;
|
|
}
|
|
if ( b === doc || contains(preferredDoc, b) ) {
|
|
return 1;
|
|
}
|
|
|
|
// Maintain original order
|
|
return sortInput ?
|
|
( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
|
|
0;
|
|
}
|
|
|
|
return compare & 4 ? -1 : 1;
|
|
}
|
|
|
|
// Not directly comparable, sort on existence of method
|
|
return a.compareDocumentPosition ? -1 : 1;
|
|
} :
|
|
function( a, b ) {
|
|
var cur,
|
|
i = 0,
|
|
aup = a.parentNode,
|
|
bup = b.parentNode,
|
|
ap = [ a ],
|
|
bp = [ b ];
|
|
|
|
// Exit early if the nodes are identical
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
|
|
// Parentless nodes are either documents or disconnected
|
|
} else if ( !aup || !bup ) {
|
|
return a === doc ? -1 :
|
|
b === doc ? 1 :
|
|
aup ? -1 :
|
|
bup ? 1 :
|
|
sortInput ?
|
|
( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
|
|
0;
|
|
|
|
// If the nodes are siblings, we can do a quick check
|
|
} else if ( aup === bup ) {
|
|
return siblingCheck( a, b );
|
|
}
|
|
|
|
// Otherwise we need full lists of their ancestors for comparison
|
|
cur = a;
|
|
while ( (cur = cur.parentNode) ) {
|
|
ap.unshift( cur );
|
|
}
|
|
cur = b;
|
|
while ( (cur = cur.parentNode) ) {
|
|
bp.unshift( cur );
|
|
}
|
|
|
|
// Walk down the tree looking for a discrepancy
|
|
while ( ap[i] === bp[i] ) {
|
|
i++;
|
|
}
|
|
|
|
return i ?
|
|
// Do a sibling check if the nodes have a common ancestor
|
|
siblingCheck( ap[i], bp[i] ) :
|
|
|
|
// Otherwise nodes in our document sort first
|
|
ap[i] === preferredDoc ? -1 :
|
|
bp[i] === preferredDoc ? 1 :
|
|
0;
|
|
};
|
|
|
|
return document;
|
|
};
|
|
|
|
Sizzle.matches = function( expr, elements ) {
|
|
return Sizzle( expr, null, null, elements );
|
|
};
|
|
|
|
Sizzle.matchesSelector = function( elem, expr ) {
|
|
// Set document vars if needed
|
|
if ( ( elem.ownerDocument || elem ) !== document ) {
|
|
setDocument( elem );
|
|
}
|
|
|
|
// Make sure that attribute selectors are quoted
|
|
expr = expr.replace( rattributeQuotes, "='$1']" );
|
|
|
|
// rbuggyQSA always contains :focus, so no need for an existence check
|
|
if ( support.matchesSelector && documentIsHTML &&
|
|
(!rbuggyMatches || !rbuggyMatches.test(expr)) &&
|
|
(!rbuggyQSA || !rbuggyQSA.test(expr)) ) {
|
|
|
|
try {
|
|
var ret = matches.call( elem, expr );
|
|
|
|
// IE 9's matchesSelector returns false on disconnected nodes
|
|
if ( ret || support.disconnectedMatch ||
|
|
// As well, disconnected nodes are said to be in a document
|
|
// fragment in IE 9
|
|
elem.document && elem.document.nodeType !== 11 ) {
|
|
return ret;
|
|
}
|
|
} catch(e) {}
|
|
}
|
|
|
|
return Sizzle( expr, document, null, [elem] ).length > 0;
|
|
};
|
|
|
|
Sizzle.contains = function( context, elem ) {
|
|
// Set document vars if needed
|
|
if ( ( context.ownerDocument || context ) !== document ) {
|
|
setDocument( context );
|
|
}
|
|
return contains( context, elem );
|
|
};
|
|
|
|
Sizzle.attr = function( elem, name ) {
|
|
// Set document vars if needed
|
|
if ( ( elem.ownerDocument || elem ) !== document ) {
|
|
setDocument( elem );
|
|
}
|
|
|
|
var fn = Expr.attrHandle[ name.toLowerCase() ],
|
|
val = fn && fn( elem, name, !documentIsHTML );
|
|
|
|
return val === undefined ?
|
|
support.attributes || !documentIsHTML ?
|
|
elem.getAttribute( name ) :
|
|
(val = elem.getAttributeNode(name)) && val.specified ?
|
|
val.value :
|
|
null :
|
|
val;
|
|
};
|
|
|
|
Sizzle.error = function( msg ) {
|
|
throw new Error( "Syntax error, unrecognized expression: " + msg );
|
|
};
|
|
|
|
// Document sorting and removing duplicates
|
|
Sizzle.uniqueSort = function( results ) {
|
|
var elem,
|
|
duplicates = [],
|
|
j = 0,
|
|
i = 0;
|
|
|
|
// Unless we *know* we can detect duplicates, assume their presence
|
|
hasDuplicate = !support.detectDuplicates;
|
|
sortInput = !support.sortStable && results.slice( 0 );
|
|
results.sort( sortOrder );
|
|
|
|
if ( hasDuplicate ) {
|
|
while ( (elem = results[i++]) ) {
|
|
if ( elem === results[ i ] ) {
|
|
j = duplicates.push( i );
|
|
}
|
|
}
|
|
while ( j-- ) {
|
|
results.splice( duplicates[ j ], 1 );
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
/**
|
|
* Checks document order of two siblings
|
|
* @param {Element} a
|
|
* @param {Element} b
|
|
* @returns Returns -1 if a precedes b, 1 if a follows b
|
|
*/
|
|
function siblingCheck( a, b ) {
|
|
var cur = b && a,
|
|
diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
|
|
|
|
// Use IE sourceIndex if available on both nodes
|
|
if ( diff ) {
|
|
return diff;
|
|
}
|
|
|
|
// Check if b follows a
|
|
if ( cur ) {
|
|
while ( (cur = cur.nextSibling) ) {
|
|
if ( cur === b ) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return a ? 1 : -1;
|
|
}
|
|
|
|
// Fetches boolean attributes by node
|
|
function boolHandler( elem, name, isXML ) {
|
|
var val;
|
|
return isXML ?
|
|
undefined :
|
|
(val = elem.getAttributeNode( name )) && val.specified ?
|
|
val.value :
|
|
elem[ name ] === true ? name.toLowerCase() : null;
|
|
}
|
|
|
|
// Fetches attributes without interpolation
|
|
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
|
|
function interpolationHandler( elem, name, isXML ) {
|
|
var val;
|
|
return isXML ?
|
|
undefined :
|
|
(val = elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ));
|
|
}
|
|
|
|
// Returns a function to use in pseudos for input types
|
|
function createInputPseudo( type ) {
|
|
return function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === "input" && elem.type === type;
|
|
};
|
|
}
|
|
|
|
// Returns a function to use in pseudos for buttons
|
|
function createButtonPseudo( type ) {
|
|
return function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return (name === "input" || name === "button") && elem.type === type;
|
|
};
|
|
}
|
|
|
|
// Returns a function to use in pseudos for positionals
|
|
function createPositionalPseudo( fn ) {
|
|
return markFunction(function( argument ) {
|
|
argument = +argument;
|
|
return markFunction(function( seed, matches ) {
|
|
var j,
|
|
matchIndexes = fn( [], seed.length, argument ),
|
|
i = matchIndexes.length;
|
|
|
|
// Match elements found at the specified indexes
|
|
while ( i-- ) {
|
|
if ( seed[ (j = matchIndexes[i]) ] ) {
|
|
seed[j] = !(matches[j] = seed[j]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Utility function for retrieving the text value of an array of DOM nodes
|
|
* @param {Array|Element} elem
|
|
*/
|
|
getText = Sizzle.getText = function( elem ) {
|
|
var node,
|
|
ret = "",
|
|
i = 0,
|
|
nodeType = elem.nodeType;
|
|
|
|
if ( !nodeType ) {
|
|
// If no nodeType, this is expected to be an array
|
|
for ( ; (node = elem[i]); i++ ) {
|
|
// Do not traverse comment nodes
|
|
ret += getText( node );
|
|
}
|
|
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
|
|
// Use textContent for elements
|
|
// innerText usage removed for consistency of new lines (see #11153)
|
|
if ( typeof elem.textContent === "string" ) {
|
|
return elem.textContent;
|
|
} else {
|
|
// Traverse its children
|
|
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
|
ret += getText( elem );
|
|
}
|
|
}
|
|
} else if ( nodeType === 3 || nodeType === 4 ) {
|
|
return elem.nodeValue;
|
|
}
|
|
// Do not include comment or processing instruction nodes
|
|
|
|
return ret;
|
|
};
|
|
|
|
Expr = Sizzle.selectors = {
|
|
|
|
// Can be adjusted by the user
|
|
cacheLength: 50,
|
|
|
|
createPseudo: markFunction,
|
|
|
|
match: matchExpr,
|
|
|
|
attrHandle: {},
|
|
|
|
find: {},
|
|
|
|
relative: {
|
|
">": { dir: "parentNode", first: true },
|
|
" ": { dir: "parentNode" },
|
|
"+": { dir: "previousSibling", first: true },
|
|
"~": { dir: "previousSibling" }
|
|
},
|
|
|
|
preFilter: {
|
|
"ATTR": function( match ) {
|
|
match[1] = match[1].replace( runescape, funescape );
|
|
|
|
// Move the given value to match[3] whether quoted or unquoted
|
|
match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
|
|
|
|
if ( match[2] === "~=" ) {
|
|
match[3] = " " + match[3] + " ";
|
|
}
|
|
|
|
return match.slice( 0, 4 );
|
|
},
|
|
|
|
"CHILD": function( match ) {
|
|
/* matches from matchExpr["CHILD"]
|
|
1 type (only|nth|...)
|
|
2 what (child|of-type)
|
|
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
|
|
4 xn-component of xn+y argument ([+-]?\d*n|)
|
|
5 sign of xn-component
|
|
6 x of xn-component
|
|
7 sign of y-component
|
|
8 y of y-component
|
|
*/
|
|
match[1] = match[1].toLowerCase();
|
|
|
|
if ( match[1].slice( 0, 3 ) === "nth" ) {
|
|
// nth-* requires argument
|
|
if ( !match[3] ) {
|
|
Sizzle.error( match[0] );
|
|
}
|
|
|
|
// numeric x and y parameters for Expr.filter.CHILD
|
|
// remember that false/true cast respectively to 0/1
|
|
match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
|
|
match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
|
|
|
|
// other types prohibit arguments
|
|
} else if ( match[3] ) {
|
|
Sizzle.error( match[0] );
|
|
}
|
|
|
|
return match;
|
|
},
|
|
|
|
"PSEUDO": function( match ) {
|
|
var excess,
|
|
unquoted = !match[5] && match[2];
|
|
|
|
if ( matchExpr["CHILD"].test( match[0] ) ) {
|
|
return null;
|
|
}
|
|
|
|
// Accept quoted arguments as-is
|
|
if ( match[4] ) {
|
|
match[2] = match[4];
|
|
|
|
// Strip excess characters from unquoted arguments
|
|
} else if ( unquoted && rpseudo.test( unquoted ) &&
|
|
// Get excess from tokenize (recursively)
|
|
(excess = tokenize( unquoted, true )) &&
|
|
// advance to the next closing parenthesis
|
|
(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
|
|
|
|
// excess is a negative index
|
|
match[0] = match[0].slice( 0, excess );
|
|
match[2] = unquoted.slice( 0, excess );
|
|
}
|
|
|
|
// Return only captures needed by the pseudo filter method (type and argument)
|
|
return match.slice( 0, 3 );
|
|
}
|
|
},
|
|
|
|
filter: {
|
|
|
|
"TAG": function( nodeNameSelector ) {
|
|
var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
|
|
return nodeNameSelector === "*" ?
|
|
function() { return true; } :
|
|
function( elem ) {
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
|
|
};
|
|
},
|
|
|
|
"CLASS": function( className ) {
|
|
var pattern = classCache[ className + " " ];
|
|
|
|
return pattern ||
|
|
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
|
|
classCache( className, function( elem ) {
|
|
return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
|
|
});
|
|
},
|
|
|
|
"ATTR": function( name, operator, check ) {
|
|
return function( elem ) {
|
|
var result = Sizzle.attr( elem, name );
|
|
|
|
if ( result == null ) {
|
|
return operator === "!=";
|
|
}
|
|
if ( !operator ) {
|
|
return true;
|
|
}
|
|
|
|
result += "";
|
|
|
|
return operator === "=" ? result === check :
|
|
operator === "!=" ? result !== check :
|
|
operator === "^=" ? check && result.indexOf( check ) === 0 :
|
|
operator === "*=" ? check && result.indexOf( check ) > -1 :
|
|
operator === "$=" ? check && result.slice( -check.length ) === check :
|
|
operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
|
|
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
|
|
false;
|
|
};
|
|
},
|
|
|
|
"CHILD": function( type, what, argument, first, last ) {
|
|
var simple = type.slice( 0, 3 ) !== "nth",
|
|
forward = type.slice( -4 ) !== "last",
|
|
ofType = what === "of-type";
|
|
|
|
return first === 1 && last === 0 ?
|
|
|
|
// Shortcut for :nth-*(n)
|
|
function( elem ) {
|
|
return !!elem.parentNode;
|
|
} :
|
|
|
|
function( elem, context, xml ) {
|
|
var cache, outerCache, node, diff, nodeIndex, start,
|
|
dir = simple !== forward ? "nextSibling" : "previousSibling",
|
|
parent = elem.parentNode,
|
|
name = ofType && elem.nodeName.toLowerCase(),
|
|
useCache = !xml && !ofType;
|
|
|
|
if ( parent ) {
|
|
|
|
// :(first|last|only)-(child|of-type)
|
|
if ( simple ) {
|
|
while ( dir ) {
|
|
node = elem;
|
|
while ( (node = node[ dir ]) ) {
|
|
if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
|
|
return false;
|
|
}
|
|
}
|
|
// Reverse direction for :only-* (if we haven't yet done so)
|
|
start = dir = type === "only" && !start && "nextSibling";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
start = [ forward ? parent.firstChild : parent.lastChild ];
|
|
|
|
// non-xml :nth-child(...) stores cache data on `parent`
|
|
if ( forward && useCache ) {
|
|
// Seek `elem` from a previously-cached index
|
|
outerCache = parent[ expando ] || (parent[ expando ] = {});
|
|
cache = outerCache[ type ] || [];
|
|
nodeIndex = cache[0] === dirruns && cache[1];
|
|
diff = cache[0] === dirruns && cache[2];
|
|
node = nodeIndex && parent.childNodes[ nodeIndex ];
|
|
|
|
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
|
|
|
// Fallback to seeking `elem` from the start
|
|
(diff = nodeIndex = 0) || start.pop()) ) {
|
|
|
|
// When found, cache indexes on `parent` and break
|
|
if ( node.nodeType === 1 && ++diff && node === elem ) {
|
|
outerCache[ type ] = [ dirruns, nodeIndex, diff ];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Use previously-cached element index if available
|
|
} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
|
|
diff = cache[1];
|
|
|
|
// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
|
|
} else {
|
|
// Use the same loop as above to seek `elem` from the start
|
|
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
|
(diff = nodeIndex = 0) || start.pop()) ) {
|
|
|
|
if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
|
|
// Cache the index of each encountered element
|
|
if ( useCache ) {
|
|
(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
|
|
}
|
|
|
|
if ( node === elem ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Incorporate the offset, then check against cycle size
|
|
diff -= last;
|
|
return diff === first || ( diff % first === 0 && diff / first >= 0 );
|
|
}
|
|
};
|
|
},
|
|
|
|
"PSEUDO": function( pseudo, argument ) {
|
|
// pseudo-class names are case-insensitive
|
|
// http://www.w3.org/TR/selectors/#pseudo-classes
|
|
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
|
|
// Remember that setFilters inherits from pseudos
|
|
var args,
|
|
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
|
|
Sizzle.error( "unsupported pseudo: " + pseudo );
|
|
|
|
// The user may use createPseudo to indicate that
|
|
// arguments are needed to create the filter function
|
|
// just as Sizzle does
|
|
if ( fn[ expando ] ) {
|
|
return fn( argument );
|
|
}
|
|
|
|
// But maintain support for old signatures
|
|
if ( fn.length > 1 ) {
|
|
args = [ pseudo, pseudo, "", argument ];
|
|
return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
|
|
markFunction(function( seed, matches ) {
|
|
var idx,
|
|
matched = fn( seed, argument ),
|
|
i = matched.length;
|
|
while ( i-- ) {
|
|
idx = indexOf.call( seed, matched[i] );
|
|
seed[ idx ] = !( matches[ idx ] = matched[i] );
|
|
}
|
|
}) :
|
|
function( elem ) {
|
|
return fn( elem, 0, args );
|
|
};
|
|
}
|
|
|
|
return fn;
|
|
}
|
|
},
|
|
|
|
pseudos: {
|
|
// Potentially complex pseudos
|
|
"not": markFunction(function( selector ) {
|
|
// Trim the selector passed to compile
|
|
// to avoid treating leading and trailing
|
|
// spaces as combinators
|
|
var input = [],
|
|
results = [],
|
|
matcher = compile( selector.replace( rtrim, "$1" ) );
|
|
|
|
return matcher[ expando ] ?
|
|
markFunction(function( seed, matches, context, xml ) {
|
|
var elem,
|
|
unmatched = matcher( seed, null, xml, [] ),
|
|
i = seed.length;
|
|
|
|
// Match elements unmatched by `matcher`
|
|
while ( i-- ) {
|
|
if ( (elem = unmatched[i]) ) {
|
|
seed[i] = !(matches[i] = elem);
|
|
}
|
|
}
|
|
}) :
|
|
function( elem, context, xml ) {
|
|
input[0] = elem;
|
|
matcher( input, null, xml, results );
|
|
return !results.pop();
|
|
};
|
|
}),
|
|
|
|
"has": markFunction(function( selector ) {
|
|
return function( elem ) {
|
|
return Sizzle( selector, elem ).length > 0;
|
|
};
|
|
}),
|
|
|
|
"contains": markFunction(function( text ) {
|
|
return function( elem ) {
|
|
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
|
|
};
|
|
}),
|
|
|
|
// "Whether an element is represented by a :lang() selector
|
|
// is based solely on the element's language value
|
|
// being equal to the identifier C,
|
|
// or beginning with the identifier C immediately followed by "-".
|
|
// The matching of C against the element's language value is performed case-insensitively.
|
|
// The identifier C does not have to be a valid language name."
|
|
// http://www.w3.org/TR/selectors/#lang-pseudo
|
|
"lang": markFunction( function( lang ) {
|
|
// lang value must be a valid identifier
|
|
if ( !ridentifier.test(lang || "") ) {
|
|
Sizzle.error( "unsupported lang: " + lang );
|
|
}
|
|
lang = lang.replace( runescape, funescape ).toLowerCase();
|
|
return function( elem ) {
|
|
var elemLang;
|
|
do {
|
|
if ( (elemLang = documentIsHTML ?
|
|
elem.lang :
|
|
elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
|
|
|
|
elemLang = elemLang.toLowerCase();
|
|
return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
|
|
}
|
|
} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
|
|
return false;
|
|
};
|
|
}),
|
|
|
|
// Miscellaneous
|
|
"target": function( elem ) {
|
|
var hash = window.location && window.location.hash;
|
|
return hash && hash.slice( 1 ) === elem.id;
|
|
},
|
|
|
|
"root": function( elem ) {
|
|
return elem === docElem;
|
|
},
|
|
|
|
"focus": function( elem ) {
|
|
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
|
|
},
|
|
|
|
// Boolean properties
|
|
"enabled": function( elem ) {
|
|
return elem.disabled === false;
|
|
},
|
|
|
|
"disabled": function( elem ) {
|
|
return elem.disabled === true;
|
|
},
|
|
|
|
"checked": function( elem ) {
|
|
// In CSS3, :checked should return both checked and selected elements
|
|
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
|
var nodeName = elem.nodeName.toLowerCase();
|
|
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
|
|
},
|
|
|
|
"selected": function( elem ) {
|
|
// Accessing this property makes selected-by-default
|
|
// options in Safari work properly
|
|
if ( elem.parentNode ) {
|
|
elem.parentNode.selectedIndex;
|
|
}
|
|
|
|
return elem.selected === true;
|
|
},
|
|
|
|
// Contents
|
|
"empty": function( elem ) {
|
|
// http://www.w3.org/TR/selectors/#empty-pseudo
|
|
// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
|
|
// not comment, processing instructions, or others
|
|
// Thanks to Diego Perini for the nodeName shortcut
|
|
// Greater than "@" means alpha characters (specifically not starting with "#" or "?")
|
|
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
|
if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
"parent": function( elem ) {
|
|
return !Expr.pseudos["empty"]( elem );
|
|
},
|
|
|
|
// Element/input types
|
|
"header": function( elem ) {
|
|
return rheader.test( elem.nodeName );
|
|
},
|
|
|
|
"input": function( elem ) {
|
|
return rinputs.test( elem.nodeName );
|
|
},
|
|
|
|
"button": function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === "input" && elem.type === "button" || name === "button";
|
|
},
|
|
|
|
"text": function( elem ) {
|
|
var attr;
|
|
// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
|
|
// use getAttribute instead to test this case
|
|
return elem.nodeName.toLowerCase() === "input" &&
|
|
elem.type === "text" &&
|
|
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
|
|
},
|
|
|
|
// Position-in-collection
|
|
"first": createPositionalPseudo(function() {
|
|
return [ 0 ];
|
|
}),
|
|
|
|
"last": createPositionalPseudo(function( matchIndexes, length ) {
|
|
return [ length - 1 ];
|
|
}),
|
|
|
|
"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
return [ argument < 0 ? argument + length : argument ];
|
|
}),
|
|
|
|
"even": createPositionalPseudo(function( matchIndexes, length ) {
|
|
var i = 0;
|
|
for ( ; i < length; i += 2 ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"odd": createPositionalPseudo(function( matchIndexes, length ) {
|
|
var i = 1;
|
|
for ( ; i < length; i += 2 ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for ( ; --i >= 0; ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for ( ; ++i < length; ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
})
|
|
}
|
|
};
|
|
|
|
// Add button/input type pseudos
|
|
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
|
|
Expr.pseudos[ i ] = createInputPseudo( i );
|
|
}
|
|
for ( i in { submit: true, reset: true } ) {
|
|
Expr.pseudos[ i ] = createButtonPseudo( i );
|
|
}
|
|
|
|
function tokenize( selector, parseOnly ) {
|
|
var matched, match, tokens, type,
|
|
soFar, groups, preFilters,
|
|
cached = tokenCache[ selector + " " ];
|
|
|
|
if ( cached ) {
|
|
return parseOnly ? 0 : cached.slice( 0 );
|
|
}
|
|
|
|
soFar = selector;
|
|
groups = [];
|
|
preFilters = Expr.preFilter;
|
|
|
|
while ( soFar ) {
|
|
|
|
// Comma and first run
|
|
if ( !matched || (match = rcomma.exec( soFar )) ) {
|
|
if ( match ) {
|
|
// Don't consume trailing commas as valid
|
|
soFar = soFar.slice( match[0].length ) || soFar;
|
|
}
|
|
groups.push( tokens = [] );
|
|
}
|
|
|
|
matched = false;
|
|
|
|
// Combinators
|
|
if ( (match = rcombinators.exec( soFar )) ) {
|
|
matched = match.shift();
|
|
tokens.push( {
|
|
value: matched,
|
|
// Cast descendant combinators to space
|
|
type: match[0].replace( rtrim, " " )
|
|
} );
|
|
soFar = soFar.slice( matched.length );
|
|
}
|
|
|
|
// Filters
|
|
for ( type in Expr.filter ) {
|
|
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
|
|
(match = preFilters[ type ]( match ))) ) {
|
|
matched = match.shift();
|
|
tokens.push( {
|
|
value: matched,
|
|
type: type,
|
|
matches: match
|
|
} );
|
|
soFar = soFar.slice( matched.length );
|
|
}
|
|
}
|
|
|
|
if ( !matched ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return the length of the invalid excess
|
|
// if we're just parsing
|
|
// Otherwise, throw an error or return tokens
|
|
return parseOnly ?
|
|
soFar.length :
|
|
soFar ?
|
|
Sizzle.error( selector ) :
|
|
// Cache the tokens
|
|
tokenCache( selector, groups ).slice( 0 );
|
|
}
|
|
|
|
function toSelector( tokens ) {
|
|
var i = 0,
|
|
len = tokens.length,
|
|
selector = "";
|
|
for ( ; i < len; i++ ) {
|
|
selector += tokens[i].value;
|
|
}
|
|
return selector;
|
|
}
|
|
|
|
function addCombinator( matcher, combinator, base ) {
|
|
var dir = combinator.dir,
|
|
checkNonElements = base && dir === "parentNode",
|
|
doneName = done++;
|
|
|
|
return combinator.first ?
|
|
// Check against closest ancestor/preceding element
|
|
function( elem, context, xml ) {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
return matcher( elem, context, xml );
|
|
}
|
|
}
|
|
} :
|
|
|
|
// Check against all ancestor/preceding elements
|
|
function( elem, context, xml ) {
|
|
var data, cache, outerCache,
|
|
dirkey = dirruns + " " + doneName;
|
|
|
|
// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
|
|
if ( xml ) {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
if ( matcher( elem, context, xml ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
outerCache = elem[ expando ] || (elem[ expando ] = {});
|
|
if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
|
|
if ( (data = cache[1]) === true || data === cachedruns ) {
|
|
return data === true;
|
|
}
|
|
} else {
|
|
cache = outerCache[ dir ] = [ dirkey ];
|
|
cache[1] = matcher( elem, context, xml ) || cachedruns;
|
|
if ( cache[1] === true ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function elementMatcher( matchers ) {
|
|
return matchers.length > 1 ?
|
|
function( elem, context, xml ) {
|
|
var i = matchers.length;
|
|
while ( i-- ) {
|
|
if ( !matchers[i]( elem, context, xml ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} :
|
|
matchers[0];
|
|
}
|
|
|
|
function condense( unmatched, map, filter, context, xml ) {
|
|
var elem,
|
|
newUnmatched = [],
|
|
i = 0,
|
|
len = unmatched.length,
|
|
mapped = map != null;
|
|
|
|
for ( ; i < len; i++ ) {
|
|
if ( (elem = unmatched[i]) ) {
|
|
if ( !filter || filter( elem, context, xml ) ) {
|
|
newUnmatched.push( elem );
|
|
if ( mapped ) {
|
|
map.push( i );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return newUnmatched;
|
|
}
|
|
|
|
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
|
|
if ( postFilter && !postFilter[ expando ] ) {
|
|
postFilter = setMatcher( postFilter );
|
|
}
|
|
if ( postFinder && !postFinder[ expando ] ) {
|
|
postFinder = setMatcher( postFinder, postSelector );
|
|
}
|
|
return markFunction(function( seed, results, context, xml ) {
|
|
var temp, i, elem,
|
|
preMap = [],
|
|
postMap = [],
|
|
preexisting = results.length,
|
|
|
|
// Get initial elements from seed or context
|
|
elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
|
|
|
|
// Prefilter to get matcher input, preserving a map for seed-results synchronization
|
|
matcherIn = preFilter && ( seed || !selector ) ?
|
|
condense( elems, preMap, preFilter, context, xml ) :
|
|
elems,
|
|
|
|
matcherOut = matcher ?
|
|
// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
|
|
postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
|
|
|
|
// ...intermediate processing is necessary
|
|
[] :
|
|
|
|
// ...otherwise use results directly
|
|
results :
|
|
matcherIn;
|
|
|
|
// Find primary matches
|
|
if ( matcher ) {
|
|
matcher( matcherIn, matcherOut, context, xml );
|
|
}
|
|
|
|
// Apply postFilter
|
|
if ( postFilter ) {
|
|
temp = condense( matcherOut, postMap );
|
|
postFilter( temp, [], context, xml );
|
|
|
|
// Un-match failing elements by moving them back to matcherIn
|
|
i = temp.length;
|
|
while ( i-- ) {
|
|
if ( (elem = temp[i]) ) {
|
|
matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( seed ) {
|
|
if ( postFinder || preFilter ) {
|
|
if ( postFinder ) {
|
|
// Get the final matcherOut by condensing this intermediate into postFinder contexts
|
|
temp = [];
|
|
i = matcherOut.length;
|
|
while ( i-- ) {
|
|
if ( (elem = matcherOut[i]) ) {
|
|
// Restore matcherIn since elem is not yet a final match
|
|
temp.push( (matcherIn[i] = elem) );
|
|
}
|
|
}
|
|
postFinder( null, (matcherOut = []), temp, xml );
|
|
}
|
|
|
|
// Move matched elements from seed to results to keep them synchronized
|
|
i = matcherOut.length;
|
|
while ( i-- ) {
|
|
if ( (elem = matcherOut[i]) &&
|
|
(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
|
|
|
|
seed[temp] = !(results[temp] = elem);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add elements to results, through postFinder if defined
|
|
} else {
|
|
matcherOut = condense(
|
|
matcherOut === results ?
|
|
matcherOut.splice( preexisting, matcherOut.length ) :
|
|
matcherOut
|
|
);
|
|
if ( postFinder ) {
|
|
postFinder( null, results, matcherOut, xml );
|
|
} else {
|
|
push.apply( results, matcherOut );
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function matcherFromTokens( tokens ) {
|
|
var checkContext, matcher, j,
|
|
len = tokens.length,
|
|
leadingRelative = Expr.relative[ tokens[0].type ],
|
|
implicitRelative = leadingRelative || Expr.relative[" "],
|
|
i = leadingRelative ? 1 : 0,
|
|
|
|
// The foundational matcher ensures that elements are reachable from top-level context(s)
|
|
matchContext = addCombinator( function( elem ) {
|
|
return elem === checkContext;
|
|
}, implicitRelative, true ),
|
|
matchAnyContext = addCombinator( function( elem ) {
|
|
return indexOf.call( checkContext, elem ) > -1;
|
|
}, implicitRelative, true ),
|
|
matchers = [ function( elem, context, xml ) {
|
|
return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
|
|
(checkContext = context).nodeType ?
|
|
matchContext( elem, context, xml ) :
|
|
matchAnyContext( elem, context, xml ) );
|
|
} ];
|
|
|
|
for ( ; i < len; i++ ) {
|
|
if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
|
|
matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
|
|
} else {
|
|
matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
|
|
|
|
// Return special upon seeing a positional matcher
|
|
if ( matcher[ expando ] ) {
|
|
// Find the next relative operator (if any) for proper handling
|
|
j = ++i;
|
|
for ( ; j < len; j++ ) {
|
|
if ( Expr.relative[ tokens[j].type ] ) {
|
|
break;
|
|
}
|
|
}
|
|
return setMatcher(
|
|
i > 1 && elementMatcher( matchers ),
|
|
i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
|
|
matcher,
|
|
i < j && matcherFromTokens( tokens.slice( i, j ) ),
|
|
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
|
|
j < len && toSelector( tokens )
|
|
);
|
|
}
|
|
matchers.push( matcher );
|
|
}
|
|
}
|
|
|
|
return elementMatcher( matchers );
|
|
}
|
|
|
|
function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
|
|
// A counter to specify which element is currently being matched
|
|
var matcherCachedRuns = 0,
|
|
bySet = setMatchers.length > 0,
|
|
byElement = elementMatchers.length > 0,
|
|
superMatcher = function( seed, context, xml, results, expandContext ) {
|
|
var elem, j, matcher,
|
|
setMatched = [],
|
|
matchedCount = 0,
|
|
i = "0",
|
|
unmatched = seed && [],
|
|
outermost = expandContext != null,
|
|
contextBackup = outermostContext,
|
|
// We must always have either seed elements or context
|
|
elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
|
|
// Use integer dirruns iff this is the outermost matcher
|
|
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
|
|
|
|
if ( outermost ) {
|
|
outermostContext = context !== document && context;
|
|
cachedruns = matcherCachedRuns;
|
|
}
|
|
|
|
// Add elements passing elementMatchers directly to results
|
|
// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
|
|
for ( ; (elem = elems[i]) != null; i++ ) {
|
|
if ( byElement && elem ) {
|
|
j = 0;
|
|
while ( (matcher = elementMatchers[j++]) ) {
|
|
if ( matcher( elem, context, xml ) ) {
|
|
results.push( elem );
|
|
break;
|
|
}
|
|
}
|
|
if ( outermost ) {
|
|
dirruns = dirrunsUnique;
|
|
cachedruns = ++matcherCachedRuns;
|
|
}
|
|
}
|
|
|
|
// Track unmatched elements for set filters
|
|
if ( bySet ) {
|
|
// They will have gone through all possible matchers
|
|
if ( (elem = !matcher && elem) ) {
|
|
matchedCount--;
|
|
}
|
|
|
|
// Lengthen the array for every element, matched or not
|
|
if ( seed ) {
|
|
unmatched.push( elem );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply set filters to unmatched elements
|
|
matchedCount += i;
|
|
if ( bySet && i !== matchedCount ) {
|
|
j = 0;
|
|
while ( (matcher = setMatchers[j++]) ) {
|
|
matcher( unmatched, setMatched, context, xml );
|
|
}
|
|
|
|
if ( seed ) {
|
|
// Reintegrate element matches to eliminate the need for sorting
|
|
if ( matchedCount > 0 ) {
|
|
while ( i-- ) {
|
|
if ( !(unmatched[i] || setMatched[i]) ) {
|
|
setMatched[i] = pop.call( results );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Discard index placeholder values to get only actual matches
|
|
setMatched = condense( setMatched );
|
|
}
|
|
|
|
// Add matches to results
|
|
push.apply( results, setMatched );
|
|
|
|
// Seedless set matches succeeding multiple successful matchers stipulate sorting
|
|
if ( outermost && !seed && setMatched.length > 0 &&
|
|
( matchedCount + setMatchers.length ) > 1 ) {
|
|
|
|
Sizzle.uniqueSort( results );
|
|
}
|
|
}
|
|
|
|
// Override manipulation of globals by nested matchers
|
|
if ( outermost ) {
|
|
dirruns = dirrunsUnique;
|
|
outermostContext = contextBackup;
|
|
}
|
|
|
|
return unmatched;
|
|
};
|
|
|
|
return bySet ?
|
|
markFunction( superMatcher ) :
|
|
superMatcher;
|
|
}
|
|
|
|
compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
|
|
var i,
|
|
setMatchers = [],
|
|
elementMatchers = [],
|
|
cached = compilerCache[ selector + " " ];
|
|
|
|
if ( !cached ) {
|
|
// Generate a function of recursive functions that can be used to check each element
|
|
if ( !group ) {
|
|
group = tokenize( selector );
|
|
}
|
|
i = group.length;
|
|
while ( i-- ) {
|
|
cached = matcherFromTokens( group[i] );
|
|
if ( cached[ expando ] ) {
|
|
setMatchers.push( cached );
|
|
} else {
|
|
elementMatchers.push( cached );
|
|
}
|
|
}
|
|
|
|
// Cache the compiled function
|
|
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
|
|
}
|
|
return cached;
|
|
};
|
|
|
|
function multipleContexts( selector, contexts, results ) {
|
|
var i = 0,
|
|
len = contexts.length;
|
|
for ( ; i < len; i++ ) {
|
|
Sizzle( selector, contexts[i], results );
|
|
}
|
|
return results;
|
|
}
|
|
|
|
function select( selector, context, results, seed ) {
|
|
var i, tokens, token, type, find,
|
|
match = tokenize( selector );
|
|
|
|
if ( !seed ) {
|
|
// Try to minimize operations if there is only one group
|
|
if ( match.length === 1 ) {
|
|
|
|
// Take a shortcut and set the context if the root selector is an ID
|
|
tokens = match[0] = match[0].slice( 0 );
|
|
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
|
|
context.nodeType === 9 && documentIsHTML &&
|
|
Expr.relative[ tokens[1].type ] ) {
|
|
|
|
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
|
|
if ( !context ) {
|
|
return results;
|
|
}
|
|
|
|
selector = selector.slice( tokens.shift().value.length );
|
|
}
|
|
|
|
// Fetch a seed set for right-to-left matching
|
|
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
|
|
while ( i-- ) {
|
|
token = tokens[i];
|
|
|
|
// Abort if we hit a combinator
|
|
if ( Expr.relative[ (type = token.type) ] ) {
|
|
break;
|
|
}
|
|
if ( (find = Expr.find[ type ]) ) {
|
|
// Search, expanding context for leading sibling combinators
|
|
if ( (seed = find(
|
|
token.matches[0].replace( runescape, funescape ),
|
|
rsibling.test( tokens[0].type ) && context.parentNode || context
|
|
)) ) {
|
|
|
|
// If seed is empty or no tokens remain, we can return early
|
|
tokens.splice( i, 1 );
|
|
selector = seed.length && toSelector( tokens );
|
|
if ( !selector ) {
|
|
push.apply( results, seed );
|
|
return results;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compile and execute a filtering function
|
|
// Provide `match` to avoid retokenization if we modified the selector above
|
|
compile( selector, match )(
|
|
seed,
|
|
context,
|
|
!documentIsHTML,
|
|
results,
|
|
rsibling.test( selector )
|
|
);
|
|
return results;
|
|
}
|
|
|
|
// Deprecated
|
|
Expr.pseudos["nth"] = Expr.pseudos["eq"];
|
|
|
|
// Easy API for creating new setFilters
|
|
function setFilters() {}
|
|
setFilters.prototype = Expr.filters = Expr.pseudos;
|
|
Expr.setFilters = new setFilters();
|
|
|
|
// One-time assignments
|
|
|
|
// Sort stability
|
|
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
|
|
|
|
// Initialize against the default document
|
|
setDocument();
|
|
|
|
// Support: Chrome<<14
|
|
// Always assume duplicates if they aren't passed to the comparison function
|
|
[0, 0].sort( sortOrder );
|
|
support.detectDuplicates = hasDuplicate;
|
|
|
|
// Support: IE<8
|
|
// Prevent attribute/property "interpolation"
|
|
assert(function( div ) {
|
|
div.innerHTML = "<a href='#'></a>";
|
|
if ( div.firstChild.getAttribute("href") !== "#" ) {
|
|
var attrs = "type|href|height|width".split("|"),
|
|
i = attrs.length;
|
|
while ( i-- ) {
|
|
Expr.attrHandle[ attrs[i] ] = interpolationHandler;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Support: IE<9
|
|
// Use getAttributeNode to fetch booleans when getAttribute lies
|
|
assert(function( div ) {
|
|
if ( div.getAttribute("disabled") != null ) {
|
|
var attrs = booleans.split("|"),
|
|
i = attrs.length;
|
|
while ( i-- ) {
|
|
Expr.attrHandle[ attrs[i] ] = boolHandler;
|
|
}
|
|
}
|
|
});
|
|
|
|
jQuery.find = Sizzle;
|
|
jQuery.expr = Sizzle.selectors;
|
|
jQuery.expr[":"] = jQuery.expr.pseudos;
|
|
jQuery.unique = Sizzle.uniqueSort;
|
|
jQuery.text = Sizzle.getText;
|
|
jQuery.isXMLDoc = Sizzle.isXML;
|
|
jQuery.contains = Sizzle.contains;
|
|
|
|
|
|
})( window );
|
|
// String to Object options format cache
|
|
var optionsCache = {};
|
|
|
|
// Convert String-formatted options into Object-formatted ones and store in cache
|
|
function createOptions( options ) {
|
|
var object = optionsCache[ options ] = {};
|
|
jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
|
|
object[ flag ] = true;
|
|
});
|
|
return object;
|
|
}
|
|
|
|
/*
|
|
* Create a callback list using the following parameters:
|
|
*
|
|
* options: an optional list of space-separated options that will change how
|
|
* the callback list behaves or a more traditional option object
|
|
*
|
|
* By default a callback list will act like an event callback list and can be
|
|
* "fired" multiple times.
|
|
*
|
|
* Possible options:
|
|
*
|
|
* once: will ensure the callback list can only be fired once (like a Deferred)
|
|
*
|
|
* memory: will keep track of previous values and will call any callback added
|
|
* after the list has been fired right away with the latest "memorized"
|
|
* values (like a Deferred)
|
|
*
|
|
* unique: will ensure a callback can only be added once (no duplicate in the list)
|
|
*
|
|
* stopOnFalse: interrupt callings when a callback returns false
|
|
*
|
|
*/
|
|
jQuery.Callbacks = function( options ) {
|
|
|
|
// Convert options from String-formatted to Object-formatted if needed
|
|
// (we check in cache first)
|
|
options = typeof options === "string" ?
|
|
( optionsCache[ options ] || createOptions( options ) ) :
|
|
jQuery.extend( {}, options );
|
|
|
|
var // Last fire value (for non-forgettable lists)
|
|
memory,
|
|
// Flag to know if list was already fired
|
|
fired,
|
|
// Flag to know if list is currently firing
|
|
firing,
|
|
// First callback to fire (used internally by add and fireWith)
|
|
firingStart,
|
|
// End of the loop when firing
|
|
firingLength,
|
|
// Index of currently firing callback (modified by remove if needed)
|
|
firingIndex,
|
|
// Actual callback list
|
|
list = [],
|
|
// Stack of fire calls for repeatable lists
|
|
stack = !options.once && [],
|
|
// Fire callbacks
|
|
fire = function( data ) {
|
|
memory = options.memory && data;
|
|
fired = true;
|
|
firingIndex = firingStart || 0;
|
|
firingStart = 0;
|
|
firingLength = list.length;
|
|
firing = true;
|
|
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
|
|
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
|
|
memory = false; // To prevent further calls using add
|
|
break;
|
|
}
|
|
}
|
|
firing = false;
|
|
if ( list ) {
|
|
if ( stack ) {
|
|
if ( stack.length ) {
|
|
fire( stack.shift() );
|
|
}
|
|
} else if ( memory ) {
|
|
list = [];
|
|
} else {
|
|
self.disable();
|
|
}
|
|
}
|
|
},
|
|
// Actual Callbacks object
|
|
self = {
|
|
// Add a callback or a collection of callbacks to the list
|
|
add: function() {
|
|
if ( list ) {
|
|
// First, we save the current length
|
|
var start = list.length;
|
|
(function add( args ) {
|
|
jQuery.each( args, function( _, arg ) {
|
|
var type = jQuery.type( arg );
|
|
if ( type === "function" ) {
|
|
if ( !options.unique || !self.has( arg ) ) {
|
|
list.push( arg );
|
|
}
|
|
} else if ( arg && arg.length && type !== "string" ) {
|
|
// Inspect recursively
|
|
add( arg );
|
|
}
|
|
});
|
|
})( arguments );
|
|
// Do we need to add the callbacks to the
|
|
// current firing batch?
|
|
if ( firing ) {
|
|
firingLength = list.length;
|
|
// With memory, if we're not firing then
|
|
// we should call right away
|
|
} else if ( memory ) {
|
|
firingStart = start;
|
|
fire( memory );
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
// Remove a callback from the list
|
|
remove: function() {
|
|
if ( list ) {
|
|
jQuery.each( arguments, function( _, arg ) {
|
|
var index;
|
|
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
|
|
list.splice( index, 1 );
|
|
// Handle firing indexes
|
|
if ( firing ) {
|
|
if ( index <= firingLength ) {
|
|
firingLength--;
|
|
}
|
|
if ( index <= firingIndex ) {
|
|
firingIndex--;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
// Check if a given callback is in the list.
|
|
// If no argument is given, return whether or not list has callbacks attached.
|
|
has: function( fn ) {
|
|
return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
|
|
},
|
|
// Remove all callbacks from the list
|
|
empty: function() {
|
|
list = [];
|
|
firingLength = 0;
|
|
return this;
|
|
},
|
|
// Have the list do nothing anymore
|
|
disable: function() {
|
|
list = stack = memory = undefined;
|
|
return this;
|
|
},
|
|
// Is it disabled?
|
|
disabled: function() {
|
|
return !list;
|
|
},
|
|
// Lock the list in its current state
|
|
lock: function() {
|
|
stack = undefined;
|
|
if ( !memory ) {
|
|
self.disable();
|
|
}
|
|
return this;
|
|
},
|
|
// Is it locked?
|
|
locked: function() {
|
|
return !stack;
|
|
},
|
|
// Call all callbacks with the given context and arguments
|
|
fireWith: function( context, args ) {
|
|
args = args || [];
|
|
args = [ context, args.slice ? args.slice() : args ];
|
|
if ( list && ( !fired || stack ) ) {
|
|
if ( firing ) {
|
|
stack.push( args );
|
|
} else {
|
|
fire( args );
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
// Call all the callbacks with the given arguments
|
|
fire: function() {
|
|
self.fireWith( this, arguments );
|
|
return this;
|
|
},
|
|
// To know if the callbacks have already been called at least once
|
|
fired: function() {
|
|
return !!fired;
|
|
}
|
|
};
|
|
|
|
return self;
|
|
};
|
|
jQuery.extend({
|
|
|
|
Deferred: function( func ) {
|
|
var tuples = [
|
|
// action, add listener, listener list, final state
|
|
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
|
|
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
|
|
[ "notify", "progress", jQuery.Callbacks("memory") ]
|
|
],
|
|
state = "pending",
|
|
promise = {
|
|
state: function() {
|
|
return state;
|
|
},
|
|
always: function() {
|
|
deferred.done( arguments ).fail( arguments );
|
|
return this;
|
|
},
|
|
then: function( /* fnDone, fnFail, fnProgress */ ) {
|
|
var fns = arguments;
|
|
return jQuery.Deferred(function( newDefer ) {
|
|
jQuery.each( tuples, function( i, tuple ) {
|
|
var action = tuple[ 0 ],
|
|
fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
|
|
// deferred[ done | fail | progress ] for forwarding actions to newDefer
|
|
deferred[ tuple[1] ](function() {
|
|
var returned = fn && fn.apply( this, arguments );
|
|
if ( returned && jQuery.isFunction( returned.promise ) ) {
|
|
returned.promise()
|
|
.done( newDefer.resolve )
|
|
.fail( newDefer.reject )
|
|
.progress( newDefer.notify );
|
|
} else {
|
|
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
|
|
}
|
|
});
|
|
});
|
|
fns = null;
|
|
}).promise();
|
|
},
|
|
// Get a promise for this deferred
|
|
// If obj is provided, the promise aspect is added to the object
|
|
promise: function( obj ) {
|
|
return obj != null ? jQuery.extend( obj, promise ) : promise;
|
|
}
|
|
},
|
|
deferred = {};
|
|
|
|
// Keep pipe for back-compat
|
|
promise.pipe = promise.then;
|
|
|
|
// Add list-specific methods
|
|
jQuery.each( tuples, function( i, tuple ) {
|
|
var list = tuple[ 2 ],
|
|
stateString = tuple[ 3 ];
|
|
|
|
// promise[ done | fail | progress ] = list.add
|
|
promise[ tuple[1] ] = list.add;
|
|
|
|
// Handle state
|
|
if ( stateString ) {
|
|
list.add(function() {
|
|
// state = [ resolved | rejected ]
|
|
state = stateString;
|
|
|
|
// [ reject_list | resolve_list ].disable; progress_list.lock
|
|
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
|
|
}
|
|
|
|
// deferred[ resolve | reject | notify ]
|
|
deferred[ tuple[0] ] = function() {
|
|
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
|
|
return this;
|
|
};
|
|
deferred[ tuple[0] + "With" ] = list.fireWith;
|
|
});
|
|
|
|
// Make the deferred a promise
|
|
promise.promise( deferred );
|
|
|
|
// Call given func if any
|
|
if ( func ) {
|
|
func.call( deferred, deferred );
|
|
}
|
|
|
|
// All done!
|
|
return deferred;
|
|
},
|
|
|
|
// Deferred helper
|
|
when: function( subordinate /* , ..., subordinateN */ ) {
|
|
var i = 0,
|
|
resolveValues = core_slice.call( arguments ),
|
|
length = resolveValues.length,
|
|
|
|
// the count of uncompleted subordinates
|
|
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
|
|
|
|
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
|
|
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
|
|
|
|
// Update function for both resolve and progress values
|
|
updateFunc = function( i, contexts, values ) {
|
|
return function( value ) {
|
|
contexts[ i ] = this;
|
|
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
|
|
if( values === progressValues ) {
|
|
deferred.notifyWith( contexts, values );
|
|
} else if ( !( --remaining ) ) {
|
|
deferred.resolveWith( contexts, values );
|
|
}
|
|
};
|
|
},
|
|
|
|
progressValues, progressContexts, resolveContexts;
|
|
|
|
// add listeners to Deferred subordinates; treat others as resolved
|
|
if ( length > 1 ) {
|
|
progressValues = new Array( length );
|
|
progressContexts = new Array( length );
|
|
resolveContexts = new Array( length );
|
|
for ( ; i < length; i++ ) {
|
|
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
|
|
resolveValues[ i ].promise()
|
|
.done( updateFunc( i, resolveContexts, resolveValues ) )
|
|
.fail( deferred.reject )
|
|
.progress( updateFunc( i, progressContexts, progressValues ) );
|
|
} else {
|
|
--remaining;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we're not waiting on anything, resolve the master
|
|
if ( !remaining ) {
|
|
deferred.resolveWith( resolveContexts, resolveValues );
|
|
}
|
|
|
|
return deferred.promise();
|
|
}
|
|
});
|
|
jQuery.support = (function( support ) {
|
|
var input = document.createElement("input"),
|
|
fragment = document.createDocumentFragment(),
|
|
div = document.createElement("div"),
|
|
select = document.createElement("select"),
|
|
opt = select.appendChild( document.createElement("option") );
|
|
|
|
// Finish early in limited environments
|
|
if ( !input.type ) {
|
|
return support;
|
|
}
|
|
|
|
input.type = "checkbox";
|
|
|
|
// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
|
|
// Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
|
|
support.checkOn = input.value !== "";
|
|
|
|
// Must access the parent to make an option select properly
|
|
// Support: IE9, IE10
|
|
support.optSelected = opt.selected;
|
|
|
|
// Will be defined later
|
|
support.reliableMarginRight = true;
|
|
support.boxSizingReliable = true;
|
|
support.pixelPosition = false;
|
|
|
|
// Make sure checked status is properly cloned
|
|
// Support: IE9, IE10
|
|
input.checked = true;
|
|
support.noCloneChecked = input.cloneNode( true ).checked;
|
|
|
|
// Make sure that the options inside disabled selects aren't marked as disabled
|
|
// (WebKit marks them as disabled)
|
|
select.disabled = true;
|
|
support.optDisabled = !opt.disabled;
|
|
|
|
// Check if an input maintains its value after becoming a radio
|
|
// Support: IE9, IE10
|
|
input = document.createElement("input");
|
|
input.value = "t";
|
|
input.type = "radio";
|
|
support.radioValue = input.value === "t";
|
|
|
|
// #11217 - WebKit loses check when the name is after the checked attribute
|
|
input.setAttribute( "checked", "t" );
|
|
input.setAttribute( "name", "t" );
|
|
|
|
fragment.appendChild( input );
|
|
|
|
// Support: Safari 5.1, Android 4.x, Android 2.3
|
|
// old WebKit doesn't clone checked state correctly in fragments
|
|
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
|
|
|
// Support: Firefox, Chrome, Safari
|
|
// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
|
|
support.focusinBubbles = "onfocusin" in window;
|
|
|
|
div.style.backgroundClip = "content-box";
|
|
div.cloneNode( true ).style.backgroundClip = "";
|
|
support.clearCloneStyle = div.style.backgroundClip === "content-box";
|
|
|
|
// Run tests that need a body at doc ready
|
|
jQuery(function() {
|
|
var container, marginDiv,
|
|
// Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
|
|
divReset = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",
|
|
body = document.getElementsByTagName("body")[ 0 ];
|
|
|
|
if ( !body ) {
|
|
// Return for frameset docs that don't have a body
|
|
return;
|
|
}
|
|
|
|
container = document.createElement("div");
|
|
container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
|
|
|
|
// Check box-sizing and margin behavior.
|
|
body.appendChild( container ).appendChild( div );
|
|
div.innerHTML = "";
|
|
// Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
|
|
div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%";
|
|
|
|
// Workaround failing boxSizing test due to offsetWidth returning wrong value
|
|
// with some non-1 values of body zoom, ticket #13543
|
|
jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
|
|
support.boxSizing = div.offsetWidth === 4;
|
|
});
|
|
|
|
// Use window.getComputedStyle because jsdom on node.js will break without it.
|
|
if ( window.getComputedStyle ) {
|
|
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
|
|
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
|
|
|
|
// Support: Android 2.3
|
|
// Check if div with explicit width and no margin-right incorrectly
|
|
// gets computed margin-right based on width of container. (#3333)
|
|
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
|
|
marginDiv = div.appendChild( document.createElement("div") );
|
|
marginDiv.style.cssText = div.style.cssText = divReset;
|
|
marginDiv.style.marginRight = marginDiv.style.width = "0";
|
|
div.style.width = "1px";
|
|
|
|
support.reliableMarginRight =
|
|
!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
|
|
}
|
|
|
|
body.removeChild( container );
|
|
});
|
|
|
|
return support;
|
|
})( {} );
|
|
|
|
/*
|
|
Implementation Summary
|
|
|
|
1. Enforce API surface and semantic compatibility with 1.9.x branch
|
|
2. Improve the module's maintainability by reducing the storage
|
|
paths to a single mechanism.
|
|
3. Use the same single mechanism to support "private" and "user" data.
|
|
4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
|
|
5. Avoid exposing implementation details on user objects (eg. expando properties)
|
|
6. Provide a clear path for implementation upgrade to WeakMap in 2014
|
|
*/
|
|
var data_user, data_priv,
|
|
rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
|
|
rmultiDash = /([A-Z])/g;
|
|
|
|
function Data() {
|
|
// Support: Android < 4,
|
|
// Old WebKit does not have Object.preventExtensions/freeze method,
|
|
// return new empty object instead with no [[set]] accessor
|
|
Object.defineProperty( this.cache = {}, 0, {
|
|
get: function() {
|
|
return {};
|
|
}
|
|
});
|
|
|
|
this.expando = jQuery.expando + Math.random();
|
|
}
|
|
|
|
Data.uid = 1;
|
|
|
|
Data.accepts = function( owner ) {
|
|
// Accepts only:
|
|
// - Node
|
|
// - Node.ELEMENT_NODE
|
|
// - Node.DOCUMENT_NODE
|
|
// - Object
|
|
// - Any
|
|
return owner.nodeType ?
|
|
owner.nodeType === 1 || owner.nodeType === 9 : true;
|
|
};
|
|
|
|
Data.prototype = {
|
|
key: function( owner ) {
|
|
// We can accept data for non-element nodes in modern browsers,
|
|
// but we should not, see #8335.
|
|
// Always return the key for a frozen object.
|
|
if ( !Data.accepts( owner ) ) {
|
|
return 0;
|
|
}
|
|
|
|
var descriptor = {},
|
|
// Check if the owner object already has a cache key
|
|
unlock = owner[ this.expando ];
|
|
|
|
// If not, create one
|
|
if ( !unlock ) {
|
|
unlock = Data.uid++;
|
|
|
|
// Secure it in a non-enumerable, non-writable property
|
|
try {
|
|
descriptor[ this.expando ] = { value: unlock };
|
|
Object.defineProperties( owner, descriptor );
|
|
|
|
// Support: Android < 4
|
|
// Fallback to a less secure definition
|
|
} catch ( e ) {
|
|
descriptor[ this.expando ] = unlock;
|
|
jQuery.extend( owner, descriptor );
|
|
}
|
|
}
|
|
|
|
// Ensure the cache object
|
|
if ( !this.cache[ unlock ] ) {
|
|
this.cache[ unlock ] = {};
|
|
}
|
|
|
|
return unlock;
|
|
},
|
|
set: function( owner, data, value ) {
|
|
var prop,
|
|
// There may be an unlock assigned to this node,
|
|
// if there is no entry for this "owner", create one inline
|
|
// and set the unlock as though an owner entry had always existed
|
|
unlock = this.key( owner ),
|
|
cache = this.cache[ unlock ];
|
|
|
|
// Handle: [ owner, key, value ] args
|
|
if ( typeof data === "string" ) {
|
|
cache[ data ] = value;
|
|
|
|
// Handle: [ owner, { properties } ] args
|
|
} else {
|
|
// Support an expectation from the old data system where plain
|
|
// objects used to initialize would be set to the cache by
|
|
// reference, instead of having properties and values copied.
|
|
// Note, this will kill the connection between
|
|
// "this.cache[ unlock ]" and "cache"
|
|
if ( jQuery.isEmptyObject( cache ) ) {
|
|
this.cache[ unlock ] = data;
|
|
// Otherwise, copy the properties one-by-one to the cache object
|
|
} else {
|
|
for ( prop in data ) {
|
|
cache[ prop ] = data[ prop ];
|
|
}
|
|
}
|
|
}
|
|
},
|
|
get: function( owner, key ) {
|
|
// Either a valid cache is found, or will be created.
|
|
// New caches will be created and the unlock returned,
|
|
// allowing direct access to the newly created
|
|
// empty data object. A valid owner object must be provided.
|
|
var cache = this.cache[ this.key( owner ) ];
|
|
|
|
return key === undefined ?
|
|
cache : cache[ key ];
|
|
},
|
|
access: function( owner, key, value ) {
|
|
// In cases where either:
|
|
//
|
|
// 1. No key was specified
|
|
// 2. A string key was specified, but no value provided
|
|
//
|
|
// Take the "read" path and allow the get method to determine
|
|
// which value to return, respectively either:
|
|
//
|
|
// 1. The entire cache object
|
|
// 2. The data stored at the key
|
|
//
|
|
if ( key === undefined ||
|
|
((key && typeof key === "string") && value === undefined) ) {
|
|
return this.get( owner, key );
|
|
}
|
|
|
|
// [*]When the key is not a string, or both a key and value
|
|
// are specified, set or extend (existing objects) with either:
|
|
//
|
|
// 1. An object of properties
|
|
// 2. A key and value
|
|
//
|
|
this.set( owner, key, value );
|
|
|
|
// Since the "set" path can have two possible entry points
|
|
// return the expected data based on which path was taken[*]
|
|
return value !== undefined ? value : key;
|
|
},
|
|
remove: function( owner, key ) {
|
|
var i, name,
|
|
unlock = this.key( owner ),
|
|
cache = this.cache[ unlock ];
|
|
|
|
if ( key === undefined ) {
|
|
this.cache[ unlock ] = {};
|
|
|
|
} else {
|
|
// Support array or space separated string of keys
|
|
if ( jQuery.isArray( key ) ) {
|
|
// If "name" is an array of keys...
|
|
// When data is initially created, via ("key", "val") signature,
|
|
// keys will be converted to camelCase.
|
|
// Since there is no way to tell _how_ a key was added, remove
|
|
// both plain key and camelCase key. #12786
|
|
// This will only penalize the array argument path.
|
|
name = key.concat( key.map( jQuery.camelCase ) );
|
|
} else {
|
|
// Try the string as a key before any manipulation
|
|
if ( key in cache ) {
|
|
name = [ key ];
|
|
} else {
|
|
// If a key with the spaces exists, use it.
|
|
// Otherwise, create an array by matching non-whitespace
|
|
name = jQuery.camelCase( key );
|
|
name = name in cache ?
|
|
[ name ] : ( name.match( core_rnotwhite ) || [] );
|
|
}
|
|
}
|
|
|
|
i = name.length;
|
|
while ( i-- ) {
|
|
delete cache[ name[ i ] ];
|
|
}
|
|
}
|
|
},
|
|
hasData: function( owner ) {
|
|
return !jQuery.isEmptyObject(
|
|
this.cache[ owner[ this.expando ] ] || {}
|
|
);
|
|
},
|
|
discard: function( owner ) {
|
|
delete this.cache[ this.key( owner ) ];
|
|
}
|
|
};
|
|
|
|
// These may be used throughout the jQuery core codebase
|
|
data_user = new Data();
|
|
data_priv = new Data();
|
|
|
|
|
|
jQuery.extend({
|
|
acceptData: Data.accepts,
|
|
|
|
hasData: function( elem ) {
|
|
return data_user.hasData( elem ) || data_priv.hasData( elem );
|
|
},
|
|
|
|
data: function( elem, name, data ) {
|
|
return data_user.access( elem, name, data );
|
|
},
|
|
|
|
removeData: function( elem, name ) {
|
|
data_user.remove( elem, name );
|
|
},
|
|
|
|
// TODO: Now that all calls to _data and _removeData have been replaced
|
|
// with direct calls to data_priv methods, these can be deprecated.
|
|
_data: function( elem, name, data ) {
|
|
return data_priv.access( elem, name, data );
|
|
},
|
|
|
|
_removeData: function( elem, name ) {
|
|
data_priv.remove( elem, name );
|
|
}
|
|
});
|
|
|
|
jQuery.fn.extend({
|
|
data: function( key, value ) {
|
|
var attrs, name,
|
|
elem = this[ 0 ],
|
|
i = 0,
|
|
data = null;
|
|
|
|
// Gets all values
|
|
if ( key === undefined ) {
|
|
if ( this.length ) {
|
|
data = data_user.get( elem );
|
|
|
|
if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
|
|
attrs = elem.attributes;
|
|
for ( ; i < attrs.length; i++ ) {
|
|
name = attrs[ i ].name;
|
|
|
|
if ( name.indexOf( "data-" ) === 0 ) {
|
|
name = jQuery.camelCase( name.substring(5) );
|
|
dataAttr( elem, name, data[ name ] );
|
|
}
|
|
}
|
|
data_priv.set( elem, "hasDataAttrs", true );
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// Sets multiple values
|
|
if ( typeof key === "object" ) {
|
|
return this.each(function() {
|
|
data_user.set( this, key );
|
|
});
|
|
}
|
|
|
|
return jQuery.access( this, function( value ) {
|
|
var data,
|
|
camelKey = jQuery.camelCase( key );
|
|
|
|
// The calling jQuery object (element matches) is not empty
|
|
// (and therefore has an element appears at this[ 0 ]) and the
|
|
// `value` parameter was not undefined. An empty jQuery object
|
|
// will result in `undefined` for elem = this[ 0 ] which will
|
|
// throw an exception if an attempt to read a data cache is made.
|
|
if ( elem && value === undefined ) {
|
|
// Attempt to get data from the cache
|
|
// with the key as-is
|
|
data = data_user.get( elem, key );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// Attempt to get data from the cache
|
|
// with the key camelized
|
|
data = data_user.get( elem, camelKey );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// Attempt to "discover" the data in
|
|
// HTML5 custom data-* attrs
|
|
data = dataAttr( elem, camelKey, undefined );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// We tried really hard, but the data doesn't exist.
|
|
return;
|
|
}
|
|
|
|
// Set the data...
|
|
this.each(function() {
|
|
// First, attempt to store a copy or reference of any
|
|
// data that might've been store with a camelCased key.
|
|
var data = data_user.get( this, camelKey );
|
|
|
|
// For HTML5 data-* attribute interop, we have to
|
|
// store property names with dashes in a camelCase form.
|
|
// This might not apply to all properties...*
|
|
data_user.set( this, camelKey, value );
|
|
|
|
// *... In the case of properties that might _actually_
|
|
// have dashes, we need to also store a copy of that
|
|
// unchanged property.
|
|
if ( key.indexOf("-") !== -1 && data !== undefined ) {
|
|
data_user.set( this, key, value );
|
|
}
|
|
});
|
|
}, null, value, arguments.length > 1, null, true );
|
|
},
|
|
|
|
removeData: function( key ) {
|
|
return this.each(function() {
|
|
data_user.remove( this, key );
|
|
});
|
|
}
|
|
});
|
|
|
|
function dataAttr( elem, key, data ) {
|
|
var name;
|
|
|
|
// If nothing was found internally, try to fetch any
|
|
// data from the HTML5 data-* attribute
|
|
if ( data === undefined && elem.nodeType === 1 ) {
|
|
name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
|
|
data = elem.getAttribute( name );
|
|
|
|
if ( typeof data === "string" ) {
|
|
try {
|
|
data = data === "true" ? true :
|
|
data === "false" ? false :
|
|
data === "null" ? null :
|
|
// Only convert to a number if it doesn't change the string
|
|
+data + "" === data ? +data :
|
|
rbrace.test( data ) ? JSON.parse( data ) :
|
|
data;
|
|
} catch( e ) {}
|
|
|
|
// Make sure we set the data so it isn't changed later
|
|
data_user.set( elem, key, data );
|
|
} else {
|
|
data = undefined;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
jQuery.extend({
|
|
queue: function( elem, type, data ) {
|
|
var queue;
|
|
|
|
if ( elem ) {
|
|
type = ( type || "fx" ) + "queue";
|
|
queue = data_priv.get( elem, type );
|
|
|
|
// Speed up dequeue by getting out quickly if this is just a lookup
|
|
if ( data ) {
|
|
if ( !queue || jQuery.isArray( data ) ) {
|
|
queue = data_priv.access( elem, type, jQuery.makeArray(data) );
|
|
} else {
|
|
queue.push( data );
|
|
}
|
|
}
|
|
return queue || [];
|
|
}
|
|
},
|
|
|
|
dequeue: function( elem, type ) {
|
|
type = type || "fx";
|
|
|
|
var queue = jQuery.queue( elem, type ),
|
|
startLength = queue.length,
|
|
fn = queue.shift(),
|
|
hooks = jQuery._queueHooks( elem, type ),
|
|
next = function() {
|
|
jQuery.dequeue( elem, type );
|
|
};
|
|
|
|
// If the fx queue is dequeued, always remove the progress sentinel
|
|
if ( fn === "inprogress" ) {
|
|
fn = queue.shift();
|
|
startLength--;
|
|
}
|
|
|
|
hooks.cur = fn;
|
|
if ( fn ) {
|
|
|
|
// Add a progress sentinel to prevent the fx queue from being
|
|
// automatically dequeued
|
|
if ( type === "fx" ) {
|
|
queue.unshift( "inprogress" );
|
|
}
|
|
|
|
// clear up the last queue stop function
|
|
delete hooks.stop;
|
|
fn.call( elem, next, hooks );
|
|
}
|
|
|
|
if ( !startLength && hooks ) {
|
|
hooks.empty.fire();
|
|
}
|
|
},
|
|
|
|
// not intended for public consumption - generates a queueHooks object, or returns the current one
|
|
_queueHooks: function( elem, type ) {
|
|
var key = type + "queueHooks";
|
|
return data_priv.get( elem, key ) || data_priv.access( elem, key, {
|
|
empty: jQuery.Callbacks("once memory").add(function() {
|
|
data_priv.remove( elem, [ type + "queue", key ] );
|
|
})
|
|
});
|
|
}
|
|
});
|
|
|
|
jQuery.fn.extend({
|
|
queue: function( type, data ) {
|
|
var setter = 2;
|
|
|
|
if ( typeof type !== "string" ) {
|
|
data = type;
|
|
type = "fx";
|
|
setter--;
|
|
}
|
|
|
|
if ( arguments.length < setter ) {
|
|
return jQuery.queue( this[0], type );
|
|
}
|
|
|
|
return data === undefined ?
|
|
this :
|
|
this.each(function() {
|
|
var queue = jQuery.queue( this, type, data );
|
|
|
|
// ensure a hooks for this queue
|
|
jQuery._queueHooks( this, type );
|
|
|
|
if ( type === "fx" && queue[0] !== "inprogress" ) {
|
|
jQuery.dequeue( this, type );
|
|
}
|
|
});
|
|
},
|
|
dequeue: function( type ) {
|
|
return this.each(function() {
|
|
jQuery.dequeue( this, type );
|
|
});
|
|
},
|
|
// Based off of the plugin by Clint Helfers, with permission.
|
|
// http://blindsignals.com/index.php/2009/07/jquery-delay/
|
|
delay: function( time, type ) {
|
|
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
|
|
type = type || "fx";
|
|
|
|
return this.queue( type, function( next, hooks ) {
|
|
var timeout = setTimeout( next, time );
|
|
hooks.stop = function() {
|
|
clearTimeout( timeout );
|
|
};
|
|
});
|
|
},
|
|
clearQueue: function( type ) {
|
|
return this.queue( type || "fx", [] );
|
|
},
|
|
// Get a promise resolved when queues of a certain type
|
|
// are emptied (fx is the type by default)
|
|
promise: function( type, obj ) {
|
|
var tmp,
|
|
count = 1,
|
|
defer = jQuery.Deferred(),
|
|
elements = this,
|
|
i = this.length,
|
|
resolve = function() {
|
|
if ( !( --count ) ) {
|
|
defer.resolveWith( elements, [ elements ] );
|
|
}
|
|
};
|
|
|
|
if ( typeof type !== "string" ) {
|
|
obj = type;
|
|
type = undefined;
|
|
}
|
|
type = type || "fx";
|
|
|
|
while( i-- ) {
|
|
tmp = data_priv.get( elements[ i ], type + "queueHooks" );
|
|
if ( tmp && tmp.empty ) {
|
|
count++;
|
|
tmp.empty.add( resolve );
|
|
}
|
|
}
|
|
resolve();
|
|
return defer.promise( obj );
|
|
}
|
|
});
|
|
var nodeHook, boolHook,
|
|
rclass = /[\t\r\n]/g,
|
|
rreturn = /\r/g,
|
|
rfocusable = /^(?:input|select|textarea|button)$/i;
|
|
|
|
jQuery.fn.extend({
|
|
attr: function( name, value ) {
|
|
return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
|
|
},
|
|
|
|
removeAttr: function( name ) {
|
|
return this.each(function() {
|
|
jQuery.removeAttr( this, name );
|
|
});
|
|
},
|
|
|
|
prop: function( name, value ) {
|
|
return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
|
|
},
|
|
|
|
removeProp: function( name ) {
|
|
return this.each(function() {
|
|
delete this[ jQuery.propFix[ name ] || name ];
|
|
});
|
|
},
|
|
|
|
addClass: function( value ) {
|
|
var classes, elem, cur, clazz, j,
|
|
i = 0,
|
|
len = this.length,
|
|
proceed = typeof value === "string" && value;
|
|
|
|
if ( jQuery.isFunction( value ) ) {
|
|
return this.each(function( j ) {
|
|
jQuery( this ).addClass( value.call( this, j, this.className ) );
|
|
});
|
|
}
|
|
|
|
if ( proceed ) {
|
|
// The disjunction here is for better compressibility (see removeClass)
|
|
classes = ( value || "" ).match( core_rnotwhite ) || [];
|
|
|
|
for ( ; i < len; i++ ) {
|
|
elem = this[ i ];
|
|
cur = elem.nodeType === 1 && ( elem.className ?
|
|
( " " + elem.className + " " ).replace( rclass, " " ) :
|
|
" "
|
|
);
|
|
|
|
if ( cur ) {
|
|
j = 0;
|
|
while ( (clazz = classes[j++]) ) {
|
|
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
|
|
cur += clazz + " ";
|
|
}
|
|
}
|
|
elem.className = jQuery.trim( cur );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
removeClass: function( value ) {
|
|
var classes, elem, cur, clazz, j,
|
|
i = 0,
|
|
len = this.length,
|
|
proceed = arguments.length === 0 || typeof value === "string" && value;
|
|
|
|
if ( jQuery.isFunction( value ) ) {
|
|
return this.each(function( j ) {
|
|
jQuery( this ).removeClass( value.call( this, j, this.className ) );
|
|
});
|
|
}
|
|
if ( proceed ) {
|
|
classes = ( value || "" ).match( core_rnotwhite ) || [];
|
|
|
|
for ( ; i < len; i++ ) {
|
|
elem = this[ i ];
|
|
// This expression is here for better compressibility (see addClass)
|
|
cur = elem.nodeType === 1 && ( elem.className ?
|
|
( " " + elem.className + " " ).replace( rclass, " " ) :
|
|
""
|
|
);
|
|
|
|
if ( cur ) {
|
|
j = 0;
|
|
while ( (clazz = classes[j++]) ) {
|
|
// Remove *all* instances
|
|
while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
|
|
cur = cur.replace( " " + clazz + " ", " " );
|
|
}
|
|
}
|
|
elem.className = value ? jQuery.trim( cur ) : "";
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
toggleClass: function( value, stateVal ) {
|
|
var type = typeof value,
|
|
isBool = typeof stateVal === "boolean";
|
|
|
|
if ( jQuery.isFunction( value ) ) {
|
|
return this.each(function( i ) {
|
|
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
|
|
});
|
|
}
|
|
|
|
return this.each(function() {
|
|
if ( type === "string" ) {
|
|
// toggle individual class names
|
|
var className,
|
|
i = 0,
|
|
self = jQuery( this ),
|
|
state = stateVal,
|
|
classNames = value.match( core_rnotwhite ) || [];
|
|
|
|
while ( (className = classNames[ i++ ]) ) {
|
|
// check each className given, space separated list
|
|
state = isBool ? state : !self.hasClass( className );
|
|
self[ state ? "addClass" : "removeClass" ]( className );
|
|
}
|
|
|
|
// Toggle whole class name
|
|
} else if ( type === core_strundefined || type === "boolean" ) {
|
|
if ( this.className ) {
|
|
// store className if set
|
|
data_priv.set( this, "__className__", this.className );
|
|
}
|
|
|
|
// If the element has a class name or if we're passed "false",
|
|
// then remove the whole classname (if there was one, the above saved it).
|
|
// Otherwise bring back whatever was previously saved (if anything),
|
|
// falling back to the empty string if nothing was stored.
|
|
this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
|
|
}
|
|
});
|
|
},
|
|
|
|
hasClass: function( selector ) {
|
|
var className = " " + selector + " ",
|
|
i = 0,
|
|
l = this.length;
|
|
for ( ; i < l; i++ ) {
|
|
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
val: function( value ) {
|
|
var hooks, ret, isFunction,
|
|
elem = this[0];
|
|
|
|
if ( !arguments.length ) {
|
|
if ( elem ) {
|
|
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
|
|
|
|
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
|
|
return ret;
|
|
}
|
|
|
|
ret = elem.value;
|
|
|
|
return typeof ret === "string" ?
|
|
// handle most common string cases
|
|
ret.replace(rreturn, "") :
|
|
// handle cases where value is null/undef or number
|
|
ret == null ? "" : ret;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
isFunction = jQuery.isFunction( value );
|
|
|
|
return this.each(function( i ) {
|
|
var val,
|
|
self = jQuery(this);
|
|
|
|
if ( this.nodeType !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
if ( isFunction ) {
|
|
val = value.call( this, i, self.val() );
|
|
} else {
|
|
val = value;
|
|
}
|
|
|
|
// Treat null/undefined as ""; convert numbers to string
|
|
if ( val == null ) {
|
|
val = "";
|
|
} else if ( typeof val === "number" ) {
|
|
val += "";
|
|
} else if ( jQuery.isArray( val ) ) {
|
|
val = jQuery.map(val, function ( value ) {
|
|
return value == null ? "" : value + "";
|
|
});
|
|
}
|
|
|
|
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
|
|
|
|
// If set returns undefined, fall back to normal setting
|
|
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
|
|
this.value = val;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
jQuery.extend({
|
|
valHooks: {
|
|
option: {
|
|
get: function( elem ) {
|
|
// attributes.value is undefined in Blackberry 4.7 but
|
|
// uses .value. See #6932
|
|
var val = elem.attributes.value;
|
|
return !val || val.specified ? elem.value : elem.text;
|
|
}
|
|
},
|
|
select: {
|
|
get: function( elem ) {
|
|
var value, option,
|
|
options = elem.options,
|
|
index = elem.selectedIndex,
|
|
one = elem.type === "select-one" || index < 0,
|
|
values = one ? null : [],
|
|
max = one ? index + 1 : options.length,
|
|
i = index < 0 ?
|
|
max :
|
|
one ? index : 0;
|
|
|
|
// Loop through all the selected options
|
|
for ( ; i < max; i++ ) {
|
|
option = options[ i ];
|
|
|
|
// IE6-9 doesn't update selected after form reset (#2551)
|
|
if ( ( option.selected || i === index ) &&
|
|
// Don't return options that are disabled or in a disabled optgroup
|
|
( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
|
|
( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
|
|
|
|
// Get the specific value for the option
|
|
value = jQuery( option ).val();
|
|
|
|
// We don't need an array for one selects
|
|
if ( one ) {
|
|
return value;
|
|
}
|
|
|
|
// Multi-Selects return an array
|
|
values.push( value );
|
|
}
|
|
}
|
|
|
|
return values;
|
|
},
|
|
|
|
set: function( elem, value ) {
|
|
var optionSet, option,
|
|
options = elem.options,
|
|
values = jQuery.makeArray( value ),
|
|
i = options.length;
|
|
|
|
while ( i-- ) {
|
|
option = options[ i ];
|
|
if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
|
|
optionSet = true;
|
|
}
|
|
}
|
|
|
|
// force browsers to behave consistently when non-matching value is set
|
|
if ( !optionSet ) {
|
|
elem.selectedIndex = -1;
|
|
}
|
|
return values;
|
|
}
|
|
}
|
|
},
|
|
|
|
attr: function( elem, name, value ) {
|
|
var hooks, ret,
|
|
nType = elem.nodeType;
|
|
|
|
// don't get/set attributes on text, comment and attribute nodes
|
|
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
|
|
return;
|
|
}
|
|
|
|
// Fallback to prop when attributes are not supported
|
|
if ( typeof elem.getAttribute === core_strundefined ) {
|
|
return jQuery.prop( elem, name, value );
|
|
}
|
|
|
|
// All attributes are lowercase
|
|
// Grab necessary hook if one is defined
|
|
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
|
name = name.toLowerCase();
|
|
hooks = jQuery.attrHooks[ name ] ||
|
|
( jQuery.expr.match.boolean.test( name ) ? boolHook : nodeHook );
|
|
}
|
|
|
|
if ( value !== undefined ) {
|
|
|
|
if ( value === null ) {
|
|
jQuery.removeAttr( elem, name );
|
|
|
|
} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
|
|
return ret;
|
|
|
|
} else {
|
|
elem.setAttribute( name, value + "" );
|
|
return value;
|
|
}
|
|
|
|
} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
|
|
return ret;
|
|
|
|
} else {
|
|
ret = jQuery.find.attr( elem, name );
|
|
|
|
// Non-existent attributes return null, we normalize to undefined
|
|
return ret == null ?
|
|
undefined :
|
|
ret;
|
|
}
|
|
},
|
|
|
|
removeAttr: function( elem, value ) {
|
|
var name, propName,
|
|
i = 0,
|
|
attrNames = value && value.match( core_rnotwhite );
|
|
|
|
if ( attrNames && elem.nodeType === 1 ) {
|
|
while ( (name = attrNames[i++]) ) {
|
|
propName = jQuery.propFix[ name ] || name;
|
|
|
|
// Boolean attributes get special treatment (#10870)
|
|
if ( jQuery.expr.match.boolean.test( name ) ) {
|
|
// Set corresponding property to false
|
|
elem[ propName ] = false;
|
|
}
|
|
|
|
elem.removeAttribute( name );
|
|
}
|
|
}
|
|
},
|
|
|
|
attrHooks: {
|
|
type: {
|
|
set: function( elem, value ) {
|
|
if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
|
|
// Setting the type on a radio button after the value resets the value in IE6-9
|
|
// Reset value to default in case type is set after value during creation
|
|
var val = elem.value;
|
|
elem.setAttribute( "type", value );
|
|
if ( val ) {
|
|
elem.value = val;
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
propFix: {
|
|
"for": "htmlFor",
|
|
"class": "className"
|
|
},
|
|
|
|
prop: function( elem, name, value ) {
|
|
var ret, hooks, notxml,
|
|
nType = elem.nodeType;
|
|
|
|
// don't get/set properties on text, comment and attribute nodes
|
|
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
|
|
return;
|
|
}
|
|
|
|
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
|
|
|
|
if ( notxml ) {
|
|
// Fix name and attach hooks
|
|
name = jQuery.propFix[ name ] || name;
|
|
hooks = jQuery.propHooks[ name ];
|
|
}
|
|
|
|
if ( value !== undefined ) {
|
|
return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
|
|
ret :
|
|
( elem[ name ] = value );
|
|
|
|
} else {
|
|
return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
|
|
ret :
|
|
elem[ name ];
|
|
}
|
|
},
|
|
|
|
propHooks: {
|
|
tabIndex: {
|
|
get: function( elem ) {
|
|
return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
|
|
elem.tabIndex :
|
|
-1;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Hooks for boolean attributes
|
|
boolHook = {
|
|
set: function( elem, value, name ) {
|
|
if ( value === false ) {
|
|
// Remove boolean attributes when set to false
|
|
jQuery.removeAttr( elem, name );
|
|
} else {
|
|
elem.setAttribute( name, name );
|
|
}
|
|
return name;
|
|
}
|
|
};
|
|
jQuery.each( jQuery.expr.match.boolean.source.match( /\w+/g ), function( i, name ) {
|
|
var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
|
|
|
|
jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
|
|
var fn = jQuery.expr.attrHandle[ name ],
|
|
ret = isXML ?
|
|
undefined :
|
|
/* jshint eqeqeq: false */
|
|
// Temporarily disable this handler to check existence
|
|
(jQuery.expr.attrHandle[ name ] = undefined) !=
|
|
getter( elem, name, isXML ) ?
|
|
|
|
name.toLowerCase() :
|
|
null;
|
|
|
|
// Restore handler
|
|
jQuery.expr.attrHandle[ name ] = fn;
|
|
|
|
return ret;
|
|
};
|
|
});
|
|
|
|
// Support: IE9+
|
|
// Selectedness for an option in an optgroup can be inaccurate
|
|
if ( !jQuery.support.optSelected ) {
|
|
jQuery.propHooks.selected = {
|
|
get: function( elem ) {
|
|
var parent = elem.parentNode;
|
|
if ( parent && parent.parentNode ) {
|
|
parent.parentNode.selectedIndex;
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
}
|
|
|
|
jQuery.each([
|
|
"tabIndex",
|
|
"readOnly",
|
|
"maxLength",
|
|
"cellSpacing",
|
|
"cellPadding",
|
|
"rowSpan",
|
|
"colSpan",
|
|
"useMap",
|
|
"frameBorder",
|
|
"contentEditable"
|
|
], function() {
|
|
jQuery.propFix[ this.toLowerCase() ] = this;
|
|
});
|
|
|
|
// Radios and checkboxes getter/setter
|
|
jQuery.each([ "radio", "checkbox" ], function() {
|
|
jQuery.valHooks[ this ] = {
|
|
set: function( elem, value ) {
|
|
if ( jQuery.isArray( value ) ) {
|
|
return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
|
|
}
|
|
}
|
|
};
|
|
if ( !jQuery.support.checkOn ) {
|
|
jQuery.valHooks[ this ].get = function( elem ) {
|
|
// Support: Webkit
|
|
// "" is returned instead of "on" if a value isn't specified
|
|
return elem.getAttribute("value") === null ? "on" : elem.value;
|
|
};
|
|
}
|
|
});
|
|
var rkeyEvent = /^key/,
|
|
rmouseEvent = /^(?:mouse|contextmenu)|click/,
|
|
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
|
|
rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
|
|
|
|
function returnTrue() {
|
|
return true;
|
|
}
|
|
|
|
function returnFalse() {
|
|
return false;
|
|
}
|
|
|
|
function safeActiveElement() {
|
|
try {
|
|
return document.activeElement;
|
|
} catch ( err ) { }
|
|
}
|
|
|
|
/*
|
|
* Helper functions for managing events -- not part of the public interface.
|
|
* Props to Dean Edwards' addEvent library for many of the ideas.
|
|
*/
|
|
jQuery.event = {
|
|
|
|
global: {},
|
|
|
|
add: function( elem, types, handler, data, selector ) {
|
|
|
|
var handleObjIn, eventHandle, tmp,
|
|
events, t, handleObj,
|
|
special, handlers, type, namespaces, origType,
|
|
elemData = data_priv.get( elem );
|
|
|
|
// Don't attach events to noData or text/comment nodes (but allow plain objects)
|
|
if ( !elemData ) {
|
|
return;
|
|
}
|
|
|
|
// Caller can pass in an object of custom data in lieu of the handler
|
|
if ( handler.handler ) {
|
|
handleObjIn = handler;
|
|
handler = handleObjIn.handler;
|
|
selector = handleObjIn.selector;
|
|
}
|
|
|
|
// Make sure that the handler has a unique ID, used to find/remove it later
|
|
if ( !handler.guid ) {
|
|
handler.guid = jQuery.guid++;
|
|
}
|
|
|
|
// Init the element's event structure and main handler, if this is the first
|
|
if ( !(events = elemData.events) ) {
|
|
events = elemData.events = {};
|
|
}
|
|
if ( !(eventHandle = elemData.handle) ) {
|
|
eventHandle = elemData.handle = function( e ) {
|
|
// Discard the second event of a jQuery.event.trigger() and
|
|
// when an event is called after a page has unloaded
|
|
return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
|
|
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
|
|
undefined;
|
|
};
|
|
// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
|
|
eventHandle.elem = elem;
|
|
}
|
|
|
|
// Handle multiple events separated by a space
|
|
types = ( types || "" ).match( core_rnotwhite ) || [""];
|
|
t = types.length;
|
|
while ( t-- ) {
|
|
tmp = rtypenamespace.exec( types[t] ) || [];
|
|
type = origType = tmp[1];
|
|
namespaces = ( tmp[2] || "" ).split( "." ).sort();
|
|
|
|
// There *must* be a type, no attaching namespace-only handlers
|
|
if ( !type ) {
|
|
continue;
|
|
}
|
|
|
|
// If event changes its type, use the special event handlers for the changed type
|
|
special = jQuery.event.special[ type ] || {};
|
|
|
|
// If selector defined, determine special event api type, otherwise given type
|
|
type = ( selector ? special.delegateType : special.bindType ) || type;
|
|
|
|
// Update special based on newly reset type
|
|
special = jQuery.event.special[ type ] || {};
|
|
|
|
// handleObj is passed to all event handlers
|
|
handleObj = jQuery.extend({
|
|
type: type,
|
|
origType: origType,
|
|
data: data,
|
|
handler: handler,
|
|
guid: handler.guid,
|
|
selector: selector,
|
|
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
|
|
namespace: namespaces.join(".")
|
|
}, handleObjIn );
|
|
|
|
// Init the event handler queue if we're the first
|
|
if ( !(handlers = events[ type ]) ) {
|
|
handlers = events[ type ] = [];
|
|
handlers.delegateCount = 0;
|
|
|
|
// Only use addEventListener if the special events handler returns false
|
|
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
|
|
if ( elem.addEventListener ) {
|
|
elem.addEventListener( type, eventHandle, false );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( special.add ) {
|
|
special.add.call( elem, handleObj );
|
|
|
|
if ( !handleObj.handler.guid ) {
|
|
handleObj.handler.guid = handler.guid;
|
|
}
|
|
}
|
|
|
|
// Add to the element's handler list, delegates in front
|
|
if ( selector ) {
|
|
handlers.splice( handlers.delegateCount++, 0, handleObj );
|
|
} else {
|
|
handlers.push( handleObj );
|
|
}
|
|
|
|
// Keep track of which events have ever been used, for event optimization
|
|
jQuery.event.global[ type ] = true;
|
|
}
|
|
|
|
// Nullify elem to prevent memory leaks in IE
|
|
elem = null;
|
|
},
|
|
|
|
// Detach an event or set of events from an element
|
|
remove: function( elem, types, handler, selector, mappedTypes ) {
|
|
|
|
var j, origCount, tmp,
|
|
events, t, handleObj,
|
|
special, handlers, type, namespaces, origType,
|
|
elemData = data_priv.hasData( elem ) && data_priv.get( elem );
|
|
|
|
if ( !elemData || !(events = elemData.events) ) {
|
|
return;
|
|
}
|
|
|
|
// Once for each type.namespace in types; type may be omitted
|
|
types = ( types || "" ).match( core_rnotwhite ) || [""];
|
|
t = types.length;
|
|
while ( t-- ) {
|
|
tmp = rtypenamespace.exec( types[t] ) || [];
|
|
type = origType = tmp[1];
|
|
namespaces = ( tmp[2] || "" ).split( "." ).sort();
|
|
|
|
// Unbind all events (on this namespace, if provided) for the element
|
|
if ( !type ) {
|
|
for ( type in events ) {
|
|
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
special = jQuery.event.special[ type ] || {};
|
|
type = ( selector ? special.delegateType : special.bindType ) || type;
|
|
handlers = events[ type ] || [];
|
|
tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
|
|
|
|
// Remove matching events
|
|
origCount = j = handlers.length;
|
|
while ( j-- ) {
|
|
handleObj = handlers[ j ];
|
|
|
|
if ( ( mappedTypes || origType === handleObj.origType ) &&
|
|
( !handler || handler.guid === handleObj.guid ) &&
|
|
( !tmp || tmp.test( handleObj.namespace ) ) &&
|
|
( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
|
|
handlers.splice( j, 1 );
|
|
|
|
if ( handleObj.selector ) {
|
|
handlers.delegateCount--;
|
|
}
|
|
if ( special.remove ) {
|
|
special.remove.call( elem, handleObj );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove generic event handler if we removed something and no more handlers exist
|
|
// (avoids potential for endless recursion during removal of special event handlers)
|
|
if ( origCount && !handlers.length ) {
|
|
if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
|
|
jQuery.removeEvent( elem, type, elemData.handle );
|
|
}
|
|
|
|
delete events[ type ];
|
|
}
|
|
}
|
|
|
|
// Remove the expando if it's no longer used
|
|
if ( jQuery.isEmptyObject( events ) ) {
|
|
delete elemData.handle;
|
|
data_priv.remove( elem, "events" );
|
|
}
|
|
},
|
|
|
|
trigger: function( event, data, elem, onlyHandlers ) {
|
|
|
|
var i, cur, tmp, bubbleType, ontype, handle, special,
|
|
eventPath = [ elem || document ],
|
|
type = core_hasOwn.call( event, "type" ) ? event.type : event,
|
|
namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
|
|
|
|
cur = tmp = elem = elem || document;
|
|
|
|
// Don't do events on text and comment nodes
|
|
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
|
|
return;
|
|
}
|
|
|
|
// focus/blur morphs to focusin/out; ensure we're not firing them right now
|
|
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( type.indexOf(".") >= 0 ) {
|
|
// Namespaced trigger; create a regexp to match event type in handle()
|
|
namespaces = type.split(".");
|
|
type = namespaces.shift();
|
|
namespaces.sort();
|
|
}
|
|
ontype = type.indexOf(":") < 0 && "on" + type;
|
|
|
|
// Caller can pass in a jQuery.Event object, Object, or just an event type string
|
|
event = event[ jQuery.expando ] ?
|
|
event :
|
|
new jQuery.Event( type, typeof event === "object" && event );
|
|
|
|
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
|
|
event.isTrigger = onlyHandlers ? 2 : 3;
|
|
event.namespace = namespaces.join(".");
|
|
event.namespace_re = event.namespace ?
|
|
new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
|
|
null;
|
|
|
|
// Clean up the event in case it is being reused
|
|
event.result = undefined;
|
|
if ( !event.target ) {
|
|
event.target = elem;
|
|
}
|
|
|
|
// Clone any incoming data and prepend the event, creating the handler arg list
|
|
data = data == null ?
|
|
[ event ] :
|
|
jQuery.makeArray( data, [ event ] );
|
|
|
|
// Allow special events to draw outside the lines
|
|
special = jQuery.event.special[ type ] || {};
|
|
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
|
|
return;
|
|
}
|
|
|
|
// Determine event propagation path in advance, per W3C events spec (#9951)
|
|
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
|
|
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
|
|
|
|
bubbleType = special.delegateType || type;
|
|
if ( !rfocusMorph.test( bubbleType + type ) ) {
|
|
cur = cur.parentNode;
|
|
}
|
|
for ( ; cur; cur = cur.parentNode ) {
|
|
eventPath.push( cur );
|
|
tmp = cur;
|
|
}
|
|
|
|
// Only add window if we got to document (e.g., not plain obj or detached DOM)
|
|
if ( tmp === (elem.ownerDocument || document) ) {
|
|
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
|
|
}
|
|
}
|
|
|
|
// Fire handlers on the event path
|
|
i = 0;
|
|
while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
|
|
|
|
event.type = i > 1 ?
|
|
bubbleType :
|
|
special.bindType || type;
|
|
|
|
// jQuery handler
|
|
handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
|
|
if ( handle ) {
|
|
handle.apply( cur, data );
|
|
}
|
|
|
|
// Native handler
|
|
handle = ontype && cur[ ontype ];
|
|
if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
event.type = type;
|
|
|
|
// If nobody prevented the default action, do it now
|
|
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
|
|
|
|
if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
|
|
jQuery.acceptData( elem ) ) {
|
|
|
|
// Call a native DOM method on the target with the same name name as the event.
|
|
// Don't do default actions on window, that's where global variables be (#6170)
|
|
if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
|
|
|
|
// Don't re-trigger an onFOO event when we call its FOO() method
|
|
tmp = elem[ ontype ];
|
|
|
|
if ( tmp ) {
|
|
elem[ ontype ] = null;
|
|
}
|
|
|
|
// Prevent re-triggering of the same event, since we already bubbled it above
|
|
jQuery.event.triggered = type;
|
|
elem[ type ]();
|
|
jQuery.event.triggered = undefined;
|
|
|
|
if ( tmp ) {
|
|
elem[ ontype ] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return event.result;
|
|
},
|
|
|
|
dispatch: function( event ) {
|
|
|
|
// Make a writable jQuery.Event from the native event object
|
|
event = jQuery.event.fix( event );
|
|
|
|
var i, j, ret, matched, handleObj,
|
|
handlerQueue = [],
|
|
args = core_slice.call( arguments ),
|
|
handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
|
|
special = jQuery.event.special[ event.type ] || {};
|
|
|
|
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
|
args[0] = event;
|
|
event.delegateTarget = this;
|
|
|
|
// Call the preDispatch hook for the mapped type, and let it bail if desired
|
|
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
|
|
return;
|
|
}
|
|
|
|
// Determine handlers
|
|
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
|
|
|
|
// Run delegates first; they may want to stop propagation beneath us
|
|
i = 0;
|
|
while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
|
|
event.currentTarget = matched.elem;
|
|
|
|
j = 0;
|
|
while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
|
|
|
|
// Triggered event must either 1) have no namespace, or
|
|
// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
|
|
if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
|
|
|
|
event.handleObj = handleObj;
|
|
event.data = handleObj.data;
|
|
|
|
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
|
|
.apply( matched.elem, args );
|
|
|
|
if ( ret !== undefined ) {
|
|
if ( (event.result = ret) === false ) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Call the postDispatch hook for the mapped type
|
|
if ( special.postDispatch ) {
|
|
special.postDispatch.call( this, event );
|
|
}
|
|
|
|
return event.result;
|
|
},
|
|
|
|
handlers: function( event, handlers ) {
|
|
var i, matches, sel, handleObj,
|
|
handlerQueue = [],
|
|
delegateCount = handlers.delegateCount,
|
|
cur = event.target;
|
|
|
|
// Find delegate handlers
|
|
// Black-hole SVG <use> instance trees (#13180)
|
|
// Avoid non-left-click bubbling in Firefox (#3861)
|
|
if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
|
|
|
|
for ( ; cur !== this; cur = cur.parentNode || this ) {
|
|
|
|
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
|
|
if ( cur.disabled !== true || event.type !== "click" ) {
|
|
matches = [];
|
|
for ( i = 0; i < delegateCount; i++ ) {
|
|
handleObj = handlers[ i ];
|
|
|
|
// Don't conflict with Object.prototype properties (#13203)
|
|
sel = handleObj.selector + " ";
|
|
|
|
if ( matches[ sel ] === undefined ) {
|
|
matches[ sel ] = handleObj.needsContext ?
|
|
jQuery( sel, this ).index( cur ) >= 0 :
|
|
jQuery.find( sel, this, null, [ cur ] ).length;
|
|
}
|
|
if ( matches[ sel ] ) {
|
|
matches.push( handleObj );
|
|
}
|
|
}
|
|
if ( matches.length ) {
|
|
handlerQueue.push({ elem: cur, handlers: matches });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the remaining (directly-bound) handlers
|
|
if ( delegateCount < handlers.length ) {
|
|
handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
|
|
}
|
|
|
|
return handlerQueue;
|
|
},
|
|
|
|
// Includes some event props shared by KeyEvent and MouseEvent
|
|
props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
|
|
|
|
fixHooks: {},
|
|
|
|
keyHooks: {
|
|
props: "char charCode key keyCode".split(" "),
|
|
filter: function( event, original ) {
|
|
|
|
// Add which for key events
|
|
if ( event.which == null ) {
|
|
event.which = original.charCode != null ? original.charCode : original.keyCode;
|
|
}
|
|
|
|
return event;
|
|
}
|
|
},
|
|
|
|
mouseHooks: {
|
|
props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
|
|
filter: function( event, original ) {
|
|
var eventDoc, doc, body,
|
|
button = original.button;
|
|
|
|
// Calculate pageX/Y if missing and clientX/Y available
|
|
if ( event.pageX == null && original.clientX != null ) {
|
|
eventDoc = event.target.ownerDocument || document;
|
|
doc = eventDoc.documentElement;
|
|
body = eventDoc.body;
|
|
|
|
event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
|
|
event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
|
|
}
|
|
|
|
// Add which for click: 1 === left; 2 === middle; 3 === right
|
|
// Note: button is not normalized, so don't use it
|
|
if ( !event.which && button !== undefined ) {
|
|
event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
|
|
}
|
|
|
|
return event;
|
|
}
|
|
},
|
|
|
|
fix: function( event ) {
|
|
if ( event[ jQuery.expando ] ) {
|
|
return event;
|
|
}
|
|
|
|
// Create a writable copy of the event object and normalize some properties
|
|
var i, prop, copy,
|
|
type = event.type,
|
|
originalEvent = event,
|
|
fixHook = this.fixHooks[ type ];
|
|
|
|
if ( !fixHook ) {
|
|
this.fixHooks[ type ] = fixHook =
|
|
rmouseEvent.test( type ) ? this.mouseHooks :
|
|
rkeyEvent.test( type ) ? this.keyHooks :
|
|
{};
|
|
}
|
|
copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
|
|
|
|
event = new jQuery.Event( originalEvent );
|
|
|
|
i = copy.length;
|
|
while ( i-- ) {
|
|
prop = copy[ i ];
|
|
event[ prop ] = originalEvent[ prop ];
|
|
}
|
|
|
|
// Support: Safari 6.0+, Chrome < 28
|
|
// Target should not be a text node (#504, #13143)
|
|
if ( event.target.nodeType === 3 ) {
|
|
event.target = event.target.parentNode;
|
|
}
|
|
|
|
return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
|
|
},
|
|
|
|
special: {
|
|
load: {
|
|
// Prevent triggered image.load events from bubbling to window.load
|
|
noBubble: true
|
|
},
|
|
focus: {
|
|
// Fire native event if possible so blur/focus sequence is correct
|
|
trigger: function() {
|
|
if ( this !== safeActiveElement() && this.focus ) {
|
|
this.focus();
|
|
return false;
|
|
}
|
|
},
|
|
delegateType: "focusin"
|
|
},
|
|
blur: {
|
|
trigger: function() {
|
|
if ( this === safeActiveElement() && this.blur ) {
|
|
this.blur();
|
|
return false;
|
|
}
|
|
},
|
|
delegateType: "focusout"
|
|
},
|
|
click: {
|
|
// For checkbox, fire native event so checked state will be right
|
|
trigger: function() {
|
|
if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
|
|
this.click();
|
|
return false;
|
|
}
|
|
},
|
|
|
|
// For cross-browser consistency, don't fire native .click() on links
|
|
_default: function( event ) {
|
|
return jQuery.nodeName( event.target, "a" );
|
|
}
|
|
},
|
|
|
|
beforeunload: {
|
|
postDispatch: function( event ) {
|
|
|
|
// Support: Firefox 20+
|
|
// Firefox doesn't alert if the returnValue field is not set.
|
|
if ( event.result !== undefined ) {
|
|
event.originalEvent.returnValue = event.result;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
simulate: function( type, elem, event, bubble ) {
|
|
// Piggyback on a donor event to simulate a different one.
|
|
// Fake originalEvent to avoid donor's stopPropagation, but if the
|
|
// simulated event prevents default then we do the same on the donor.
|
|
var e = jQuery.extend(
|
|
new jQuery.Event(),
|
|
event,
|
|
{
|
|
type: type,
|
|
isSimulated: true,
|
|
originalEvent: {}
|
|
}
|
|
);
|
|
if ( bubble ) {
|
|
jQuery.event.trigger( e, null, elem );
|
|
} else {
|
|
jQuery.event.dispatch.call( elem, e );
|
|
}
|
|
if ( e.isDefaultPrevented() ) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
};
|
|
|
|
jQuery.removeEvent = function( elem, type, handle ) {
|
|
if ( elem.removeEventListener ) {
|
|
elem.removeEventListener( type, handle, false );
|
|
}
|
|
};
|
|
|
|
jQuery.Event = function( src, props ) {
|
|
// Allow instantiation without the 'new' keyword
|
|
if ( !(this instanceof jQuery.Event) ) {
|
|
return new jQuery.Event( src, props );
|
|
}
|
|
|
|
// Event object
|
|
if ( src && src.type ) {
|
|
this.originalEvent = src;
|
|
this.type = src.type;
|
|
|
|
// Events bubbling up the document may have been marked as prevented
|
|
// by a handler lower down the tree; reflect the correct value.
|
|
this.isDefaultPrevented = ( src.defaultPrevented ||
|
|
src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
|
|
|
|
// Event type
|
|
} else {
|
|
this.type = src;
|
|
}
|
|
|
|
// Put explicitly provided properties onto the event object
|
|
if ( props ) {
|
|
jQuery.extend( this, props );
|
|
}
|
|
|
|
// Create a timestamp if incoming event doesn't have one
|
|
this.timeStamp = src && src.timeStamp || jQuery.now();
|
|
|
|
// Mark it as fixed
|
|
this[ jQuery.expando ] = true;
|
|
};
|
|
|
|
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
|
|
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
|
jQuery.Event.prototype = {
|
|
isDefaultPrevented: returnFalse,
|
|
isPropagationStopped: returnFalse,
|
|
isImmediatePropagationStopped: returnFalse,
|
|
|
|
preventDefault: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isDefaultPrevented = returnTrue;
|
|
|
|
if ( e && e.preventDefault ) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
stopPropagation: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isPropagationStopped = returnTrue;
|
|
|
|
if ( e && e.stopPropagation ) {
|
|
e.stopPropagation();
|
|
}
|
|
},
|
|
stopImmediatePropagation: function() {
|
|
this.isImmediatePropagationStopped = returnTrue;
|
|
this.stopPropagation();
|
|
}
|
|
};
|
|
|
|
// Create mouseenter/leave events using mouseover/out and event-time checks
|
|
// Support: Chrome 15+
|
|
jQuery.each({
|
|
mouseenter: "mouseover",
|
|
mouseleave: "mouseout"
|
|
}, function( orig, fix ) {
|
|
jQuery.event.special[ orig ] = {
|
|
delegateType: fix,
|
|
bindType: fix,
|
|
|
|
handle: function( event ) {
|
|
var ret,
|
|
target = this,
|
|
related = event.relatedTarget,
|
|
handleObj = event.handleObj;
|
|
|
|
// For mousenter/leave call the handler if related is outside the target.
|
|
// NB: No relatedTarget if the mouse left/entered the browser window
|
|
if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
|
|
event.type = handleObj.origType;
|
|
ret = handleObj.handler.apply( this, arguments );
|
|
event.type = fix;
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
});
|
|
|
|
// Create "bubbling" focus and blur events
|
|
// Support: Firefox, Chrome, Safari
|
|
if ( !jQuery.support.focusinBubbles ) {
|
|
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
|
|
|
|
// Attach a single capturing handler while someone wants focusin/focusout
|
|
var attaches = 0,
|
|
handler = function( event ) {
|
|
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
|
|
};
|
|
|
|
jQuery.event.special[ fix ] = {
|
|
setup: function() {
|
|
if ( attaches++ === 0 ) {
|
|
document.addEventListener( orig, handler, true );
|
|
}
|
|
},
|
|
teardown: function() {
|
|
if ( --attaches === 0 ) {
|
|
document.removeEventListener( orig, handler, true );
|
|
}
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
jQuery.fn.extend({
|
|
|
|
on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
|
|
var origFn, type;
|
|
|
|
// Types can be a map of types/handlers
|
|
if ( typeof types === "object" ) {
|
|
// ( types-Object, selector, data )
|
|
if ( typeof selector !== "string" ) {
|
|
// ( types-Object, data )
|
|
data = data || selector;
|
|
selector = undefined;
|
|
}
|
|
for ( type in types ) {
|
|
this.on( type, selector, data, types[ type ], one );
|
|
}
|
|
return this;
|
|
}
|
|
|
|
if ( data == null && fn == null ) {
|
|
// ( types, fn )
|
|
fn = selector;
|
|
data = selector = undefined;
|
|
} else if ( fn == null ) {
|
|
if ( typeof selector === "string" ) {
|
|
// ( types, selector, fn )
|
|
fn = data;
|
|
data = undefined;
|
|
} else {
|
|
// ( types, data, fn )
|
|
fn = data;
|
|
data = selector;
|
|
selector = undefined;
|
|
}
|
|
}
|
|
if ( fn === false ) {
|
|
fn = returnFalse;
|
|
} else if ( !fn ) {
|
|
return this;
|
|
}
|
|
|
|
if ( one === 1 ) {
|
|
origFn = fn;
|
|
fn = function( event ) {
|
|
// Can use an empty set, since event contains the info
|
|
jQuery().off( event );
|
|
return origFn.apply( this, arguments );
|
|
};
|
|
// Use same guid so caller can remove using origFn
|
|
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
|
|
}
|
|
return this.each( function() {
|
|
jQuery.event.add( this, types, fn, data, selector );
|
|
});
|
|
},
|
|
one: function( types, selector, data, fn ) {
|
|
return this.on( types, selector, data, fn, 1 );
|
|
},
|
|
off: function( types, selector, fn ) {
|
|
var handleObj, type;
|
|
if ( types && types.preventDefault && types.handleObj ) {
|
|
// ( event ) dispatched jQuery.Event
|
|
handleObj = types.handleObj;
|
|
jQuery( types.delegateTarget ).off(
|
|
handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
|
|
handleObj.selector,
|
|
handleObj.handler
|
|
);
|
|
return this;
|
|
}
|
|
if ( typeof types === "object" ) {
|
|
// ( types-object [, selector] )
|
|
for ( type in types ) {
|
|
this.off( type, selector, types[ type ] );
|
|
}
|
|
return this;
|
|
}
|
|
if ( selector === false || typeof selector === "function" ) {
|
|
// ( types [, fn] )
|
|
fn = selector;
|
|
selector = undefined;
|
|
}
|
|
if ( fn === false ) {
|
|
fn = returnFalse;
|
|
}
|
|
return this.each(function() {
|
|
jQuery.event.remove( this, types, fn, selector );
|
|
});
|
|
},
|
|
|
|
trigger: function( type, data ) {
|
|
return this.each(function() {
|
|
jQuery.event.trigger( type, data, this );
|
|
});
|
|
},
|
|
triggerHandler: function( type, data ) {
|
|
var elem = this[0];
|
|
if ( elem ) {
|
|
return jQuery.event.trigger( type, data, elem, true );
|
|
}
|
|
}
|
|
});
|
|
var isSimple = /^.[^:#\[\.,]*$/,
|
|
rneedsContext = jQuery.expr.match.needsContext,
|
|
// methods guaranteed to produce a unique set when starting from a unique set
|
|
guaranteedUnique = {
|
|
children: true,
|
|
contents: true,
|
|
next: true,
|
|
prev: true
|
|
};
|
|
|
|
jQuery.fn.extend({
|
|
find: function( selector ) {
|
|
var self, matched, i,
|
|
l = this.length;
|
|
|
|
if ( typeof selector !== "string" ) {
|
|
self = this;
|
|
return this.pushStack( jQuery( selector ).filter(function() {
|
|
for ( i = 0; i < l; i++ ) {
|
|
if ( jQuery.contains( self[ i ], this ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}) );
|
|
}
|
|
|
|
matched = [];
|
|
for ( i = 0; i < l; i++ ) {
|
|
jQuery.find( selector, this[ i ], matched );
|
|
}
|
|
|
|
// Needed because $( selector, context ) becomes $( context ).find( selector )
|
|
matched = this.pushStack( l > 1 ? jQuery.unique( matched ) : matched );
|
|
matched.selector = ( this.selector ? this.selector + " " : "" ) + selector;
|
|
return matched;
|
|
},
|
|
|
|
has: function( target ) {
|
|
var targets = jQuery( target, this ),
|
|
l = targets.length;
|
|
|
|
return this.filter(function() {
|
|
var i = 0;
|
|
for ( ; i < l; i++ ) {
|
|
if ( jQuery.contains( this, targets[i] ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
not: function( selector ) {
|
|
return this.pushStack( winnow(this, selector || [], true) );
|
|
},
|
|
|
|
filter: function( selector ) {
|
|
return this.pushStack( winnow(this, selector || [], false) );
|
|
},
|
|
|
|
is: function( selector ) {
|
|
return !!selector && (
|
|
typeof selector === "string" ?
|
|
// If this is a positional/relative selector, check membership in the returned set
|
|
// so $("p:first").is("p:last") won't return true for a doc with two "p".
|
|
rneedsContext.test( selector ) ?
|
|
jQuery( selector, this.context ).index( this[ 0 ] ) >= 0 :
|
|
jQuery.filter( selector, this ).length > 0 :
|
|
this.filter( selector ).length > 0 );
|
|
},
|
|
|
|
closest: function( selectors, context ) {
|
|
var cur,
|
|
i = 0,
|
|
l = this.length,
|
|
matched = [],
|
|
pos = ( rneedsContext.test( selectors ) || typeof selectors !== "string" ) ?
|
|
jQuery( selectors, context || this.context ) :
|
|
0;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
|
|
// Always skip document fragments
|
|
if ( cur.nodeType < 11 && (pos ?
|
|
pos.index(cur) > -1 :
|
|
|
|
// Don't pass non-elements to Sizzle
|
|
cur.nodeType === 1 &&
|
|
jQuery.find.matchesSelector(cur, selectors)) ) {
|
|
|
|
cur = matched.push( cur );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
|
|
},
|
|
|
|
// Determine the position of an element within
|
|
// the matched set of elements
|
|
index: function( elem ) {
|
|
|
|
// No argument, return index in parent
|
|
if ( !elem ) {
|
|
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
|
|
}
|
|
|
|
// index in selector
|
|
if ( typeof elem === "string" ) {
|
|
return core_indexOf.call( jQuery( elem ), this[ 0 ] );
|
|
}
|
|
|
|
// Locate the position of the desired element
|
|
return core_indexOf.call( this,
|
|
|
|
// If it receives a jQuery object, the first element is used
|
|
elem.jquery ? elem[ 0 ] : elem
|
|
);
|
|
},
|
|
|
|
add: function( selector, context ) {
|
|
var set = typeof selector === "string" ?
|
|
jQuery( selector, context ) :
|
|
jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
|
|
all = jQuery.merge( this.get(), set );
|
|
|
|
return this.pushStack( jQuery.unique(all) );
|
|
},
|
|
|
|
addBack: function( selector ) {
|
|
return this.add( selector == null ?
|
|
this.prevObject : this.prevObject.filter(selector)
|
|
);
|
|
}
|
|
});
|
|
|
|
function sibling( cur, dir ) {
|
|
while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
|
|
|
|
return cur;
|
|
}
|
|
|
|
jQuery.each({
|
|
parent: function( elem ) {
|
|
var parent = elem.parentNode;
|
|
return parent && parent.nodeType !== 11 ? parent : null;
|
|
},
|
|
parents: function( elem ) {
|
|
return jQuery.dir( elem, "parentNode" );
|
|
},
|
|
parentsUntil: function( elem, i, until ) {
|
|
return jQuery.dir( elem, "parentNode", until );
|
|
},
|
|
next: function( elem ) {
|
|
return sibling( elem, "nextSibling" );
|
|
},
|
|
prev: function( elem ) {
|
|
return sibling( elem, "previousSibling" );
|
|
},
|
|
nextAll: function( elem ) {
|
|
return jQuery.dir( elem, "nextSibling" );
|
|
},
|
|
prevAll: function( elem ) {
|
|
return jQuery.dir( elem, "previousSibling" );
|
|
},
|
|
nextUntil: function( elem, i, until ) {
|
|
return jQuery.dir( elem, "nextSibling", until );
|
|
},
|
|
prevUntil: function( elem, i, until ) {
|
|
return jQuery.dir( elem, "previousSibling", until );
|
|
},
|
|
siblings: function( elem ) {
|
|
return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
|
|
},
|
|
children: function( elem ) {
|
|
return jQuery.sibling( elem.firstChild );
|
|
},
|
|
contents: function( elem ) {
|
|
return jQuery.nodeName( elem, "iframe" ) ?
|
|
elem.contentDocument || elem.contentWindow.document :
|
|
jQuery.merge( [], elem.childNodes );
|
|
}
|
|
}, function( name, fn ) {
|
|
jQuery.fn[ name ] = function( until, selector ) {
|
|
var matched = jQuery.map( this, fn, until );
|
|
|
|
if ( name.slice( -5 ) !== "Until" ) {
|
|
selector = until;
|
|
}
|
|
|
|
if ( selector && typeof selector === "string" ) {
|
|
matched = jQuery.filter( selector, matched );
|
|
}
|
|
|
|
if ( this.length > 1 ) {
|
|
// Remove duplicates
|
|
if ( !guaranteedUnique[ name ] ) {
|
|
jQuery.unique( matched );
|
|
}
|
|
|
|
// Reverse order for parents* and prev*
|
|
if ( name[ 0 ] === "p" ) {
|
|
matched.reverse();
|
|
}
|
|
}
|
|
|
|
return this.pushStack( matched );
|
|
};
|
|
});
|
|
|
|
jQuery.extend({
|
|
filter: function( expr, elems, not ) {
|
|
var elem = elems[ 0 ];
|
|
|
|
if ( not ) {
|
|
expr = ":not(" + expr + ")";
|
|
}
|
|
|
|
return elems.length === 1 && elem.nodeType === 1 ?
|
|
jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
|
|
jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
|
|
return elem.nodeType === 1;
|
|
}));
|
|
},
|
|
|
|
dir: function( elem, dir, until ) {
|
|
var matched = [],
|
|
truncate = until !== undefined;
|
|
|
|
while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
if ( truncate && jQuery( elem ).is( until ) ) {
|
|
break;
|
|
}
|
|
matched.push( elem );
|
|
}
|
|
}
|
|
return matched;
|
|
},
|
|
|
|
sibling: function( n, elem ) {
|
|
var matched = [];
|
|
|
|
for ( ; n; n = n.nextSibling ) {
|
|
if ( n.nodeType === 1 && n !== elem ) {
|
|
matched.push( n );
|
|
}
|
|
}
|
|
|
|
return matched;
|
|
}
|
|
});
|
|
|
|
// Implement the identical functionality for filter and not
|
|
function winnow( elements, qualifier, not ) {
|
|
if ( jQuery.isFunction( qualifier ) ) {
|
|
return jQuery.grep( elements, function( elem, i ) {
|
|
/* jshint -W018 */
|
|
return !!qualifier.call( elem, i, elem ) !== not;
|
|
});
|
|
|
|
}
|
|
|
|
if ( qualifier.nodeType ) {
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( elem === qualifier ) !== not;
|
|
});
|
|
|
|
}
|
|
|
|
if ( typeof qualifier === "string" ) {
|
|
if ( isSimple.test( qualifier ) ) {
|
|
return jQuery.filter( qualifier, elements, not );
|
|
}
|
|
|
|
qualifier = jQuery.filter( qualifier, elements );
|
|
}
|
|
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
|
|
});
|
|
}
|
|
var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
|
|
rtagName = /<([\w:]+)/,
|
|
rhtml = /<|&#?\w+;/,
|
|
rnoInnerhtml = /<(?:script|style|link)/i,
|
|
manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
|
|
// checked="checked" or checked
|
|
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
|
rscriptType = /^$|\/(?:java|ecma)script/i,
|
|
rscriptTypeMasked = /^true\/(.*)/,
|
|
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
|
|
|
|
// We have to close these tags to support XHTML (#13200)
|
|
wrapMap = {
|
|
|
|
// Support: IE 9
|
|
option: [ 1, "<select multiple='multiple'>", "</select>" ],
|
|
|
|
thead: [ 1, "<table>", "</table>" ],
|
|
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
|
|
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
|
|
|
|
_default: [ 0, "", "" ]
|
|
};
|
|
|
|
// Support: IE 9
|
|
wrapMap.optgroup = wrapMap.option;
|
|
|
|
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.col = wrapMap.thead;
|
|
wrapMap.th = wrapMap.td;
|
|
|
|
jQuery.fn.extend({
|
|
text: function( value ) {
|
|
return jQuery.access( this, function( value ) {
|
|
return value === undefined ?
|
|
jQuery.text( this ) :
|
|
this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
|
|
}, null, value, arguments.length );
|
|
},
|
|
|
|
append: function() {
|
|
return this.domManip( arguments, function( elem ) {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
var target = manipulationTarget( this, elem );
|
|
target.appendChild( elem );
|
|
}
|
|
});
|
|
},
|
|
|
|
prepend: function() {
|
|
return this.domManip( arguments, function( elem ) {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
var target = manipulationTarget( this, elem );
|
|
target.insertBefore( elem, target.firstChild );
|
|
}
|
|
});
|
|
},
|
|
|
|
before: function() {
|
|
return this.domManip( arguments, function( elem ) {
|
|
if ( this.parentNode ) {
|
|
this.parentNode.insertBefore( elem, this );
|
|
}
|
|
});
|
|
},
|
|
|
|
after: function() {
|
|
return this.domManip( arguments, function( elem ) {
|
|
if ( this.parentNode ) {
|
|
this.parentNode.insertBefore( elem, this.nextSibling );
|
|
}
|
|
});
|
|
},
|
|
|
|
// keepData is for internal use only--do not document
|
|
remove: function( selector, keepData ) {
|
|
var elem,
|
|
elems = selector ? jQuery.filter( selector, this ) : this,
|
|
i = 0;
|
|
|
|
for ( ; (elem = elems[i]) != null; i++ ) {
|
|
if ( !keepData && elem.nodeType === 1 ) {
|
|
jQuery.cleanData( getAll( elem ) );
|
|
}
|
|
|
|
if ( elem.parentNode ) {
|
|
if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
|
|
setGlobalEval( getAll( elem, "script" ) );
|
|
}
|
|
elem.parentNode.removeChild( elem );
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
empty: function() {
|
|
var elem,
|
|
i = 0;
|
|
|
|
for ( ; (elem = this[i]) != null; i++ ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
|
|
// Prevent memory leaks
|
|
jQuery.cleanData( getAll( elem, false ) );
|
|
|
|
// Remove any remaining nodes
|
|
elem.textContent = "";
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
clone: function( dataAndEvents, deepDataAndEvents ) {
|
|
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
|
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
|
|
|
return this.map( function () {
|
|
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
|
|
});
|
|
},
|
|
|
|
html: function( value ) {
|
|
return jQuery.access( this, function( value ) {
|
|
var elem = this[ 0 ] || {},
|
|
i = 0,
|
|
l = this.length;
|
|
|
|
if ( value === undefined && elem.nodeType === 1 ) {
|
|
return elem.innerHTML;
|
|
}
|
|
|
|
// See if we can take a shortcut and just use innerHTML
|
|
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
|
|
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
|
|
|
|
value = value.replace( rxhtmlTag, "<$1></$2>" );
|
|
|
|
try {
|
|
for ( ; i < l; i++ ) {
|
|
elem = this[ i ] || {};
|
|
|
|
// Remove element nodes and prevent memory leaks
|
|
if ( elem.nodeType === 1 ) {
|
|
jQuery.cleanData( getAll( elem, false ) );
|
|
elem.innerHTML = value;
|
|
}
|
|
}
|
|
|
|
elem = 0;
|
|
|
|
// If using innerHTML throws an exception, use the fallback method
|
|
} catch( e ) {}
|
|
}
|
|
|
|
if ( elem ) {
|
|
this.empty().append( value );
|
|
}
|
|
}, null, value, arguments.length );
|
|
},
|
|
|
|
replaceWith: function() {
|
|
var
|
|
// Snapshot the DOM in case .domManip sweeps something relevant into its fragment
|
|
args = jQuery.map( this, function( elem ) {
|
|
return [ elem.nextSibling, elem.parentNode ];
|
|
}),
|
|
i = 0;
|
|
|
|
// Make the changes, replacing each context element with the new content
|
|
this.domManip( arguments, function( elem ) {
|
|
var next = args[ i++ ],
|
|
parent = args[ i++ ];
|
|
|
|
if ( parent ) {
|
|
jQuery( this ).remove();
|
|
parent.insertBefore( elem, next );
|
|
}
|
|
// Allow new content to include elements from the context set
|
|
}, true );
|
|
|
|
// Force removal if there was no new content (e.g., from empty arguments)
|
|
return i ? this : this.remove();
|
|
},
|
|
|
|
detach: function( selector ) {
|
|
return this.remove( selector, true );
|
|
},
|
|
|
|
domManip: function( args, callback, allowIntersection ) {
|
|
|
|
// Flatten any nested arrays
|
|
args = core_concat.apply( [], args );
|
|
|
|
var fragment, first, scripts, hasScripts, node, doc,
|
|
i = 0,
|
|
l = this.length,
|
|
set = this,
|
|
iNoClone = l - 1,
|
|
value = args[ 0 ],
|
|
isFunction = jQuery.isFunction( value );
|
|
|
|
// We can't cloneNode fragments that contain checked, in WebKit
|
|
if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
|
|
return this.each(function( index ) {
|
|
var self = set.eq( index );
|
|
if ( isFunction ) {
|
|
args[ 0 ] = value.call( this, index, self.html() );
|
|
}
|
|
self.domManip( args, callback, allowIntersection );
|
|
});
|
|
}
|
|
|
|
if ( l ) {
|
|
fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
|
|
first = fragment.firstChild;
|
|
|
|
if ( fragment.childNodes.length === 1 ) {
|
|
fragment = first;
|
|
}
|
|
|
|
if ( first ) {
|
|
scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
|
|
hasScripts = scripts.length;
|
|
|
|
// Use the original fragment for the last item instead of the first because it can end up
|
|
// being emptied incorrectly in certain situations (#8070).
|
|
for ( ; i < l; i++ ) {
|
|
node = fragment;
|
|
|
|
if ( i !== iNoClone ) {
|
|
node = jQuery.clone( node, true, true );
|
|
|
|
// Keep references to cloned scripts for later restoration
|
|
if ( hasScripts ) {
|
|
// Support: QtWebKit
|
|
// jQuery.merge because core_push.apply(_, arraylike) throws
|
|
jQuery.merge( scripts, getAll( node, "script" ) );
|
|
}
|
|
}
|
|
|
|
callback.call( this[ i ], node, i );
|
|
}
|
|
|
|
if ( hasScripts ) {
|
|
doc = scripts[ scripts.length - 1 ].ownerDocument;
|
|
|
|
// Reenable scripts
|
|
jQuery.map( scripts, restoreScript );
|
|
|
|
// Evaluate executable scripts on first document insertion
|
|
for ( i = 0; i < hasScripts; i++ ) {
|
|
node = scripts[ i ];
|
|
if ( rscriptType.test( node.type || "" ) &&
|
|
!data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
|
|
|
|
if ( node.src ) {
|
|
// Hope ajax is available...
|
|
jQuery._evalUrl( node.src );
|
|
} else {
|
|
jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
});
|
|
|
|
jQuery.each({
|
|
appendTo: "append",
|
|
prependTo: "prepend",
|
|
insertBefore: "before",
|
|
insertAfter: "after",
|
|
replaceAll: "replaceWith"
|
|
}, function( name, original ) {
|
|
jQuery.fn[ name ] = function( selector ) {
|
|
var elems,
|
|
ret = [],
|
|
insert = jQuery( selector ),
|
|
last = insert.length - 1,
|
|
i = 0;
|
|
|
|
for ( ; i <= last; i++ ) {
|
|
elems = i === last ? this : this.clone( true );
|
|
jQuery( insert[ i ] )[ original ]( elems );
|
|
|
|
// Support: QtWebKit
|
|
// .get() because core_push.apply(_, arraylike) throws
|
|
core_push.apply( ret, elems.get() );
|
|
}
|
|
|
|
return this.pushStack( ret );
|
|
};
|
|
});
|
|
|
|
jQuery.extend({
|
|
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
|
|
var i, l, srcElements, destElements,
|
|
clone = elem.cloneNode( true ),
|
|
inPage = jQuery.contains( elem.ownerDocument, elem );
|
|
|
|
// Support: IE >= 9
|
|
// Fix Cloning issues
|
|
if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
|
|
|
|
// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
|
|
destElements = getAll( clone );
|
|
srcElements = getAll( elem );
|
|
|
|
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
|
fixInput( srcElements[ i ], destElements[ i ] );
|
|
}
|
|
}
|
|
|
|
// Copy the events from the original to the clone
|
|
if ( dataAndEvents ) {
|
|
if ( deepDataAndEvents ) {
|
|
srcElements = srcElements || getAll( elem );
|
|
destElements = destElements || getAll( clone );
|
|
|
|
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
|
cloneCopyEvent( srcElements[ i ], destElements[ i ] );
|
|
}
|
|
} else {
|
|
cloneCopyEvent( elem, clone );
|
|
}
|
|
}
|
|
|
|
// Preserve script evaluation history
|
|
destElements = getAll( clone, "script" );
|
|
if ( destElements.length > 0 ) {
|
|
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
|
|
}
|
|
|
|
// Return the cloned set
|
|
return clone;
|
|
},
|
|
|
|
buildFragment: function( elems, context, scripts, selection ) {
|
|
var elem, tmp, tag, wrap, contains, j,
|
|
i = 0,
|
|
l = elems.length,
|
|
fragment = context.createDocumentFragment(),
|
|
nodes = [];
|
|
|
|
for ( ; i < l; i++ ) {
|
|
elem = elems[ i ];
|
|
|
|
if ( elem || elem === 0 ) {
|
|
|
|
// Add nodes directly
|
|
if ( jQuery.type( elem ) === "object" ) {
|
|
// Support: QtWebKit
|
|
// jQuery.merge because core_push.apply(_, arraylike) throws
|
|
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
|
|
|
|
// Convert non-html into a text node
|
|
} else if ( !rhtml.test( elem ) ) {
|
|
nodes.push( context.createTextNode( elem ) );
|
|
|
|
// Convert html into DOM nodes
|
|
} else {
|
|
tmp = tmp || fragment.appendChild( context.createElement("div") );
|
|
|
|
// Deserialize a standard representation
|
|
tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
|
|
wrap = wrapMap[ tag ] || wrapMap._default;
|
|
tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
|
|
|
|
// Descend through wrappers to the right content
|
|
j = wrap[ 0 ];
|
|
while ( j-- ) {
|
|
tmp = tmp.firstChild;
|
|
}
|
|
|
|
// Support: QtWebKit
|
|
// jQuery.merge because core_push.apply(_, arraylike) throws
|
|
jQuery.merge( nodes, tmp.childNodes );
|
|
|
|
// Remember the top-level container
|
|
tmp = fragment.firstChild;
|
|
|
|
// Fixes #12346
|
|
// Support: Webkit, IE
|
|
tmp.textContent = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove wrapper from fragment
|
|
fragment.textContent = "";
|
|
|
|
i = 0;
|
|
while ( (elem = nodes[ i++ ]) ) {
|
|
|
|
// #4087 - If origin and destination elements are the same, and this is
|
|
// that element, do not do anything
|
|
if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
|
|
continue;
|
|
}
|
|
|
|
contains = jQuery.contains( elem.ownerDocument, elem );
|
|
|
|
// Append to fragment
|
|
tmp = getAll( fragment.appendChild( elem ), "script" );
|
|
|
|
// Preserve script evaluation history
|
|
if ( contains ) {
|
|
setGlobalEval( tmp );
|
|
}
|
|
|
|
// Capture executables
|
|
if ( scripts ) {
|
|
j = 0;
|
|
while ( (elem = tmp[ j++ ]) ) {
|
|
if ( rscriptType.test( elem.type || "" ) ) {
|
|
scripts.push( elem );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fragment;
|
|
},
|
|
|
|
cleanData: function( elems ) {
|
|
var data, elem, type,
|
|
l = elems.length,
|
|
i = 0,
|
|
special = jQuery.event.special;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
elem = elems[ i ];
|
|
|
|
if ( jQuery.acceptData( elem ) ) {
|
|
|
|
data = data_priv.access( elem );
|
|
|
|
if ( data ) {
|
|
for ( type in data.events ) {
|
|
if ( special[ type ] ) {
|
|
jQuery.event.remove( elem, type );
|
|
|
|
// This is a shortcut to avoid jQuery.event.remove's overhead
|
|
} else {
|
|
jQuery.removeEvent( elem, type, data.handle );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Discard any remaining `private` and `user` data
|
|
// One day we'll replace the dual arrays with a WeakMap and this won't be an issue.
|
|
// (Splices the data objects out of the internal cache arrays)
|
|
data_user.discard( elem );
|
|
data_priv.discard( elem );
|
|
}
|
|
},
|
|
|
|
_evalUrl: function( url ) {
|
|
return jQuery.ajax({
|
|
url: url,
|
|
type: "GET",
|
|
dataType: "text",
|
|
async: false,
|
|
global: false,
|
|
success: jQuery.globalEval
|
|
});
|
|
}
|
|
});
|
|
|
|
// Support: 1.x compatibility
|
|
// Manipulating tables requires a tbody
|
|
function manipulationTarget( elem, content ) {
|
|
return jQuery.nodeName( elem, "table" ) &&
|
|
jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
|
|
|
|
elem.getElementsByTagName("tbody")[0] ||
|
|
elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
|
|
elem;
|
|
}
|
|
|
|
// Replace/restore the type attribute of script elements for safe DOM manipulation
|
|
function disableScript( elem ) {
|
|
elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
|
|
return elem;
|
|
}
|
|
function restoreScript( elem ) {
|
|
var match = rscriptTypeMasked.exec( elem.type );
|
|
|
|
if ( match ) {
|
|
elem.type = match[ 1 ];
|
|
} else {
|
|
elem.removeAttribute("type");
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
// Mark scripts as having already been evaluated
|
|
function setGlobalEval( elems, refElements ) {
|
|
var l = elems.length,
|
|
i = 0;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
data_priv.set(
|
|
elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
|
|
);
|
|
}
|
|
}
|
|
|
|
function cloneCopyEvent( src, dest ) {
|
|
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
|
|
|
|
if ( dest.nodeType !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
// 1. Copy private data: events, handlers, etc.
|
|
if ( data_priv.hasData( src ) ) {
|
|
pdataOld = data_priv.access( src );
|
|
pdataCur = jQuery.extend( {}, pdataOld );
|
|
events = pdataOld.events;
|
|
|
|
data_priv.set( dest, pdataCur );
|
|
|
|
if ( events ) {
|
|
delete pdataCur.handle;
|
|
pdataCur.events = {};
|
|
|
|
for ( type in events ) {
|
|
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
|
jQuery.event.add( dest, type, events[ type ][ i ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Copy user data
|
|
if ( data_user.hasData( src ) ) {
|
|
udataOld = data_user.access( src );
|
|
udataCur = jQuery.extend( {}, udataOld );
|
|
|
|
data_user.set( dest, udataCur );
|
|
}
|
|
}
|
|
|
|
|
|
function getAll( context, tag ) {
|
|
var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
|
|
context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
|
|
[];
|
|
|
|
return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
|
|
jQuery.merge( [ context ], ret ) :
|
|
ret;
|
|
}
|
|
|
|
// Support: IE >= 9
|
|
function fixInput( src, dest ) {
|
|
var nodeName = dest.nodeName.toLowerCase();
|
|
|
|
// Fails to persist the checked state of a cloned checkbox or radio button.
|
|
if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
|
|
dest.checked = src.checked;
|
|
|
|
// Fails to return the selected option to the default selected state when cloning options
|
|
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
|
dest.defaultValue = src.defaultValue;
|
|
}
|
|
}
|
|
jQuery.fn.extend({
|
|
wrapAll: function( html ) {
|
|
var wrap;
|
|
|
|
if ( jQuery.isFunction( html ) ) {
|
|
return this.each(function( i ) {
|
|
jQuery( this ).wrapAll( html.call(this, i) );
|
|
});
|
|
}
|
|
|
|
if ( this[ 0 ] ) {
|
|
|
|
// The elements to wrap the target around
|
|
wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
|
|
|
|
if ( this[ 0 ].parentNode ) {
|
|
wrap.insertBefore( this[ 0 ] );
|
|
}
|
|
|
|
wrap.map(function() {
|
|
var elem = this;
|
|
|
|
while ( elem.firstElementChild ) {
|
|
elem = elem.firstElementChild;
|
|
}
|
|
|
|
return elem;
|
|
}).append( this );
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
wrapInner: function( html ) {
|
|
if ( jQuery.isFunction( html ) ) {
|
|
return this.each(function( i ) {
|
|
jQuery( this ).wrapInner( html.call(this, i) );
|
|
});
|
|
}
|
|
|
|
return this.each(function() {
|
|
var self = jQuery( this ),
|
|
contents = self.contents();
|
|
|
|
if ( contents.length ) {
|
|
contents.wrapAll( html );
|
|
|
|
} else {
|
|
self.append( html );
|
|
}
|
|
});
|
|
},
|
|
|
|
wrap: function( html ) {
|
|
var isFunction = jQuery.isFunction( html );
|
|
|
|
return this.each(function( i ) {
|
|
jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
|
|
});
|
|
},
|
|
|
|
unwrap: function() {
|
|
return this.parent().each(function() {
|
|
if ( !jQuery.nodeName( this, "body" ) ) {
|
|
jQuery( this ).replaceWith( this.childNodes );
|
|
}
|
|
}).end();
|
|
}
|
|
});
|
|
var curCSS, iframe,
|
|
// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
|
|
// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
|
|
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
|
|
rmargin = /^margin/,
|
|
rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
|
|
rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
|
|
rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
|
|
elemdisplay = { BODY: "block" },
|
|
|
|
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
|
cssNormalTransform = {
|
|
letterSpacing: 0,
|
|
fontWeight: 400
|
|
},
|
|
|
|
cssExpand = [ "Top", "Right", "Bottom", "Left" ],
|
|
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
|
|
|
|
// return a css property mapped to a potentially vendor prefixed property
|
|
function vendorPropName( style, name ) {
|
|
|
|
// shortcut for names that are not vendor prefixed
|
|
if ( name in style ) {
|
|
return name;
|
|
}
|
|
|
|
// check for vendor prefixed names
|
|
var capName = name.charAt(0).toUpperCase() + name.slice(1),
|
|
origName = name,
|
|
i = cssPrefixes.length;
|
|
|
|
while ( i-- ) {
|
|
name = cssPrefixes[ i ] + capName;
|
|
if ( name in style ) {
|
|
return name;
|
|
}
|
|
}
|
|
|
|
return origName;
|
|
}
|
|
|
|
function isHidden( elem, el ) {
|
|
// isHidden might be called from jQuery#filter function;
|
|
// in that case, element will be second argument
|
|
elem = el || elem;
|
|
return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
|
|
}
|
|
|
|
// NOTE: we've included the "window" in window.getComputedStyle
|
|
// because jsdom on node.js will break without it.
|
|
function getStyles( elem ) {
|
|
return window.getComputedStyle( elem, null );
|
|
}
|
|
|
|
function showHide( elements, show ) {
|
|
var display, elem, hidden,
|
|
values = [],
|
|
index = 0,
|
|
length = elements.length;
|
|
|
|
for ( ; index < length; index++ ) {
|
|
elem = elements[ index ];
|
|
if ( !elem.style ) {
|
|
continue;
|
|
}
|
|
|
|
values[ index ] = data_priv.get( elem, "olddisplay" );
|
|
display = elem.style.display;
|
|
if ( show ) {
|
|
// Reset the inline display of this element to learn if it is
|
|
// being hidden by cascaded rules or not
|
|
if ( !values[ index ] && display === "none" ) {
|
|
elem.style.display = "";
|
|
}
|
|
|
|
// Set elements which have been overridden with display: none
|
|
// in a stylesheet to whatever the default browser style is
|
|
// for such an element
|
|
if ( elem.style.display === "" && isHidden( elem ) ) {
|
|
values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
|
|
}
|
|
} else {
|
|
|
|
if ( !values[ index ] ) {
|
|
hidden = isHidden( elem );
|
|
|
|
if ( display && display !== "none" || !hidden ) {
|
|
data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the display of most of the elements in a second loop
|
|
// to avoid the constant reflow
|
|
for ( index = 0; index < length; index++ ) {
|
|
elem = elements[ index ];
|
|
if ( !elem.style ) {
|
|
continue;
|
|
}
|
|
if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
|
|
elem.style.display = show ? values[ index ] || "" : "none";
|
|
}
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
jQuery.fn.extend({
|
|
css: function( name, value ) {
|
|
return jQuery.access( this, function( elem, name, value ) {
|
|
var styles, len,
|
|
map = {},
|
|
i = 0;
|
|
|
|
if ( jQuery.isArray( name ) ) {
|
|
styles = getStyles( elem );
|
|
len = name.length;
|
|
|
|
for ( ; i < len; i++ ) {
|
|
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
return value !== undefined ?
|
|
jQuery.style( elem, name, value ) :
|
|
jQuery.css( elem, name );
|
|
}, name, value, arguments.length > 1 );
|
|
},
|
|
show: function() {
|
|
return showHide( this, true );
|
|
},
|
|
hide: function() {
|
|
return showHide( this );
|
|
},
|
|
toggle: function( state ) {
|
|
var bool = typeof state === "boolean";
|
|
|
|
return this.each(function() {
|
|
if ( bool ? state : isHidden( this ) ) {
|
|
jQuery( this ).show();
|
|
} else {
|
|
jQuery( this ).hide();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
jQuery.extend({
|
|
// Add in style property hooks for overriding the default
|
|
// behavior of getting and setting a style property
|
|
cssHooks: {
|
|
opacity: {
|
|
get: function( elem, computed ) {
|
|
if ( computed ) {
|
|
// We should always get a number back from opacity
|
|
var ret = curCSS( elem, "opacity" );
|
|
return ret === "" ? "1" : ret;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// Exclude the following css properties to add px
|
|
cssNumber: {
|
|
"columnCount": true,
|
|
"fillOpacity": true,
|
|
"fontWeight": true,
|
|
"lineHeight": true,
|
|
"opacity": true,
|
|
"orphans": true,
|
|
"widows": true,
|
|
"zIndex": true,
|
|
"zoom": true
|
|
},
|
|
|
|
// Add in properties whose names you wish to fix before
|
|
// setting or getting the value
|
|
cssProps: {
|
|
// normalize float css property
|
|
"float": "cssFloat"
|
|
},
|
|
|
|
// Get and set the style property on a DOM Node
|
|
style: function( elem, name, value, extra ) {
|
|
// Don't set styles on text and comment nodes
|
|
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
|
|
return;
|
|
}
|
|
|
|
// Make sure that we're working with the right name
|
|
var ret, type, hooks,
|
|
origName = jQuery.camelCase( name ),
|
|
style = elem.style;
|
|
|
|
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
|
|
|
|
// gets hook for the prefixed version
|
|
// followed by the unprefixed version
|
|
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
|
|
|
// Check if we're setting a value
|
|
if ( value !== undefined ) {
|
|
type = typeof value;
|
|
|
|
// convert relative number strings (+= or -=) to relative numbers. #7345
|
|
if ( type === "string" && (ret = rrelNum.exec( value )) ) {
|
|
value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
|
|
// Fixes bug #9237
|
|
type = "number";
|
|
}
|
|
|
|
// Make sure that NaN and null values aren't set. See: #7116
|
|
if ( value == null || type === "number" && isNaN( value ) ) {
|
|
return;
|
|
}
|
|
|
|
// If a number was passed in, add 'px' to the (except for certain CSS properties)
|
|
if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
|
|
value += "px";
|
|
}
|
|
|
|
// Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
|
|
// but it would mean to define eight (for every problematic property) identical functions
|
|
if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
|
|
style[ name ] = "inherit";
|
|
}
|
|
|
|
// If a hook was provided, use that value, otherwise just set the specified value
|
|
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
|
|
style[ name ] = value;
|
|
}
|
|
|
|
} else {
|
|
// If a hook was provided get the non-computed value from there
|
|
if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
|
|
return ret;
|
|
}
|
|
|
|
// Otherwise just get the value from the style object
|
|
return style[ name ];
|
|
}
|
|
},
|
|
|
|
css: function( elem, name, extra, styles ) {
|
|
var val, num, hooks,
|
|
origName = jQuery.camelCase( name );
|
|
|
|
// Make sure that we're working with the right name
|
|
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
|
|
|
|
// gets hook for the prefixed version
|
|
// followed by the unprefixed version
|
|
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
|
|
|
// If a hook was provided get the computed value from there
|
|
if ( hooks && "get" in hooks ) {
|
|
val = hooks.get( elem, true, extra );
|
|
}
|
|
|
|
// Otherwise, if a way to get the computed value exists, use that
|
|
if ( val === undefined ) {
|
|
val = curCSS( elem, name, styles );
|
|
}
|
|
|
|
//convert "normal" to computed value
|
|
if ( val === "normal" && name in cssNormalTransform ) {
|
|
val = cssNormalTransform[ name ];
|
|
}
|
|
|
|
// Return, converting to number if forced or a qualifier was provided and val looks numeric
|
|
if ( extra === "" || extra ) {
|
|
num = parseFloat( val );
|
|
return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
|
|
}
|
|
return val;
|
|
}
|
|
});
|
|
|
|
curCSS = function( elem, name, _computed ) {
|
|
var width, minWidth, maxWidth,
|
|
computed = _computed || getStyles( elem ),
|
|
|
|
// Support: IE9
|
|
// getPropertyValue is only needed for .css('filter') in IE9, see #12537
|
|
ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
|
|
style = elem.style;
|
|
|
|
if ( computed ) {
|
|
|
|
if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
|
|
ret = jQuery.style( elem, name );
|
|
}
|
|
|
|
// Support: Safari 5.1
|
|
// A tribute to the "awesome hack by Dean Edwards"
|
|
// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
|
|
// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
|
|
if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
|
|
|
|
// Remember the original values
|
|
width = style.width;
|
|
minWidth = style.minWidth;
|
|
maxWidth = style.maxWidth;
|
|
|
|
// Put in the new values to get a computed value out
|
|
style.minWidth = style.maxWidth = style.width = ret;
|
|
ret = computed.width;
|
|
|
|
// Revert the changed values
|
|
style.width = width;
|
|
style.minWidth = minWidth;
|
|
style.maxWidth = maxWidth;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
|
|
function setPositiveNumber( elem, value, subtract ) {
|
|
var matches = rnumsplit.exec( value );
|
|
return matches ?
|
|
// Guard against undefined "subtract", e.g., when used as in cssHooks
|
|
Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
|
|
value;
|
|
}
|
|
|
|
function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
|
|
var i = extra === ( isBorderBox ? "border" : "content" ) ?
|
|
// If we already have the right measurement, avoid augmentation
|
|
4 :
|
|
// Otherwise initialize for horizontal or vertical properties
|
|
name === "width" ? 1 : 0,
|
|
|
|
val = 0;
|
|
|
|
for ( ; i < 4; i += 2 ) {
|
|
// both box models exclude margin, so add it if we want it
|
|
if ( extra === "margin" ) {
|
|
val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
|
|
}
|
|
|
|
if ( isBorderBox ) {
|
|
// border-box includes padding, so remove it if we want content
|
|
if ( extra === "content" ) {
|
|
val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
|
}
|
|
|
|
// at this point, extra isn't border nor margin, so remove border
|
|
if ( extra !== "margin" ) {
|
|
val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
}
|
|
} else {
|
|
// at this point, extra isn't content, so add padding
|
|
val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
|
|
|
// at this point, extra isn't content nor padding, so add border
|
|
if ( extra !== "padding" ) {
|
|
val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
}
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
function getWidthOrHeight( elem, name, extra ) {
|
|
|
|
// Start with offset property, which is equivalent to the border-box value
|
|
var valueIsBorderBox = true,
|
|
val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
|
|
styles = getStyles( elem ),
|
|
isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
|
|
|
|
// some non-html elements return undefined for offsetWidth, so check for null/undefined
|
|
// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
|
|
// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
|
|
if ( val <= 0 || val == null ) {
|
|
// Fall back to computed then uncomputed css if necessary
|
|
val = curCSS( elem, name, styles );
|
|
if ( val < 0 || val == null ) {
|
|
val = elem.style[ name ];
|
|
}
|
|
|
|
// Computed unit is not pixels. Stop here and return.
|
|
if ( rnumnonpx.test(val) ) {
|
|
return val;
|
|
}
|
|
|
|
// we need the check for style in case a browser which returns unreliable values
|
|
// for getComputedStyle silently falls back to the reliable elem.style
|
|
valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
|
|
|
|
// Normalize "", auto, and prepare for extra
|
|
val = parseFloat( val ) || 0;
|
|
}
|
|
|
|
// use the active box-sizing model to add/subtract irrelevant styles
|
|
return ( val +
|
|
augmentWidthOrHeight(
|
|
elem,
|
|
name,
|
|
extra || ( isBorderBox ? "border" : "content" ),
|
|
valueIsBorderBox,
|
|
styles
|
|
)
|
|
) + "px";
|
|
}
|
|
|
|
// Try to determine the default display value of an element
|
|
function css_defaultDisplay( nodeName ) {
|
|
var doc = document,
|
|
display = elemdisplay[ nodeName ];
|
|
|
|
if ( !display ) {
|
|
display = actualDisplay( nodeName, doc );
|
|
|
|
// If the simple way fails, read from inside an iframe
|
|
if ( display === "none" || !display ) {
|
|
// Use the already-created iframe if possible
|
|
iframe = ( iframe ||
|
|
jQuery("<iframe frameborder='0' width='0' height='0'/>")
|
|
.css( "cssText", "display:block !important" )
|
|
).appendTo( doc.documentElement );
|
|
|
|
// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
|
|
doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
|
|
doc.write("<!doctype html><html><body>");
|
|
doc.close();
|
|
|
|
display = actualDisplay( nodeName, doc );
|
|
iframe.detach();
|
|
}
|
|
|
|
// Store the correct default display
|
|
elemdisplay[ nodeName ] = display;
|
|
}
|
|
|
|
return display;
|
|
}
|
|
|
|
// Called ONLY from within css_defaultDisplay
|
|
function actualDisplay( name, doc ) {
|
|
var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
|
|
display = jQuery.css( elem[0], "display" );
|
|
elem.remove();
|
|
return display;
|
|
}
|
|
|
|
jQuery.each([ "height", "width" ], function( i, name ) {
|
|
jQuery.cssHooks[ name ] = {
|
|
get: function( elem, computed, extra ) {
|
|
if ( computed ) {
|
|
// certain elements can have dimension info if we invisibly show them
|
|
// however, it must have a current display style that would benefit from this
|
|
return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
|
|
jQuery.swap( elem, cssShow, function() {
|
|
return getWidthOrHeight( elem, name, extra );
|
|
}) :
|
|
getWidthOrHeight( elem, name, extra );
|
|
}
|
|
},
|
|
|
|
set: function( elem, value, extra ) {
|
|
var styles = extra && getStyles( elem );
|
|
return setPositiveNumber( elem, value, extra ?
|
|
augmentWidthOrHeight(
|
|
elem,
|
|
name,
|
|
extra,
|
|
jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
|
|
styles
|
|
) : 0
|
|
);
|
|
}
|
|
};
|
|
});
|
|
|
|
// These hooks cannot be added until DOM ready because the support test
|
|
// for it is not run until after DOM ready
|
|
jQuery(function() {
|
|
// Support: Android 2.3
|
|
if ( !jQuery.support.reliableMarginRight ) {
|
|
jQuery.cssHooks.marginRight = {
|
|
get: function( elem, computed ) {
|
|
if ( computed ) {
|
|
// Support: Android 2.3
|
|
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
|
|
// Work around by temporarily setting element display to inline-block
|
|
return jQuery.swap( elem, { "display": "inline-block" },
|
|
curCSS, [ elem, "marginRight" ] );
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
|
|
// getComputedStyle returns percent when specified for top/left/bottom/right
|
|
// rather than make the css module depend on the offset module, we just check for it here
|
|
if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
|
|
jQuery.each( [ "top", "left" ], function( i, prop ) {
|
|
jQuery.cssHooks[ prop ] = {
|
|
get: function( elem, computed ) {
|
|
if ( computed ) {
|
|
computed = curCSS( elem, prop );
|
|
// if curCSS returns percentage, fallback to offset
|
|
return rnumnonpx.test( computed ) ?
|
|
jQuery( elem ).position()[ prop ] + "px" :
|
|
computed;
|
|
}
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
if ( jQuery.expr && jQuery.expr.filters ) {
|
|
jQuery.expr.filters.hidden = function( elem ) {
|
|
// Support: Opera <= 12.12
|
|
// Opera reports offsetWidths and offsetHeights less than zero on some elements
|
|
return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
|
|
};
|
|
|
|
jQuery.expr.filters.visible = function( elem ) {
|
|
return !jQuery.expr.filters.hidden( elem );
|
|
};
|
|
}
|
|
|
|
// These hooks are used by animate to expand properties
|
|
jQuery.each({
|
|
margin: "",
|
|
padding: "",
|
|
border: "Width"
|
|
}, function( prefix, suffix ) {
|
|
jQuery.cssHooks[ prefix + suffix ] = {
|
|
expand: function( value ) {
|
|
var i = 0,
|
|
expanded = {},
|
|
|
|
// assumes a single number if not a string
|
|
parts = typeof value === "string" ? value.split(" ") : [ value ];
|
|
|
|
for ( ; i < 4; i++ ) {
|
|
expanded[ prefix + cssExpand[ i ] + suffix ] =
|
|
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
|
|
}
|
|
|
|
return expanded;
|
|
}
|
|
};
|
|
|
|
if ( !rmargin.test( prefix ) ) {
|
|
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
|
|
}
|
|
});
|
|
var r20 = /%20/g,
|
|
rbracket = /\[\]$/,
|
|
rCRLF = /\r?\n/g,
|
|
rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
|
|
rsubmittable = /^(?:input|select|textarea|keygen)/i;
|
|
|
|
jQuery.fn.extend({
|
|
serialize: function() {
|
|
return jQuery.param( this.serializeArray() );
|
|
},
|
|
serializeArray: function() {
|
|
return this.map(function(){
|
|
// Can add propHook for "elements" to filter or add form elements
|
|
var elements = jQuery.prop( this, "elements" );
|
|
return elements ? jQuery.makeArray( elements ) : this;
|
|
})
|
|
.filter(function(){
|
|
var type = this.type;
|
|
// Use .is(":disabled") so that fieldset[disabled] works
|
|
return this.name && !jQuery( this ).is( ":disabled" ) &&
|
|
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
|
|
( this.checked || !manipulation_rcheckableType.test( type ) );
|
|
})
|
|
.map(function( i, elem ){
|
|
var val = jQuery( this ).val();
|
|
|
|
return val == null ?
|
|
null :
|
|
jQuery.isArray( val ) ?
|
|
jQuery.map( val, function( val ){
|
|
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
|
}) :
|
|
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
|
}).get();
|
|
}
|
|
});
|
|
|
|
//Serialize an array of form elements or a set of
|
|
//key/values into a query string
|
|
jQuery.param = function( a, traditional ) {
|
|
var prefix,
|
|
s = [],
|
|
add = function( key, value ) {
|
|
// If value is a function, invoke it and return its value
|
|
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
|
|
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
|
|
};
|
|
|
|
// Set traditional to true for jQuery <= 1.3.2 behavior.
|
|
if ( traditional === undefined ) {
|
|
traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
|
|
}
|
|
|
|
// If an array was passed in, assume that it is an array of form elements.
|
|
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
|
|
// Serialize the form elements
|
|
jQuery.each( a, function() {
|
|
add( this.name, this.value );
|
|
});
|
|
|
|
} else {
|
|
// If traditional, encode the "old" way (the way 1.3.2 or older
|
|
// did it), otherwise encode params recursively.
|
|
for ( prefix in a ) {
|
|
buildParams( prefix, a[ prefix ], traditional, add );
|
|
}
|
|
}
|
|
|
|
// Return the resulting serialization
|
|
return s.join( "&" ).replace( r20, "+" );
|
|
};
|
|
|
|
function buildParams( prefix, obj, traditional, add ) {
|
|
var name;
|
|
|
|
if ( jQuery.isArray( obj ) ) {
|
|
// Serialize array item.
|
|
jQuery.each( obj, function( i, v ) {
|
|
if ( traditional || rbracket.test( prefix ) ) {
|
|
// Treat each array item as a scalar.
|
|
add( prefix, v );
|
|
|
|
} else {
|
|
// Item is non-scalar (array or object), encode its numeric index.
|
|
buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
|
|
}
|
|
});
|
|
|
|
} else if ( !traditional && jQuery.type( obj ) === "object" ) {
|
|
// Serialize object item.
|
|
for ( name in obj ) {
|
|
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
|
|
}
|
|
|
|
} else {
|
|
// Serialize scalar item.
|
|
add( prefix, obj );
|
|
}
|
|
}
|
|
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
|
|
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
|
|
"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
|
|
|
|
// Handle event binding
|
|
jQuery.fn[ name ] = function( data, fn ) {
|
|
return arguments.length > 0 ?
|
|
this.on( name, null, data, fn ) :
|
|
this.trigger( name );
|
|
};
|
|
});
|
|
|
|
jQuery.fn.extend({
|
|
hover: function( fnOver, fnOut ) {
|
|
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
|
|
},
|
|
|
|
bind: function( types, data, fn ) {
|
|
return this.on( types, null, data, fn );
|
|
},
|
|
unbind: function( types, fn ) {
|
|
return this.off( types, null, fn );
|
|
},
|
|
|
|
delegate: function( selector, types, data, fn ) {
|
|
return this.on( types, selector, data, fn );
|
|
},
|
|
undelegate: function( selector, types, fn ) {
|
|
// ( namespace ) or ( selector, types [, fn] )
|
|
return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
|
|
}
|
|
});
|
|
var
|
|
// Document location
|
|
ajaxLocParts,
|
|
ajaxLocation,
|
|
|
|
ajax_nonce = jQuery.now(),
|
|
|
|
ajax_rquery = /\?/,
|
|
rhash = /#.*$/,
|
|
rts = /([?&])_=[^&]*/,
|
|
rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
|
|
// #7653, #8125, #8152: local protocol detection
|
|
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
|
|
rnoContent = /^(?:GET|HEAD)$/,
|
|
rprotocol = /^\/\//,
|
|
rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
|
|
|
|
// Keep a copy of the old load method
|
|
_load = jQuery.fn.load,
|
|
|
|
/* Prefilters
|
|
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
|
|
* 2) These are called:
|
|
* - BEFORE asking for a transport
|
|
* - AFTER param serialization (s.data is a string if s.processData is true)
|
|
* 3) key is the dataType
|
|
* 4) the catchall symbol "*" can be used
|
|
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
|
|
*/
|
|
prefilters = {},
|
|
|
|
/* Transports bindings
|
|
* 1) key is the dataType
|
|
* 2) the catchall symbol "*" can be used
|
|
* 3) selection will start with transport dataType and THEN go to "*" if needed
|
|
*/
|
|
transports = {},
|
|
|
|
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
|
|
allTypes = "*/".concat("*");
|
|
|
|
// #8138, IE may throw an exception when accessing
|
|
// a field from window.location if document.domain has been set
|
|
try {
|
|
ajaxLocation = location.href;
|
|
} catch( e ) {
|
|
// Use the href attribute of an A element
|
|
// since IE will modify it given document.location
|
|
ajaxLocation = document.createElement( "a" );
|
|
ajaxLocation.href = "";
|
|
ajaxLocation = ajaxLocation.href;
|
|
}
|
|
|
|
// Segment location into parts
|
|
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
|
|
|
|
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
|
|
function addToPrefiltersOrTransports( structure ) {
|
|
|
|
// dataTypeExpression is optional and defaults to "*"
|
|
return function( dataTypeExpression, func ) {
|
|
|
|
if ( typeof dataTypeExpression !== "string" ) {
|
|
func = dataTypeExpression;
|
|
dataTypeExpression = "*";
|
|
}
|
|
|
|
var dataType,
|
|
i = 0,
|
|
dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
|
|
|
|
if ( jQuery.isFunction( func ) ) {
|
|
// For each dataType in the dataTypeExpression
|
|
while ( (dataType = dataTypes[i++]) ) {
|
|
// Prepend if requested
|
|
if ( dataType[0] === "+" ) {
|
|
dataType = dataType.slice( 1 ) || "*";
|
|
(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
|
|
|
|
// Otherwise append
|
|
} else {
|
|
(structure[ dataType ] = structure[ dataType ] || []).push( func );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Base inspection function for prefilters and transports
|
|
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
|
|
|
|
var inspected = {},
|
|
seekingTransport = ( structure === transports );
|
|
|
|
function inspect( dataType ) {
|
|
var selected;
|
|
inspected[ dataType ] = true;
|
|
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
|
|
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
|
|
if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
|
|
options.dataTypes.unshift( dataTypeOrTransport );
|
|
inspect( dataTypeOrTransport );
|
|
return false;
|
|
} else if ( seekingTransport ) {
|
|
return !( selected = dataTypeOrTransport );
|
|
}
|
|
});
|
|
return selected;
|
|
}
|
|
|
|
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
|
|
}
|
|
|
|
// A special extend for ajax options
|
|
// that takes "flat" options (not to be deep extended)
|
|
// Fixes #9887
|
|
function ajaxExtend( target, src ) {
|
|
var key, deep,
|
|
flatOptions = jQuery.ajaxSettings.flatOptions || {};
|
|
|
|
for ( key in src ) {
|
|
if ( src[ key ] !== undefined ) {
|
|
( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
|
|
}
|
|
}
|
|
if ( deep ) {
|
|
jQuery.extend( true, target, deep );
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
jQuery.fn.load = function( url, params, callback ) {
|
|
if ( typeof url !== "string" && _load ) {
|
|
return _load.apply( this, arguments );
|
|
}
|
|
|
|
var selector, type, response,
|
|
self = this,
|
|
off = url.indexOf(" ");
|
|
|
|
if ( off >= 0 ) {
|
|
selector = url.slice( off );
|
|
url = url.slice( 0, off );
|
|
}
|
|
|
|
// If it's a function
|
|
if ( jQuery.isFunction( params ) ) {
|
|
|
|
// We assume that it's the callback
|
|
callback = params;
|
|
params = undefined;
|
|
|
|
// Otherwise, build a param string
|
|
} else if ( params && typeof params === "object" ) {
|
|
type = "POST";
|
|
}
|
|
|
|
// If we have elements to modify, make the request
|
|
if ( self.length > 0 ) {
|
|
jQuery.ajax({
|
|
url: url,
|
|
|
|
// if "type" variable is undefined, then "GET" method will be used
|
|
type: type,
|
|
dataType: "html",
|
|
data: params
|
|
}).done(function( responseText ) {
|
|
|
|
// Save response for use in complete callback
|
|
response = arguments;
|
|
|
|
self.html( selector ?
|
|
|
|
// If a selector was specified, locate the right elements in a dummy div
|
|
// Exclude scripts to avoid IE 'Permission Denied' errors
|
|
jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
|
|
|
|
// Otherwise use the full result
|
|
responseText );
|
|
|
|
}).complete( callback && function( jqXHR, status ) {
|
|
self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
|
|
});
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
// Attach a bunch of functions for handling common AJAX events
|
|
jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
|
|
jQuery.fn[ type ] = function( fn ){
|
|
return this.on( type, fn );
|
|
};
|
|
});
|
|
|
|
jQuery.extend({
|
|
|
|
// Counter for holding the number of active queries
|
|
active: 0,
|
|
|
|
// Last-Modified header cache for next request
|
|
lastModified: {},
|
|
etag: {},
|
|
|
|
ajaxSettings: {
|
|
url: ajaxLocation,
|
|
type: "GET",
|
|
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
|
|
global: true,
|
|
processData: true,
|
|
async: true,
|
|
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
|
/*
|
|
timeout: 0,
|
|
data: null,
|
|
dataType: null,
|
|
username: null,
|
|
password: null,
|
|
cache: null,
|
|
throws: false,
|
|
traditional: false,
|
|
headers: {},
|
|
*/
|
|
|
|
accepts: {
|
|
"*": allTypes,
|
|
text: "text/plain",
|
|
html: "text/html",
|
|
xml: "application/xml, text/xml",
|
|
json: "application/json, text/javascript"
|
|
},
|
|
|
|
contents: {
|
|
xml: /xml/,
|
|
html: /html/,
|
|
json: /json/
|
|
},
|
|
|
|
responseFields: {
|
|
xml: "responseXML",
|
|
text: "responseText",
|
|
json: "responseJSON"
|
|
},
|
|
|
|
// Data converters
|
|
// Keys separate source (or catchall "*") and destination types with a single space
|
|
converters: {
|
|
|
|
// Convert anything to text
|
|
"* text": String,
|
|
|
|
// Text to html (true = no transformation)
|
|
"text html": true,
|
|
|
|
// Evaluate text as a json expression
|
|
"text json": jQuery.parseJSON,
|
|
|
|
// Parse text as xml
|
|
"text xml": jQuery.parseXML
|
|
},
|
|
|
|
// For options that shouldn't be deep extended:
|
|
// you can add your own custom options here if
|
|
// and when you create one that shouldn't be
|
|
// deep extended (see ajaxExtend)
|
|
flatOptions: {
|
|
url: true,
|
|
context: true
|
|
}
|
|
},
|
|
|
|
// Creates a full fledged settings object into target
|
|
// with both ajaxSettings and settings fields.
|
|
// If target is omitted, writes into ajaxSettings.
|
|
ajaxSetup: function( target, settings ) {
|
|
return settings ?
|
|
|
|
// Building a settings object
|
|
ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
|
|
|
|
// Extending ajaxSettings
|
|
ajaxExtend( jQuery.ajaxSettings, target );
|
|
},
|
|
|
|
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
|
|
ajaxTransport: addToPrefiltersOrTransports( transports ),
|
|
|
|
// Main method
|
|
ajax: function( url, options ) {
|
|
|
|
// If url is an object, simulate pre-1.5 signature
|
|
if ( typeof url === "object" ) {
|
|
options = url;
|
|
url = undefined;
|
|
}
|
|
|
|
// Force options to be an object
|
|
options = options || {};
|
|
|
|
var transport,
|
|
// URL without anti-cache param
|
|
cacheURL,
|
|
// Response headers
|
|
responseHeadersString,
|
|
responseHeaders,
|
|
// timeout handle
|
|
timeoutTimer,
|
|
// Cross-domain detection vars
|
|
parts,
|
|
// To know if global events are to be dispatched
|
|
fireGlobals,
|
|
// Loop variable
|
|
i,
|
|
// Create the final options object
|
|
s = jQuery.ajaxSetup( {}, options ),
|
|
// Callbacks context
|
|
callbackContext = s.context || s,
|
|
// Context for global events is callbackContext if it is a DOM node or jQuery collection
|
|
globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
|
|
jQuery( callbackContext ) :
|
|
jQuery.event,
|
|
// Deferreds
|
|
deferred = jQuery.Deferred(),
|
|
completeDeferred = jQuery.Callbacks("once memory"),
|
|
// Status-dependent callbacks
|
|
statusCode = s.statusCode || {},
|
|
// Headers (they are sent all at once)
|
|
requestHeaders = {},
|
|
requestHeadersNames = {},
|
|
// The jqXHR state
|
|
state = 0,
|
|
// Default abort message
|
|
strAbort = "canceled",
|
|
// Fake xhr
|
|
jqXHR = {
|
|
readyState: 0,
|
|
|
|
// Builds headers hashtable if needed
|
|
getResponseHeader: function( key ) {
|
|
var match;
|
|
if ( state === 2 ) {
|
|
if ( !responseHeaders ) {
|
|
responseHeaders = {};
|
|
while ( (match = rheaders.exec( responseHeadersString )) ) {
|
|
responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
|
|
}
|
|
}
|
|
match = responseHeaders[ key.toLowerCase() ];
|
|
}
|
|
return match == null ? null : match;
|
|
},
|
|
|
|
// Raw string
|
|
getAllResponseHeaders: function() {
|
|
return state === 2 ? responseHeadersString : null;
|
|
},
|
|
|
|
// Caches the header
|
|
setRequestHeader: function( name, value ) {
|
|
var lname = name.toLowerCase();
|
|
if ( !state ) {
|
|
name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
|
|
requestHeaders[ name ] = value;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Overrides response content-type header
|
|
overrideMimeType: function( type ) {
|
|
if ( !state ) {
|
|
s.mimeType = type;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Status-dependent callbacks
|
|
statusCode: function( map ) {
|
|
var code;
|
|
if ( map ) {
|
|
if ( state < 2 ) {
|
|
for ( code in map ) {
|
|
// Lazy-add the new callback in a way that preserves old ones
|
|
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
|
|
}
|
|
} else {
|
|
// Execute the appropriate callbacks
|
|
jqXHR.always( map[ jqXHR.status ] );
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Cancel the request
|
|
abort: function( statusText ) {
|
|
var finalText = statusText || strAbort;
|
|
if ( transport ) {
|
|
transport.abort( finalText );
|
|
}
|
|
done( 0, finalText );
|
|
return this;
|
|
}
|
|
};
|
|
|
|
// Attach deferreds
|
|
deferred.promise( jqXHR ).complete = completeDeferred.add;
|
|
jqXHR.success = jqXHR.done;
|
|
jqXHR.error = jqXHR.fail;
|
|
|
|
// Remove hash character (#7531: and string promotion)
|
|
// Add protocol if not provided (prefilters might expect it)
|
|
// Handle falsy url in the settings object (#10093: consistency with old signature)
|
|
// We also use the url parameter if available
|
|
s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
|
|
.replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
|
|
|
|
// Alias method option to type as per ticket #12004
|
|
s.type = options.method || options.type || s.method || s.type;
|
|
|
|
// Extract dataTypes list
|
|
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
|
|
|
|
// A cross-domain request is in order when we have a protocol:host:port mismatch
|
|
if ( s.crossDomain == null ) {
|
|
parts = rurl.exec( s.url.toLowerCase() );
|
|
s.crossDomain = !!( parts &&
|
|
( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
|
|
( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
|
|
( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
|
|
);
|
|
}
|
|
|
|
// Convert data if not already a string
|
|
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
|
s.data = jQuery.param( s.data, s.traditional );
|
|
}
|
|
|
|
// Apply prefilters
|
|
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
|
|
|
|
// If request was aborted inside a prefilter, stop there
|
|
if ( state === 2 ) {
|
|
return jqXHR;
|
|
}
|
|
|
|
// We can fire global events as of now if asked to
|
|
fireGlobals = s.global;
|
|
|
|
// Watch for a new set of requests
|
|
if ( fireGlobals && jQuery.active++ === 0 ) {
|
|
jQuery.event.trigger("ajaxStart");
|
|
}
|
|
|
|
// Uppercase the type
|
|
s.type = s.type.toUpperCase();
|
|
|
|
// Determine if request has content
|
|
s.hasContent = !rnoContent.test( s.type );
|
|
|
|
// Save the URL in case we're toying with the If-Modified-Since
|
|
// and/or If-None-Match header later on
|
|
cacheURL = s.url;
|
|
|
|
// More options handling for requests with no content
|
|
if ( !s.hasContent ) {
|
|
|
|
// If data is available, append data to url
|
|
if ( s.data ) {
|
|
cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
|
|
// #9682: remove data so that it's not used in an eventual retry
|
|
delete s.data;
|
|
}
|
|
|
|
// Add anti-cache in url if needed
|
|
if ( s.cache === false ) {
|
|
s.url = rts.test( cacheURL ) ?
|
|
|
|
// If there is already a '_' parameter, set its value
|
|
cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
|
|
|
|
// Otherwise add one to the end
|
|
cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
|
|
}
|
|
}
|
|
|
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
|
if ( s.ifModified ) {
|
|
if ( jQuery.lastModified[ cacheURL ] ) {
|
|
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
|
|
}
|
|
if ( jQuery.etag[ cacheURL ] ) {
|
|
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
|
|
}
|
|
}
|
|
|
|
// Set the correct header, if data is being sent
|
|
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
|
|
jqXHR.setRequestHeader( "Content-Type", s.contentType );
|
|
}
|
|
|
|
// Set the Accepts header for the server, depending on the dataType
|
|
jqXHR.setRequestHeader(
|
|
"Accept",
|
|
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
|
|
s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
|
|
s.accepts[ "*" ]
|
|
);
|
|
|
|
// Check for headers option
|
|
for ( i in s.headers ) {
|
|
jqXHR.setRequestHeader( i, s.headers[ i ] );
|
|
}
|
|
|
|
// Allow custom headers/mimetypes and early abort
|
|
if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
|
|
// Abort if not done already and return
|
|
return jqXHR.abort();
|
|
}
|
|
|
|
// aborting is no longer a cancellation
|
|
strAbort = "abort";
|
|
|
|
// Install callbacks on deferreds
|
|
for ( i in { success: 1, error: 1, complete: 1 } ) {
|
|
jqXHR[ i ]( s[ i ] );
|
|
}
|
|
|
|
// Get transport
|
|
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
|
|
|
|
// If no transport, we auto-abort
|
|
if ( !transport ) {
|
|
done( -1, "No Transport" );
|
|
} else {
|
|
jqXHR.readyState = 1;
|
|
|
|
// Send global event
|
|
if ( fireGlobals ) {
|
|
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
|
|
}
|
|
// Timeout
|
|
if ( s.async && s.timeout > 0 ) {
|
|
timeoutTimer = setTimeout(function() {
|
|
jqXHR.abort("timeout");
|
|
}, s.timeout );
|
|
}
|
|
|
|
try {
|
|
state = 1;
|
|
transport.send( requestHeaders, done );
|
|
} catch ( e ) {
|
|
// Propagate exception as error if not done
|
|
if ( state < 2 ) {
|
|
done( -1, e );
|
|
// Simply rethrow otherwise
|
|
} else {
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Callback for when everything is done
|
|
function done( status, nativeStatusText, responses, headers ) {
|
|
var isSuccess, success, error, response, modified,
|
|
statusText = nativeStatusText;
|
|
|
|
// Called once
|
|
if ( state === 2 ) {
|
|
return;
|
|
}
|
|
|
|
// State is "done" now
|
|
state = 2;
|
|
|
|
// Clear timeout if it exists
|
|
if ( timeoutTimer ) {
|
|
clearTimeout( timeoutTimer );
|
|
}
|
|
|
|
// Dereference transport for early garbage collection
|
|
// (no matter how long the jqXHR object will be used)
|
|
transport = undefined;
|
|
|
|
// Cache response headers
|
|
responseHeadersString = headers || "";
|
|
|
|
// Set readyState
|
|
jqXHR.readyState = status > 0 ? 4 : 0;
|
|
|
|
// Determine if successful
|
|
isSuccess = status >= 200 && status < 300 || status === 304;
|
|
|
|
// Get response data
|
|
if ( responses ) {
|
|
response = ajaxHandleResponses( s, jqXHR, responses );
|
|
}
|
|
|
|
// Convert no matter what (that way responseXXX fields are always set)
|
|
response = ajaxConvert( s, response, jqXHR, isSuccess );
|
|
|
|
// If successful, handle type chaining
|
|
if ( isSuccess ) {
|
|
|
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
|
if ( s.ifModified ) {
|
|
modified = jqXHR.getResponseHeader("Last-Modified");
|
|
if ( modified ) {
|
|
jQuery.lastModified[ cacheURL ] = modified;
|
|
}
|
|
modified = jqXHR.getResponseHeader("etag");
|
|
if ( modified ) {
|
|
jQuery.etag[ cacheURL ] = modified;
|
|
}
|
|
}
|
|
|
|
// if no content
|
|
if ( status === 204 ) {
|
|
statusText = "nocontent";
|
|
|
|
// if not modified
|
|
} else if ( status === 304 ) {
|
|
statusText = "notmodified";
|
|
|
|
// If we have data, let's convert it
|
|
} else {
|
|
statusText = response.state;
|
|
success = response.data;
|
|
error = response.error;
|
|
isSuccess = !error;
|
|
}
|
|
} else {
|
|
// We extract error from statusText
|
|
// then normalize statusText and status for non-aborts
|
|
error = statusText;
|
|
if ( status || !statusText ) {
|
|
statusText = "error";
|
|
if ( status < 0 ) {
|
|
status = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set data for the fake xhr object
|
|
jqXHR.status = status;
|
|
jqXHR.statusText = ( nativeStatusText || statusText ) + "";
|
|
|
|
// Success/Error
|
|
if ( isSuccess ) {
|
|
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
|
|
} else {
|
|
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
|
|
}
|
|
|
|
// Status-dependent callbacks
|
|
jqXHR.statusCode( statusCode );
|
|
statusCode = undefined;
|
|
|
|
if ( fireGlobals ) {
|
|
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
|
|
[ jqXHR, s, isSuccess ? success : error ] );
|
|
}
|
|
|
|
// Complete
|
|
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
|
|
|
|
if ( fireGlobals ) {
|
|
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
|
|
// Handle the global AJAX counter
|
|
if ( !( --jQuery.active ) ) {
|
|
jQuery.event.trigger("ajaxStop");
|
|
}
|
|
}
|
|
}
|
|
|
|
return jqXHR;
|
|
},
|
|
|
|
getJSON: function( url, data, callback ) {
|
|
return jQuery.get( url, data, callback, "json" );
|
|
},
|
|
|
|
getScript: function( url, callback ) {
|
|
return jQuery.get( url, undefined, callback, "script" );
|
|
}
|
|
});
|
|
|
|
jQuery.each( [ "get", "post" ], function( i, method ) {
|
|
jQuery[ method ] = function( url, data, callback, type ) {
|
|
// shift arguments if data argument was omitted
|
|
if ( jQuery.isFunction( data ) ) {
|
|
type = type || callback;
|
|
callback = data;
|
|
data = undefined;
|
|
}
|
|
|
|
return jQuery.ajax({
|
|
url: url,
|
|
type: method,
|
|
dataType: type,
|
|
data: data,
|
|
success: callback
|
|
});
|
|
};
|
|
});
|
|
|
|
/* Handles responses to an ajax request:
|
|
* - finds the right dataType (mediates between content-type and expected dataType)
|
|
* - returns the corresponding response
|
|
*/
|
|
function ajaxHandleResponses( s, jqXHR, responses ) {
|
|
|
|
var ct, type, finalDataType, firstDataType,
|
|
contents = s.contents,
|
|
dataTypes = s.dataTypes;
|
|
|
|
// Remove auto dataType and get content-type in the process
|
|
while( dataTypes[ 0 ] === "*" ) {
|
|
dataTypes.shift();
|
|
if ( ct === undefined ) {
|
|
ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
|
|
}
|
|
}
|
|
|
|
// Check if we're dealing with a known content-type
|
|
if ( ct ) {
|
|
for ( type in contents ) {
|
|
if ( contents[ type ] && contents[ type ].test( ct ) ) {
|
|
dataTypes.unshift( type );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check to see if we have a response for the expected dataType
|
|
if ( dataTypes[ 0 ] in responses ) {
|
|
finalDataType = dataTypes[ 0 ];
|
|
} else {
|
|
// Try convertible dataTypes
|
|
for ( type in responses ) {
|
|
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
|
|
finalDataType = type;
|
|
break;
|
|
}
|
|
if ( !firstDataType ) {
|
|
firstDataType = type;
|
|
}
|
|
}
|
|
// Or just use first one
|
|
finalDataType = finalDataType || firstDataType;
|
|
}
|
|
|
|
// If we found a dataType
|
|
// We add the dataType to the list if needed
|
|
// and return the corresponding response
|
|
if ( finalDataType ) {
|
|
if ( finalDataType !== dataTypes[ 0 ] ) {
|
|
dataTypes.unshift( finalDataType );
|
|
}
|
|
return responses[ finalDataType ];
|
|
}
|
|
}
|
|
|
|
/* Chain conversions given the request and the original response
|
|
* Also sets the responseXXX fields on the jqXHR instance
|
|
*/
|
|
function ajaxConvert( s, response, jqXHR, isSuccess ) {
|
|
var conv2, current, conv, tmp, prev,
|
|
converters = {},
|
|
// Work with a copy of dataTypes in case we need to modify it for conversion
|
|
dataTypes = s.dataTypes.slice();
|
|
|
|
// Create converters map with lowercased keys
|
|
if ( dataTypes[ 1 ] ) {
|
|
for ( conv in s.converters ) {
|
|
converters[ conv.toLowerCase() ] = s.converters[ conv ];
|
|
}
|
|
}
|
|
|
|
current = dataTypes.shift();
|
|
|
|
// Convert to each sequential dataType
|
|
while ( current ) {
|
|
|
|
if ( s.responseFields[ current ] ) {
|
|
jqXHR[ s.responseFields[ current ] ] = response;
|
|
}
|
|
|
|
// Apply the dataFilter if provided
|
|
if ( !prev && isSuccess && s.dataFilter ) {
|
|
response = s.dataFilter( response, s.dataType );
|
|
}
|
|
|
|
prev = current;
|
|
current = dataTypes.shift();
|
|
|
|
if ( current ) {
|
|
|
|
// There's only work to do if current dataType is non-auto
|
|
if ( current === "*" ) {
|
|
|
|
current = prev;
|
|
|
|
// Convert response if prev dataType is non-auto and differs from current
|
|
} else if ( prev !== "*" && prev !== current ) {
|
|
|
|
// Seek a direct converter
|
|
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
|
|
|
|
// If none found, seek a pair
|
|
if ( !conv ) {
|
|
for ( conv2 in converters ) {
|
|
|
|
// If conv2 outputs current
|
|
tmp = conv2.split( " " );
|
|
if ( tmp[ 1 ] === current ) {
|
|
|
|
// If prev can be converted to accepted input
|
|
conv = converters[ prev + " " + tmp[ 0 ] ] ||
|
|
converters[ "* " + tmp[ 0 ] ];
|
|
if ( conv ) {
|
|
// Condense equivalence converters
|
|
if ( conv === true ) {
|
|
conv = converters[ conv2 ];
|
|
|
|
// Otherwise, insert the intermediate dataType
|
|
} else if ( converters[ conv2 ] !== true ) {
|
|
current = tmp[ 0 ];
|
|
dataTypes.unshift( tmp[ 1 ] );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply converter (if not an equivalence)
|
|
if ( conv !== true ) {
|
|
|
|
// Unless errors are allowed to bubble, catch and return them
|
|
if ( conv && s[ "throws" ] ) {
|
|
response = conv( response );
|
|
} else {
|
|
try {
|
|
response = conv( response );
|
|
} catch ( e ) {
|
|
return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return { state: "success", data: response };
|
|
}
|
|
// Install script dataType
|
|
jQuery.ajaxSetup({
|
|
accepts: {
|
|
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
|
|
},
|
|
contents: {
|
|
script: /(?:java|ecma)script/
|
|
},
|
|
converters: {
|
|
"text script": function( text ) {
|
|
jQuery.globalEval( text );
|
|
return text;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle cache's special case and crossDomain
|
|
jQuery.ajaxPrefilter( "script", function( s ) {
|
|
if ( s.cache === undefined ) {
|
|
s.cache = false;
|
|
}
|
|
if ( s.crossDomain ) {
|
|
s.type = "GET";
|
|
}
|
|
});
|
|
|
|
// Bind script tag hack transport
|
|
jQuery.ajaxTransport( "script", function( s ) {
|
|
// This transport only deals with cross domain requests
|
|
if ( s.crossDomain ) {
|
|
var script, callback;
|
|
return {
|
|
send: function( _, complete ) {
|
|
script = jQuery("<script>").prop({
|
|
async: true,
|
|
charset: s.scriptCharset,
|
|
src: s.url
|
|
}).on(
|
|
"load error",
|
|
callback = function( evt ) {
|
|
script.remove();
|
|
callback = null;
|
|
if ( evt ) {
|
|
complete( evt.type === "error" ? 404 : 200, evt.type );
|
|
}
|
|
}
|
|
);
|
|
document.head.appendChild( script[ 0 ] );
|
|
},
|
|
abort: function() {
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|
|
var oldCallbacks = [],
|
|
rjsonp = /(=)\?(?=&|$)|\?\?/;
|
|
|
|
// Default jsonp settings
|
|
jQuery.ajaxSetup({
|
|
jsonp: "callback",
|
|
jsonpCallback: function() {
|
|
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
|
|
this[ callback ] = true;
|
|
return callback;
|
|
}
|
|
});
|
|
|
|
// Detect, normalize options and install callbacks for jsonp requests
|
|
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
|
|
|
|
var callbackName, overwritten, responseContainer,
|
|
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
|
|
"url" :
|
|
typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
|
|
);
|
|
|
|
// Handle iff the expected data type is "jsonp" or we have a parameter to set
|
|
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
|
|
|
|
// Get callback name, remembering preexisting value associated with it
|
|
callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
|
|
s.jsonpCallback() :
|
|
s.jsonpCallback;
|
|
|
|
// Insert callback into url or form data
|
|
if ( jsonProp ) {
|
|
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
|
|
} else if ( s.jsonp !== false ) {
|
|
s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
|
|
}
|
|
|
|
// Use data converter to retrieve json after script execution
|
|
s.converters["script json"] = function() {
|
|
if ( !responseContainer ) {
|
|
jQuery.error( callbackName + " was not called" );
|
|
}
|
|
return responseContainer[ 0 ];
|
|
};
|
|
|
|
// force json dataType
|
|
s.dataTypes[ 0 ] = "json";
|
|
|
|
// Install callback
|
|
overwritten = window[ callbackName ];
|
|
window[ callbackName ] = function() {
|
|
responseContainer = arguments;
|
|
};
|
|
|
|
// Clean-up function (fires after converters)
|
|
jqXHR.always(function() {
|
|
// Restore preexisting value
|
|
window[ callbackName ] = overwritten;
|
|
|
|
// Save back as free
|
|
if ( s[ callbackName ] ) {
|
|
// make sure that re-using the options doesn't screw things around
|
|
s.jsonpCallback = originalSettings.jsonpCallback;
|
|
|
|
// save the callback name for future use
|
|
oldCallbacks.push( callbackName );
|
|
}
|
|
|
|
// Call if it was a function and we have a response
|
|
if ( responseContainer && jQuery.isFunction( overwritten ) ) {
|
|
overwritten( responseContainer[ 0 ] );
|
|
}
|
|
|
|
responseContainer = overwritten = undefined;
|
|
});
|
|
|
|
// Delegate to script
|
|
return "script";
|
|
}
|
|
});
|
|
jQuery.ajaxSettings.xhr = function() {
|
|
try {
|
|
return new XMLHttpRequest();
|
|
} catch( e ) {}
|
|
};
|
|
|
|
var xhrSupported = jQuery.ajaxSettings.xhr(),
|
|
xhrSuccessStatus = {
|
|
// file protocol always yields status code 0, assume 200
|
|
0: 200,
|
|
// Support: IE9
|
|
// #1450: sometimes IE returns 1223 when it should be 204
|
|
1223: 204
|
|
},
|
|
// Support: IE9
|
|
// We need to keep track of outbound xhr and abort them manually
|
|
// because IE is not smart enough to do it all by itself
|
|
xhrId = 0,
|
|
xhrCallbacks = {};
|
|
|
|
if ( window.ActiveXObject ) {
|
|
jQuery( window ).on( "unload", function() {
|
|
for( var key in xhrCallbacks ) {
|
|
xhrCallbacks[ key ]();
|
|
}
|
|
xhrCallbacks = undefined;
|
|
});
|
|
}
|
|
|
|
jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
|
|
jQuery.support.ajax = xhrSupported = !!xhrSupported;
|
|
|
|
jQuery.ajaxTransport(function( options ) {
|
|
var callback;
|
|
// Cross domain only allowed if supported through XMLHttpRequest
|
|
if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
|
|
return {
|
|
send: function( headers, complete ) {
|
|
var i, id,
|
|
xhr = options.xhr();
|
|
xhr.open( options.type, options.url, options.async, options.username, options.password );
|
|
// Apply custom fields if provided
|
|
if ( options.xhrFields ) {
|
|
for ( i in options.xhrFields ) {
|
|
xhr[ i ] = options.xhrFields[ i ];
|
|
}
|
|
}
|
|
// Override mime type if needed
|
|
if ( options.mimeType && xhr.overrideMimeType ) {
|
|
xhr.overrideMimeType( options.mimeType );
|
|
}
|
|
// X-Requested-With header
|
|
// For cross-domain requests, seeing as conditions for a preflight are
|
|
// akin to a jigsaw puzzle, we simply never set it to be sure.
|
|
// (it can always be set on a per-request basis or even using ajaxSetup)
|
|
// For same-domain requests, won't change header if already provided.
|
|
if ( !options.crossDomain && !headers["X-Requested-With"] ) {
|
|
headers["X-Requested-With"] = "XMLHttpRequest";
|
|
}
|
|
// Set headers
|
|
for ( i in headers ) {
|
|
xhr.setRequestHeader( i, headers[ i ] );
|
|
}
|
|
// Callback
|
|
callback = function( type ) {
|
|
return function() {
|
|
if ( callback ) {
|
|
delete xhrCallbacks[ id ];
|
|
callback = xhr.onload = xhr.onerror = null;
|
|
if ( type === "abort" ) {
|
|
xhr.abort();
|
|
} else if ( type === "error" ) {
|
|
complete(
|
|
// file protocol always yields status 0, assume 404
|
|
xhr.status || 404,
|
|
xhr.statusText
|
|
);
|
|
} else {
|
|
complete(
|
|
xhrSuccessStatus[ xhr.status ] || xhr.status,
|
|
xhr.statusText,
|
|
// Support: IE9
|
|
// #11426: When requesting binary data, IE9 will throw an exception
|
|
// on any attempt to access responseText
|
|
typeof xhr.responseText === "string" ? {
|
|
text: xhr.responseText
|
|
} : undefined,
|
|
xhr.getAllResponseHeaders()
|
|
);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
// Listen to events
|
|
xhr.onload = callback();
|
|
xhr.onerror = callback("error");
|
|
// Create the abort callback
|
|
callback = xhrCallbacks[( id = xhrId++ )] = callback("abort");
|
|
// Do send the request
|
|
// This may raise an exception which is actually
|
|
// handled in jQuery.ajax (so no try/catch here)
|
|
xhr.send( options.hasContent && options.data || null );
|
|
},
|
|
abort: function() {
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|
|
var fxNow, timerId,
|
|
rfxtypes = /^(?:toggle|show|hide)$/,
|
|
rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
|
|
rrun = /queueHooks$/,
|
|
animationPrefilters = [ defaultPrefilter ],
|
|
tweeners = {
|
|
"*": [function( prop, value ) {
|
|
var end, unit,
|
|
tween = this.createTween( prop, value ),
|
|
parts = rfxnum.exec( value ),
|
|
target = tween.cur(),
|
|
start = +target || 0,
|
|
scale = 1,
|
|
maxIterations = 20;
|
|
|
|
if ( parts ) {
|
|
end = +parts[2];
|
|
unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
|
|
|
|
// We need to compute starting value
|
|
if ( unit !== "px" && start ) {
|
|
// Iteratively approximate from a nonzero starting point
|
|
// Prefer the current property, because this process will be trivial if it uses the same units
|
|
// Fallback to end or a simple constant
|
|
start = jQuery.css( tween.elem, prop, true ) || end || 1;
|
|
|
|
do {
|
|
// If previous iteration zeroed out, double until we get *something*
|
|
// Use a string for doubling factor so we don't accidentally see scale as unchanged below
|
|
scale = scale || ".5";
|
|
|
|
// Adjust and apply
|
|
start = start / scale;
|
|
jQuery.style( tween.elem, prop, start + unit );
|
|
|
|
// Update scale, tolerating zero or NaN from tween.cur()
|
|
// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
|
|
} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
|
|
}
|
|
|
|
tween.unit = unit;
|
|
tween.start = start;
|
|
// If a +=/-= token was provided, we're doing a relative animation
|
|
tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
|
|
}
|
|
return tween;
|
|
}]
|
|
};
|
|
|
|
// Animations created synchronously will run synchronously
|
|
function createFxNow() {
|
|
setTimeout(function() {
|
|
fxNow = undefined;
|
|
});
|
|
return ( fxNow = jQuery.now() );
|
|
}
|
|
|
|
function createTweens( animation, props ) {
|
|
jQuery.each( props, function( prop, value ) {
|
|
var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
|
|
index = 0,
|
|
length = collection.length;
|
|
for ( ; index < length; index++ ) {
|
|
if ( collection[ index ].call( animation, prop, value ) ) {
|
|
|
|
// we're done with this property
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function Animation( elem, properties, options ) {
|
|
var result,
|
|
stopped,
|
|
index = 0,
|
|
length = animationPrefilters.length,
|
|
deferred = jQuery.Deferred().always( function() {
|
|
// don't match elem in the :animated selector
|
|
delete tick.elem;
|
|
}),
|
|
tick = function() {
|
|
if ( stopped ) {
|
|
return false;
|
|
}
|
|
var currentTime = fxNow || createFxNow(),
|
|
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
|
|
// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
|
|
temp = remaining / animation.duration || 0,
|
|
percent = 1 - temp,
|
|
index = 0,
|
|
length = animation.tweens.length;
|
|
|
|
for ( ; index < length ; index++ ) {
|
|
animation.tweens[ index ].run( percent );
|
|
}
|
|
|
|
deferred.notifyWith( elem, [ animation, percent, remaining ]);
|
|
|
|
if ( percent < 1 && length ) {
|
|
return remaining;
|
|
} else {
|
|
deferred.resolveWith( elem, [ animation ] );
|
|
return false;
|
|
}
|
|
},
|
|
animation = deferred.promise({
|
|
elem: elem,
|
|
props: jQuery.extend( {}, properties ),
|
|
opts: jQuery.extend( true, { specialEasing: {} }, options ),
|
|
originalProperties: properties,
|
|
originalOptions: options,
|
|
startTime: fxNow || createFxNow(),
|
|
duration: options.duration,
|
|
tweens: [],
|
|
createTween: function( prop, end ) {
|
|
var tween = jQuery.Tween( elem, animation.opts, prop, end,
|
|
animation.opts.specialEasing[ prop ] || animation.opts.easing );
|
|
animation.tweens.push( tween );
|
|
return tween;
|
|
},
|
|
stop: function( gotoEnd ) {
|
|
var index = 0,
|
|
// if we are going to the end, we want to run all the tweens
|
|
// otherwise we skip this part
|
|
length = gotoEnd ? animation.tweens.length : 0;
|
|
if ( stopped ) {
|
|
return this;
|
|
}
|
|
stopped = true;
|
|
for ( ; index < length ; index++ ) {
|
|
animation.tweens[ index ].run( 1 );
|
|
}
|
|
|
|
// resolve when we played the last frame
|
|
// otherwise, reject
|
|
if ( gotoEnd ) {
|
|
deferred.resolveWith( elem, [ animation, gotoEnd ] );
|
|
} else {
|
|
deferred.rejectWith( elem, [ animation, gotoEnd ] );
|
|
}
|
|
return this;
|
|
}
|
|
}),
|
|
props = animation.props;
|
|
|
|
propFilter( props, animation.opts.specialEasing );
|
|
|
|
for ( ; index < length ; index++ ) {
|
|
result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
|
|
if ( result ) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
createTweens( animation, props );
|
|
|
|
if ( jQuery.isFunction( animation.opts.start ) ) {
|
|
animation.opts.start.call( elem, animation );
|
|
}
|
|
|
|
jQuery.fx.timer(
|
|
jQuery.extend( tick, {
|
|
elem: elem,
|
|
anim: animation,
|
|
queue: animation.opts.queue
|
|
})
|
|
);
|
|
|
|
// attach callbacks from options
|
|
return animation.progress( animation.opts.progress )
|
|
.done( animation.opts.done, animation.opts.complete )
|
|
.fail( animation.opts.fail )
|
|
.always( animation.opts.always );
|
|
}
|
|
|
|
function propFilter( props, specialEasing ) {
|
|
var index, name, easing, value, hooks;
|
|
|
|
// camelCase, specialEasing and expand cssHook pass
|
|
for ( index in props ) {
|
|
name = jQuery.camelCase( index );
|
|
easing = specialEasing[ name ];
|
|
value = props[ index ];
|
|
if ( jQuery.isArray( value ) ) {
|
|
easing = value[ 1 ];
|
|
value = props[ index ] = value[ 0 ];
|
|
}
|
|
|
|
if ( index !== name ) {
|
|
props[ name ] = value;
|
|
delete props[ index ];
|
|
}
|
|
|
|
hooks = jQuery.cssHooks[ name ];
|
|
if ( hooks && "expand" in hooks ) {
|
|
value = hooks.expand( value );
|
|
delete props[ name ];
|
|
|
|
// not quite $.extend, this wont overwrite keys already present.
|
|
// also - reusing 'index' from above because we have the correct "name"
|
|
for ( index in value ) {
|
|
if ( !( index in props ) ) {
|
|
props[ index ] = value[ index ];
|
|
specialEasing[ index ] = easing;
|
|
}
|
|
}
|
|
} else {
|
|
specialEasing[ name ] = easing;
|
|
}
|
|
}
|
|
}
|
|
|
|
jQuery.Animation = jQuery.extend( Animation, {
|
|
|
|
tweener: function( props, callback ) {
|
|
if ( jQuery.isFunction( props ) ) {
|
|
callback = props;
|
|
props = [ "*" ];
|
|
} else {
|
|
props = props.split(" ");
|
|
}
|
|
|
|
var prop,
|
|
index = 0,
|
|
length = props.length;
|
|
|
|
for ( ; index < length ; index++ ) {
|
|
prop = props[ index ];
|
|
tweeners[ prop ] = tweeners[ prop ] || [];
|
|
tweeners[ prop ].unshift( callback );
|
|
}
|
|
},
|
|
|
|
prefilter: function( callback, prepend ) {
|
|
if ( prepend ) {
|
|
animationPrefilters.unshift( callback );
|
|
} else {
|
|
animationPrefilters.push( callback );
|
|
}
|
|
}
|
|
});
|
|
|
|
function defaultPrefilter( elem, props, opts ) {
|
|
/* jshint validthis: true */
|
|
var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,
|
|
anim = this,
|
|
style = elem.style,
|
|
orig = {},
|
|
handled = [],
|
|
hidden = elem.nodeType && isHidden( elem );
|
|
|
|
// handle queue: false promises
|
|
if ( !opts.queue ) {
|
|
hooks = jQuery._queueHooks( elem, "fx" );
|
|
if ( hooks.unqueued == null ) {
|
|
hooks.unqueued = 0;
|
|
oldfire = hooks.empty.fire;
|
|
hooks.empty.fire = function() {
|
|
if ( !hooks.unqueued ) {
|
|
oldfire();
|
|
}
|
|
};
|
|
}
|
|
hooks.unqueued++;
|
|
|
|
anim.always(function() {
|
|
// doing this makes sure that the complete handler will be called
|
|
// before this completes
|
|
anim.always(function() {
|
|
hooks.unqueued--;
|
|
if ( !jQuery.queue( elem, "fx" ).length ) {
|
|
hooks.empty.fire();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// height/width overflow pass
|
|
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
|
|
// Make sure that nothing sneaks out
|
|
// Record all 3 overflow attributes because IE9-10 do not
|
|
// change the overflow attribute when overflowX and
|
|
// overflowY are set to the same value
|
|
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
|
|
|
|
// Set display property to inline-block for height/width
|
|
// animations on inline elements that are having width/height animated
|
|
if ( jQuery.css( elem, "display" ) === "inline" &&
|
|
jQuery.css( elem, "float" ) === "none" ) {
|
|
|
|
style.display = "inline-block";
|
|
}
|
|
}
|
|
|
|
if ( opts.overflow ) {
|
|
style.overflow = "hidden";
|
|
anim.always(function() {
|
|
style.overflow = opts.overflow[ 0 ];
|
|
style.overflowX = opts.overflow[ 1 ];
|
|
style.overflowY = opts.overflow[ 2 ];
|
|
});
|
|
}
|
|
|
|
|
|
// show/hide pass
|
|
dataShow = data_priv.get( elem, "fxshow" );
|
|
for ( index in props ) {
|
|
value = props[ index ];
|
|
if ( rfxtypes.exec( value ) ) {
|
|
delete props[ index ];
|
|
toggle = toggle || value === "toggle";
|
|
if ( value === ( hidden ? "hide" : "show" ) ) {
|
|
|
|
// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
|
|
if( value === "show" && dataShow !== undefined && dataShow[ index ] !== undefined ) {
|
|
hidden = true;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
handled.push( index );
|
|
}
|
|
}
|
|
|
|
length = handled.length;
|
|
if ( length ) {
|
|
dataShow = data_priv.get( elem, "fxshow" ) || data_priv.access( elem, "fxshow", {} );
|
|
if ( "hidden" in dataShow ) {
|
|
hidden = dataShow.hidden;
|
|
}
|
|
|
|
// store state if its toggle - enables .stop().toggle() to "reverse"
|
|
if ( toggle ) {
|
|
dataShow.hidden = !hidden;
|
|
}
|
|
if ( hidden ) {
|
|
jQuery( elem ).show();
|
|
} else {
|
|
anim.done(function() {
|
|
jQuery( elem ).hide();
|
|
});
|
|
}
|
|
anim.done(function() {
|
|
var prop;
|
|
|
|
data_priv.remove( elem, "fxshow" );
|
|
for ( prop in orig ) {
|
|
jQuery.style( elem, prop, orig[ prop ] );
|
|
}
|
|
});
|
|
for ( index = 0 ; index < length ; index++ ) {
|
|
prop = handled[ index ];
|
|
tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
|
|
orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
|
|
|
|
if ( !( prop in dataShow ) ) {
|
|
dataShow[ prop ] = tween.start;
|
|
if ( hidden ) {
|
|
tween.end = tween.start;
|
|
tween.start = prop === "width" || prop === "height" ? 1 : 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function Tween( elem, options, prop, end, easing ) {
|
|
return new Tween.prototype.init( elem, options, prop, end, easing );
|
|
}
|
|
jQuery.Tween = Tween;
|
|
|
|
Tween.prototype = {
|
|
constructor: Tween,
|
|
init: function( elem, options, prop, end, easing, unit ) {
|
|
this.elem = elem;
|
|
this.prop = prop;
|
|
this.easing = easing || "swing";
|
|
this.options = options;
|
|
this.start = this.now = this.cur();
|
|
this.end = end;
|
|
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
|
|
},
|
|
cur: function() {
|
|
var hooks = Tween.propHooks[ this.prop ];
|
|
|
|
return hooks && hooks.get ?
|
|
hooks.get( this ) :
|
|
Tween.propHooks._default.get( this );
|
|
},
|
|
run: function( percent ) {
|
|
var eased,
|
|
hooks = Tween.propHooks[ this.prop ];
|
|
|
|
if ( this.options.duration ) {
|
|
this.pos = eased = jQuery.easing[ this.easing ](
|
|
percent, this.options.duration * percent, 0, 1, this.options.duration
|
|
);
|
|
} else {
|
|
this.pos = eased = percent;
|
|
}
|
|
this.now = ( this.end - this.start ) * eased + this.start;
|
|
|
|
if ( this.options.step ) {
|
|
this.options.step.call( this.elem, this.now, this );
|
|
}
|
|
|
|
if ( hooks && hooks.set ) {
|
|
hooks.set( this );
|
|
} else {
|
|
Tween.propHooks._default.set( this );
|
|
}
|
|
return this;
|
|
}
|
|
};
|
|
|
|
Tween.prototype.init.prototype = Tween.prototype;
|
|
|
|
Tween.propHooks = {
|
|
_default: {
|
|
get: function( tween ) {
|
|
var result;
|
|
|
|
if ( tween.elem[ tween.prop ] != null &&
|
|
(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
|
|
return tween.elem[ tween.prop ];
|
|
}
|
|
|
|
// passing an empty string as a 3rd parameter to .css will automatically
|
|
// attempt a parseFloat and fallback to a string if the parse fails
|
|
// so, simple values such as "10px" are parsed to Float.
|
|
// complex values such as "rotate(1rad)" are returned as is.
|
|
result = jQuery.css( tween.elem, tween.prop, "" );
|
|
// Empty strings, null, undefined and "auto" are converted to 0.
|
|
return !result || result === "auto" ? 0 : result;
|
|
},
|
|
set: function( tween ) {
|
|
// use step hook for back compat - use cssHook if its there - use .style if its
|
|
// available and use plain properties where available
|
|
if ( jQuery.fx.step[ tween.prop ] ) {
|
|
jQuery.fx.step[ tween.prop ]( tween );
|
|
} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
|
|
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
|
|
} else {
|
|
tween.elem[ tween.prop ] = tween.now;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Support: IE9
|
|
// Panic based approach to setting things on disconnected nodes
|
|
|
|
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
|
|
set: function( tween ) {
|
|
if ( tween.elem.nodeType && tween.elem.parentNode ) {
|
|
tween.elem[ tween.prop ] = tween.now;
|
|
}
|
|
}
|
|
};
|
|
|
|
jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
|
|
var cssFn = jQuery.fn[ name ];
|
|
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
|
return speed == null || typeof speed === "boolean" ?
|
|
cssFn.apply( this, arguments ) :
|
|
this.animate( genFx( name, true ), speed, easing, callback );
|
|
};
|
|
});
|
|
|
|
jQuery.fn.extend({
|
|
fadeTo: function( speed, to, easing, callback ) {
|
|
|
|
// show any hidden elements after setting opacity to 0
|
|
return this.filter( isHidden ).css( "opacity", 0 ).show()
|
|
|
|
// animate to the value specified
|
|
.end().animate({ opacity: to }, speed, easing, callback );
|
|
},
|
|
animate: function( prop, speed, easing, callback ) {
|
|
var empty = jQuery.isEmptyObject( prop ),
|
|
optall = jQuery.speed( speed, easing, callback ),
|
|
doAnimation = function() {
|
|
// Operate on a copy of prop so per-property easing won't be lost
|
|
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
|
|
doAnimation.finish = function() {
|
|
anim.stop( true );
|
|
};
|
|
// Empty animations, or finishing resolves immediately
|
|
if ( empty || data_priv.get( this, "finish" ) ) {
|
|
anim.stop( true );
|
|
}
|
|
};
|
|
doAnimation.finish = doAnimation;
|
|
|
|
return empty || optall.queue === false ?
|
|
this.each( doAnimation ) :
|
|
this.queue( optall.queue, doAnimation );
|
|
},
|
|
stop: function( type, clearQueue, gotoEnd ) {
|
|
var stopQueue = function( hooks ) {
|
|
var stop = hooks.stop;
|
|
delete hooks.stop;
|
|
stop( gotoEnd );
|
|
};
|
|
|
|
if ( typeof type !== "string" ) {
|
|
gotoEnd = clearQueue;
|
|
clearQueue = type;
|
|
type = undefined;
|
|
}
|
|
if ( clearQueue && type !== false ) {
|
|
this.queue( type || "fx", [] );
|
|
}
|
|
|
|
return this.each(function() {
|
|
var dequeue = true,
|
|
index = type != null && type + "queueHooks",
|
|
timers = jQuery.timers,
|
|
data = data_priv.get( this );
|
|
|
|
if ( index ) {
|
|
if ( data[ index ] && data[ index ].stop ) {
|
|
stopQueue( data[ index ] );
|
|
}
|
|
} else {
|
|
for ( index in data ) {
|
|
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
|
|
stopQueue( data[ index ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( index = timers.length; index--; ) {
|
|
if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
|
|
timers[ index ].anim.stop( gotoEnd );
|
|
dequeue = false;
|
|
timers.splice( index, 1 );
|
|
}
|
|
}
|
|
|
|
// start the next in the queue if the last step wasn't forced
|
|
// timers currently will call their complete callbacks, which will dequeue
|
|
// but only if they were gotoEnd
|
|
if ( dequeue || !gotoEnd ) {
|
|
jQuery.dequeue( this, type );
|
|
}
|
|
});
|
|
},
|
|
finish: function( type ) {
|
|
if ( type !== false ) {
|
|
type = type || "fx";
|
|
}
|
|
return this.each(function() {
|
|
var index,
|
|
data = data_priv.get( this ),
|
|
queue = data[ type + "queue" ],
|
|
hooks = data[ type + "queueHooks" ],
|
|
timers = jQuery.timers,
|
|
length = queue ? queue.length : 0;
|
|
|
|
// enable finishing flag on private data
|
|
data.finish = true;
|
|
|
|
// empty the queue first
|
|
jQuery.queue( this, type, [] );
|
|
|
|
if ( hooks && hooks.cur && hooks.cur.finish ) {
|
|
hooks.cur.finish.call( this );
|
|
}
|
|
|
|
// look for any active animations, and finish them
|
|
for ( index = timers.length; index--; ) {
|
|
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
|
|
timers[ index ].anim.stop( true );
|
|
timers.splice( index, 1 );
|
|
}
|
|
}
|
|
|
|
// look for any animations in the old queue and finish them
|
|
for ( index = 0; index < length; index++ ) {
|
|
if ( queue[ index ] && queue[ index ].finish ) {
|
|
queue[ index ].finish.call( this );
|
|
}
|
|
}
|
|
|
|
// turn off finishing flag
|
|
delete data.finish;
|
|
});
|
|
}
|
|
});
|
|
|
|
// Generate parameters to create a standard animation
|
|
function genFx( type, includeWidth ) {
|
|
var which,
|
|
attrs = { height: type },
|
|
i = 0;
|
|
|
|
// if we include width, step value is 1 to do all cssExpand values,
|
|
// if we don't include width, step value is 2 to skip over Left and Right
|
|
includeWidth = includeWidth? 1 : 0;
|
|
for( ; i < 4 ; i += 2 - includeWidth ) {
|
|
which = cssExpand[ i ];
|
|
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
|
|
}
|
|
|
|
if ( includeWidth ) {
|
|
attrs.opacity = attrs.width = type;
|
|
}
|
|
|
|
return attrs;
|
|
}
|
|
|
|
// Generate shortcuts for custom animations
|
|
jQuery.each({
|
|
slideDown: genFx("show"),
|
|
slideUp: genFx("hide"),
|
|
slideToggle: genFx("toggle"),
|
|
fadeIn: { opacity: "show" },
|
|
fadeOut: { opacity: "hide" },
|
|
fadeToggle: { opacity: "toggle" }
|
|
}, function( name, props ) {
|
|
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
|
return this.animate( props, speed, easing, callback );
|
|
};
|
|
});
|
|
|
|
jQuery.speed = function( speed, easing, fn ) {
|
|
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
|
|
complete: fn || !fn && easing ||
|
|
jQuery.isFunction( speed ) && speed,
|
|
duration: speed,
|
|
easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
|
|
};
|
|
|
|
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
|
|
opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
|
|
|
|
// normalize opt.queue - true/undefined/null -> "fx"
|
|
if ( opt.queue == null || opt.queue === true ) {
|
|
opt.queue = "fx";
|
|
}
|
|
|
|
// Queueing
|
|
opt.old = opt.complete;
|
|
|
|
opt.complete = function() {
|
|
if ( jQuery.isFunction( opt.old ) ) {
|
|
opt.old.call( this );
|
|
}
|
|
|
|
if ( opt.queue ) {
|
|
jQuery.dequeue( this, opt.queue );
|
|
}
|
|
};
|
|
|
|
return opt;
|
|
};
|
|
|
|
jQuery.easing = {
|
|
linear: function( p ) {
|
|
return p;
|
|
},
|
|
swing: function( p ) {
|
|
return 0.5 - Math.cos( p*Math.PI ) / 2;
|
|
}
|
|
};
|
|
|
|
jQuery.timers = [];
|
|
jQuery.fx = Tween.prototype.init;
|
|
jQuery.fx.tick = function() {
|
|
var timer,
|
|
timers = jQuery.timers,
|
|
i = 0;
|
|
|
|
fxNow = jQuery.now();
|
|
|
|
for ( ; i < timers.length; i++ ) {
|
|
timer = timers[ i ];
|
|
// Checks the timer has not already been removed
|
|
if ( !timer() && timers[ i ] === timer ) {
|
|
timers.splice( i--, 1 );
|
|
}
|
|
}
|
|
|
|
if ( !timers.length ) {
|
|
jQuery.fx.stop();
|
|
}
|
|
fxNow = undefined;
|
|
};
|
|
|
|
jQuery.fx.timer = function( timer ) {
|
|
if ( timer() && jQuery.timers.push( timer ) ) {
|
|
jQuery.fx.start();
|
|
}
|
|
};
|
|
|
|
jQuery.fx.interval = 13;
|
|
|
|
jQuery.fx.start = function() {
|
|
if ( !timerId ) {
|
|
timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
|
|
}
|
|
};
|
|
|
|
jQuery.fx.stop = function() {
|
|
clearInterval( timerId );
|
|
timerId = null;
|
|
};
|
|
|
|
jQuery.fx.speeds = {
|
|
slow: 600,
|
|
fast: 200,
|
|
// Default speed
|
|
_default: 400
|
|
};
|
|
|
|
// Back Compat <1.8 extension point
|
|
jQuery.fx.step = {};
|
|
|
|
if ( jQuery.expr && jQuery.expr.filters ) {
|
|
jQuery.expr.filters.animated = function( elem ) {
|
|
return jQuery.grep(jQuery.timers, function( fn ) {
|
|
return elem === fn.elem;
|
|
}).length;
|
|
};
|
|
}
|
|
jQuery.fn.offset = function( options ) {
|
|
if ( arguments.length ) {
|
|
return options === undefined ?
|
|
this :
|
|
this.each(function( i ) {
|
|
jQuery.offset.setOffset( this, options, i );
|
|
});
|
|
}
|
|
|
|
var docElem, win,
|
|
elem = this[ 0 ],
|
|
box = { top: 0, left: 0 },
|
|
doc = elem && elem.ownerDocument;
|
|
|
|
if ( !doc ) {
|
|
return;
|
|
}
|
|
|
|
docElem = doc.documentElement;
|
|
|
|
// Make sure it's not a disconnected DOM node
|
|
if ( !jQuery.contains( docElem, elem ) ) {
|
|
return box;
|
|
}
|
|
|
|
// If we don't have gBCR, just use 0,0 rather than error
|
|
// BlackBerry 5, iOS 3 (original iPhone)
|
|
if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
|
|
box = elem.getBoundingClientRect();
|
|
}
|
|
win = getWindow( doc );
|
|
return {
|
|
top: box.top + win.pageYOffset - docElem.clientTop,
|
|
left: box.left + win.pageXOffset - docElem.clientLeft
|
|
};
|
|
};
|
|
|
|
jQuery.offset = {
|
|
|
|
setOffset: function( elem, options, i ) {
|
|
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
|
|
position = jQuery.css( elem, "position" ),
|
|
curElem = jQuery( elem ),
|
|
props = {};
|
|
|
|
// Set position first, in-case top/left are set even on static elem
|
|
if ( position === "static" ) {
|
|
elem.style.position = "relative";
|
|
}
|
|
|
|
curOffset = curElem.offset();
|
|
curCSSTop = jQuery.css( elem, "top" );
|
|
curCSSLeft = jQuery.css( elem, "left" );
|
|
calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
|
|
|
|
// Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
|
|
if ( calculatePosition ) {
|
|
curPosition = curElem.position();
|
|
curTop = curPosition.top;
|
|
curLeft = curPosition.left;
|
|
|
|
} else {
|
|
curTop = parseFloat( curCSSTop ) || 0;
|
|
curLeft = parseFloat( curCSSLeft ) || 0;
|
|
}
|
|
|
|
if ( jQuery.isFunction( options ) ) {
|
|
options = options.call( elem, i, curOffset );
|
|
}
|
|
|
|
if ( options.top != null ) {
|
|
props.top = ( options.top - curOffset.top ) + curTop;
|
|
}
|
|
if ( options.left != null ) {
|
|
props.left = ( options.left - curOffset.left ) + curLeft;
|
|
}
|
|
|
|
if ( "using" in options ) {
|
|
options.using.call( elem, props );
|
|
|
|
} else {
|
|
curElem.css( props );
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
jQuery.fn.extend({
|
|
|
|
position: function() {
|
|
if ( !this[ 0 ] ) {
|
|
return;
|
|
}
|
|
|
|
var offsetParent, offset,
|
|
elem = this[ 0 ],
|
|
parentOffset = { top: 0, left: 0 };
|
|
|
|
// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
|
|
if ( jQuery.css( elem, "position" ) === "fixed" ) {
|
|
// We assume that getBoundingClientRect is available when computed position is fixed
|
|
offset = elem.getBoundingClientRect();
|
|
|
|
} else {
|
|
// Get *real* offsetParent
|
|
offsetParent = this.offsetParent();
|
|
|
|
// Get correct offsets
|
|
offset = this.offset();
|
|
if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
|
|
parentOffset = offsetParent.offset();
|
|
}
|
|
|
|
// Add offsetParent borders
|
|
parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
|
|
parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
|
|
}
|
|
|
|
// Subtract parent offsets and element margins
|
|
return {
|
|
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
|
|
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
|
|
};
|
|
},
|
|
|
|
offsetParent: function() {
|
|
return this.map(function() {
|
|
var offsetParent = this.offsetParent || docElem;
|
|
|
|
while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
|
|
offsetParent = offsetParent.offsetParent;
|
|
}
|
|
|
|
return offsetParent || docElem;
|
|
});
|
|
}
|
|
});
|
|
|
|
|
|
// Create scrollLeft and scrollTop methods
|
|
jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
|
|
var top = "pageYOffset" === prop;
|
|
|
|
jQuery.fn[ method ] = function( val ) {
|
|
return jQuery.access( this, function( elem, method, val ) {
|
|
var win = getWindow( elem );
|
|
|
|
if ( val === undefined ) {
|
|
return win ? win[ prop ] : elem[ method ];
|
|
}
|
|
|
|
if ( win ) {
|
|
win.scrollTo(
|
|
!top ? val : window.pageXOffset,
|
|
top ? val : window.pageYOffset
|
|
);
|
|
|
|
} else {
|
|
elem[ method ] = val;
|
|
}
|
|
}, method, val, arguments.length, null );
|
|
};
|
|
});
|
|
|
|
function getWindow( elem ) {
|
|
return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
|
|
}
|
|
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
|
|
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
|
|
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
|
|
// margin is only for outerHeight, outerWidth
|
|
jQuery.fn[ funcName ] = function( margin, value ) {
|
|
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
|
|
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
|
|
|
|
return jQuery.access( this, function( elem, type, value ) {
|
|
var doc;
|
|
|
|
if ( jQuery.isWindow( elem ) ) {
|
|
// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
|
|
// isn't a whole lot we can do. See pull request at this URL for discussion:
|
|
// https://github.com/jquery/jquery/pull/764
|
|
return elem.document.documentElement[ "client" + name ];
|
|
}
|
|
|
|
// Get document width or height
|
|
if ( elem.nodeType === 9 ) {
|
|
doc = elem.documentElement;
|
|
|
|
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
|
|
// whichever is greatest
|
|
return Math.max(
|
|
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
|
|
elem.body[ "offset" + name ], doc[ "offset" + name ],
|
|
doc[ "client" + name ]
|
|
);
|
|
}
|
|
|
|
return value === undefined ?
|
|
// Get width or height on the element, requesting but not forcing parseFloat
|
|
jQuery.css( elem, type, extra ) :
|
|
|
|
// Set width or height on the element
|
|
jQuery.style( elem, type, value, extra );
|
|
}, type, chainable ? margin : undefined, chainable, null );
|
|
};
|
|
});
|
|
});
|
|
// Limit scope pollution from any deprecated API
|
|
// (function() {
|
|
|
|
// The number of elements contained in the matched element set
|
|
jQuery.fn.size = function() {
|
|
return this.length;
|
|
};
|
|
|
|
jQuery.fn.andSelf = jQuery.fn.addBack;
|
|
|
|
// })();
|
|
if ( typeof module === "object" && typeof module.exports === "object" ) {
|
|
// Expose jQuery as module.exports in loaders that implement the Node
|
|
// module pattern (including browserify). Do not create the global, since
|
|
// the user will be storing it themselves locally, and globals are frowned
|
|
// upon in the Node module world.
|
|
module.exports = jQuery;
|
|
} else {
|
|
// Register as a named AMD module, since jQuery can be concatenated with other
|
|
// files that may use define, but not via a proper concatenation script that
|
|
// understands anonymous AMD modules. A named AMD is safest and most robust
|
|
// way to register. Lowercase jquery is used because AMD module names are
|
|
// derived from file names, and jQuery is normally delivered in a lowercase
|
|
// file name. Do this after creating the global so that if an AMD module wants
|
|
// to call noConflict to hide this version of jQuery, it will work.
|
|
if ( typeof define === "function" && define.amd ) {
|
|
define( "jquery", [], function () { return jQuery; } );
|
|
}
|
|
}
|
|
|
|
// If there is a window object, that at least has a document property,
|
|
// define jQuery and $ identifiers
|
|
if ( typeof window === "object" && typeof window.document === "object" ) {
|
|
window.jQuery = window.$ = jQuery;
|
|
}
|
|
|
|
})( window );
|
|
|
|
(function(e){if("function"==typeof bootstrap)bootstrap("xmpp",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeXMPP=e}else"undefined"!=typeof window?window.XMPP=e():global.XMPP=e()})(function(){var define,ses,bootstrap,module,exports;
|
|
return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
|
|
exports.Message = require('./lib/stanza/message');
|
|
exports.Presence = require('./lib/stanza/presence');
|
|
exports.Iq = require('./lib/stanza/iq');
|
|
|
|
exports.Client = require('./lib/client');
|
|
exports.crypto = require('crypto');
|
|
|
|
exports.createClient = function (opts) {
|
|
var client = new exports.Client(opts);
|
|
|
|
client.use(require('./lib/plugins/disco'));
|
|
client.use(require('./lib/plugins/chatstates'));
|
|
client.use(require('./lib/plugins/delayed'));
|
|
client.use(require('./lib/plugins/forwarding'));
|
|
client.use(require('./lib/plugins/carbons'));
|
|
client.use(require('./lib/plugins/time'));
|
|
client.use(require('./lib/plugins/mam'));
|
|
client.use(require('./lib/plugins/receipts'));
|
|
client.use(require('./lib/plugins/idle'));
|
|
client.use(require('./lib/plugins/correction'));
|
|
client.use(require('./lib/plugins/attention'));
|
|
client.use(require('./lib/plugins/version'));
|
|
client.use(require('./lib/plugins/invisible'));
|
|
client.use(require('./lib/plugins/muc'));
|
|
client.use(require('./lib/plugins/webrtc'));
|
|
client.use(require('./lib/plugins/pubsub'));
|
|
client.use(require('./lib/plugins/avatar'));
|
|
|
|
return client;
|
|
};
|
|
|
|
},{"./lib/client":2,"./lib/plugins/attention":3,"./lib/plugins/avatar":4,"./lib/plugins/carbons":5,"./lib/plugins/chatstates":6,"./lib/plugins/correction":7,"./lib/plugins/delayed":8,"./lib/plugins/disco":9,"./lib/plugins/forwarding":10,"./lib/plugins/idle":11,"./lib/plugins/invisible":12,"./lib/plugins/mam":13,"./lib/plugins/muc":14,"./lib/plugins/pubsub":15,"./lib/plugins/receipts":16,"./lib/plugins/time":17,"./lib/plugins/version":18,"./lib/plugins/webrtc":19,"./lib/stanza/iq":33,"./lib/stanza/message":35,"./lib/stanza/presence":37,"crypto":60}],2:[function(require,module,exports){
|
|
var WildEmitter = require('wildemitter');
|
|
var _ = require('../vendor/lodash');
|
|
var async = require('async');
|
|
var uuid = require('node-uuid');
|
|
var SASL = require('./stanza/sasl');
|
|
var Message = require('./stanza/message');
|
|
var Presence = require('./stanza/presence');
|
|
var Iq = require('./stanza/iq');
|
|
var WSConnection = require('./websocket');
|
|
var getHostMeta = require('hostmeta');
|
|
var SASLFactory = require('saslmechanisms');
|
|
|
|
SASLFactory = new SASLFactory();
|
|
SASLFactory.use(require('sasl-external'));
|
|
SASLFactory.use(require('sasl-scram-sha-1'));
|
|
SASLFactory.use(require('sasl-digest-md5'));
|
|
SASLFactory.use(require('sasl-plain'));
|
|
SASLFactory.use(require('sasl-anonymous'));
|
|
|
|
|
|
// Ensure that all basic stanza relationships are established
|
|
require('./stanza/stream');
|
|
require('./stanza/sm');
|
|
require('./stanza/roster');
|
|
require('./stanza/error');
|
|
require('./stanza/streamError');
|
|
require('./stanza/streamFeatures');
|
|
require('./stanza/bind');
|
|
require('./stanza/session');
|
|
|
|
|
|
function Client(opts) {
|
|
var self = this;
|
|
|
|
WildEmitter.call(this);
|
|
|
|
this.config = opts || {};
|
|
this._idPrefix = uuid.v4();
|
|
this._idCount = 0;
|
|
|
|
this.negotiatedFeatures = {};
|
|
this.featureOrder = [
|
|
'sasl',
|
|
'streamManagement',
|
|
'bind',
|
|
'streamManagement',
|
|
'session'
|
|
];
|
|
this.features = {};
|
|
|
|
this.conn = new WSConnection();
|
|
this.conn.on('*', function (eventName, data) {
|
|
self.emit(eventName, data);
|
|
});
|
|
|
|
this.on('streamFeatures', function (features) {
|
|
var series = [function (cb) { cb(null, features); }];
|
|
var seriesNames = ['setup'];
|
|
|
|
self.featureOrder.forEach(function (name) {
|
|
if (features._extensions[name] && !self.negotiatedFeatures[name]) {
|
|
series.push(function (features, cb) {
|
|
if (!self.negotiatedFeatures[name] && self.features[name]) {
|
|
self.features[name](features, cb);
|
|
} else {
|
|
cb(null, features);
|
|
}
|
|
});
|
|
seriesNames.push(name);
|
|
}
|
|
});
|
|
|
|
async.waterfall(series, function (cmd) {
|
|
if (cmd === 'restart') {
|
|
self.conn.restart();
|
|
} else if (cmd === 'disconnect') {
|
|
self.disconnect();
|
|
}
|
|
});
|
|
});
|
|
|
|
this.features.sasl = function (features, cb) {
|
|
var mech = SASLFactory.create(features.sasl.mechanisms);
|
|
|
|
self.on('sasl:success', 'sasl', function () {
|
|
self.negotiatedFeatures.sasl = true;
|
|
self.releaseGroup('sasl');
|
|
self.emit('auth:success');
|
|
cb('restart');
|
|
});
|
|
self.on('sasl:challenge', 'sasl', function (challenge) {
|
|
mech.challenge(challenge.value);
|
|
self.send(new SASL.Response({
|
|
value: mech.response(self.getCredentials())
|
|
}));
|
|
cb();
|
|
});
|
|
self.on('sasl:failure', 'sasl', function () {
|
|
self.releaseGroup('sasl');
|
|
self.emit('auth:failed');
|
|
cb('disconnect');
|
|
});
|
|
self.on('sasl:abort', 'sasl', function () {
|
|
self.releaseGroup('sasl');
|
|
self.emit('auth:failed');
|
|
cb('disconnect');
|
|
});
|
|
|
|
var auth = {
|
|
mechanism: mech.name
|
|
};
|
|
|
|
if (mech.clientFirst) {
|
|
auth.value = mech.response(self.getCredentials());
|
|
}
|
|
self.send(new SASL.Auth(auth));
|
|
};
|
|
|
|
this.features.bind = function (features, cb) {
|
|
self.sendIq({
|
|
type: 'set',
|
|
bind: {
|
|
resource: self.config.resource
|
|
}
|
|
}, function (err, resp) {
|
|
self.negotiatedFeatures.bind = true;
|
|
self.emit('session:bound', resp.bind.jid);
|
|
self.jid = resp.bind.jid;
|
|
if (!features._extensions.session) {
|
|
self.sessionStarted = true;
|
|
self.emit('session:started', resp.bind.jid);
|
|
}
|
|
cb(null, features);
|
|
});
|
|
};
|
|
|
|
this.features.session = function (features, cb) {
|
|
self.sendIq({
|
|
type: 'set',
|
|
session: {}
|
|
}, function () {
|
|
self.negotiatedFeatures.session = true;
|
|
self.sessionStarted = true;
|
|
self.emit('session:started', self.jid);
|
|
cb(null, features);
|
|
});
|
|
};
|
|
|
|
this.features.streamManagement = function (features, cb) {
|
|
self.on('stream:management:enabled', 'sm', function (enabled) {
|
|
self.conn.sm.enabled(enabled);
|
|
self.negotiatedFeatures.streamManagement = true;
|
|
|
|
self.on('stream:management:ack', 'connection', function (ack) {
|
|
self.conn.sm.process(ack);
|
|
});
|
|
|
|
self.on('stream:management:request', 'connection', function (request) {
|
|
self.conn.sm.ack();
|
|
});
|
|
|
|
self.releaseGroup('sm');
|
|
cb(null, features);
|
|
});
|
|
|
|
self.on('stream:management:resumed', 'sm', function (resumed) {
|
|
self.conn.sm.enabled(resumed);
|
|
self.negotiatedFeatures.streamManagement = true;
|
|
self.negotiatedFeatures.bind = true;
|
|
self.sessionStarted = true;
|
|
|
|
self.on('stream:management:ack', 'connection', function (ack) {
|
|
self.conn.sm.process(ack);
|
|
});
|
|
|
|
self.on('stream:management:request', 'connection', function (request) {
|
|
self.conn.sm.ack();
|
|
});
|
|
|
|
self.releaseGroup('sm');
|
|
cb(null, features);
|
|
});
|
|
|
|
self.on('stream:management:failed', 'sm', function (failed) {
|
|
self.conn.sm.failed();
|
|
self.emit('session:end');
|
|
self.releaseGroup('session');
|
|
self.releaseGroup('sm');
|
|
cb(null, features);
|
|
});
|
|
|
|
|
|
if (!self.conn.sm.id) {
|
|
if (self.negotiatedFeatures.bind) {
|
|
self.conn.sm.enable();
|
|
} else {
|
|
cb(null, features);
|
|
}
|
|
} else if (self.conn.sm.id && self.conn.sm.allowResume) {
|
|
self.conn.sm.resume();
|
|
} else {
|
|
cb(null, features);
|
|
}
|
|
};
|
|
|
|
this.on('disconnected', function () {
|
|
self.sessionStarted = false;
|
|
self.negotiatedFeatures.sasl = false;
|
|
self.negotiatedFeatures.streamManagement = false;
|
|
self.negotiatedFeatures.bind = false;
|
|
self.releaseGroup('connection');
|
|
});
|
|
|
|
this.on('iq:set:roster', function (iq) {
|
|
self.emit('roster:update', iq);
|
|
self.sendIq({
|
|
id: iq.id,
|
|
type: 'result'
|
|
});
|
|
});
|
|
|
|
this.on('iq', function (iq) {
|
|
var iqType = iq.type;
|
|
var exts = Object.keys(iq._extensions);
|
|
var children = iq.xml.childNodes;
|
|
|
|
var childCount = 0;
|
|
_.each(children, function (child) {
|
|
if (child.nodeType === 1) {
|
|
childCount += 1;
|
|
}
|
|
});
|
|
|
|
if (iq.type === 'get' || iq.type === 'set') {
|
|
// Invalid request
|
|
if (childCount != 1) {
|
|
return self.sendIq({
|
|
id: iq.id,
|
|
type: 'error',
|
|
error: {
|
|
type: 'modify',
|
|
condition: 'bad-request'
|
|
}
|
|
});
|
|
}
|
|
|
|
// Valid request, but we don't have support for the
|
|
// payload data.
|
|
if (!exts.length) {
|
|
return self.sendIq({
|
|
id: iq.id,
|
|
type: 'error',
|
|
error: {
|
|
type: 'cancel',
|
|
condition: 'feature-not-implemented'
|
|
}
|
|
});
|
|
}
|
|
|
|
var iqEvent = 'iq:' + iqType + ':' + exts[0];
|
|
if (self.callbacks[iqEvent]) {
|
|
self.emit(iqEvent, iq);
|
|
} else {
|
|
// We support the payload data, but there's
|
|
// nothing registered to handle it.
|
|
self.sendIq({
|
|
id: iq.id,
|
|
type: 'error',
|
|
error: {
|
|
type: 'cancel',
|
|
condition: 'feature-not-implemented'
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
this.on('message', function (msg) {
|
|
if (Object.keys(msg.$body).length) {
|
|
if (msg.type === 'chat' || msg.type === 'normal') {
|
|
self.emit('chat', msg);
|
|
} else if (msg.type === 'groupchat') {
|
|
self.emit('groupchat', msg);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.on('presence', function (pres) {
|
|
var presType = pres.type || 'available';
|
|
self.emit(presType, pres);
|
|
});
|
|
}
|
|
|
|
Client.prototype = Object.create(WildEmitter.prototype, {
|
|
constructor: {
|
|
value: Client
|
|
}
|
|
});
|
|
|
|
Client.prototype.__defineGetter__('stream', function () {
|
|
return this.conn ? this.conn.stream : undefined;
|
|
});
|
|
|
|
Client.prototype.use = function (pluginInit) {
|
|
pluginInit(this);
|
|
};
|
|
|
|
Client.prototype.nextId = function () {
|
|
return this._idPrefix + '-' + (this._idCount++).toString(16);
|
|
};
|
|
|
|
Client.prototype.discoverBindings = function (server, cb) {
|
|
getHostMeta(server, function (err, data) {
|
|
if (err) return cb(err, []);
|
|
|
|
var results = [];
|
|
var links = data.links || [];
|
|
|
|
links.forEach(function (link) {
|
|
if (link.href && link.rel === 'urn:xmpp:altconnect:websocket') {
|
|
results.push(link.href);
|
|
}
|
|
});
|
|
|
|
cb(false, results);
|
|
});
|
|
};
|
|
|
|
Client.prototype.getCredentials = function () {
|
|
var creds = this.config.credentials || {};
|
|
var requestedJID = this.config.jid;
|
|
|
|
var username = creds.username || requestedJID.slice(0, requestedJID.indexOf('@'));
|
|
var server = creds.server || requestedJID.slice(requestedJID.indexOf('@') + 1);
|
|
|
|
var defaultCreds = {
|
|
username: username,
|
|
password: this.config.password,
|
|
server: server,
|
|
host: server,
|
|
realm: server,
|
|
serviceType: 'xmpp',
|
|
serviceName: server
|
|
};
|
|
|
|
return _.extend(defaultCreds, creds);
|
|
};
|
|
|
|
Client.prototype.connect = function (opts) {
|
|
var self = this;
|
|
|
|
_.extend(self.config, opts || {});
|
|
|
|
if (self.config.wsURL) {
|
|
return self.conn.connect(self.config);
|
|
}
|
|
|
|
self.discoverBindings(self.config.server, function (err, endpoints) {
|
|
if (!err && endpoints.length) {
|
|
self.config.wsURL = endpoints[0];
|
|
self.conn.connect(self.config);
|
|
} else {
|
|
self.disconnect();
|
|
}
|
|
});
|
|
};
|
|
|
|
Client.prototype.disconnect = function () {
|
|
if (this.sessionStarted) {
|
|
this.emit('session:end');
|
|
this.releaseGroup('session');
|
|
}
|
|
this.sessionStarted = false;
|
|
this.releaseGroup('connection');
|
|
if (this.conn) {
|
|
this.conn.disconnect();
|
|
}
|
|
};
|
|
|
|
Client.prototype.send = function (data) {
|
|
this.conn.send(data);
|
|
};
|
|
|
|
Client.prototype.sendMessage = function (data) {
|
|
data = data || {};
|
|
if (!data.id) {
|
|
data.id = this.nextId();
|
|
}
|
|
var message = new Message(data);
|
|
|
|
this.emit('message:sent', message);
|
|
this.send(message);
|
|
};
|
|
|
|
Client.prototype.sendPresence = function (data) {
|
|
data = data || {};
|
|
if (!data.id) {
|
|
data.id = this.nextId();
|
|
}
|
|
this.send(new Presence(data));
|
|
};
|
|
|
|
Client.prototype.sendIq = function (data, cb) {
|
|
data = data || {};
|
|
cb = cb || function () {};
|
|
if (!data.id) {
|
|
data.id = this.nextId();
|
|
}
|
|
if (data.type === 'get' || data.type === 'set') {
|
|
this.once('id:' + data.id, 'session', function (resp) {
|
|
if (resp._extensions.error) {
|
|
cb(resp, null);
|
|
} else {
|
|
cb(null, resp);
|
|
}
|
|
});
|
|
}
|
|
this.send(new Iq(data));
|
|
};
|
|
|
|
Client.prototype.getRoster = function (cb) {
|
|
var self = this;
|
|
cb = cb || function () {};
|
|
|
|
this.sendIq({
|
|
type: 'get',
|
|
roster: {
|
|
ver: self.config.rosterVer
|
|
}
|
|
}, function (err, resp) {
|
|
if (err) {
|
|
return cb(err);
|
|
}
|
|
if (resp.type === 'result') {
|
|
if (resp.roster.ver) {
|
|
self.config.rosterVer = resp.roster.ver;
|
|
self.emit('roster:ver', resp.roster.ver);
|
|
}
|
|
}
|
|
cb(null, resp);
|
|
});
|
|
};
|
|
|
|
Client.prototype.updateRosterItem = function (item, cb) {
|
|
this.sendIq({
|
|
type: 'set',
|
|
roster: {
|
|
items: [item]
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
Client.prototype.removeRosterItem = function (jid, cb) {
|
|
this.updateRosterItem({jid: jid, subscription: 'remove'}, cb);
|
|
};
|
|
|
|
Client.prototype.subscribe = function (jid) {
|
|
this.sendPresence({type: 'subscribe', to: jid});
|
|
};
|
|
|
|
Client.prototype.unsubscribe = function (jid) {
|
|
this.sendPresence({type: 'unsubscribe', to: jid});
|
|
};
|
|
|
|
Client.prototype.acceptSubscription = function (jid) {
|
|
this.sendPresence({type: 'subscribed', to: jid});
|
|
};
|
|
|
|
Client.prototype.denySubscription = function (jid) {
|
|
this.sendPresence({type: 'unsubscribed', to: jid});
|
|
};
|
|
|
|
|
|
module.exports = Client;
|
|
|
|
},{"../vendor/lodash":90,"./stanza/bind":23,"./stanza/error":30,"./stanza/iq":33,"./stanza/message":35,"./stanza/presence":37,"./stanza/roster":41,"./stanza/sasl":43,"./stanza/session":44,"./stanza/sm":45,"./stanza/stream":46,"./stanza/streamError":47,"./stanza/streamFeatures":48,"./websocket":52,"async":53,"hostmeta":67,"node-uuid":76,"sasl-anonymous":78,"sasl-digest-md5":80,"sasl-external":82,"sasl-plain":84,"sasl-scram-sha-1":86,"saslmechanisms":88,"wildemitter":89}],3:[function(require,module,exports){
|
|
require('../stanza/attention');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:attention:0');
|
|
|
|
|
|
client.getAttention = function (jid, opts) {
|
|
opts = opts || {};
|
|
opts.to = jid;
|
|
opts.type = 'headline';
|
|
opts.attention = true;
|
|
client.sendMessage(opts);
|
|
};
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg._extensions._attention) {
|
|
client.emit('attention', msg);
|
|
}
|
|
});
|
|
};
|
|
|
|
},{"../stanza/attention":21}],4:[function(require,module,exports){
|
|
var stanzas = require('../stanza/avatar');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:avatar:metadata+notify');
|
|
|
|
client.on('pubsubEvent', function (msg) {
|
|
if (!msg.event._extensions.updated) return;
|
|
if (msg.event.updated.node !== 'urn:xmpp:avatar:metadata') return;
|
|
|
|
client.emit('avatar', {
|
|
jid: msg.from,
|
|
avatars: msg.event.updated.published[0].avatars
|
|
});
|
|
});
|
|
|
|
client.publishAvatar = function (id, data, cb) {
|
|
client.publish(null, 'urn:xmpp:avatar:data', {
|
|
id: id,
|
|
avatarData: data
|
|
}, cb);
|
|
};
|
|
|
|
client.useAvatars = function (info, cb) {
|
|
client.publish(null, 'urn:xmpp:avatar:metadata', {
|
|
id: 'current',
|
|
avatars: info
|
|
}, cb);
|
|
};
|
|
|
|
client.getAvatar = function (jid, id, cb) {
|
|
client.getItem(jid, 'urn:xmpp:avatar:data', id, cb);
|
|
};
|
|
};
|
|
|
|
},{"../stanza/avatar":22}],5:[function(require,module,exports){
|
|
var stanzas = require('../stanza/carbons');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:carbons:2');
|
|
|
|
client.enableCarbons = function (cb) {
|
|
this.sendIq({
|
|
type: 'set',
|
|
enableCarbons: true
|
|
}, cb);
|
|
};
|
|
|
|
client.disableCarbons = function (cb) {
|
|
this.sendIq({
|
|
type: 'set',
|
|
disableCarbons: true
|
|
}, cb);
|
|
};
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg._extensions.carbonSent) {
|
|
return client.emit('carbon:sent', msg);
|
|
}
|
|
if (msg._extensions.carbonReceived) {
|
|
return client.emit('carbon:received', msg);
|
|
}
|
|
});
|
|
};
|
|
|
|
},{"../stanza/carbons":25}],6:[function(require,module,exports){
|
|
var stanzas = require('../stanza/chatstates');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('http://jabber.org/protocol/chatstates');
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg.chatState) {
|
|
client.emit('chatState', {
|
|
to: msg.to,
|
|
from: msg.from,
|
|
chatState: msg.chatState
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
},{"../stanza/chatstates":26}],7:[function(require,module,exports){
|
|
var stanzas = require('../stanza/replace');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:message-correct:0');
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg.replace) {
|
|
client.emit('replace', msg);
|
|
client.emit('replace:' + msg.id, msg);
|
|
}
|
|
});
|
|
};
|
|
|
|
},{"../stanza/replace":40}],8:[function(require,module,exports){
|
|
var stanzas = require('../stanza/delayed');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:delay');
|
|
};
|
|
|
|
},{"../stanza/delayed":28}],9:[function(require,module,exports){
|
|
/*global unescape, escape */
|
|
|
|
var _ = require('../../vendor/lodash');
|
|
var crypto = require('crypto');
|
|
|
|
require('../stanza/disco');
|
|
require('../stanza/caps');
|
|
|
|
|
|
var UTF8 = {
|
|
encode: function (s) {
|
|
return unescape(encodeURIComponent(s));
|
|
},
|
|
decode: function (s) {
|
|
return decodeURIComponent(escape(s));
|
|
}
|
|
};
|
|
|
|
|
|
function verifyVerString(info, hash, check) {
|
|
if (hash === 'sha-1') {
|
|
hash = 'sha1';
|
|
}
|
|
var computed = this._generatedVerString(info, hash);
|
|
return computed && computed == check;
|
|
}
|
|
|
|
|
|
function generateVerString(info, hash) {
|
|
var S = '';
|
|
var features = info.features.sort();
|
|
var identities = [];
|
|
var formTypes = {};
|
|
var formOrder = [];
|
|
|
|
|
|
_.forEach(info.identities, function (identity) {
|
|
identities.push([
|
|
identity.category || '',
|
|
identity.type || '',
|
|
identity.lang || '',
|
|
identity.name || ''
|
|
].join('/'));
|
|
});
|
|
|
|
var idLen = identities.length;
|
|
var featureLen = features.length;
|
|
|
|
identities = _.unique(identities, true);
|
|
features = _.unique(features, true);
|
|
|
|
if (featureLen != features.length || idLen != identities.length) {
|
|
return false;
|
|
}
|
|
|
|
|
|
S += identities.join('<') + '<';
|
|
S += features.join('<') + '<';
|
|
|
|
|
|
var illFormed = false;
|
|
_.forEach(info.extensions, function (ext) {
|
|
var fields = ext.fields;
|
|
for (var i = 0, len = fields.length; i < len; i++) {
|
|
if (fields[i].name == 'FORM_TYPE' && fields[i].type == 'hidden') {
|
|
var name = fields[i].value;
|
|
if (formTypes[name]) {
|
|
illFormed = true;
|
|
return;
|
|
}
|
|
formTypes[name] = ext;
|
|
formOrder.push(name);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
if (illFormed) {
|
|
return false;
|
|
}
|
|
|
|
formOrder.sort();
|
|
|
|
_.forEach(formOrder, function (name) {
|
|
var ext = formTypes[name];
|
|
var fields = {};
|
|
var fieldOrder = [];
|
|
|
|
S += '<' + name;
|
|
|
|
_.forEach(ext.fields, function (field) {
|
|
var fieldName = field.name;
|
|
if (fieldName != 'FORM_TYPE') {
|
|
var values = field.value || '';
|
|
if (typeof values != 'object') {
|
|
values = values.split('\n');
|
|
}
|
|
fields[fieldName] = values.sort();
|
|
fieldOrder.push(fieldName);
|
|
}
|
|
});
|
|
|
|
fieldOrder.sort();
|
|
|
|
_.forEach(fieldOrder, function (fieldName) {
|
|
S += '<' + fieldName;
|
|
_.forEach(fields[fieldName], function (val) {
|
|
S += '<' + val;
|
|
});
|
|
});
|
|
});
|
|
|
|
if (hash === 'sha-1') {
|
|
hash = 'sha1';
|
|
}
|
|
|
|
var ver = crypto.createHash(hash).update(UTF8.encode(S)).digest('base64');
|
|
var padding = 4 - ver.length % 4;
|
|
if (padding === 4) {
|
|
padding = 0;
|
|
}
|
|
|
|
for (var i = 0; i < padding; i++) {
|
|
ver += '=';
|
|
}
|
|
return ver;
|
|
}
|
|
|
|
|
|
function Disco(client) {
|
|
this.features = {};
|
|
this.identities = {};
|
|
this.extensions = {};
|
|
this.items = {};
|
|
this.caps = {};
|
|
}
|
|
|
|
Disco.prototype = {
|
|
constructor: {
|
|
value: Disco
|
|
},
|
|
addFeature: function (feature, node) {
|
|
node = node || '';
|
|
if (!this.features[node]) {
|
|
this.features[node] = [];
|
|
}
|
|
this.features[node].push(feature);
|
|
},
|
|
addIdentity: function (identity, node) {
|
|
node = node || '';
|
|
if (!this.identities[node]) {
|
|
this.identities[node] = [];
|
|
}
|
|
this.identities[node].push(identity);
|
|
},
|
|
addItem: function (item, node) {
|
|
node = node || '';
|
|
if (!this.items[node]) {
|
|
this.items[node] = [];
|
|
}
|
|
this.items[node].push(item);
|
|
},
|
|
addExtension: function (form, node) {
|
|
node = node || '';
|
|
if (!this.extensions[node]) {
|
|
this.extensions[node] = [];
|
|
}
|
|
this.extensions[node].push(form);
|
|
}
|
|
};
|
|
|
|
module.exports = function (client) {
|
|
client.disco = new Disco(client);
|
|
|
|
client.disco.addFeature('http://jabber.org/protocol/disco#info');
|
|
client.disco.addIdentity({
|
|
category: 'client',
|
|
type: 'web'
|
|
});
|
|
|
|
client.getDiscoInfo = function (jid, node, cb) {
|
|
this.sendIq({
|
|
to: jid,
|
|
type: 'get',
|
|
discoInfo: {
|
|
node: node
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.getDiscoItems = function (jid, node, cb) {
|
|
this.sendIq({
|
|
to: jid,
|
|
type: 'get',
|
|
discoItems: {
|
|
node: node
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.updateCaps = function () {
|
|
this.disco.caps = {
|
|
node: this.config.capsNode || 'https://stanza.io',
|
|
hash: 'sha-1',
|
|
ver: generateVerString({
|
|
identities: this.disco.identities[''],
|
|
features: this.disco.features[''],
|
|
extensions: this.disco.extensions['']
|
|
}, 'sha-1')
|
|
};
|
|
};
|
|
|
|
client.on('iq:get:discoInfo', function (iq) {
|
|
var node = iq.discoInfo.node;
|
|
var reportedNode = iq.discoInfo.node;
|
|
|
|
if (node === client.disco.caps.node + '#' + client.disco.caps.ver) {
|
|
reportedNode = node;
|
|
node = '';
|
|
}
|
|
client.sendIq(iq.resultReply({
|
|
discoInfo: {
|
|
node: reportedNode,
|
|
identities: client.disco.identities[node] || [],
|
|
features: client.disco.features[node] || [],
|
|
extensions: client.disco.extensions[node] || []
|
|
}
|
|
}));
|
|
});
|
|
|
|
client.on('iq:get:discoItems', function (iq) {
|
|
var node = iq.discoInfo.node;
|
|
client.sendIq(iq.resultReply({
|
|
discoItems: {
|
|
node: node,
|
|
items: client.disco.items[node] || []
|
|
}
|
|
}));
|
|
});
|
|
};
|
|
|
|
},{"../../vendor/lodash":90,"../stanza/caps":24,"../stanza/disco":29,"crypto":60}],10:[function(require,module,exports){
|
|
var stanzas = require('../stanza/forwarded');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:forward:0');
|
|
};
|
|
|
|
},{"../stanza/forwarded":31}],11:[function(require,module,exports){
|
|
var stanzas = require('../stanza/idle');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:idle:0');
|
|
};
|
|
|
|
},{"../stanza/idle":32}],12:[function(require,module,exports){
|
|
require('../stanza/visibility');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.goInvisible = function (cb) {
|
|
this.sendIq({
|
|
type: 'set',
|
|
invisible: true
|
|
});
|
|
};
|
|
|
|
client.goVisible = function (cb) {
|
|
this.sendIq({
|
|
type: 'set',
|
|
visible: true
|
|
});
|
|
};
|
|
};
|
|
|
|
},{"../stanza/visibility":51}],13:[function(require,module,exports){
|
|
var stanzas = require('../stanza/mam');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:mam:tmp');
|
|
|
|
client.getHistory = function (opts, cb) {
|
|
var self = this;
|
|
var queryid = this.nextId();
|
|
|
|
opts = opts || {};
|
|
opts.queryid = queryid;
|
|
|
|
var mamResults = [];
|
|
this.on('mam:' + queryid, 'session', function (msg) {
|
|
mamResults.push(msg);
|
|
});
|
|
|
|
cb = cb || function () {};
|
|
|
|
this.sendIq({
|
|
type: 'get',
|
|
id: queryid,
|
|
mamQuery: opts
|
|
}, function (err, resp) {
|
|
if (err) {
|
|
cb(err);
|
|
} else {
|
|
self.off('mam:' + queryid);
|
|
resp.mamQuery.results = mamResults;
|
|
cb(null, resp);
|
|
}
|
|
});
|
|
};
|
|
|
|
client.getHistoryPreferences = function (cb) {
|
|
client.sendIq({
|
|
type: 'get',
|
|
mamPrefs: {}
|
|
}, cb);
|
|
};
|
|
|
|
client.setHistoryPreferences = function (opts, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
mamPrefs: opts
|
|
}, cb);
|
|
};
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg._extensions.mam) {
|
|
client.emit('mam:' + msg.mam.queryid, msg);
|
|
}
|
|
});
|
|
};
|
|
|
|
},{"../stanza/mam":34}],14:[function(require,module,exports){
|
|
require('../stanza/muc');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.joinRoom = function (room, nick, opts) {
|
|
opts = opts || {};
|
|
opts.to = room + '/' + nick;
|
|
opts.caps = this.disco.caps;
|
|
opts.joinMuc = opts.joinMuc || {};
|
|
|
|
this.sendPresence(opts);
|
|
};
|
|
|
|
client.leaveRoom = function (room, nick, opts) {
|
|
opts = opts || {};
|
|
opts.to = room + '/' + nick;
|
|
opts.type = 'unavailable';
|
|
this.sendPresence(opts);
|
|
};
|
|
};
|
|
|
|
},{"../stanza/muc":36}],15:[function(require,module,exports){
|
|
var stanzas = require('../stanza/pubsub');
|
|
|
|
|
|
module.exports = function (client) {
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg._extensions.event) {
|
|
client.emit('pubsubEvent', msg);
|
|
}
|
|
});
|
|
|
|
client.subscribeToNode = function (jid, opts, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
to: jid,
|
|
pubsub: {
|
|
subscribe: {
|
|
node: opts.node,
|
|
jid: opts.jid || client.jid
|
|
}
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.unsubscribeFromNode = function (jid, opts, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
to: jid,
|
|
pubsub: {
|
|
unsubscribe: {
|
|
node: opts.node,
|
|
jid: opts.jid || client.jid.split('/')[0]
|
|
}
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.publish = function (jid, node, item, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
to: jid,
|
|
pubsub: {
|
|
publish: {
|
|
node: node,
|
|
item: item
|
|
}
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.getItem = function (jid, node, id, cb) {
|
|
client.sendIq({
|
|
type: 'get',
|
|
to: jid,
|
|
pubsub: {
|
|
retrieve: {
|
|
node: node,
|
|
item: id
|
|
}
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.getItems = function (jid, node, opts, cb) {
|
|
opts = opts || {};
|
|
opts.node = node;
|
|
client.sendIq({
|
|
type: 'get',
|
|
to: jid,
|
|
pubsub: {
|
|
retrieve: {
|
|
node: node,
|
|
max: opts.max
|
|
},
|
|
rsm: opts.rsm
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.retract = function (jid, node, id, notify, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
to: jid,
|
|
pubsub: {
|
|
retract: {
|
|
node: node,
|
|
notify: notify,
|
|
id: id
|
|
}
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.purgeNode = function (jid, node, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
to: jid,
|
|
pubsubOwner: {
|
|
purge: node
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.deleteNode = function (jid, node, cb) {
|
|
client.sendIq({
|
|
type: 'set',
|
|
to: jid,
|
|
pubsubOwner: {
|
|
del: node
|
|
}
|
|
}, cb);
|
|
};
|
|
|
|
client.createNode = function (jid, node, config, cb) {
|
|
var cmd = {
|
|
type: 'set',
|
|
to: jid,
|
|
pubsubOwner: {
|
|
create: node
|
|
}
|
|
};
|
|
|
|
if (config) {
|
|
cmd.pubsubOwner.config = {form: config};
|
|
}
|
|
|
|
client.sendIq(cmd, cb);
|
|
};
|
|
};
|
|
|
|
},{"../stanza/pubsub":38}],16:[function(require,module,exports){
|
|
var stanzas = require('../stanza/receipts');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:receipts');
|
|
|
|
client.on('message', function (msg) {
|
|
var ackTypes = {
|
|
normal: true,
|
|
chat: true,
|
|
headline: true
|
|
};
|
|
if (ackTypes[msg.type] && msg.requestReceipt && !msg._extensions.receipt) {
|
|
client.sendMessage({
|
|
to: msg.from,
|
|
receipt: {
|
|
id: msg.id
|
|
},
|
|
id: msg.id
|
|
});
|
|
}
|
|
if (msg._extensions.receipt) {
|
|
client.emit('receipt:' + msg.receipt.id);
|
|
}
|
|
});
|
|
};
|
|
|
|
},{"../stanza/receipts":39}],17:[function(require,module,exports){
|
|
var stanzas = require('../stanza/time');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('urn:xmpp:time');
|
|
|
|
client.getTime = function (jid, cb) {
|
|
this.sendIq({
|
|
to: jid,
|
|
type: 'get',
|
|
time: true
|
|
}, cb);
|
|
};
|
|
|
|
client.on('iq:get:time', function (iq) {
|
|
var time = new Date();
|
|
client.sendIq(iq.resultReply({
|
|
time: {
|
|
utc: time,
|
|
tzo: time.getTimezoneOffset()
|
|
}
|
|
}));
|
|
});
|
|
};
|
|
|
|
},{"../stanza/time":49}],18:[function(require,module,exports){
|
|
require('../stanza/version');
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.disco.addFeature('jabber:iq:version');
|
|
|
|
client.on('iq:get:version', function (iq) {
|
|
client.sendIq(iq.resultReply({
|
|
version: client.config.version || {
|
|
name: 'stanza.io'
|
|
}
|
|
}));
|
|
});
|
|
|
|
client.getSoftwareVersion = function (jid, cb) {
|
|
this.sendIq({
|
|
to: jid,
|
|
type: 'get',
|
|
version: {}
|
|
}, cb);
|
|
};
|
|
};
|
|
|
|
},{"../stanza/version":50}],19:[function(require,module,exports){
|
|
var uuid = require('node-uuid');
|
|
|
|
// normalize environment
|
|
var RTCPeerConnection = null;
|
|
var RTCSessionDescription = null;
|
|
var RTCIceCandidate = null;
|
|
var getUserMedia = null;
|
|
var attachMediaStream = null;
|
|
var reattachMediaStream = null;
|
|
var browser = null;
|
|
var webRTCSupport = true;
|
|
|
|
|
|
if (navigator.mozGetUserMedia) {
|
|
browser = "firefox";
|
|
|
|
// The RTCPeerConnection object.
|
|
RTCPeerConnection = window.mozRTCPeerConnection;
|
|
|
|
// The RTCSessionDescription object.
|
|
RTCSessionDescription = window.mozRTCSessionDescription;
|
|
|
|
// The RTCIceCandidate object.
|
|
RTCIceCandidate = window.mozRTCIceCandidate;
|
|
|
|
// Get UserMedia (only difference is the prefix).
|
|
// Code from Adam Barth.
|
|
getUserMedia = navigator.mozGetUserMedia.bind(navigator);
|
|
|
|
// Attach a media stream to an element.
|
|
attachMediaStream = function (element, stream) {
|
|
element.mozSrcObject = stream;
|
|
element.play();
|
|
};
|
|
|
|
reattachMediaStream = function (to, from) {
|
|
to.mozSrcObject = from.mozSrcObject;
|
|
to.play();
|
|
};
|
|
|
|
// Fake get{Video,Audio}Tracks
|
|
MediaStream.prototype.getVideoTracks = function () {
|
|
return [];
|
|
};
|
|
|
|
MediaStream.prototype.getAudioTracks = function () {
|
|
return [];
|
|
};
|
|
} else if (navigator.webkitGetUserMedia) {
|
|
browser = "chrome";
|
|
|
|
// The RTCPeerConnection object.
|
|
RTCPeerConnection = window.webkitRTCPeerConnection;
|
|
|
|
// Get UserMedia (only difference is the prefix).
|
|
// Code from Adam Barth.
|
|
getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
|
|
|
|
// Attach a media stream to an element.
|
|
attachMediaStream = function (element, stream) {
|
|
element.autoplay = true;
|
|
element.src = webkitURL.createObjectURL(stream);
|
|
};
|
|
|
|
reattachMediaStream = function (to, from) {
|
|
to.src = from.src;
|
|
};
|
|
|
|
// The representation of tracks in a stream is changed in M26.
|
|
// Unify them for earlier Chrome versions in the coexisting period.
|
|
if (!webkitMediaStream.prototype.getVideoTracks) {
|
|
webkitMediaStream.prototype.getVideoTracks = function () {
|
|
return this.videoTracks;
|
|
};
|
|
webkitMediaStream.prototype.getAudioTracks = function () {
|
|
return this.audioTracks;
|
|
};
|
|
}
|
|
|
|
// New syntax of getXXXStreams method in M26.
|
|
if (!window.webkitRTCPeerConnection.prototype.getLocalStreams) {
|
|
window.webkitRTCPeerConnection.prototype.getLocalStreams = function () {
|
|
return this.localStreams;
|
|
};
|
|
window.webkitRTCPeerConnection.prototype.getRemoteStreams = function () {
|
|
return this.remoteStreams;
|
|
};
|
|
}
|
|
} else {
|
|
webRTCSupport = false;
|
|
}
|
|
|
|
|
|
function WebRTC(client) {
|
|
var self = this;
|
|
|
|
this.client = client;
|
|
this.peerConnectionConfig = {
|
|
iceServers: browser == 'firefox' ? [{url: 'stun:124.124.124.2'}] : [{url: 'stun:stun.l.google.com:19302'}]
|
|
};
|
|
this.peerConnectionConstraints = {
|
|
optional: [{DtlsSrtpKeyAgreement: true}]
|
|
};
|
|
this.media = {
|
|
audio: true,
|
|
video: {
|
|
mandatory: {},
|
|
optional: []
|
|
}
|
|
};
|
|
this.sessions = {};
|
|
this.peerSessions = {};
|
|
|
|
this.attachMediaStream = attachMediaStream;
|
|
|
|
// check for support
|
|
if (!webRTCSupport) {
|
|
client.emit('webrtc:unsupported');
|
|
return self;
|
|
} else {
|
|
client.emit('webrtc:supported');
|
|
|
|
client.disco.addFeature('http://stanza.io/protocol/sox');
|
|
|
|
client.on('message', function (msg) {
|
|
if (msg.type !== 'error' && msg._extensions.sox) {
|
|
var session;
|
|
var fullId = msg.from + ':' + msg.sox.sid;
|
|
|
|
if (msg.sox.type === 'offer') {
|
|
console.log('got an offer');
|
|
session = new Peer(client, msg.from, msg.sox.sid);
|
|
self.sessions[fullId] = session;
|
|
if (!self.peerSessions[msg.from]) {
|
|
self.peerSessions[msg.from] = [];
|
|
}
|
|
self.peerSessions[msg.from].push(fullId);
|
|
} else if (msg.sox.type === 'answer') {
|
|
console.log('got an answer');
|
|
session = self.sessions[fullId];
|
|
if (session) {
|
|
console.log('Setting remote description');
|
|
session.conn.setRemoteDescription(new RTCSessionDescription({
|
|
type: 'answer',
|
|
sdp: msg.sox.sdp
|
|
}));
|
|
}
|
|
} else if (msg.sox.type === 'candidate') {
|
|
session = self.sessions[fullId];
|
|
if (session) {
|
|
console.log('Adding new ICE candidate');
|
|
session.conn.addIceCandidate(new RTCIceCandidate({
|
|
sdpMLineIndex: msg.sox.label,
|
|
candidate: msg.sox.sdp
|
|
}));
|
|
}
|
|
}
|
|
client.emit('webrtc:' + msg.sox.type, msg);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
WebRTC.prototype = {
|
|
constructor: {
|
|
value: WebRTC
|
|
},
|
|
testReadiness: function () {
|
|
var self = this;
|
|
if (this.localStream && this.client.sessionStarted) {
|
|
// This timeout is a workaround for the strange no-audio bug
|
|
// as described here: https://code.google.com/p/webrtc/issues/detail?id=1525
|
|
// remove timeout when this is fixed.
|
|
setTimeout(function () {
|
|
self.client.emit('webrtc:ready');
|
|
}, 1000);
|
|
}
|
|
},
|
|
startLocalMedia: function (element) {
|
|
var self = this;
|
|
getUserMedia(this.media, function (stream) {
|
|
attachMediaStream(element, stream);
|
|
self.localStream = stream;
|
|
self.testReadiness();
|
|
}, function () {
|
|
throw new Error('Failed to get access to local media.');
|
|
});
|
|
},
|
|
offerSession: function (peer) {
|
|
var self = this;
|
|
var sid = uuid.v4();
|
|
var session = new Peer(this.client, peer, sid);
|
|
|
|
this.sessions[peer + ':' + sid] = session;
|
|
if (!this.peerSessions[peer]) {
|
|
this.peerSessions[peer] = [];
|
|
}
|
|
this.peerSessions[peer].push(peer + ':' + sid);
|
|
|
|
session.conn.createOffer(function (sdp) {
|
|
console.log('Setting local description');
|
|
session.conn.setLocalDescription(sdp);
|
|
console.log('Sending offer');
|
|
self.client.sendMessage({
|
|
to: peer,
|
|
sox: {
|
|
type: 'offer',
|
|
sid: sid,
|
|
sdp: sdp.sdp
|
|
}
|
|
});
|
|
}, null, this.mediaConstraints);
|
|
},
|
|
acceptSession: function (offerMsg) {
|
|
var self = this;
|
|
var session = self.sessions[offerMsg.from + ':' + offerMsg.sox.sid];
|
|
|
|
if (session) {
|
|
console.log('Setting remote description');
|
|
session.conn.setRemoteDescription(new RTCSessionDescription({
|
|
type: 'offer',
|
|
sdp: offerMsg.sox.sdp
|
|
}));
|
|
session.conn.createAnswer(function (sdp) {
|
|
console.log('Setting local description');
|
|
session.conn.setLocalDescription(sdp);
|
|
console.log('Sending answer');
|
|
self.client.sendMessage({
|
|
to: session.jid,
|
|
sox: {
|
|
type: 'answer',
|
|
sid: session.sid,
|
|
sdp: sdp.sdp
|
|
}
|
|
});
|
|
}, null, this.mediaConstraints);
|
|
}
|
|
},
|
|
declineSession: function (offerMsg) {
|
|
this.endSession(offerMsg.from, offerMsg.sox.sid);
|
|
},
|
|
endSession: function (peer, sid) {
|
|
var session = this.sessions[peer + ':' + sid];
|
|
if (session) {
|
|
var fullId = peer + ':' + sid;
|
|
var index = this.peerSessions[peer].indexOf(fullId);
|
|
|
|
if (index != -1) {
|
|
this.peerSessions.splice(index, 1);
|
|
}
|
|
this.sessions[fullId] = undefined;
|
|
|
|
session.conn.close();
|
|
this.client.emit('webrtc:stream:removed', {
|
|
sid: session.sid,
|
|
peer: session.jid
|
|
});
|
|
|
|
this.client.sendMessage({
|
|
to: peer,
|
|
sox: {
|
|
type: 'end',
|
|
sid: sid
|
|
}
|
|
});
|
|
}
|
|
},
|
|
// Audio controls
|
|
mute: function () {
|
|
this._audioEnabled(false);
|
|
this.client.emit('webrtc:audio:off');
|
|
},
|
|
unmute: function () {
|
|
this._audioEnabled(true);
|
|
this.client.emit('webrtc:audio:on');
|
|
},
|
|
// Video controls
|
|
pauseVideo: function () {
|
|
this._videoEnabled(false);
|
|
this.client.emit('webrtc:video:off');
|
|
},
|
|
resumeVideo: function () {
|
|
this._videoEnabled(true);
|
|
this.client.emit('webrtc:video:on');
|
|
},
|
|
// Combined controls
|
|
pause: function () {
|
|
this.mute();
|
|
this.pauseVideo();
|
|
},
|
|
resume: function () {
|
|
this.unmute();
|
|
this.resumeVideo();
|
|
},
|
|
// Internal methods for enabling/disabling audio/video
|
|
_audioEnabled: function (bool) {
|
|
this.localStream.getAudioTracks().forEach(function (track) {
|
|
track.enabled = !!bool;
|
|
});
|
|
},
|
|
_videoEnabled: function (bool) {
|
|
this.localStream.getVideoTracks().forEach(function (track) {
|
|
track.enabled = !!bool;
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
function Peer(client, jid, sid) {
|
|
var self = this;
|
|
|
|
this.client = client;
|
|
this.jid = jid;
|
|
this.sid = sid;
|
|
this.closed = false;
|
|
|
|
this.conn = new RTCPeerConnection(client.webrtc.peerConnectionConfig, client.webrtc.peerConnectionConstraints);
|
|
this.conn.addStream(client.webrtc.localStream);
|
|
this.conn.onicecandidate = function (event) {
|
|
if (self.closed) return;
|
|
if (event.candidate) {
|
|
console.log('Sending candidate');
|
|
self.client.sendMessage({
|
|
mto: self.jid,
|
|
sox: {
|
|
type: 'candidate',
|
|
sid: self.sid,
|
|
label: event.candidate.sdpMLineIndex,
|
|
id: event.candidate.sdpMid,
|
|
sdp: event.candidate.candidate
|
|
}
|
|
});
|
|
} else {
|
|
console.log('End of ICE candidates');
|
|
}
|
|
};
|
|
this.conn.onaddstream = function (event) {
|
|
self.client.emit('webrtc:stream:added', {
|
|
stream: event.stream,
|
|
sid: self.sid,
|
|
peer: self.jid
|
|
});
|
|
};
|
|
this.conn.onremovestream = function (event) {
|
|
self.client.emit('webrtc:stream:removed', {
|
|
sid: self.sid,
|
|
peer: self.jid
|
|
});
|
|
};
|
|
|
|
this.mediaConstraints = {
|
|
mandatory: {
|
|
OfferToReceiveAudio: true,
|
|
OfferToReceiveVideo: true
|
|
}
|
|
};
|
|
}
|
|
|
|
Peer.prototype = {
|
|
constructor: {
|
|
value: Peer
|
|
}
|
|
};
|
|
|
|
|
|
module.exports = function (client) {
|
|
client.webrtc = new WebRTC(client);
|
|
};
|
|
|
|
},{"node-uuid":76}],20:[function(require,module,exports){
|
|
var SM = require('./stanza/sm');
|
|
var MAX_SEQ = Math.pow(2, 32);
|
|
|
|
|
|
function mod(v, n) {
|
|
return ((v % n) + n) % n;
|
|
}
|
|
|
|
|
|
function StreamManagement(conn) {
|
|
this.conn = conn;
|
|
this.id = false;
|
|
this.allowResume = true;
|
|
this.started = false;
|
|
this.lastAck = 0;
|
|
this.handled = 0;
|
|
this.windowSize = 1;
|
|
this.windowCount = 0;
|
|
this.unacked = [];
|
|
}
|
|
|
|
StreamManagement.prototype = {
|
|
constructor: {
|
|
value: StreamManagement
|
|
},
|
|
enable: function () {
|
|
var enable = new SM.Enable();
|
|
enable.resume = this.allowResume;
|
|
this.conn.send(enable);
|
|
this.handled = 0;
|
|
this.started = true;
|
|
},
|
|
resume: function () {
|
|
var resume = new SM.Resume({
|
|
h: this.handled,
|
|
previd: this.id
|
|
});
|
|
this.conn.send(resume);
|
|
this.started = true;
|
|
},
|
|
enabled: function (resp) {
|
|
this.id = resp.id;
|
|
},
|
|
resumed: function (resp) {
|
|
this.id = resp.id;
|
|
if (resp.h) {
|
|
this.process(resp, true);
|
|
}
|
|
},
|
|
failed: function (resp) {
|
|
this.started = false;
|
|
this.id = false;
|
|
this.lastAck = 0;
|
|
this.handled = 0;
|
|
this.windowCount = 0;
|
|
this.unacked = [];
|
|
},
|
|
ack: function () {
|
|
this.conn.send(new SM.Ack({
|
|
h: this.handled
|
|
}));
|
|
},
|
|
request: function () {
|
|
this.conn.send(new SM.Request());
|
|
},
|
|
process: function (ack, resend) {
|
|
var self = this;
|
|
var numAcked = mod(ack.h - this.lastAck, MAX_SEQ);
|
|
|
|
for (var i = 0; i < numAcked && this.unacked.length > 0; i++) {
|
|
this.conn.emit('stanza:acked', this.unacked.shift());
|
|
}
|
|
if (resend) {
|
|
var resendUnacked = this.unacked;
|
|
this.unacked = [];
|
|
resendUnacked.forEach(function (stanza) {
|
|
self.conn.send(stanza);
|
|
});
|
|
}
|
|
this.lastAck = ack.h;
|
|
},
|
|
track: function (stanza) {
|
|
var name = stanza._name;
|
|
var acceptable = {
|
|
message: true,
|
|
presence: true,
|
|
iq: true
|
|
};
|
|
|
|
if (this.started && acceptable[name]) {
|
|
this.unacked.push(stanza);
|
|
this.windowCount += 1;
|
|
if (this.windowCount == this.windowSize) {
|
|
this.request();
|
|
this.windowCount = 0;
|
|
}
|
|
}
|
|
},
|
|
handle: function (stanza) {
|
|
if (this.started) {
|
|
this.handled = mod(this.handled + 1, MAX_SEQ);
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = StreamManagement;
|
|
|
|
},{"./stanza/sm":45}],21:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
|
|
|
|
function Attention(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Attention.prototype = {
|
|
constructor: {
|
|
value: Attention
|
|
},
|
|
NS: 'urn:xmpp:attention:0',
|
|
EL: 'attention',
|
|
_name: '_attention',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
Message.prototype.__defineGetter__('attention', function () {
|
|
return !!this._extensions._attention;
|
|
});
|
|
Message.prototype.__defineSetter__('attention', function (value) {
|
|
if (value) {
|
|
this._attention = true;
|
|
} else if (this._extensions._attention) {
|
|
this.xml.removeChild(this._extensions._attention.xml);
|
|
delete this._extensions._attention;
|
|
}
|
|
});
|
|
|
|
|
|
stanza.extend(Message, Attention);
|
|
|
|
module.exports = Attention;
|
|
|
|
},{"./message":35,"jxt":74}],22:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
var Item = require('./pubsub').Item;
|
|
var EventItem = require('./pubsub').EventItem;
|
|
|
|
|
|
function getAvatarData() {
|
|
return stanza.getSubText(this.xml, 'urn:xmpp:avatar:data', 'data');
|
|
}
|
|
|
|
function setAvatarData(value) {
|
|
stanza.setSubText(this.xml, 'urn:xmpp:avatar:data', 'data', value);
|
|
stanza.setSubAttribute(this.xml, 'urn:xmpp:avatar:data', 'data', 'xmlns', 'urn:xmpp:avatar:data');
|
|
}
|
|
|
|
function getAvatars() {
|
|
var metadata = stanza.find(this.xml, 'urn:xmpp:avatar:metadata', 'metadata');
|
|
var results = [];
|
|
if (metadata.length) {
|
|
var avatars = stanza.find(metadata[0], 'urn:xmpp:avatar:metadata', 'info');
|
|
_.forEach(avatars, function (info) {
|
|
results.push(new Avatar({}, info));
|
|
});
|
|
}
|
|
return results;
|
|
}
|
|
|
|
function setAvatars(value) {
|
|
var metadata = stanza.findOrCreate(this.xml, 'urn:xmpp:avatar:metadata', 'metadata');
|
|
stanza.setAttribute(metadata, 'xmlns', 'urn:xmpp:avatar:metadata');
|
|
_.forEach(value, function (info) {
|
|
var avatar = new Avatar(info);
|
|
metadata.appendChild(avatar.xml);
|
|
});
|
|
}
|
|
|
|
|
|
Item.prototype.__defineGetter__('avatarData', getAvatarData);
|
|
Item.prototype.__defineSetter__('avatarData', setAvatarData);
|
|
EventItem.prototype.__defineGetter__('avatarData', getAvatarData);
|
|
EventItem.prototype.__defineSetter__('avatarData', setAvatarData);
|
|
|
|
Item.prototype.__defineGetter__('avatars', getAvatars);
|
|
Item.prototype.__defineSetter__('avatars', setAvatars);
|
|
EventItem.prototype.__defineGetter__('avatars', getAvatars);
|
|
EventItem.prototype.__defineSetter__('avatars', setAvatars);
|
|
|
|
|
|
|
|
function Avatar(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Avatar.prototype = {
|
|
constructor: {
|
|
value: Avatar
|
|
},
|
|
_name: 'avatars',
|
|
NS: 'urn:xmpp:avatar:metadata',
|
|
EL: 'info',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get bytes() {
|
|
return stanza.getAttribute(this.xml, 'bytes');
|
|
},
|
|
set bytes(value) {
|
|
stanza.setAttribute(this.xml, 'bytes', value);
|
|
},
|
|
get height() {
|
|
return stanza.getAttribute(this.xml, 'height');
|
|
},
|
|
set height(value) {
|
|
stanza.setAttribute(this.xml, 'height', value);
|
|
},
|
|
get width() {
|
|
return stanza.getAttribute(this.xml, 'width');
|
|
},
|
|
set width(value) {
|
|
stanza.setAttribute(this.xml, 'width', value);
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type', 'image/png');
|
|
},
|
|
set type(value) {
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
},
|
|
get url() {
|
|
return stanza.getAttribute(this.xml, 'url');
|
|
},
|
|
set url(value) {
|
|
stanza.setAttribute(this.xml, 'url', value);
|
|
}
|
|
};
|
|
|
|
|
|
module.exports = Avatar;
|
|
|
|
},{"../../vendor/lodash":90,"./pubsub":38,"jxt":74}],23:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
var StreamFeatures = require('./streamFeatures');
|
|
|
|
|
|
function Bind(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Bind.prototype = {
|
|
constructor: {
|
|
value: Bind
|
|
},
|
|
_name: 'bind',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-bind',
|
|
EL: 'bind',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get resource() {
|
|
return stanza.getSubText(this.xml, this.NS, 'resource');
|
|
},
|
|
set resource(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'resource');
|
|
},
|
|
get jid() {
|
|
return stanza.getSubText(this.xml, this.NS, 'jid');
|
|
},
|
|
set jid(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'jid');
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Iq, Bind);
|
|
stanza.extend(StreamFeatures, Bind);
|
|
|
|
|
|
module.exports = Bind;
|
|
|
|
},{"./iq":33,"./streamFeatures":48,"jxt":74}],24:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Presence = require('./presence');
|
|
var StreamFeatures = require('./streamFeatures');
|
|
|
|
|
|
function Caps(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Caps.prototype = {
|
|
constructor: {
|
|
value: Caps
|
|
},
|
|
NS: 'http://jabber.org/protocol/caps',
|
|
EL: 'c',
|
|
_name: 'caps',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get ver() {
|
|
return stanza.getAttribute(this.xml, 'ver');
|
|
},
|
|
set ver(value) {
|
|
stanza.setAttribute(this.xml, 'ver', value);
|
|
},
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get hash() {
|
|
return stanza.getAttribute(this.xml, 'hash');
|
|
},
|
|
set hash(value) {
|
|
stanza.setAttribute(this.xml, 'hash', value);
|
|
},
|
|
get ext() {
|
|
return stanza.getAttribute(this.xml, 'ext');
|
|
},
|
|
set ext(value) {
|
|
stanza.setAttribute(this.xml, 'ext', value);
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Presence, Caps);
|
|
stanza.extend(StreamFeatures, Caps);
|
|
|
|
|
|
module.exports = Caps;
|
|
|
|
},{"./presence":37,"./streamFeatures":48,"jxt":74}],25:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
var Iq = require('./iq');
|
|
var Forwarded = require('./forwarded');
|
|
|
|
|
|
function Sent(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Sent.prototype = {
|
|
constructor: {
|
|
value: Sent
|
|
},
|
|
NS: 'urn:xmpp:carbons:2',
|
|
EL: 'sent',
|
|
_name: 'carbonSent',
|
|
_eventname: 'carbon:sent',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Received(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Received.prototype = {
|
|
constructor: {
|
|
value: Received
|
|
},
|
|
NS: 'urn:xmpp:carbons:2',
|
|
EL: 'received',
|
|
_name: 'carbonReceived',
|
|
_eventname: 'carbon:received',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Private(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Private.prototype = {
|
|
constructor: {
|
|
value: Private
|
|
},
|
|
NS: 'urn:xmpp:carbons:2',
|
|
EL: 'private',
|
|
_name: 'carbonPrivate',
|
|
_eventname: 'carbon:private',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Enable(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Enable.prototype = {
|
|
constructor: {
|
|
value: Enable
|
|
},
|
|
NS: 'urn:xmpp:carbons:2',
|
|
EL: 'enable',
|
|
_name: 'enableCarbons',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Disable(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Disable.prototype = {
|
|
constructor: {
|
|
value: Disable
|
|
},
|
|
NS: 'urn:xmpp:carbons:2',
|
|
EL: 'disable',
|
|
_name: 'disableCarbons',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
stanza.extend(Sent, Forwarded);
|
|
stanza.extend(Received, Forwarded);
|
|
stanza.extend(Message, Sent);
|
|
stanza.extend(Message, Received);
|
|
stanza.extend(Message, Private);
|
|
stanza.extend(Iq, Enable);
|
|
stanza.extend(Iq, Disable);
|
|
|
|
|
|
exports.Sent = Sent;
|
|
exports.Received = Received;
|
|
exports.Private = Private;
|
|
exports.Enable = Enable;
|
|
exports.Disable = Disable;
|
|
|
|
},{"./forwarded":31,"./iq":33,"./message":35,"jxt":74}],26:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
|
|
|
|
function ChatStateActive(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
ChatStateActive.prototype = {
|
|
constructor: {
|
|
value: ChatStateActive
|
|
},
|
|
NS: 'http://jabber.org/protocol/chatstates',
|
|
EL: 'active',
|
|
_name: 'chatStateActive',
|
|
_eventname: 'chat:active',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
function ChatStateComposing(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
ChatStateComposing.prototype = {
|
|
constructor: {
|
|
value: ChatStateComposing
|
|
},
|
|
NS: 'http://jabber.org/protocol/chatstates',
|
|
EL: 'composing',
|
|
_name: 'chatStateComposing',
|
|
_eventname: 'chat:composing',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
function ChatStatePaused(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
ChatStatePaused.prototype = {
|
|
constructor: {
|
|
value: ChatStatePaused
|
|
},
|
|
NS: 'http://jabber.org/protocol/chatstates',
|
|
EL: 'paused',
|
|
_name: 'chatStatePaused',
|
|
_eventname: 'chat:paused',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
function ChatStateInactive(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
ChatStateInactive.prototype = {
|
|
constructor: {
|
|
value: ChatStateInactive
|
|
},
|
|
NS: 'http://jabber.org/protocol/chatstates',
|
|
EL: 'inactive',
|
|
_name: 'chatStateInactive',
|
|
_eventname: 'chat:inactive',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
function ChatStateGone(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
ChatStateGone.prototype = {
|
|
constructor: {
|
|
value: ChatStateGone
|
|
},
|
|
NS: 'http://jabber.org/protocol/chatstates',
|
|
EL: 'gone',
|
|
_name: 'chatStateGone',
|
|
_eventname: 'chat:gone',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
stanza.extend(Message, ChatStateActive);
|
|
stanza.extend(Message, ChatStateComposing);
|
|
stanza.extend(Message, ChatStatePaused);
|
|
stanza.extend(Message, ChatStateInactive);
|
|
stanza.extend(Message, ChatStateGone);
|
|
|
|
|
|
Message.prototype.__defineGetter__('chatState', function () {
|
|
var self = this;
|
|
var states = ['Active', 'Composing', 'Paused', 'Inactive', 'Gone'];
|
|
|
|
for (var i = 0; i < states.length; i++) {
|
|
if (self._extensions['chatState' + states[i]]) {
|
|
return states[i].toLowerCase();
|
|
}
|
|
}
|
|
return '';
|
|
});
|
|
Message.prototype.__defineSetter__('chatState', function (value) {
|
|
var self = this;
|
|
var states = ['Active', 'Composing', 'Paused', 'Inactive', 'Gone'];
|
|
|
|
states.forEach(function (state) {
|
|
if (self._extensions['chatState' + state]) {
|
|
self.xml.removeChild(self._extensions['chatState' + state].xml);
|
|
delete self._extensions['chatState' + state];
|
|
}
|
|
});
|
|
if (value) {
|
|
this['chatState' + value.charAt(0).toUpperCase() + value.slice(1)];
|
|
}
|
|
});
|
|
|
|
},{"./message":35,"jxt":74}],27:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
|
|
|
|
function DataForm(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
DataForm.prototype = {
|
|
constructor: {
|
|
value: DataForm
|
|
},
|
|
NS: 'jabber:x:data',
|
|
EL: 'x',
|
|
_name: 'form',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get title() {
|
|
return stanza.getSubText(this.xml, this.NS, 'title');
|
|
},
|
|
set title(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'title', value);
|
|
},
|
|
get instructions() {
|
|
return stanza.getMultiSubText(this.xml, this.NS, 'title').join('\n');
|
|
},
|
|
set instructions(value) {
|
|
stanza.setMultiSubText(this.xml, this.NS, 'title', value.split('\n'));
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type', 'form');
|
|
},
|
|
set type(value) {
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
},
|
|
get fields() {
|
|
var fields = stanza.find(this.xml, this.NS, 'field');
|
|
var results = [];
|
|
|
|
_.forEach(fields, function (field) {
|
|
results.push(new Field({}, field).toJSON());
|
|
});
|
|
return results;
|
|
},
|
|
set fields(value) {
|
|
var self = this;
|
|
_.forEach(value, function (field) {
|
|
self.addField(field);
|
|
});
|
|
},
|
|
addField: function (opts) {
|
|
var field = new Field(opts);
|
|
this.xml.appendChild(field.xml);
|
|
},
|
|
};
|
|
|
|
|
|
function Field(data, xml) {
|
|
stanza.init(this, xml, data);
|
|
this._type = data.type || this.type;
|
|
return this;
|
|
}
|
|
Field.prototype = {
|
|
constructor: {
|
|
value: Field
|
|
},
|
|
NS: 'jabber:x:data',
|
|
EL: 'field',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type', 'text-single');
|
|
},
|
|
set type(value) {
|
|
this._type = value;
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
},
|
|
get name() {
|
|
return stanza.getAttribute(this.xml, 'var');
|
|
},
|
|
set name(value) {
|
|
stanza.setAttribute(this.xml, 'var', value);
|
|
},
|
|
get desc() {
|
|
return stanza.getSubText(this.xml, this.NS, 'desc');
|
|
},
|
|
set desc(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'desc', value);
|
|
},
|
|
get value() {
|
|
var vals = stanza.getMultiSubText(this.xml, this.NS, 'value');
|
|
if (this._type === 'boolean') {
|
|
return vals[0] === '1' || vals[0] === 'true';
|
|
}
|
|
if (vals.length > 1) {
|
|
if (this._type === 'text-multi') {
|
|
return vals.join('\n');
|
|
}
|
|
return vals;
|
|
}
|
|
return vals[0];
|
|
},
|
|
set value(value) {
|
|
if (this._type === 'boolean') {
|
|
stanza.setSubText(this.xml, this.NS, 'value', value ? '1' : '0');
|
|
} else {
|
|
if (this._type === 'text-multi') {
|
|
value = value.split('\n');
|
|
}
|
|
stanza.setMultiSubText(this.xml, this.NS, 'value', value);
|
|
}
|
|
},
|
|
get required() {
|
|
var req = stanza.find(this.xml, this.NS, 'required');
|
|
return req.length > 0;
|
|
},
|
|
set required(value) {
|
|
var reqs = stanza.find(this.xml, this.NS, 'required');
|
|
if (value && reqs.length === 0) {
|
|
var req = document.createElementNS(this.NS, 'required');
|
|
this.xml.appendChild(req);
|
|
} else if (!value && reqs.length > 0) {
|
|
_.forEach(reqs, function (req) {
|
|
this.xml.removeChild(req);
|
|
});
|
|
}
|
|
},
|
|
get label() {
|
|
return stanza.getAttribute(this.xml, 'label');
|
|
},
|
|
set label(value) {
|
|
stanza.setAttribute(this.xml, 'label', value);
|
|
},
|
|
get options() {
|
|
var self = this;
|
|
return stanza.getMultiSubText(this.xml, this.NS, 'option', function (sub) {
|
|
return stanza.getSubText(sub, self.NS, 'value');
|
|
});
|
|
},
|
|
set options(value) {
|
|
var self = this;
|
|
stanza.setMultiSubText(this.xml, this.NS, 'option', value, function (val) {
|
|
var opt = document.createElementNS(self.NS, 'option');
|
|
var value = document.createElementNS(self.NS, 'value');
|
|
|
|
opt.appendChild(value);
|
|
value.textContent = val;
|
|
self.xml.appendChild(opt);
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Message, DataForm);
|
|
|
|
|
|
exports.DataForm = DataForm;
|
|
exports.Field = Field;
|
|
|
|
},{"../../vendor/lodash":90,"./message":35,"jxt":74}],28:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
var Presence = require('./presence');
|
|
|
|
|
|
function DelayedDelivery(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
DelayedDelivery.prototype = {
|
|
constructor: {
|
|
value: DelayedDelivery
|
|
},
|
|
NS: 'urn:xmpp:delay',
|
|
EL: 'delay',
|
|
_name: 'delay',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get from() {
|
|
return stanza.getAttribute(this.xml, 'from');
|
|
},
|
|
set from(value) {
|
|
stanza.setAttribute(this.xml, 'from', value);
|
|
},
|
|
get stamp() {
|
|
return new Date(stanza.getAttribute(this.xml, 'stamp') || Date.now());
|
|
},
|
|
set stamp(value) {
|
|
stanza.setAttribute(this.xml, 'stamp', value.toISOString());
|
|
},
|
|
get reason() {
|
|
return this.xml.textContent || '';
|
|
},
|
|
set reason(value) {
|
|
this.xml.textContent = value;
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Message, DelayedDelivery);
|
|
stanza.extend(Presence, DelayedDelivery);
|
|
|
|
|
|
module.exports = DelayedDelivery;
|
|
|
|
},{"./message":35,"./presence":37,"jxt":74}],29:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
var RSM = require('./rsm');
|
|
var DataForm = require('./dataforms').DataForm;
|
|
|
|
|
|
function DiscoInfo(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
DiscoInfo.prototype = {
|
|
constructor: {
|
|
value: DiscoInfo
|
|
},
|
|
_name: 'discoInfo',
|
|
NS: 'http://jabber.org/protocol/disco#info',
|
|
EL: 'query',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get identities() {
|
|
var result = [];
|
|
var identities = stanza.find(this.xml, this.NS, 'identity');
|
|
identities.forEach(function (identity) {
|
|
result.push({
|
|
category: stanza.getAttribute(identity, 'category'),
|
|
type: stanza.getAttribute(identity, 'type'),
|
|
lang: identity.getAttributeNS(stanza.XML_NS, 'lang'),
|
|
name: stanza.getAttribute(identity, 'name')
|
|
});
|
|
});
|
|
return result;
|
|
},
|
|
set identities(values) {
|
|
var self = this;
|
|
|
|
var existing = stanza.find(this.xml, this.NS, 'identity');
|
|
existing.forEach(function (item) {
|
|
self.xml.removeChild(item);
|
|
});
|
|
values.forEach(function (value) {
|
|
var identity = document.createElementNS(self.NS, 'identity');
|
|
stanza.setAttribute(identity, 'category', value.category);
|
|
stanza.setAttribute(identity, 'type', value.type);
|
|
stanza.setAttribute(identity, 'name', value.name);
|
|
if (value.lang) {
|
|
identity.setAttributeNS(stanza.XML_NS, 'lang', value.lang);
|
|
}
|
|
self.xml.appendChild(identity);
|
|
});
|
|
|
|
},
|
|
get features() {
|
|
var result = [];
|
|
var features = stanza.find(this.xml, this.NS, 'feature');
|
|
features.forEach(function (feature) {
|
|
result.push(feature.getAttribute('var'));
|
|
});
|
|
return result;
|
|
},
|
|
set features(values) {
|
|
var self = this;
|
|
|
|
var existing = stanza.find(this.xml, this.NS, 'feature');
|
|
existing.forEach(function (item) {
|
|
self.xml.removeChild(item);
|
|
});
|
|
values.forEach(function (value) {
|
|
var feature = document.createElementNS(self.NS, 'feature');
|
|
feature.setAttribute('var', value);
|
|
self.xml.appendChild(feature);
|
|
});
|
|
},
|
|
get extensions() {
|
|
var self = this;
|
|
var result = [];
|
|
|
|
var forms = stanza.find(this.xml, DataForm.NS, DataForm.EL);
|
|
forms.forEach(function (form) {
|
|
var ext = new DataForm({}, form);
|
|
result.push(ext.toJSON());
|
|
});
|
|
},
|
|
set extensions(value) {
|
|
var self = this;
|
|
|
|
var forms = stanza.find(this.xml, DataForm.NS, DataForm.EL);
|
|
forms.forEach(function (form) {
|
|
self.xml.removeChild(form);
|
|
});
|
|
|
|
value.forEach(function (ext) {
|
|
var form = new DataForm(ext);
|
|
self.xml.appendChild(form.xml);
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
function DiscoItems(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
DiscoItems.prototype = {
|
|
constructor: {
|
|
value: DiscoInfo
|
|
},
|
|
_name: 'discoItems',
|
|
NS: 'http://jabber.org/protocol/disco#items',
|
|
EL: 'query',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get items() {
|
|
var result = [];
|
|
var items = stanza.find(this.xml, this.NS, 'item');
|
|
items.forEach(function (item) {
|
|
result.push({
|
|
jid: stanza.getAttribute(item, 'jid'),
|
|
node: stanza.getAttribute(item, 'node'),
|
|
name: stanza.getAttribute(item, 'name')
|
|
});
|
|
});
|
|
return result;
|
|
},
|
|
set items(values) {
|
|
var self = this;
|
|
|
|
var existing = stanza.find(this.xml, this.NS, 'item');
|
|
existing.forEach(function (item) {
|
|
self.xml.removeChild(item);
|
|
});
|
|
values.forEach(function (value) {
|
|
var item = document.createElementNS(self.NS, 'item');
|
|
stanza.setAttribute(item, 'jid', value.jid);
|
|
stanza.setAttribute(item, 'node', value.node);
|
|
stanza.setAttribute(item, 'name', value.name);
|
|
self.xml.appendChild(item);
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Iq, DiscoInfo);
|
|
stanza.extend(Iq, DiscoItems);
|
|
stanza.extend(DiscoItems, RSM);
|
|
|
|
exports.DiscoInfo = DiscoInfo;
|
|
exports.DiscoItems = DiscoItems;
|
|
|
|
},{"../../vendor/lodash":90,"./dataforms":27,"./iq":33,"./rsm":42,"jxt":74}],30:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
var Presence = require('./presence');
|
|
var Iq = require('./iq');
|
|
|
|
|
|
function Error(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Error.prototype = {
|
|
constructor: {
|
|
value: Error
|
|
},
|
|
_name: 'error',
|
|
NS: 'jabber:client',
|
|
EL: 'error',
|
|
_ERR_NS: 'urn:ietf:params:xml:ns:xmpp-stanzas',
|
|
_CONDITIONS: [
|
|
'bad-request', 'conflict', 'feature-not-implemented',
|
|
'forbidden', 'gone', 'internal-server-error',
|
|
'item-not-found', 'jid-malformed', 'not-acceptable',
|
|
'not-allowed', 'not-authorized', 'payment-required',
|
|
'recipient-unavailable', 'redirect',
|
|
'registration-required', 'remote-server-not-found',
|
|
'remote-server-timeout', 'resource-constraint',
|
|
'service-unavailable', 'subscription-required',
|
|
'undefined-condition', 'unexpected-request'
|
|
],
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get lang() {
|
|
if (this.parent) {
|
|
return this.parent.lang;
|
|
}
|
|
return '';
|
|
},
|
|
get condition() {
|
|
var self = this;
|
|
var result = [];
|
|
this._CONDITIONS.forEach(function (condition) {
|
|
var exists = stanza.find(self.xml, self._ERR_NS, condition);
|
|
if (exists.length) {
|
|
result.push(exists[0].tagName);
|
|
}
|
|
});
|
|
return result[0] || '';
|
|
},
|
|
set condition(value) {
|
|
var self = this;
|
|
this._CONDITIONS.forEach(function (condition) {
|
|
var exists = stanza.find(self.xml, self._ERR_NS, condition);
|
|
if (exists.length) {
|
|
self.xml.removeChild(exists[0]);
|
|
}
|
|
});
|
|
|
|
if (value) {
|
|
var condition = document.createElementNS(this._ERR_NS, value);
|
|
condition.setAttribute('xmlns', this._ERR_NS);
|
|
this.xml.appendChild(condition);
|
|
}
|
|
},
|
|
get gone() {
|
|
return stanza.getSubText(this.xml, this._ERR_NS, 'gone');
|
|
},
|
|
set gone(value) {
|
|
this.condition = 'gone';
|
|
stanza.setSubText(this.xml, this._ERR_NS, 'gone', value);
|
|
},
|
|
get redirect() {
|
|
return stanza.getSubText(this.xml, this._ERR_NS, 'redirect');
|
|
},
|
|
set redirect(value) {
|
|
this.condition = 'redirect';
|
|
stanza.setSubText(this.xml, this._ERR_NS, 'redirect', value);
|
|
},
|
|
get code() {
|
|
return stanza.getAttribute(this.xml, 'code');
|
|
},
|
|
set code(value) {
|
|
stanza.setAttribute(this.xml, 'code', value);
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type');
|
|
},
|
|
set type(value) {
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
},
|
|
get by() {
|
|
return stanza.getAttribute(this.xml, 'by');
|
|
},
|
|
set by(value) {
|
|
stanza.setAttribute(this.xml, 'by', value);
|
|
},
|
|
get $text() {
|
|
return stanza.getSubLangText(this.xml, this._ERR_NS, 'text', this.lang);
|
|
},
|
|
set text(value) {
|
|
stanza.setSubLangText(this.xml, this._ERR_NS, 'text', value, this.lang);
|
|
},
|
|
get text() {
|
|
var text = this.$text;
|
|
return text[this.lang] || '';
|
|
},
|
|
};
|
|
|
|
stanza.extend(Message, Error);
|
|
stanza.extend(Presence, Error);
|
|
stanza.extend(Iq, Error);
|
|
|
|
|
|
module.exports = Error;
|
|
|
|
},{"../../vendor/lodash":90,"./iq":33,"./message":35,"./presence":37,"jxt":74}],31:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
var Presence = require('./presence');
|
|
var Iq = require('./iq');
|
|
var DelayedDelivery = require('./delayed');
|
|
|
|
|
|
function Forwarded(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Forwarded.prototype = {
|
|
constructor: {
|
|
value: Forwarded
|
|
},
|
|
NS: 'urn:xmpp:forward:0',
|
|
EL: 'forwarded',
|
|
_name: 'forwarded',
|
|
_eventname: 'forward',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
stanza.extend(Message, Forwarded);
|
|
stanza.extend(Forwarded, Message);
|
|
stanza.extend(Forwarded, Presence);
|
|
stanza.extend(Forwarded, Iq);
|
|
stanza.extend(Forwarded, DelayedDelivery);
|
|
|
|
|
|
module.exports = Forwarded;
|
|
|
|
},{"./delayed":28,"./iq":33,"./message":35,"./presence":37,"jxt":74}],32:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Presence = require('./presence');
|
|
|
|
|
|
function Idle(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Idle.prototype = {
|
|
constructor: {
|
|
value: Idle
|
|
},
|
|
NS: 'urn:xmpp:idle:0',
|
|
EL: 'idle',
|
|
_name: 'idle',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get since() {
|
|
return new Date(stanza.getAttribute(this.xml, 'since') || Date.now());
|
|
},
|
|
set since(value) {
|
|
stanza.setAttribute(this.xml, 'since', value.toISOString());
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Presence, Idle);
|
|
|
|
|
|
module.exports = Idle;
|
|
|
|
},{"./presence":37,"jxt":74}],33:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function Iq(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Iq.prototype = {
|
|
constructor: {
|
|
value: Iq
|
|
},
|
|
_name: 'iq',
|
|
NS: 'jabber:client',
|
|
EL: 'iq',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
resultReply: function (data) {
|
|
data.to = this.from;
|
|
data.id = this.id;
|
|
data.type = 'result';
|
|
return new Iq(data);
|
|
},
|
|
errorReply: function (data) {
|
|
data.to = this.from;
|
|
data.id = this.id;
|
|
data.type = 'error';
|
|
return new Iq(data);
|
|
},
|
|
get lang() {
|
|
return this.xml.getAttributeNS(stanza.XML_NS, 'lang') || '';
|
|
},
|
|
set lang(value) {
|
|
this.xml.setAttributeNS(stanza.XML_NS, 'lang', value);
|
|
},
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get to() {
|
|
return stanza.getAttribute(this.xml, 'to');
|
|
},
|
|
set to(value) {
|
|
stanza.setAttribute(this.xml, 'to', value);
|
|
},
|
|
get from() {
|
|
return stanza.getAttribute(this.xml, 'from');
|
|
},
|
|
set from(value) {
|
|
stanza.setAttribute(this.xml, 'from', value);
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type');
|
|
},
|
|
set type(value) {
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
}
|
|
};
|
|
|
|
stanza.topLevel(Iq);
|
|
|
|
|
|
module.exports = Iq;
|
|
|
|
},{"jxt":74}],34:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
var Iq = require('./iq');
|
|
var Forwarded = require('./forwarded');
|
|
var RSM = require('./rsm');
|
|
|
|
|
|
function MAMQuery(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
MAMQuery.prototype = {
|
|
constructor: {
|
|
value: MAMQuery
|
|
},
|
|
NS: 'urn:xmpp:mam:tmp',
|
|
EL: 'query',
|
|
_name: 'mamQuery',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get queryid() {
|
|
return stanza.getAttribute(this.xml, 'queryid');
|
|
},
|
|
set queryid(value) {
|
|
stanza.setAttribute(this.xml, 'queryid', value);
|
|
},
|
|
get start() {
|
|
return new Date(stanza.getSubText(this.xml, this.NS, 'start') || Date.now());
|
|
},
|
|
set start(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'start', value.toISOString());
|
|
},
|
|
get end() {
|
|
return new Date(stanza.getSubText(this.xml, this.NS, 'end') || Date.now());
|
|
},
|
|
set end(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'end', value.toISOString());
|
|
}
|
|
};
|
|
MAMQuery.prototype.__defineGetter__('with', function () {
|
|
return stanza.getSubText(this.xml, this.NS, 'with');
|
|
});
|
|
MAMQuery.prototype.__defineSetter__('with', function (value) {
|
|
stanza.setSubText(this.xml, this.NS, 'with', value);
|
|
});
|
|
|
|
|
|
function Result(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Result.prototype = {
|
|
constructor: {
|
|
value: Result
|
|
},
|
|
NS: 'urn:xmpp:mam:tmp',
|
|
EL: 'result',
|
|
_name: 'mam',
|
|
_eventname: 'mam:result',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get queryid() {
|
|
return stanza.getAttribute(this.xml, 'queryid');
|
|
},
|
|
set queryid(value) {
|
|
stanza.setAttribute(this.xml, 'queryid', value);
|
|
},
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Archived(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Archived.prototype = {
|
|
constructor: {
|
|
value: Result
|
|
},
|
|
NS: 'urn:xmpp:mam:tmp',
|
|
EL: 'archived',
|
|
_name: 'archived',
|
|
_eventname: 'mam:archived',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get by() {
|
|
return stanza.getAttribute(this.xml, 'by');
|
|
},
|
|
set by(value) {
|
|
stanza.setAttribute(this.xml, 'by', value);
|
|
},
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Prefs(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Prefs.prototype = {
|
|
constructor: {
|
|
value: Prefs
|
|
},
|
|
NS: 'urn:xmpp:mam:tmp',
|
|
EL: 'prefs',
|
|
_name: 'mamPrefs',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get defaultCondition() {
|
|
return stanza.getAttribute(this.xml, 'default');
|
|
},
|
|
set defaultCondition(value) {
|
|
stanza.setAttribute(this.xml, 'default', value);
|
|
},
|
|
get always() {
|
|
var results = [];
|
|
var container = stanza.find(this.xml, this.NS, 'always');
|
|
if (container.length === 0) {
|
|
return results;
|
|
}
|
|
container = container[0];
|
|
var jids = stanza.getMultiSubText(container, this.NS, 'jid');
|
|
jids.forEach(function (jid) {
|
|
results.push(jid.textContent);
|
|
});
|
|
return results;
|
|
},
|
|
set always(value) {
|
|
if (value.length > 0) {
|
|
var container = stanza.find(this.xml, this.NS, 'always');
|
|
stanza.setMultiSubText(container, this.NS, 'jid', value);
|
|
}
|
|
},
|
|
get never() {
|
|
var results = [];
|
|
var container = stanza.find(this.xml, this.NS, 'always');
|
|
if (container.length === 0) {
|
|
return results;
|
|
}
|
|
container = container[0];
|
|
var jids = stanza.getMultiSubText(container, this.NS, 'jid');
|
|
jids.forEach(function (jid) {
|
|
results.push(jid.textContent);
|
|
});
|
|
return results;
|
|
|
|
},
|
|
set never(value) {
|
|
if (value.length > 0) {
|
|
var container = stanza.find(this.xml, this.NS, 'never');
|
|
stanza.setMultiSubText(container, this.NS, 'jid', value);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
stanza.extend(Iq, MAMQuery);
|
|
stanza.extend(Iq, Prefs);
|
|
stanza.extend(Message, Result);
|
|
stanza.extend(Message, Archived);
|
|
stanza.extend(Result, Forwarded);
|
|
stanza.extend(MAMQuery, RSM);
|
|
|
|
exports.MAMQuery = MAMQuery;
|
|
exports.Result = Result;
|
|
|
|
},{"./forwarded":31,"./iq":33,"./message":35,"./rsm":42,"jxt":74}],35:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function Message(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Message.prototype = {
|
|
constructor: {
|
|
value: Message
|
|
},
|
|
_name: 'message',
|
|
NS: 'jabber:client',
|
|
EL: 'message',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get lang() {
|
|
return this.xml.getAttributeNS(stanza.XML_NS, 'lang') || '';
|
|
},
|
|
set lang(value) {
|
|
this.xml.setAttributeNS(stanza.XML_NS, 'lang', value);
|
|
},
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get to() {
|
|
return stanza.getAttribute(this.xml, 'to');
|
|
},
|
|
set to(value) {
|
|
stanza.setAttribute(this.xml, 'to', value);
|
|
},
|
|
get from() {
|
|
return stanza.getAttribute(this.xml, 'from');
|
|
},
|
|
set from(value) {
|
|
stanza.setAttribute(this.xml, 'from', value);
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type', 'normal');
|
|
},
|
|
set type(value) {
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
},
|
|
get body() {
|
|
var bodies = this.$body;
|
|
return bodies[this.lang] || '';
|
|
},
|
|
get $body() {
|
|
return stanza.getSubLangText(this.xml, this.NS, 'body', this.lang);
|
|
},
|
|
set body(value) {
|
|
stanza.setSubLangText(this.xml, this.NS, 'body', value, this.lang);
|
|
},
|
|
get thread() {
|
|
return stanza.getSubText(this.xml, this.NS, 'thread');
|
|
},
|
|
set thread(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'thread', value);
|
|
},
|
|
get parentThread() {
|
|
return stanza.getSubAttribute(this.xml, this.NS, 'thread', 'parent');
|
|
},
|
|
set parentThread(value) {
|
|
stanza.setSubAttribute(this.xml, this.NS, 'thread', 'parent', value);
|
|
}
|
|
};
|
|
|
|
stanza.topLevel(Message);
|
|
|
|
|
|
module.exports = Message;
|
|
|
|
},{"../../vendor/lodash":90,"jxt":74}],36:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
var Presence = require('./presence');
|
|
var Iq = require('./iq');
|
|
|
|
|
|
function MUCJoin(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
MUCJoin.prototype = {
|
|
constructor: {
|
|
value: MUCJoin
|
|
},
|
|
NS: 'http://jabber.org/protocol/muc',
|
|
EL: 'x',
|
|
_name: 'joinMuc',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get password() {
|
|
return stanza.getSubText(this.xml, this.NS, 'password');
|
|
},
|
|
set password(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'password', value);
|
|
},
|
|
get history() {
|
|
var result = {};
|
|
var hist = stanza.find(this.xml, this.NS, 'history');
|
|
|
|
if (!hist.length) {
|
|
return {};
|
|
}
|
|
hist = hist[0];
|
|
|
|
var maxchars = hist.getAttribute('maxchars') || '';
|
|
var maxstanzas = hist.getAttribute('maxstanas') || '';
|
|
var seconds = hist.getAttribute('seconds') || '';
|
|
var since = hist.getAttribute('since') || '';
|
|
|
|
|
|
if (maxchars) {
|
|
result.maxchars = parseInt(maxchars, 10);
|
|
}
|
|
if (maxstanzas) {
|
|
result.maxstanzas = parseInt(maxstanzas, 10);
|
|
}
|
|
if (seconds) {
|
|
result.seconds = parseInt(seconds, 10);
|
|
}
|
|
if (since) {
|
|
result.since = new Date(since);
|
|
}
|
|
},
|
|
set history(opts) {
|
|
var existing = stanza.find(this.xml, this.NS, 'history');
|
|
if (existing.length) {
|
|
for (var i = 0; i < existing.length; i++) {
|
|
this.xml.removeChild(existing[i]);
|
|
}
|
|
}
|
|
|
|
var hist = document.createElementNS(this.NS, 'history');
|
|
this.xml.appendChild(hist);
|
|
|
|
if (opts.maxchars) {
|
|
hist.setAttribute('' + opts.maxchars);
|
|
}
|
|
if (opts.maxstanzas) {
|
|
hist.setAttribute('' + opts.maxstanzas);
|
|
}
|
|
if (opts.seconds) {
|
|
hist.setAttribute('' + opts.seconds);
|
|
}
|
|
if (opts.since) {
|
|
hist.setAttribute(opts.since.toISOString());
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Presence, MUCJoin);
|
|
|
|
exports.MUCJoin = MUCJoin;
|
|
|
|
},{"./iq":33,"./message":35,"./presence":37,"jxt":74}],37:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function Presence(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Presence.prototype = {
|
|
constructor: {
|
|
value: Presence
|
|
},
|
|
_name: 'presence',
|
|
NS: 'jabber:client',
|
|
EL: 'presence',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get lang() {
|
|
return this.xml.getAttributeNS(stanza.XML_NS, 'lang') || '';
|
|
},
|
|
set lang(value) {
|
|
this.xml.setAttributeNS(stanza.XML_NS, 'lang', value);
|
|
},
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get to() {
|
|
return stanza.getAttribute(this.xml, 'to');
|
|
},
|
|
set to(value) {
|
|
stanza.setAttribute(this.xml, 'to', value);
|
|
},
|
|
get from() {
|
|
return stanza.getAttribute(this.xml, 'from');
|
|
},
|
|
set from(value) {
|
|
stanza.setAttribute(this.xml, 'from', value);
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'type', 'available');
|
|
},
|
|
set type(value) {
|
|
if (value === 'available') {
|
|
value = false;
|
|
}
|
|
stanza.setAttribute(this.xml, 'type', value);
|
|
},
|
|
get status() {
|
|
var statuses = this.$status;
|
|
return statuses[this.lang] || '';
|
|
},
|
|
get $status() {
|
|
return stanza.getSubLangText(this.xml, this.NS, 'status', this.lang);
|
|
},
|
|
set status(value) {
|
|
stanza.setSubLangText(this.xml, this.NS, 'status', value, this.lang);
|
|
},
|
|
get priority() {
|
|
return stanza.getSubText(this.xml, this.NS, 'priority');
|
|
},
|
|
set priority(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'priority', value);
|
|
},
|
|
get show() {
|
|
return stanza.getSubText(this.xml, this.NS, 'show');
|
|
},
|
|
set show(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'show', value);
|
|
}
|
|
};
|
|
|
|
stanza.topLevel(Presence);
|
|
|
|
|
|
module.exports = Presence;
|
|
|
|
},{"../../vendor/lodash":90,"jxt":74}],38:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
var Message = require('./message');
|
|
var Form = require('./dataforms').DataForm;
|
|
var RSM = require('./rsm');
|
|
|
|
|
|
function Pubsub(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Pubsub.prototype = {
|
|
constructor: {
|
|
value: Pubsub
|
|
},
|
|
_name: 'pubsub',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'pubsub',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get publishOptions() {
|
|
var conf = stanza.find(this.xml, this.NS, 'publish-options');
|
|
if (conf.length && conf[0].childNodes.length) {
|
|
return new Form({}, conf[0].childNodes[0]);
|
|
}
|
|
},
|
|
set publishOptions(value) {
|
|
var conf = stanza.findOrCreate(this.xml, this.NS, 'publish-options');
|
|
if (value) {
|
|
var form = new Form(value);
|
|
conf.appendChild(form.xml);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
function PubsubOwner(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
PubsubOwner.prototype = {
|
|
constructor: {
|
|
value: PubsubOwner
|
|
},
|
|
_name: 'pubsubOwner',
|
|
NS: 'http://jabber.org/protocol/pubsub#owner',
|
|
EL: 'pubsub',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get create() {
|
|
return stanza.getSubAttribute(this.xml, this.NS, 'create', 'node');
|
|
},
|
|
set create(value) {
|
|
stanza.setSubAttribute(this.xml, this.NS, 'create', 'node', value);
|
|
},
|
|
get purge() {
|
|
return stanza.getSubAttribute(this.xml, this.NS, 'purge', 'node');
|
|
},
|
|
set purge(value) {
|
|
stanza.setSubAttribute(this.xml, this.NS, 'purge', 'node', value);
|
|
},
|
|
get del() {
|
|
return stanza.getSubAttribute(this.xml, this.NS, 'delete', 'node');
|
|
},
|
|
set del(value) {
|
|
stanza.setSubAttribute(this.xml, this.NS, 'delete', 'node', value);
|
|
},
|
|
get redirect() {
|
|
var del = stanza.find(this.xml, this.NS, 'delete');
|
|
if (del.length) {
|
|
return stanza.getSubAttribute(del, this.NS, 'redirect', 'uri');
|
|
}
|
|
return '';
|
|
},
|
|
set redirect(value) {
|
|
var del = stanza.findOrCreate(this.xml, this.NS, 'delete');
|
|
stanza.setSubAttribute(del, this.NS, 'redirect', 'uri', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Configure(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Configure.prototype = {
|
|
constructor: {
|
|
value: Configure
|
|
},
|
|
_name: 'config',
|
|
NS: 'http://jabber.org/protocol/pubsub#owner',
|
|
EL: 'configure',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Event(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Event.prototype = {
|
|
constructor: {
|
|
value: Event
|
|
},
|
|
_name: 'event',
|
|
NS: 'http://jabber.org/protocol/pubsub#event',
|
|
EL: 'event',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Subscribe(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Subscribe.prototype = {
|
|
constructor: {
|
|
value: Subscribe
|
|
},
|
|
_name: 'subscribe',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'subscribe',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get jid() {
|
|
return stanza.getAttribute(this.xml, 'jid');
|
|
},
|
|
set jid(value) {
|
|
stanza.setAttribute(this.xml, 'jid', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Subscription(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Subscription.prototype = {
|
|
constructor: {
|
|
value: Subscription
|
|
},
|
|
_name: 'subscription',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'subscription',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get jid() {
|
|
return stanza.getAttribute(this.xml, 'jid');
|
|
},
|
|
set jid(value) {
|
|
stanza.setAttribute(this.xml, 'jid', value);
|
|
},
|
|
get subid() {
|
|
return stanza.getAttribute(this.xml, 'subid');
|
|
},
|
|
set subid(value) {
|
|
stanza.setAttribute(this.xml, 'subid', value);
|
|
},
|
|
get type() {
|
|
return stanza.getAttribute(this.xml, 'subscription');
|
|
},
|
|
set type(value) {
|
|
stanza.setAttribute(this.xml, 'subscription', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Unsubscribe(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Unsubscribe.prototype = {
|
|
constructor: {
|
|
value: Unsubscribe
|
|
},
|
|
_name: 'unsubscribe',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'unsubscribe',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get jid() {
|
|
return stanza.getAttribute(this.xml, 'jid');
|
|
},
|
|
set jid(value) {
|
|
stanza.setAttribute(this.xml, 'jid', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Publish(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Publish.prototype = {
|
|
constructor: {
|
|
value: Publish
|
|
},
|
|
_name: 'publish',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'publish',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get item() {
|
|
var items = this.items;
|
|
if (items.length) {
|
|
return items[0];
|
|
}
|
|
},
|
|
set item(value) {
|
|
this.items = [value];
|
|
}
|
|
};
|
|
|
|
|
|
function Retract(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Retract.prototype = {
|
|
constructor: {
|
|
value: Retract
|
|
},
|
|
_name: 'retract',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'retract',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get notify() {
|
|
var notify = stanza.getAttribute(this.xml, 'notify');
|
|
return notify === 'true' || notify === '1';
|
|
},
|
|
set notify(value) {
|
|
if (value) {
|
|
value = '1';
|
|
}
|
|
stanza.setAttribute(this.xml, 'notify', value);
|
|
},
|
|
get id() {
|
|
return stanza.getSubAttribute(this.xml, this.NS, 'item', 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setSubAttribute(this.xml, this.NS, 'item', 'id', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Retrieve(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Retrieve.prototype = {
|
|
constructor: {
|
|
value: Retrieve
|
|
},
|
|
_name: 'retrieve',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'items',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get max() {
|
|
return stanza.getAttribute(this.xml, 'max_items');
|
|
},
|
|
set max(value) {
|
|
stanza.setAttribute(this.xml, 'max_items', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Item(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Item.prototype = {
|
|
constructor: {
|
|
value: Item
|
|
},
|
|
_name: 'item',
|
|
NS: 'http://jabber.org/protocol/pubsub',
|
|
EL: 'item',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
}
|
|
};
|
|
|
|
|
|
function EventItems(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
EventItems.prototype = {
|
|
constructor: {
|
|
value: EventItems
|
|
},
|
|
_name: 'updated',
|
|
NS: 'http://jabber.org/protocol/pubsub#event',
|
|
EL: 'items',
|
|
toString: stanza.toString,
|
|
toJSON: function () {
|
|
var json = stanza.toJSON.apply(this);
|
|
var items = [];
|
|
_.forEach(json.published, function (item) {
|
|
items.push(item.toJSON());
|
|
});
|
|
json.published = items;
|
|
return json;
|
|
},
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get published() {
|
|
var results = [];
|
|
var items = stanza.find(this.xml, this.NS, 'item');
|
|
|
|
_.forEach(items, function (xml) {
|
|
results.push(new EventItem({}, xml));
|
|
});
|
|
return results;
|
|
},
|
|
set published(value) {
|
|
var self = this;
|
|
_.forEach(value, function (data) {
|
|
var item = new EventItem(data);
|
|
this.xml.appendChild(item.xml);
|
|
});
|
|
},
|
|
get retracted() {
|
|
var results = [];
|
|
var retracted = stanza.find(this.xml, this.NS, 'retract');
|
|
|
|
_.forEach(retracted, function (xml) {
|
|
results.push(xml.getAttribute('id'));
|
|
});
|
|
return results;
|
|
},
|
|
set retracted(value) {
|
|
var self = this;
|
|
_.forEach(value, function (id) {
|
|
var retracted = document.createElementNS(self.NS, 'retract');
|
|
retracted.setAttribute('id', id);
|
|
this.xml.appendChild(retracted);
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
function EventItem(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
EventItem.prototype = {
|
|
constructor: {
|
|
value: EventItem
|
|
},
|
|
_name: 'eventItem',
|
|
NS: 'http://jabber.org/protocol/pubsub#event',
|
|
EL: 'item',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get node() {
|
|
return stanza.getAttribute(this.xml, 'node');
|
|
},
|
|
set node(value) {
|
|
stanza.setAttribute(this.xml, 'node', value);
|
|
},
|
|
get publisher() {
|
|
return stanza.getAttribute(this.xml, 'publisher');
|
|
},
|
|
set publisher(value) {
|
|
stanza.setAttribute(this.xml, 'publisher', value);
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Pubsub, Subscribe);
|
|
stanza.extend(Pubsub, Unsubscribe);
|
|
stanza.extend(Pubsub, Publish);
|
|
stanza.extend(Pubsub, Retrieve);
|
|
stanza.extend(Pubsub, Subscription);
|
|
stanza.extend(PubsubOwner, Configure);
|
|
stanza.extend(Publish, Item);
|
|
stanza.extend(Configure, Form);
|
|
stanza.extend(Pubsub, RSM);
|
|
stanza.extend(Event, EventItems);
|
|
stanza.extend(Message, Event);
|
|
stanza.extend(Iq, Pubsub);
|
|
stanza.extend(Iq, PubsubOwner);
|
|
|
|
exports.Pubsub = Pubsub;
|
|
exports.Item = Item;
|
|
exports.EventItem = EventItem;
|
|
|
|
},{"../../vendor/lodash":90,"./dataforms":27,"./iq":33,"./message":35,"./rsm":42,"jxt":74}],39:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
|
|
|
|
function Request(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Request.prototype = {
|
|
constructor: {
|
|
value: Request
|
|
},
|
|
NS: 'urn:xmpp:receipts',
|
|
EL: 'request',
|
|
_name: '_requestReceipt',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
function Received(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Received.prototype = {
|
|
constructor: {
|
|
value: Received
|
|
},
|
|
NS: 'urn:xmpp:receipts',
|
|
EL: 'received',
|
|
_name: 'receipt',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
}
|
|
};
|
|
|
|
|
|
Message.prototype.__defineGetter__('requestReceipt', function () {
|
|
return !!this._extensions._requestReceipt;
|
|
});
|
|
Message.prototype.__defineSetter__('requestReceipt', function (value) {
|
|
if (value) {
|
|
this._requestReceipt = true;
|
|
} else if (this._extensions._requestReceipt) {
|
|
this.xml.removeChild(this._extensions._requestReceipt.xml);
|
|
delete this._extensions._requestReceipt;
|
|
}
|
|
});
|
|
|
|
|
|
stanza.extend(Message, Received);
|
|
stanza.extend(Message, Request);
|
|
|
|
exports.Request = Request;
|
|
exports.Received = Received;
|
|
|
|
},{"./message":35,"jxt":74}],40:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Message = require('./message');
|
|
|
|
|
|
function Replace(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Replace.prototype = {
|
|
constructor: {
|
|
value: Replace
|
|
},
|
|
NS: 'urn:xmpp:message-correct:0',
|
|
EL: 'replace',
|
|
_name: '_replace',
|
|
toString: stanza.toString,
|
|
toJSON: undefined,
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Message, Replace);
|
|
|
|
Message.prototype.__defineGetter__('replace', function () {
|
|
if (this._extensions._replace) {
|
|
return this._replace.id;
|
|
}
|
|
return '';
|
|
});
|
|
Message.prototype.__defineSetter__('replace', function (value) {
|
|
if (value) {
|
|
this._replace.id = value;
|
|
} else if (this._extensions._replace) {
|
|
this.xml.removeChild(this._extensions._replace.xml);
|
|
delete this._extensions._replace;
|
|
}
|
|
});
|
|
|
|
|
|
module.exports = Replace;
|
|
|
|
},{"./message":35,"jxt":74}],41:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
|
|
|
|
function Roster(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Roster.prototype = {
|
|
constructor: {
|
|
value: Roster
|
|
},
|
|
_name: 'roster',
|
|
NS: 'jabber:iq:roster',
|
|
EL: 'query',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get ver() {
|
|
return stanza.getAttribute(this.xml, 'ver');
|
|
},
|
|
set ver(value) {
|
|
var force = (value === '');
|
|
stanza.setAttribute(this.xml, 'ver', value, force);
|
|
},
|
|
get items() {
|
|
var self = this;
|
|
|
|
var items = stanza.find(this.xml, this.NS, 'item');
|
|
if (!items.length) {
|
|
return [];
|
|
}
|
|
var results = [];
|
|
items.forEach(function (item) {
|
|
var data = {
|
|
jid: stanza.getAttribute(item, 'jid', undefined),
|
|
name: stanza.getAttribute(item, 'name', undefined),
|
|
subscription: stanza.getAttribute(item, 'subscription', 'none'),
|
|
ask: stanza.getAttribute(item, 'ask', undefined),
|
|
groups: []
|
|
};
|
|
var groups = stanza.find(item, self.NS, 'group');
|
|
groups.forEach(function (group) {
|
|
data.groups.push(group.textContent);
|
|
});
|
|
results.push(data);
|
|
});
|
|
return results;
|
|
},
|
|
set items(values) {
|
|
var self = this;
|
|
values.forEach(function (value) {
|
|
var item = document.createElementNS(self.NS, 'item');
|
|
stanza.setAttribute(item, 'jid', value.jid);
|
|
stanza.setAttribute(item, 'name', value.name);
|
|
stanza.setAttribute(item, 'subscription', value.subscription);
|
|
stanza.setAttribute(item, 'ask', value.ask);
|
|
(value.groups || []).forEach(function (name) {
|
|
var group = document.createElementNS(self.NS, 'group');
|
|
group.textContent = name;
|
|
item.appendChild(group);
|
|
});
|
|
self.xml.appendChild(item);
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Iq, Roster);
|
|
|
|
|
|
module.exports = Roster;
|
|
|
|
},{"../../vendor/lodash":90,"./iq":33,"jxt":74}],42:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function RSM(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
RSM.prototype = {
|
|
constructor: {
|
|
value: RSM
|
|
},
|
|
NS: 'http://jabber.org/protocol/rsm',
|
|
EL: 'set',
|
|
_name: 'rsm',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get after() {
|
|
return stanza.getSubText(this.xml, this.NS, 'after');
|
|
},
|
|
set after(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'after', value);
|
|
},
|
|
get before() {
|
|
return stanza.getSubText(this.xml, this.NS, 'before');
|
|
},
|
|
set before(value) {
|
|
if (value === true) {
|
|
stanza.findOrCreate(this.xml, this.NS, 'before');
|
|
} else {
|
|
stanza.setSubText(this.xml, this.NS, 'before', value);
|
|
}
|
|
},
|
|
get count() {
|
|
return parseInt(stanza.getSubText(this.xml, this.NS, 'count') || '0', 10);
|
|
},
|
|
set count(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'count', value.toString());
|
|
},
|
|
get first() {
|
|
return stanza.getSubText(this.xml, this.NS, 'first');
|
|
},
|
|
set first(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'first', value);
|
|
},
|
|
get firstIndex() {
|
|
return stanza.getSubAttribute(this.xml, this.NS, 'first', 'index');
|
|
},
|
|
set firstIndex(value) {
|
|
stanza.setSubAttribute(this.xml, this.NS, 'first', 'index', value);
|
|
},
|
|
get index() {
|
|
return stanza.getSubText(this.xml, this.NS, 'index');
|
|
},
|
|
set index(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'index', value);
|
|
},
|
|
get last() {
|
|
return stanza.getSubText(this.xml, this.NS, 'last');
|
|
},
|
|
set last(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'last', value);
|
|
},
|
|
get max() {
|
|
return stanza.getSubText(this.xml, this.NS, 'max');
|
|
},
|
|
set max(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'max', value.toString());
|
|
}
|
|
};
|
|
|
|
|
|
module.exports = RSM;
|
|
|
|
},{"jxt":74}],43:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var _ = require('../../vendor/lodash');
|
|
var StreamFeatures = require('./streamFeatures');
|
|
|
|
|
|
function Mechanisms(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Mechanisms.prototype = {
|
|
constructor: {
|
|
value: Mechanisms
|
|
},
|
|
_name: 'sasl',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'mechanisms',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
required: true,
|
|
get mechanisms() {
|
|
var result = [];
|
|
var mechs = stanza.find(this.xml, this.NS, 'mechanism');
|
|
mechs.forEach(function (mech) {
|
|
result.push(mech.textContent);
|
|
});
|
|
return result;
|
|
},
|
|
set mechanisms(value) {
|
|
var self = this;
|
|
var mechs = stanza.find(this.xml, this.NS, 'mechanism');
|
|
mechs.forEach(function (mech) {
|
|
self.xml.remove(mech);
|
|
});
|
|
value.forEach(function (name) {
|
|
var mech = document.createElementNS(self.NS, 'mechanism');
|
|
mech.textContent = name;
|
|
self.xml.appendChild(mech);
|
|
});
|
|
}
|
|
};
|
|
|
|
|
|
function Auth(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Auth.prototype = {
|
|
constructor: {
|
|
value: Auth
|
|
},
|
|
_name: 'saslAuth',
|
|
_eventname: 'sasl:auth',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'auth',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get value() {
|
|
if (this.xml.textContent && this.xml.textContent != '=') {
|
|
return atob(this.xml.textContent);
|
|
}
|
|
return '';
|
|
},
|
|
set value(value) {
|
|
this.xml.textContent = btoa(value) || '=';
|
|
},
|
|
get mechanism() {
|
|
return stanza.getAttribute(this.xml, 'mechanism');
|
|
},
|
|
set mechanism(value) {
|
|
stanza.setAttribute(this.xml, 'mechanism', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Challenge(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Challenge.prototype = {
|
|
constructor: {
|
|
value: Challenge
|
|
},
|
|
_name: 'saslChallenge',
|
|
_eventname: 'sasl:challenge',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'challenge',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get value() {
|
|
if (this.xml.textContent && this.xml.textContent != '=') {
|
|
return atob(this.xml.textContent);
|
|
}
|
|
return '';
|
|
},
|
|
set value(value) {
|
|
this.xml.textContent = btoa(value) || '=';
|
|
}
|
|
};
|
|
|
|
|
|
function Response(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Response.prototype = {
|
|
constructor: {
|
|
value: Response
|
|
},
|
|
_name: 'saslResponse',
|
|
_eventname: 'sasl:response',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'response',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get value() {
|
|
if (this.xml.textContent && this.xml.textContent != '=') {
|
|
return atob(this.xml.textContent);
|
|
}
|
|
return '';
|
|
},
|
|
set value(value) {
|
|
this.xml.textContent = btoa(value) || '=';
|
|
}
|
|
};
|
|
|
|
|
|
function Success(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Success.prototype = {
|
|
constructor: {
|
|
value: Success
|
|
},
|
|
_name: 'saslSuccess',
|
|
_eventname: 'sasl:success',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'success',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get value() {
|
|
if (this.xml.textContent && this.xml.textContent != '=') {
|
|
return atob(this.xml.textContent);
|
|
}
|
|
return '';
|
|
},
|
|
set value(value) {
|
|
this.xml.textContent = btoa(value) || '=';
|
|
}
|
|
};
|
|
|
|
|
|
function Failure(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Failure.prototype = {
|
|
constructor: {
|
|
value: Success
|
|
},
|
|
_CONDITIONS: [
|
|
'aborted', 'account-disabled', 'credentials-expired',
|
|
'encryption-required', 'incorrect-encoding', 'invalid-authzid',
|
|
'invalid-mechanism', 'malformed-request', 'mechanism-too-weak',
|
|
'not-authorized', 'temporary-auth-failure',
|
|
],
|
|
_name: 'saslFailure',
|
|
_eventname: 'sasl:failure',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'failure',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get lang() {
|
|
return this._lang || '';
|
|
},
|
|
set lang(value) {
|
|
this._lang = value;
|
|
},
|
|
get condition() {
|
|
var self = this;
|
|
var result = [];
|
|
this._CONDITIONS.forEach(function (condition) {
|
|
var exists = stanza.find(self.xml, this.NS, condition);
|
|
if (exists.length) {
|
|
result.push(exists[0].tagName);
|
|
}
|
|
});
|
|
return result[0] || '';
|
|
},
|
|
set condition(value) {
|
|
var self = this;
|
|
this._CONDITIONS.forEach(function (condition) {
|
|
var exists = stanza.find(self.xml, self.NS, condition);
|
|
if (exists.length) {
|
|
self.xml.removeChild(exists[0]);
|
|
}
|
|
});
|
|
|
|
if (value) {
|
|
var condition = document.createElementNS(this.NS, value);
|
|
condition.setAttribute('xmlns', this.NS);
|
|
this.xml.appendChild(condition);
|
|
}
|
|
},
|
|
get text() {
|
|
var text = this.$text;
|
|
return text[this.lang] || '';
|
|
},
|
|
get $text() {
|
|
return stanza.getSubLangText(this.xml, this.NS, 'text', this.lang);
|
|
},
|
|
set text(value) {
|
|
stanza.setSubLangText(this.xml, this.NS, 'text', value, this.lang);
|
|
}
|
|
};
|
|
|
|
|
|
function Abort(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Abort.prototype = {
|
|
constructor: {
|
|
value: Abort
|
|
},
|
|
_name: 'saslAbort',
|
|
_eventname: 'sasl:abort',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
|
|
EL: 'abort',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
stanza.extend(StreamFeatures, Mechanisms, 'sasl');
|
|
stanza.topLevel(Auth);
|
|
stanza.topLevel(Challenge);
|
|
stanza.topLevel(Response);
|
|
stanza.topLevel(Success);
|
|
stanza.topLevel(Failure);
|
|
stanza.topLevel(Abort);
|
|
|
|
|
|
exports.Mechanisms = Mechanisms;
|
|
exports.Auth = Auth;
|
|
exports.Challenge = Challenge;
|
|
exports.Response = Response;
|
|
exports.Success = Success;
|
|
exports.Failure = Failure;
|
|
exports.Abort = Abort;
|
|
|
|
},{"../../vendor/lodash":90,"./streamFeatures":48,"jxt":74}],44:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
var StreamFeatures = require('./streamFeatures');
|
|
|
|
|
|
function Session(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Session.prototype = {
|
|
constructor: {
|
|
value: Session
|
|
},
|
|
_name: 'session',
|
|
NS: 'urn:ietf:params:xml:ns:xmpp-session',
|
|
EL: 'session',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
stanza.extend(StreamFeatures, Session);
|
|
stanza.extend(Iq, Session);
|
|
|
|
|
|
module.exports = Session;
|
|
|
|
},{"./iq":33,"./streamFeatures":48,"jxt":74}],45:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var StreamFeatures = require('./streamFeatures');
|
|
|
|
|
|
function SMFeature(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
SMFeature.prototype = {
|
|
constructor: {
|
|
value: SMFeature
|
|
},
|
|
_name: 'streamManagement',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'sm',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Enable(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Enable.prototype = {
|
|
constructor: {
|
|
value: Enable
|
|
},
|
|
_name: 'smEnable',
|
|
_eventname: 'stream:management:enable',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'enable',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get resume() {
|
|
return stanza.getBoolAttribute(this.xml, 'resume');
|
|
},
|
|
set resume(val) {
|
|
stanza.setBoolAttribute(this.xml, 'resume', val);
|
|
}
|
|
};
|
|
|
|
|
|
function Enabled(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Enabled.prototype = {
|
|
constructor: {
|
|
value: Enabled
|
|
},
|
|
_name: 'smEnabled',
|
|
_eventname: 'stream:management:enabled',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'enabled',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get resume() {
|
|
return stanza.getBoolAttribute(this.xml, 'resume');
|
|
},
|
|
set resume(val) {
|
|
stanza.setBoolAttribute(this.xml, 'resume', val);
|
|
}
|
|
};
|
|
|
|
|
|
function Resume(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Resume.prototype = {
|
|
constructor: {
|
|
value: Resume
|
|
},
|
|
_name: 'smResume',
|
|
_eventname: 'stream:management:resume',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'resume',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get h() {
|
|
return parseInt(stanza.getAttribute(this.xml, 'h', '0'), 10);
|
|
},
|
|
set h(value) {
|
|
stanza.setAttribute(this.xml, 'h', '' + value);
|
|
},
|
|
get previd() {
|
|
return stanza.getAttribute(this.xml, 'previd');
|
|
},
|
|
set previd(value) {
|
|
stanza.setAttribute(this.xml, 'previd', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Resumed(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Resumed.prototype = {
|
|
constructor: {
|
|
value: Resumed
|
|
},
|
|
_name: 'smResumed',
|
|
_eventname: 'stream:management:resumed',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'resumed',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get h() {
|
|
return parseInt(stanza.getAttribute(this.xml, 'h', '0'), 10);
|
|
},
|
|
set h(value) {
|
|
stanza.setAttribute(this.xml, 'h', '' + value);
|
|
},
|
|
get previd() {
|
|
return stanza.getAttribute(this.xml, 'previd');
|
|
},
|
|
set previd(value) {
|
|
stanza.setAttribute(this.xml, 'previd', value);
|
|
}
|
|
};
|
|
|
|
|
|
function Failed(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Failed.prototype = {
|
|
constructor: {
|
|
value: Failed
|
|
},
|
|
_name: 'smFailed',
|
|
_eventname: 'stream:management:failed',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'failed',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
function Ack(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Ack.prototype = {
|
|
constructor: {
|
|
value: Ack
|
|
},
|
|
_name: 'smAck',
|
|
_eventname: 'stream:management:ack',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'a',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get h() {
|
|
return parseInt(stanza.getAttribute(this.xml, 'h', '0'), 10);
|
|
},
|
|
set h(value) {
|
|
stanza.setAttribute(this.xml, 'h', '' + value);
|
|
}
|
|
};
|
|
|
|
|
|
function Request(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Request.prototype = {
|
|
constructor: {
|
|
value: Request
|
|
},
|
|
_name: 'smRequest',
|
|
_eventname: 'stream:management:request',
|
|
NS: 'urn:xmpp:sm:3',
|
|
EL: 'r',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON
|
|
};
|
|
|
|
|
|
stanza.extend(StreamFeatures, SMFeature);
|
|
stanza.topLevel(Ack);
|
|
stanza.topLevel(Request);
|
|
stanza.topLevel(Enable);
|
|
stanza.topLevel(Enabled);
|
|
stanza.topLevel(Resume);
|
|
stanza.topLevel(Resumed);
|
|
stanza.topLevel(Failed);
|
|
|
|
|
|
exports.SMFeature = SMFeature;
|
|
exports.Enable = Enable;
|
|
exports.Enabled = Enabled;
|
|
exports.Resume = Resume;
|
|
exports.Resumed = Resumed;
|
|
exports.Failed = Failed;
|
|
exports.Ack = Ack;
|
|
exports.Request = Request;
|
|
|
|
},{"./streamFeatures":48,"jxt":74}],46:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function Stream(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Stream.prototype = {
|
|
constructor: {
|
|
value: Stream
|
|
},
|
|
_name: 'stream',
|
|
NS: 'http://etherx.jabber.org/streams',
|
|
EL: 'stream',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get lang() {
|
|
return this.xml.getAttributeNS(stanza.XML_NS, 'lang') || '';
|
|
},
|
|
set lang(value) {
|
|
this.xml.setAttributeNS(stanza.XML_NS, 'lang', value);
|
|
},
|
|
get id() {
|
|
return stanza.getAttribute(this.xml, 'id');
|
|
},
|
|
set id(value) {
|
|
stanza.setAttribute(this.xml, 'id', value);
|
|
},
|
|
get version() {
|
|
return stanza.getAttribute(this.xml, 'version', '1.0');
|
|
},
|
|
set version(value) {
|
|
stanza.setAttribute(this.xml, 'version', value);
|
|
},
|
|
get to() {
|
|
return stanza.getAttribute(this.xml, 'to');
|
|
},
|
|
set to(value) {
|
|
stanza.setAttribute(this.xml, 'to', value);
|
|
},
|
|
get from() {
|
|
return stanza.getAttribute(this.xml, 'from');
|
|
},
|
|
set from(value) {
|
|
stanza.setAttribute(this.xml, 'from', value);
|
|
}
|
|
};
|
|
|
|
module.exports = Stream;
|
|
|
|
},{"jxt":74}],47:[function(require,module,exports){
|
|
var _ = require('../../vendor/lodash');
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function StreamError(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
StreamError.prototype = {
|
|
constructor: {
|
|
value: StreamError
|
|
},
|
|
_name: 'streamError',
|
|
NS: 'http://etherx.jabber.org/streams',
|
|
EL: 'error',
|
|
_ERR_NS: 'urn:ietf:params:xml:ns:xmpp-streams',
|
|
_CONDITIONS: [
|
|
'bad-format', 'bad-namespace-prefix', 'conflict',
|
|
'connection-timeout', 'host-gone', 'host-unknown',
|
|
'improper-addressing', 'internal-server-error', 'invalid-from',
|
|
'invalid-namespace', 'invalid-xml', 'not-authorized',
|
|
'not-well-formed', 'policy-violation', 'remote-connection-failed',
|
|
'reset', 'resource-constraint', 'restricted-xml', 'see-other-host',
|
|
'system-shutdown', 'undefined-condition', 'unsupported-encoding',
|
|
'unsupported-feature', 'unsupported-stanza-type',
|
|
'unsupported-version'
|
|
],
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get lang() {
|
|
return this._lang || '';
|
|
},
|
|
set lang(value) {
|
|
this._lang = value;
|
|
},
|
|
get condition() {
|
|
var self = this;
|
|
var result = [];
|
|
this._CONDITIONS.forEach(function (condition) {
|
|
var exists = stanza.find(self.xml, self._ERR_NS, condition);
|
|
if (exists.length) {
|
|
result.push(exists[0].tagName);
|
|
}
|
|
});
|
|
return result[0] || '';
|
|
},
|
|
set condition(value) {
|
|
var self = this;
|
|
this._CONDITIONS.forEach(function (condition) {
|
|
var exists = stanza.find(self.xml, self._ERR_NS, condition);
|
|
if (exists.length) {
|
|
self.xml.removeChild(exists[0]);
|
|
}
|
|
});
|
|
|
|
if (value) {
|
|
var condition = document.createElementNS(this._ERR_NS, value);
|
|
condition.setAttribute('xmlns', this._ERR_NS);
|
|
this.xml.appendChild(condition);
|
|
}
|
|
},
|
|
get seeOtherHost() {
|
|
return stanza.getSubText(this.xml, this._ERR_NS, 'see-other-host');
|
|
},
|
|
set seeOtherHost(value) {
|
|
this.condition = 'see-other-host';
|
|
stanza.setSubText(this.xml, this._ERR_NS, 'see-other-host', value);
|
|
},
|
|
get text() {
|
|
var text = this.$text;
|
|
return text[this.lang] || '';
|
|
},
|
|
get $text() {
|
|
return stanza.getSubLangText(this.xml, this._ERR_NS, 'text', this.lang);
|
|
},
|
|
set text(value) {
|
|
stanza.setSubLangText(this.xml, this._ERR_NS, 'text', value, this.lang);
|
|
}
|
|
};
|
|
|
|
stanza.topLevel(StreamError);
|
|
|
|
|
|
module.exports = StreamError;
|
|
|
|
},{"../../vendor/lodash":90,"jxt":74}],48:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
|
|
|
|
function StreamFeatures(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
StreamFeatures.prototype = {
|
|
constructor: {
|
|
value: StreamFeatures
|
|
},
|
|
_name: 'streamFeatures',
|
|
NS: 'http://etherx.jabber.org/streams',
|
|
EL: 'features',
|
|
_FEATURES: [],
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get features() {
|
|
return this._extensions;
|
|
}
|
|
};
|
|
|
|
stanza.topLevel(StreamFeatures);
|
|
|
|
|
|
module.exports = StreamFeatures;
|
|
|
|
},{"jxt":74}],49:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
|
|
|
|
function EntityTime(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
EntityTime.prototype = {
|
|
constructor: {
|
|
value: EntityTime
|
|
},
|
|
NS: 'urn:xmpp:time',
|
|
EL: 'time',
|
|
_name: 'time',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get tzo() {
|
|
var split, hrs, min;
|
|
var sign = -1;
|
|
var formatted = stanza.getSubText(this.xml, this.NS, 'tzo');
|
|
|
|
if (!formatted) {
|
|
return 0;
|
|
}
|
|
if (formatted.charAt(0) === '-') {
|
|
sign = 1;
|
|
formatted.slice(1);
|
|
}
|
|
split = formatted.split(':');
|
|
hrs = parseInt(split[0], 10);
|
|
min = parseInt(split[1], 10);
|
|
return (hrs * 60 + min) * sign;
|
|
},
|
|
set tzo(value) {
|
|
var hrs, min;
|
|
var formatted = '-';
|
|
if (typeof value === 'number') {
|
|
if (value < 0) {
|
|
value = -value;
|
|
formatted = '+';
|
|
}
|
|
hrs = value / 60;
|
|
min = value % 60;
|
|
formatted += (hrs < 10 ? '0' : '') + hrs + ':' + (min < 10 ? '0' : '') + min;
|
|
} else {
|
|
formatted = value;
|
|
}
|
|
stanza.setSubText(this.xml, this.NS, 'tzo', formatted);
|
|
},
|
|
get utc() {
|
|
var stamp = stanza.getSubText(this.xml, this.NS, 'utc');
|
|
if (stamp) {
|
|
return new Date(stamp || Date.now());
|
|
}
|
|
return '';
|
|
},
|
|
set utc(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'utc', value.toISOString());
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Iq, EntityTime);
|
|
|
|
module.exports = EntityTime;
|
|
|
|
},{"./iq":33,"jxt":74}],50:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
|
|
|
|
function Version(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Version.prototype = {
|
|
constructor: {
|
|
value: Version
|
|
},
|
|
NS: 'jabber:iq:version',
|
|
EL: 'query',
|
|
_name: 'version',
|
|
toString: stanza.toString,
|
|
toJSON: stanza.toJSON,
|
|
get name() {
|
|
return stanza.getSubText(this.xml, this.NS, 'name');
|
|
},
|
|
set name(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'name', value);
|
|
},
|
|
get version() {
|
|
return stanza.getSubText(this.xml, this.NS, 'version');
|
|
},
|
|
set version(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'version', value);
|
|
},
|
|
get os() {
|
|
return stanza.getSubText(this.xml, this.NS, 'os');
|
|
},
|
|
set os(value) {
|
|
stanza.setSubText(this.xml, this.NS, 'os', value);
|
|
}
|
|
};
|
|
|
|
|
|
stanza.extend(Iq, Version);
|
|
|
|
|
|
module.exports = Version;
|
|
|
|
},{"./iq":33,"jxt":74}],51:[function(require,module,exports){
|
|
var stanza = require('jxt');
|
|
var Iq = require('./iq');
|
|
|
|
|
|
function Visible(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Visible.prototype = {
|
|
constructor: {
|
|
value: Visible
|
|
},
|
|
NS: 'urn:xmpp:invisible:0',
|
|
EL: 'visible',
|
|
_name: '_visible',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
function Invisible(data, xml) {
|
|
return stanza.init(this, xml, data);
|
|
}
|
|
Invisible.prototype = {
|
|
constructor: {
|
|
value: Invisible
|
|
},
|
|
NS: 'urn:xmpp:invisible:0',
|
|
EL: 'invisible',
|
|
_name: '_invisible',
|
|
toString: stanza.toString,
|
|
toJSON: undefined
|
|
};
|
|
|
|
|
|
|
|
Iq.prototype.__defineGetter__('visible', function () {
|
|
return !!this._extensions._visible;
|
|
});
|
|
Iq.prototype.__defineSetter__('visible', function (value) {
|
|
if (value) {
|
|
this._visible = true;
|
|
} else if (this._extensions._visible) {
|
|
this.xml.removeChild(this._extensions._visible.xml);
|
|
delete this._extensions._visible;
|
|
}
|
|
});
|
|
|
|
|
|
Iq.prototype.__defineGetter__('invisible', function () {
|
|
return !!this._extensions._invisible;
|
|
});
|
|
Iq.prototype.__defineSetter__('invisible', function (value) {
|
|
if (value) {
|
|
this._invisible = true;
|
|
} else if (this._extensions._invisible) {
|
|
this.xml.removeChild(this._extensions._invisible.xml);
|
|
delete this._extensions._invisible;
|
|
}
|
|
});
|
|
|
|
|
|
stanza.extend(Iq, Visible);
|
|
stanza.extend(Iq, Invisible);
|
|
|
|
exports.Visible = Visible;
|
|
exports.Invisible = Invisible;
|
|
|
|
},{"./iq":33,"jxt":74}],52:[function(require,module,exports){
|
|
var WildEmitter = require('wildemitter');
|
|
var _ = require('../vendor/lodash');
|
|
var async = require('async');
|
|
var Stream = require('./stanza/stream');
|
|
var Message = require('./stanza/message');
|
|
var Presence = require('./stanza/presence');
|
|
var Iq = require('./stanza/iq');
|
|
var StreamManagement = require('./sm');
|
|
var uuid = require('node-uuid');
|
|
|
|
|
|
function WSConnection() {
|
|
var self = this;
|
|
|
|
WildEmitter.call(this);
|
|
|
|
self.sm = new StreamManagement(self);
|
|
|
|
self.sendQueue = async.queue(function (data, cb) {
|
|
if (self.conn) {
|
|
self.emit('raw:outgoing', data);
|
|
|
|
self.sm.track(data);
|
|
|
|
if (typeof data !== 'string') {
|
|
data = data.toString();
|
|
}
|
|
|
|
self.conn.send(data);
|
|
}
|
|
cb();
|
|
}, 1);
|
|
|
|
function wrap(data) {
|
|
var result = [self.streamStart, data, self.streamEnd].join('');
|
|
return result;
|
|
}
|
|
|
|
function parse(data) {
|
|
var nodes = (self.parser.parseFromString(data, 'application/xml')).childNodes;
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
if (nodes[i].nodeType === 1) {
|
|
return nodes[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
self.on('connected', function () {
|
|
self.send([
|
|
'<stream:stream',
|
|
'xmlns:stream="http://etherx.jabber.org/streams"',
|
|
'xmlns="jabber:client"',
|
|
'version="' + (self.config.version || '1.0') + '"',
|
|
'xml:lang="' + (self.config.lang || 'en') + '"',
|
|
'to="' + self.config.server + '">'
|
|
].join(' '));
|
|
});
|
|
|
|
self.on('raw:incoming', function (data) {
|
|
var streamData, ended;
|
|
|
|
data = data.trim();
|
|
data = data.replace(/^(\s*<\?.*\?>\s*)*/, '');
|
|
if (data === '') {
|
|
return;
|
|
}
|
|
|
|
if (data.match(self.streamEnd)) {
|
|
return self.disconnect();
|
|
} else if (self.hasStream) {
|
|
try {
|
|
streamData = new Stream({}, parse(wrap(data)));
|
|
} catch (e) {
|
|
return self.disconnect();
|
|
}
|
|
} else {
|
|
// Inspect start of stream element to get NS prefix name
|
|
var parts = data.match(/^<(\S+:)?(\S+) /);
|
|
self.streamStart = data;
|
|
self.streamEnd = '</' + (parts[1] || '') + parts[2] + '>';
|
|
|
|
ended = false;
|
|
try {
|
|
streamData = new Stream({}, parse(data + self.streamEnd));
|
|
} catch (e) {
|
|
try {
|
|
streamData = new Stream({}, parse(data));
|
|
ended = true;
|
|
} catch (e2) {
|
|
return self.disconnect();
|
|
}
|
|
}
|
|
|
|
self.hasStream = true;
|
|
self.stream = streamData;
|
|
self.emit('stream:start', streamData);
|
|
}
|
|
|
|
_.each(streamData._extensions, function (stanzaObj) {
|
|
if (!stanzaObj.lang) {
|
|
stanzaObj.lang = self.stream.lang;
|
|
}
|
|
|
|
if (stanzaObj._name === 'message' || stanzaObj._name === 'presence' || stanzaObj._name === 'iq') {
|
|
self.sm.handle(stanzaObj);
|
|
self.emit('stanza', stanzaObj);
|
|
}
|
|
self.emit(stanzaObj._eventname || stanzaObj._name, stanzaObj);
|
|
self.emit('stream:data', stanzaObj);
|
|
|
|
if (stanzaObj.id) {
|
|
self.emit('id:' + stanzaObj.id, stanzaObj);
|
|
}
|
|
});
|
|
|
|
if (ended) {
|
|
self.emit('stream:end');
|
|
}
|
|
});
|
|
}
|
|
|
|
WSConnection.prototype = Object.create(WildEmitter.prototype, {
|
|
constructor: {
|
|
value: WSConnection
|
|
}
|
|
});
|
|
|
|
WSConnection.prototype.connect = function (opts) {
|
|
var self = this;
|
|
|
|
self.config = opts;
|
|
|
|
self.hasStream = false;
|
|
self.streamStart = '<stream:stream xmlns:stream="http://etherx.jabber.org/streams">';
|
|
self.streamEnd = '</stream:stream>';
|
|
self.parser = new DOMParser();
|
|
self.serializer = new XMLSerializer();
|
|
|
|
self.conn = new WebSocket(opts.wsURL, 'xmpp');
|
|
|
|
self.conn.onopen = function () {
|
|
self.emit('connected', self);
|
|
};
|
|
|
|
self.conn.onclose = function () {
|
|
self.emit('disconnected', self);
|
|
};
|
|
|
|
self.conn.onmessage = function (wsMsg) {
|
|
self.emit('raw:incoming', wsMsg.data);
|
|
};
|
|
};
|
|
|
|
WSConnection.prototype.disconnect = function () {
|
|
if (this.conn) {
|
|
if (this.hasStream) {
|
|
this.conn.send('</stream:stream>');
|
|
this.emit('raw:outgoing', '</stream:stream>');
|
|
this.emit('stream:end');
|
|
}
|
|
this.hasStream = false;
|
|
this.conn.close();
|
|
this.stream = undefined;
|
|
this.conn = undefined;
|
|
}
|
|
};
|
|
|
|
WSConnection.prototype.restart = function () {
|
|
var self = this;
|
|
self.hasStream = false;
|
|
self.send([
|
|
'<stream:stream',
|
|
'xmlns:stream="http://etherx.jabber.org/streams"',
|
|
'xmlns="jabber:client"',
|
|
'version="' + (self.config.version || '1.0') + '"',
|
|
'xml:lang="' + (self.config.lang || 'en') + '"',
|
|
'to="' + self.config.server + '">'
|
|
].join(' '));
|
|
};
|
|
|
|
WSConnection.prototype.send = function (data) {
|
|
this.sendQueue.push(data);
|
|
};
|
|
|
|
|
|
module.exports = WSConnection;
|
|
|
|
},{"../vendor/lodash":90,"./sm":20,"./stanza/iq":33,"./stanza/message":35,"./stanza/presence":37,"./stanza/stream":46,"async":53,"node-uuid":76,"wildemitter":89}],53:[function(require,module,exports){
|
|
var process=require("__browserify_process");/*global setImmediate: false, setTimeout: false, console: false */
|
|
(function () {
|
|
|
|
var async = {};
|
|
|
|
// global on the server, window in the browser
|
|
var root, previous_async;
|
|
|
|
root = this;
|
|
if (root != null) {
|
|
previous_async = root.async;
|
|
}
|
|
|
|
async.noConflict = function () {
|
|
root.async = previous_async;
|
|
return async;
|
|
};
|
|
|
|
function only_once(fn) {
|
|
var called = false;
|
|
return function() {
|
|
if (called) throw new Error("Callback was already called.");
|
|
called = true;
|
|
fn.apply(root, arguments);
|
|
}
|
|
}
|
|
|
|
//// cross-browser compatiblity functions ////
|
|
|
|
var _each = function (arr, iterator) {
|
|
if (arr.forEach) {
|
|
return arr.forEach(iterator);
|
|
}
|
|
for (var i = 0; i < arr.length; i += 1) {
|
|
iterator(arr[i], i, arr);
|
|
}
|
|
};
|
|
|
|
var _map = function (arr, iterator) {
|
|
if (arr.map) {
|
|
return arr.map(iterator);
|
|
}
|
|
var results = [];
|
|
_each(arr, function (x, i, a) {
|
|
results.push(iterator(x, i, a));
|
|
});
|
|
return results;
|
|
};
|
|
|
|
var _reduce = function (arr, iterator, memo) {
|
|
if (arr.reduce) {
|
|
return arr.reduce(iterator, memo);
|
|
}
|
|
_each(arr, function (x, i, a) {
|
|
memo = iterator(memo, x, i, a);
|
|
});
|
|
return memo;
|
|
};
|
|
|
|
var _keys = function (obj) {
|
|
if (Object.keys) {
|
|
return Object.keys(obj);
|
|
}
|
|
var keys = [];
|
|
for (var k in obj) {
|
|
if (obj.hasOwnProperty(k)) {
|
|
keys.push(k);
|
|
}
|
|
}
|
|
return keys;
|
|
};
|
|
|
|
//// exported async module functions ////
|
|
|
|
//// nextTick implementation with browser-compatible fallback ////
|
|
if (typeof process === 'undefined' || !(process.nextTick)) {
|
|
if (typeof setImmediate === 'function') {
|
|
async.nextTick = function (fn) {
|
|
// not a direct alias for IE10 compatibility
|
|
setImmediate(fn);
|
|
};
|
|
async.setImmediate = async.nextTick;
|
|
}
|
|
else {
|
|
async.nextTick = function (fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
async.setImmediate = async.nextTick;
|
|
}
|
|
}
|
|
else {
|
|
async.nextTick = process.nextTick;
|
|
if (typeof setImmediate !== 'undefined') {
|
|
async.setImmediate = setImmediate;
|
|
}
|
|
else {
|
|
async.setImmediate = async.nextTick;
|
|
}
|
|
}
|
|
|
|
async.each = function (arr, iterator, callback) {
|
|
callback = callback || function () {};
|
|
if (!arr.length) {
|
|
return callback();
|
|
}
|
|
var completed = 0;
|
|
_each(arr, function (x) {
|
|
iterator(x, only_once(function (err) {
|
|
if (err) {
|
|
callback(err);
|
|
callback = function () {};
|
|
}
|
|
else {
|
|
completed += 1;
|
|
if (completed >= arr.length) {
|
|
callback(null);
|
|
}
|
|
}
|
|
}));
|
|
});
|
|
};
|
|
async.forEach = async.each;
|
|
|
|
async.eachSeries = function (arr, iterator, callback) {
|
|
callback = callback || function () {};
|
|
if (!arr.length) {
|
|
return callback();
|
|
}
|
|
var completed = 0;
|
|
var iterate = function () {
|
|
iterator(arr[completed], function (err) {
|
|
if (err) {
|
|
callback(err);
|
|
callback = function () {};
|
|
}
|
|
else {
|
|
completed += 1;
|
|
if (completed >= arr.length) {
|
|
callback(null);
|
|
}
|
|
else {
|
|
iterate();
|
|
}
|
|
}
|
|
});
|
|
};
|
|
iterate();
|
|
};
|
|
async.forEachSeries = async.eachSeries;
|
|
|
|
async.eachLimit = function (arr, limit, iterator, callback) {
|
|
var fn = _eachLimit(limit);
|
|
fn.apply(null, [arr, iterator, callback]);
|
|
};
|
|
async.forEachLimit = async.eachLimit;
|
|
|
|
var _eachLimit = function (limit) {
|
|
|
|
return function (arr, iterator, callback) {
|
|
callback = callback || function () {};
|
|
if (!arr.length || limit <= 0) {
|
|
return callback();
|
|
}
|
|
var completed = 0;
|
|
var started = 0;
|
|
var running = 0;
|
|
|
|
(function replenish () {
|
|
if (completed >= arr.length) {
|
|
return callback();
|
|
}
|
|
|
|
while (running < limit && started < arr.length) {
|
|
started += 1;
|
|
running += 1;
|
|
iterator(arr[started - 1], function (err) {
|
|
if (err) {
|
|
callback(err);
|
|
callback = function () {};
|
|
}
|
|
else {
|
|
completed += 1;
|
|
running -= 1;
|
|
if (completed >= arr.length) {
|
|
callback();
|
|
}
|
|
else {
|
|
replenish();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
})();
|
|
};
|
|
};
|
|
|
|
|
|
var doParallel = function (fn) {
|
|
return function () {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
return fn.apply(null, [async.each].concat(args));
|
|
};
|
|
};
|
|
var doParallelLimit = function(limit, fn) {
|
|
return function () {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
return fn.apply(null, [_eachLimit(limit)].concat(args));
|
|
};
|
|
};
|
|
var doSeries = function (fn) {
|
|
return function () {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
return fn.apply(null, [async.eachSeries].concat(args));
|
|
};
|
|
};
|
|
|
|
|
|
var _asyncMap = function (eachfn, arr, iterator, callback) {
|
|
var results = [];
|
|
arr = _map(arr, function (x, i) {
|
|
return {index: i, value: x};
|
|
});
|
|
eachfn(arr, function (x, callback) {
|
|
iterator(x.value, function (err, v) {
|
|
results[x.index] = v;
|
|
callback(err);
|
|
});
|
|
}, function (err) {
|
|
callback(err, results);
|
|
});
|
|
};
|
|
async.map = doParallel(_asyncMap);
|
|
async.mapSeries = doSeries(_asyncMap);
|
|
async.mapLimit = function (arr, limit, iterator, callback) {
|
|
return _mapLimit(limit)(arr, iterator, callback);
|
|
};
|
|
|
|
var _mapLimit = function(limit) {
|
|
return doParallelLimit(limit, _asyncMap);
|
|
};
|
|
|
|
// reduce only has a series version, as doing reduce in parallel won't
|
|
// work in many situations.
|
|
async.reduce = function (arr, memo, iterator, callback) {
|
|
async.eachSeries(arr, function (x, callback) {
|
|
iterator(memo, x, function (err, v) {
|
|
memo = v;
|
|
callback(err);
|
|
});
|
|
}, function (err) {
|
|
callback(err, memo);
|
|
});
|
|
};
|
|
// inject alias
|
|
async.inject = async.reduce;
|
|
// foldl alias
|
|
async.foldl = async.reduce;
|
|
|
|
async.reduceRight = function (arr, memo, iterator, callback) {
|
|
var reversed = _map(arr, function (x) {
|
|
return x;
|
|
}).reverse();
|
|
async.reduce(reversed, memo, iterator, callback);
|
|
};
|
|
// foldr alias
|
|
async.foldr = async.reduceRight;
|
|
|
|
var _filter = function (eachfn, arr, iterator, callback) {
|
|
var results = [];
|
|
arr = _map(arr, function (x, i) {
|
|
return {index: i, value: x};
|
|
});
|
|
eachfn(arr, function (x, callback) {
|
|
iterator(x.value, function (v) {
|
|
if (v) {
|
|
results.push(x);
|
|
}
|
|
callback();
|
|
});
|
|
}, function (err) {
|
|
callback(_map(results.sort(function (a, b) {
|
|
return a.index - b.index;
|
|
}), function (x) {
|
|
return x.value;
|
|
}));
|
|
});
|
|
};
|
|
async.filter = doParallel(_filter);
|
|
async.filterSeries = doSeries(_filter);
|
|
// select alias
|
|
async.select = async.filter;
|
|
async.selectSeries = async.filterSeries;
|
|
|
|
var _reject = function (eachfn, arr, iterator, callback) {
|
|
var results = [];
|
|
arr = _map(arr, function (x, i) {
|
|
return {index: i, value: x};
|
|
});
|
|
eachfn(arr, function (x, callback) {
|
|
iterator(x.value, function (v) {
|
|
if (!v) {
|
|
results.push(x);
|
|
}
|
|
callback();
|
|
});
|
|
}, function (err) {
|
|
callback(_map(results.sort(function (a, b) {
|
|
return a.index - b.index;
|
|
}), function (x) {
|
|
return x.value;
|
|
}));
|
|
});
|
|
};
|
|
async.reject = doParallel(_reject);
|
|
async.rejectSeries = doSeries(_reject);
|
|
|
|
var _detect = function (eachfn, arr, iterator, main_callback) {
|
|
eachfn(arr, function (x, callback) {
|
|
iterator(x, function (result) {
|
|
if (result) {
|
|
main_callback(x);
|
|
main_callback = function () {};
|
|
}
|
|
else {
|
|
callback();
|
|
}
|
|
});
|
|
}, function (err) {
|
|
main_callback();
|
|
});
|
|
};
|
|
async.detect = doParallel(_detect);
|
|
async.detectSeries = doSeries(_detect);
|
|
|
|
async.some = function (arr, iterator, main_callback) {
|
|
async.each(arr, function (x, callback) {
|
|
iterator(x, function (v) {
|
|
if (v) {
|
|
main_callback(true);
|
|
main_callback = function () {};
|
|
}
|
|
callback();
|
|
});
|
|
}, function (err) {
|
|
main_callback(false);
|
|
});
|
|
};
|
|
// any alias
|
|
async.any = async.some;
|
|
|
|
async.every = function (arr, iterator, main_callback) {
|
|
async.each(arr, function (x, callback) {
|
|
iterator(x, function (v) {
|
|
if (!v) {
|
|
main_callback(false);
|
|
main_callback = function () {};
|
|
}
|
|
callback();
|
|
});
|
|
}, function (err) {
|
|
main_callback(true);
|
|
});
|
|
};
|
|
// all alias
|
|
async.all = async.every;
|
|
|
|
async.sortBy = function (arr, iterator, callback) {
|
|
async.map(arr, function (x, callback) {
|
|
iterator(x, function (err, criteria) {
|
|
if (err) {
|
|
callback(err);
|
|
}
|
|
else {
|
|
callback(null, {value: x, criteria: criteria});
|
|
}
|
|
});
|
|
}, function (err, results) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
else {
|
|
var fn = function (left, right) {
|
|
var a = left.criteria, b = right.criteria;
|
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
};
|
|
callback(null, _map(results.sort(fn), function (x) {
|
|
return x.value;
|
|
}));
|
|
}
|
|
});
|
|
};
|
|
|
|
async.auto = function (tasks, callback) {
|
|
callback = callback || function () {};
|
|
var keys = _keys(tasks);
|
|
if (!keys.length) {
|
|
return callback(null);
|
|
}
|
|
|
|
var results = {};
|
|
|
|
var listeners = [];
|
|
var addListener = function (fn) {
|
|
listeners.unshift(fn);
|
|
};
|
|
var removeListener = function (fn) {
|
|
for (var i = 0; i < listeners.length; i += 1) {
|
|
if (listeners[i] === fn) {
|
|
listeners.splice(i, 1);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
var taskComplete = function () {
|
|
_each(listeners.slice(0), function (fn) {
|
|
fn();
|
|
});
|
|
};
|
|
|
|
addListener(function () {
|
|
if (_keys(results).length === keys.length) {
|
|
callback(null, results);
|
|
callback = function () {};
|
|
}
|
|
});
|
|
|
|
_each(keys, function (k) {
|
|
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
|
|
var taskCallback = function (err) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
if (args.length <= 1) {
|
|
args = args[0];
|
|
}
|
|
if (err) {
|
|
var safeResults = {};
|
|
_each(_keys(results), function(rkey) {
|
|
safeResults[rkey] = results[rkey];
|
|
});
|
|
safeResults[k] = args;
|
|
callback(err, safeResults);
|
|
// stop subsequent errors hitting callback multiple times
|
|
callback = function () {};
|
|
}
|
|
else {
|
|
results[k] = args;
|
|
async.setImmediate(taskComplete);
|
|
}
|
|
};
|
|
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
|
|
var ready = function () {
|
|
return _reduce(requires, function (a, x) {
|
|
return (a && results.hasOwnProperty(x));
|
|
}, true) && !results.hasOwnProperty(k);
|
|
};
|
|
if (ready()) {
|
|
task[task.length - 1](taskCallback, results);
|
|
}
|
|
else {
|
|
var listener = function () {
|
|
if (ready()) {
|
|
removeListener(listener);
|
|
task[task.length - 1](taskCallback, results);
|
|
}
|
|
};
|
|
addListener(listener);
|
|
}
|
|
});
|
|
};
|
|
|
|
async.waterfall = function (tasks, callback) {
|
|
callback = callback || function () {};
|
|
if (tasks.constructor !== Array) {
|
|
var err = new Error('First argument to waterfall must be an array of functions');
|
|
return callback(err);
|
|
}
|
|
if (!tasks.length) {
|
|
return callback();
|
|
}
|
|
var wrapIterator = function (iterator) {
|
|
return function (err) {
|
|
if (err) {
|
|
callback.apply(null, arguments);
|
|
callback = function () {};
|
|
}
|
|
else {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
var next = iterator.next();
|
|
if (next) {
|
|
args.push(wrapIterator(next));
|
|
}
|
|
else {
|
|
args.push(callback);
|
|
}
|
|
async.setImmediate(function () {
|
|
iterator.apply(null, args);
|
|
});
|
|
}
|
|
};
|
|
};
|
|
wrapIterator(async.iterator(tasks))();
|
|
};
|
|
|
|
var _parallel = function(eachfn, tasks, callback) {
|
|
callback = callback || function () {};
|
|
if (tasks.constructor === Array) {
|
|
eachfn.map(tasks, function (fn, callback) {
|
|
if (fn) {
|
|
fn(function (err) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
if (args.length <= 1) {
|
|
args = args[0];
|
|
}
|
|
callback.call(null, err, args);
|
|
});
|
|
}
|
|
}, callback);
|
|
}
|
|
else {
|
|
var results = {};
|
|
eachfn.each(_keys(tasks), function (k, callback) {
|
|
tasks[k](function (err) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
if (args.length <= 1) {
|
|
args = args[0];
|
|
}
|
|
results[k] = args;
|
|
callback(err);
|
|
});
|
|
}, function (err) {
|
|
callback(err, results);
|
|
});
|
|
}
|
|
};
|
|
|
|
async.parallel = function (tasks, callback) {
|
|
_parallel({ map: async.map, each: async.each }, tasks, callback);
|
|
};
|
|
|
|
async.parallelLimit = function(tasks, limit, callback) {
|
|
_parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
|
|
};
|
|
|
|
async.series = function (tasks, callback) {
|
|
callback = callback || function () {};
|
|
if (tasks.constructor === Array) {
|
|
async.mapSeries(tasks, function (fn, callback) {
|
|
if (fn) {
|
|
fn(function (err) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
if (args.length <= 1) {
|
|
args = args[0];
|
|
}
|
|
callback.call(null, err, args);
|
|
});
|
|
}
|
|
}, callback);
|
|
}
|
|
else {
|
|
var results = {};
|
|
async.eachSeries(_keys(tasks), function (k, callback) {
|
|
tasks[k](function (err) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
if (args.length <= 1) {
|
|
args = args[0];
|
|
}
|
|
results[k] = args;
|
|
callback(err);
|
|
});
|
|
}, function (err) {
|
|
callback(err, results);
|
|
});
|
|
}
|
|
};
|
|
|
|
async.iterator = function (tasks) {
|
|
var makeCallback = function (index) {
|
|
var fn = function () {
|
|
if (tasks.length) {
|
|
tasks[index].apply(null, arguments);
|
|
}
|
|
return fn.next();
|
|
};
|
|
fn.next = function () {
|
|
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
|
|
};
|
|
return fn;
|
|
};
|
|
return makeCallback(0);
|
|
};
|
|
|
|
async.apply = function (fn) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
return function () {
|
|
return fn.apply(
|
|
null, args.concat(Array.prototype.slice.call(arguments))
|
|
);
|
|
};
|
|
};
|
|
|
|
var _concat = function (eachfn, arr, fn, callback) {
|
|
var r = [];
|
|
eachfn(arr, function (x, cb) {
|
|
fn(x, function (err, y) {
|
|
r = r.concat(y || []);
|
|
cb(err);
|
|
});
|
|
}, function (err) {
|
|
callback(err, r);
|
|
});
|
|
};
|
|
async.concat = doParallel(_concat);
|
|
async.concatSeries = doSeries(_concat);
|
|
|
|
async.whilst = function (test, iterator, callback) {
|
|
if (test()) {
|
|
iterator(function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
async.whilst(test, iterator, callback);
|
|
});
|
|
}
|
|
else {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
async.doWhilst = function (iterator, test, callback) {
|
|
iterator(function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
if (test()) {
|
|
async.doWhilst(iterator, test, callback);
|
|
}
|
|
else {
|
|
callback();
|
|
}
|
|
});
|
|
};
|
|
|
|
async.until = function (test, iterator, callback) {
|
|
if (!test()) {
|
|
iterator(function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
async.until(test, iterator, callback);
|
|
});
|
|
}
|
|
else {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
async.doUntil = function (iterator, test, callback) {
|
|
iterator(function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
if (!test()) {
|
|
async.doUntil(iterator, test, callback);
|
|
}
|
|
else {
|
|
callback();
|
|
}
|
|
});
|
|
};
|
|
|
|
async.queue = function (worker, concurrency) {
|
|
if (concurrency === undefined) {
|
|
concurrency = 1;
|
|
}
|
|
function _insert(q, data, pos, callback) {
|
|
if(data.constructor !== Array) {
|
|
data = [data];
|
|
}
|
|
_each(data, function(task) {
|
|
var item = {
|
|
data: task,
|
|
callback: typeof callback === 'function' ? callback : null
|
|
};
|
|
|
|
if (pos) {
|
|
q.tasks.unshift(item);
|
|
} else {
|
|
q.tasks.push(item);
|
|
}
|
|
|
|
if (q.saturated && q.tasks.length === concurrency) {
|
|
q.saturated();
|
|
}
|
|
async.setImmediate(q.process);
|
|
});
|
|
}
|
|
|
|
var workers = 0;
|
|
var q = {
|
|
tasks: [],
|
|
concurrency: concurrency,
|
|
saturated: null,
|
|
empty: null,
|
|
drain: null,
|
|
push: function (data, callback) {
|
|
_insert(q, data, false, callback);
|
|
},
|
|
unshift: function (data, callback) {
|
|
_insert(q, data, true, callback);
|
|
},
|
|
process: function () {
|
|
if (workers < q.concurrency && q.tasks.length) {
|
|
var task = q.tasks.shift();
|
|
if (q.empty && q.tasks.length === 0) {
|
|
q.empty();
|
|
}
|
|
workers += 1;
|
|
var next = function () {
|
|
workers -= 1;
|
|
if (task.callback) {
|
|
task.callback.apply(task, arguments);
|
|
}
|
|
if (q.drain && q.tasks.length + workers === 0) {
|
|
q.drain();
|
|
}
|
|
q.process();
|
|
};
|
|
var cb = only_once(next);
|
|
worker(task.data, cb);
|
|
}
|
|
},
|
|
length: function () {
|
|
return q.tasks.length;
|
|
},
|
|
running: function () {
|
|
return workers;
|
|
}
|
|
};
|
|
return q;
|
|
};
|
|
|
|
async.cargo = function (worker, payload) {
|
|
var working = false,
|
|
tasks = [];
|
|
|
|
var cargo = {
|
|
tasks: tasks,
|
|
payload: payload,
|
|
saturated: null,
|
|
empty: null,
|
|
drain: null,
|
|
push: function (data, callback) {
|
|
if(data.constructor !== Array) {
|
|
data = [data];
|
|
}
|
|
_each(data, function(task) {
|
|
tasks.push({
|
|
data: task,
|
|
callback: typeof callback === 'function' ? callback : null
|
|
});
|
|
if (cargo.saturated && tasks.length === payload) {
|
|
cargo.saturated();
|
|
}
|
|
});
|
|
async.setImmediate(cargo.process);
|
|
},
|
|
process: function process() {
|
|
if (working) return;
|
|
if (tasks.length === 0) {
|
|
if(cargo.drain) cargo.drain();
|
|
return;
|
|
}
|
|
|
|
var ts = typeof payload === 'number'
|
|
? tasks.splice(0, payload)
|
|
: tasks.splice(0);
|
|
|
|
var ds = _map(ts, function (task) {
|
|
return task.data;
|
|
});
|
|
|
|
if(cargo.empty) cargo.empty();
|
|
working = true;
|
|
worker(ds, function () {
|
|
working = false;
|
|
|
|
var args = arguments;
|
|
_each(ts, function (data) {
|
|
if (data.callback) {
|
|
data.callback.apply(null, args);
|
|
}
|
|
});
|
|
|
|
process();
|
|
});
|
|
},
|
|
length: function () {
|
|
return tasks.length;
|
|
},
|
|
running: function () {
|
|
return working;
|
|
}
|
|
};
|
|
return cargo;
|
|
};
|
|
|
|
var _console_fn = function (name) {
|
|
return function (fn) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
fn.apply(null, args.concat([function (err) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
if (typeof console !== 'undefined') {
|
|
if (err) {
|
|
if (console.error) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
else if (console[name]) {
|
|
_each(args, function (x) {
|
|
console[name](x);
|
|
});
|
|
}
|
|
}
|
|
}]));
|
|
};
|
|
};
|
|
async.log = _console_fn('log');
|
|
async.dir = _console_fn('dir');
|
|
/*async.info = _console_fn('info');
|
|
async.warn = _console_fn('warn');
|
|
async.error = _console_fn('error');*/
|
|
|
|
async.memoize = function (fn, hasher) {
|
|
var memo = {};
|
|
var queues = {};
|
|
hasher = hasher || function (x) {
|
|
return x;
|
|
};
|
|
var memoized = function () {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
var callback = args.pop();
|
|
var key = hasher.apply(null, args);
|
|
if (key in memo) {
|
|
callback.apply(null, memo[key]);
|
|
}
|
|
else if (key in queues) {
|
|
queues[key].push(callback);
|
|
}
|
|
else {
|
|
queues[key] = [callback];
|
|
fn.apply(null, args.concat([function () {
|
|
memo[key] = arguments;
|
|
var q = queues[key];
|
|
delete queues[key];
|
|
for (var i = 0, l = q.length; i < l; i++) {
|
|
q[i].apply(null, arguments);
|
|
}
|
|
}]));
|
|
}
|
|
};
|
|
memoized.memo = memo;
|
|
memoized.unmemoized = fn;
|
|
return memoized;
|
|
};
|
|
|
|
async.unmemoize = function (fn) {
|
|
return function () {
|
|
return (fn.unmemoized || fn).apply(null, arguments);
|
|
};
|
|
};
|
|
|
|
async.times = function (count, iterator, callback) {
|
|
var counter = [];
|
|
for (var i = 0; i < count; i++) {
|
|
counter.push(i);
|
|
}
|
|
return async.map(counter, iterator, callback);
|
|
};
|
|
|
|
async.timesSeries = function (count, iterator, callback) {
|
|
var counter = [];
|
|
for (var i = 0; i < count; i++) {
|
|
counter.push(i);
|
|
}
|
|
return async.mapSeries(counter, iterator, callback);
|
|
};
|
|
|
|
async.compose = function (/* functions... */) {
|
|
var fns = Array.prototype.reverse.call(arguments);
|
|
return function () {
|
|
var that = this;
|
|
var args = Array.prototype.slice.call(arguments);
|
|
var callback = args.pop();
|
|
async.reduce(fns, args, function (newargs, fn, cb) {
|
|
fn.apply(that, newargs.concat([function () {
|
|
var err = arguments[0];
|
|
var nextargs = Array.prototype.slice.call(arguments, 1);
|
|
cb(err, nextargs);
|
|
}]))
|
|
},
|
|
function (err, results) {
|
|
callback.apply(that, [err].concat(results));
|
|
});
|
|
};
|
|
};
|
|
|
|
var _applyEach = function (eachfn, fns /*args...*/) {
|
|
var go = function () {
|
|
var that = this;
|
|
var args = Array.prototype.slice.call(arguments);
|
|
var callback = args.pop();
|
|
return eachfn(fns, function (fn, cb) {
|
|
fn.apply(that, args.concat([cb]));
|
|
},
|
|
callback);
|
|
};
|
|
if (arguments.length > 2) {
|
|
var args = Array.prototype.slice.call(arguments, 2);
|
|
return go.apply(this, args);
|
|
}
|
|
else {
|
|
return go;
|
|
}
|
|
};
|
|
async.applyEach = doParallel(_applyEach);
|
|
async.applyEachSeries = doSeries(_applyEach);
|
|
|
|
async.forever = function (fn, callback) {
|
|
function next(err) {
|
|
if (err) {
|
|
if (callback) {
|
|
return callback(err);
|
|
}
|
|
throw err;
|
|
}
|
|
fn(next);
|
|
}
|
|
next();
|
|
};
|
|
|
|
// AMD / RequireJS
|
|
if (typeof define !== 'undefined' && define.amd) {
|
|
define([], function () {
|
|
return async;
|
|
});
|
|
}
|
|
// Node.js
|
|
else if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = async;
|
|
}
|
|
// included directly via <script> tag
|
|
else {
|
|
root.async = async;
|
|
}
|
|
|
|
}());
|
|
|
|
},{"__browserify_process":66}],54:[function(require,module,exports){
|
|
// UTILITY
|
|
var util = require('util');
|
|
var Buffer = require("buffer").Buffer;
|
|
var pSlice = Array.prototype.slice;
|
|
|
|
function objectKeys(object) {
|
|
if (Object.keys) return Object.keys(object);
|
|
var result = [];
|
|
for (var name in object) {
|
|
if (Object.prototype.hasOwnProperty.call(object, name)) {
|
|
result.push(name);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// 1. The assert module provides functions that throw
|
|
// AssertionError's when particular conditions are not met. The
|
|
// assert module must conform to the following interface.
|
|
|
|
var assert = module.exports = ok;
|
|
|
|
// 2. The AssertionError is defined in assert.
|
|
// new assert.AssertionError({ message: message,
|
|
// actual: actual,
|
|
// expected: expected })
|
|
|
|
assert.AssertionError = function AssertionError(options) {
|
|
this.name = 'AssertionError';
|
|
this.message = options.message;
|
|
this.actual = options.actual;
|
|
this.expected = options.expected;
|
|
this.operator = options.operator;
|
|
var stackStartFunction = options.stackStartFunction || fail;
|
|
|
|
if (Error.captureStackTrace) {
|
|
Error.captureStackTrace(this, stackStartFunction);
|
|
}
|
|
};
|
|
|
|
// assert.AssertionError instanceof Error
|
|
util.inherits(assert.AssertionError, Error);
|
|
|
|
function replacer(key, value) {
|
|
if (value === undefined) {
|
|
return '' + value;
|
|
}
|
|
if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) {
|
|
return value.toString();
|
|
}
|
|
if (typeof value === 'function' || value instanceof RegExp) {
|
|
return value.toString();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function truncate(s, n) {
|
|
if (typeof s == 'string') {
|
|
return s.length < n ? s : s.slice(0, n);
|
|
} else {
|
|
return s;
|
|
}
|
|
}
|
|
|
|
assert.AssertionError.prototype.toString = function() {
|
|
if (this.message) {
|
|
return [this.name + ':', this.message].join(' ');
|
|
} else {
|
|
return [
|
|
this.name + ':',
|
|
truncate(JSON.stringify(this.actual, replacer), 128),
|
|
this.operator,
|
|
truncate(JSON.stringify(this.expected, replacer), 128)
|
|
].join(' ');
|
|
}
|
|
};
|
|
|
|
// At present only the three keys mentioned above are used and
|
|
// understood by the spec. Implementations or sub modules can pass
|
|
// other keys to the AssertionError's constructor - they will be
|
|
// ignored.
|
|
|
|
// 3. All of the following functions must throw an AssertionError
|
|
// when a corresponding condition is not met, with a message that
|
|
// may be undefined if not provided. All assertion methods provide
|
|
// both the actual and expected values to the assertion error for
|
|
// display purposes.
|
|
|
|
function fail(actual, expected, message, operator, stackStartFunction) {
|
|
throw new assert.AssertionError({
|
|
message: message,
|
|
actual: actual,
|
|
expected: expected,
|
|
operator: operator,
|
|
stackStartFunction: stackStartFunction
|
|
});
|
|
}
|
|
|
|
// EXTENSION! allows for well behaved errors defined elsewhere.
|
|
assert.fail = fail;
|
|
|
|
// 4. Pure assertion tests whether a value is truthy, as determined
|
|
// by !!guard.
|
|
// assert.ok(guard, message_opt);
|
|
// This statement is equivalent to assert.equal(true, guard,
|
|
// message_opt);. To test strictly for the value true, use
|
|
// assert.strictEqual(true, guard, message_opt);.
|
|
|
|
function ok(value, message) {
|
|
if (!!!value) fail(value, true, message, '==', assert.ok);
|
|
}
|
|
assert.ok = ok;
|
|
|
|
// 5. The equality assertion tests shallow, coercive equality with
|
|
// ==.
|
|
// assert.equal(actual, expected, message_opt);
|
|
|
|
assert.equal = function equal(actual, expected, message) {
|
|
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
|
|
};
|
|
|
|
// 6. The non-equality assertion tests for whether two objects are not equal
|
|
// with != assert.notEqual(actual, expected, message_opt);
|
|
|
|
assert.notEqual = function notEqual(actual, expected, message) {
|
|
if (actual == expected) {
|
|
fail(actual, expected, message, '!=', assert.notEqual);
|
|
}
|
|
};
|
|
|
|
// 7. The equivalence assertion tests a deep equality relation.
|
|
// assert.deepEqual(actual, expected, message_opt);
|
|
|
|
assert.deepEqual = function deepEqual(actual, expected, message) {
|
|
if (!_deepEqual(actual, expected)) {
|
|
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
|
|
}
|
|
};
|
|
|
|
function _deepEqual(actual, expected) {
|
|
// 7.1. All identical values are equivalent, as determined by ===.
|
|
if (actual === expected) {
|
|
return true;
|
|
|
|
} else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
|
|
if (actual.length != expected.length) return false;
|
|
|
|
for (var i = 0; i < actual.length; i++) {
|
|
if (actual[i] !== expected[i]) return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
// 7.2. If the expected value is a Date object, the actual value is
|
|
// equivalent if it is also a Date object that refers to the same time.
|
|
} else if (actual instanceof Date && expected instanceof Date) {
|
|
return actual.getTime() === expected.getTime();
|
|
|
|
// 7.3. Other pairs that do not both pass typeof value == 'object',
|
|
// equivalence is determined by ==.
|
|
} else if (typeof actual != 'object' && typeof expected != 'object') {
|
|
return actual == expected;
|
|
|
|
// 7.4. For all other Object pairs, including Array objects, equivalence is
|
|
// determined by having the same number of owned properties (as verified
|
|
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
|
// (although not necessarily the same order), equivalent values for every
|
|
// corresponding key, and an identical 'prototype' property. Note: this
|
|
// accounts for both named and indexed properties on Arrays.
|
|
} else {
|
|
return objEquiv(actual, expected);
|
|
}
|
|
}
|
|
|
|
function isUndefinedOrNull(value) {
|
|
return value === null || value === undefined;
|
|
}
|
|
|
|
function isArguments(object) {
|
|
return Object.prototype.toString.call(object) == '[object Arguments]';
|
|
}
|
|
|
|
function objEquiv(a, b) {
|
|
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
|
|
return false;
|
|
// an identical 'prototype' property.
|
|
if (a.prototype !== b.prototype) return false;
|
|
//~~~I've managed to break Object.keys through screwy arguments passing.
|
|
// Converting to array solves the problem.
|
|
if (isArguments(a)) {
|
|
if (!isArguments(b)) {
|
|
return false;
|
|
}
|
|
a = pSlice.call(a);
|
|
b = pSlice.call(b);
|
|
return _deepEqual(a, b);
|
|
}
|
|
try {
|
|
var ka = objectKeys(a),
|
|
kb = objectKeys(b),
|
|
key, i;
|
|
} catch (e) {//happens when one is a string literal and the other isn't
|
|
return false;
|
|
}
|
|
// having the same number of owned properties (keys incorporates
|
|
// hasOwnProperty)
|
|
if (ka.length != kb.length)
|
|
return false;
|
|
//the same set of keys (although not necessarily the same order),
|
|
ka.sort();
|
|
kb.sort();
|
|
//~~~cheap key test
|
|
for (i = ka.length - 1; i >= 0; i--) {
|
|
if (ka[i] != kb[i])
|
|
return false;
|
|
}
|
|
//equivalent values for every corresponding key, and
|
|
//~~~possibly expensive deep test
|
|
for (i = ka.length - 1; i >= 0; i--) {
|
|
key = ka[i];
|
|
if (!_deepEqual(a[key], b[key])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// 8. The non-equivalence assertion tests for any deep inequality.
|
|
// assert.notDeepEqual(actual, expected, message_opt);
|
|
|
|
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
|
if (_deepEqual(actual, expected)) {
|
|
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
|
|
}
|
|
};
|
|
|
|
// 9. The strict equality assertion tests strict equality, as determined by ===.
|
|
// assert.strictEqual(actual, expected, message_opt);
|
|
|
|
assert.strictEqual = function strictEqual(actual, expected, message) {
|
|
if (actual !== expected) {
|
|
fail(actual, expected, message, '===', assert.strictEqual);
|
|
}
|
|
};
|
|
|
|
// 10. The strict non-equality assertion tests for strict inequality, as
|
|
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
|
|
|
|
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
|
if (actual === expected) {
|
|
fail(actual, expected, message, '!==', assert.notStrictEqual);
|
|
}
|
|
};
|
|
|
|
function expectedException(actual, expected) {
|
|
if (!actual || !expected) {
|
|
return false;
|
|
}
|
|
|
|
if (expected instanceof RegExp) {
|
|
return expected.test(actual);
|
|
} else if (actual instanceof expected) {
|
|
return true;
|
|
} else if (expected.call({}, actual) === true) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function _throws(shouldThrow, block, expected, message) {
|
|
var actual;
|
|
|
|
if (typeof expected === 'string') {
|
|
message = expected;
|
|
expected = null;
|
|
}
|
|
|
|
try {
|
|
block();
|
|
} catch (e) {
|
|
actual = e;
|
|
}
|
|
|
|
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
|
|
(message ? ' ' + message : '.');
|
|
|
|
if (shouldThrow && !actual) {
|
|
fail('Missing expected exception' + message);
|
|
}
|
|
|
|
if (!shouldThrow && expectedException(actual, expected)) {
|
|
fail('Got unwanted exception' + message);
|
|
}
|
|
|
|
if ((shouldThrow && actual && expected &&
|
|
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
|
|
throw actual;
|
|
}
|
|
}
|
|
|
|
// 11. Expected to throw an error:
|
|
// assert.throws(block, Error_opt, message_opt);
|
|
|
|
assert.throws = function(block, /*optional*/error, /*optional*/message) {
|
|
_throws.apply(this, [true].concat(pSlice.call(arguments)));
|
|
};
|
|
|
|
// EXTENSION! This is annoying to write outside this module.
|
|
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
|
|
_throws.apply(this, [false].concat(pSlice.call(arguments)));
|
|
};
|
|
|
|
assert.ifError = function(err) { if (err) {throw err;}};
|
|
|
|
},{"buffer":58,"util":56}],55:[function(require,module,exports){
|
|
var process=require("__browserify_process");if (!process.EventEmitter) process.EventEmitter = function () {};
|
|
|
|
var EventEmitter = exports.EventEmitter = process.EventEmitter;
|
|
var isArray = typeof Array.isArray === 'function'
|
|
? Array.isArray
|
|
: function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]'
|
|
}
|
|
;
|
|
function indexOf (xs, x) {
|
|
if (xs.indexOf) return xs.indexOf(x);
|
|
for (var i = 0; i < xs.length; i++) {
|
|
if (x === xs[i]) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// By default EventEmitters will print a warning if more than
|
|
// 10 listeners are added to it. This is a useful default which
|
|
// helps finding memory leaks.
|
|
//
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
// that to be increased. Set to zero for unlimited.
|
|
var defaultMaxListeners = 10;
|
|
EventEmitter.prototype.setMaxListeners = function(n) {
|
|
if (!this._events) this._events = {};
|
|
this._events.maxListeners = n;
|
|
};
|
|
|
|
|
|
EventEmitter.prototype.emit = function(type) {
|
|
// If there is no 'error' event listener then throw.
|
|
if (type === 'error') {
|
|
if (!this._events || !this._events.error ||
|
|
(isArray(this._events.error) && !this._events.error.length))
|
|
{
|
|
if (arguments[1] instanceof Error) {
|
|
throw arguments[1]; // Unhandled 'error' event
|
|
} else {
|
|
throw new Error("Uncaught, unspecified 'error' event.");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!this._events) return false;
|
|
var handler = this._events[type];
|
|
if (!handler) return false;
|
|
|
|
if (typeof handler == 'function') {
|
|
switch (arguments.length) {
|
|
// fast cases
|
|
case 1:
|
|
handler.call(this);
|
|
break;
|
|
case 2:
|
|
handler.call(this, arguments[1]);
|
|
break;
|
|
case 3:
|
|
handler.call(this, arguments[1], arguments[2]);
|
|
break;
|
|
// slower
|
|
default:
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
handler.apply(this, args);
|
|
}
|
|
return true;
|
|
|
|
} else if (isArray(handler)) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
var listeners = handler.slice();
|
|
for (var i = 0, l = listeners.length; i < l; i++) {
|
|
listeners[i].apply(this, args);
|
|
}
|
|
return true;
|
|
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// EventEmitter is defined in src/node_events.cc
|
|
// EventEmitter.prototype.emit() is also defined there.
|
|
EventEmitter.prototype.addListener = function(type, listener) {
|
|
if ('function' !== typeof listener) {
|
|
throw new Error('addListener only takes instances of Function');
|
|
}
|
|
|
|
if (!this._events) this._events = {};
|
|
|
|
// To avoid recursion in the case that type == "newListeners"! Before
|
|
// adding it to the listeners, first emit "newListeners".
|
|
this.emit('newListener', type, listener);
|
|
|
|
if (!this._events[type]) {
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
this._events[type] = listener;
|
|
} else if (isArray(this._events[type])) {
|
|
|
|
// Check for listener leak
|
|
if (!this._events[type].warned) {
|
|
var m;
|
|
if (this._events.maxListeners !== undefined) {
|
|
m = this._events.maxListeners;
|
|
} else {
|
|
m = defaultMaxListeners;
|
|
}
|
|
|
|
if (m && m > 0 && this._events[type].length > m) {
|
|
this._events[type].warned = true;
|
|
console.error('(node) warning: possible EventEmitter memory ' +
|
|
'leak detected. %d listeners added. ' +
|
|
'Use emitter.setMaxListeners() to increase limit.',
|
|
this._events[type].length);
|
|
console.trace();
|
|
}
|
|
}
|
|
|
|
// If we've already got an array, just append.
|
|
this._events[type].push(listener);
|
|
} else {
|
|
// Adding the second element, need to change to array.
|
|
this._events[type] = [this._events[type], listener];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
|
|
|
EventEmitter.prototype.once = function(type, listener) {
|
|
var self = this;
|
|
self.on(type, function g() {
|
|
self.removeListener(type, g);
|
|
listener.apply(this, arguments);
|
|
});
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeListener = function(type, listener) {
|
|
if ('function' !== typeof listener) {
|
|
throw new Error('removeListener only takes instances of Function');
|
|
}
|
|
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (!this._events || !this._events[type]) return this;
|
|
|
|
var list = this._events[type];
|
|
|
|
if (isArray(list)) {
|
|
var i = indexOf(list, listener);
|
|
if (i < 0) return this;
|
|
list.splice(i, 1);
|
|
if (list.length == 0)
|
|
delete this._events[type];
|
|
} else if (this._events[type] === listener) {
|
|
delete this._events[type];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) {
|
|
if (arguments.length === 0) {
|
|
this._events = {};
|
|
return this;
|
|
}
|
|
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (type && this._events && this._events[type]) this._events[type] = null;
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.listeners = function(type) {
|
|
if (!this._events) this._events = {};
|
|
if (!this._events[type]) this._events[type] = [];
|
|
if (!isArray(this._events[type])) {
|
|
this._events[type] = [this._events[type]];
|
|
}
|
|
return this._events[type];
|
|
};
|
|
|
|
EventEmitter.listenerCount = function(emitter, type) {
|
|
var ret;
|
|
if (!emitter._events || !emitter._events[type])
|
|
ret = 0;
|
|
else if (typeof emitter._events[type] === 'function')
|
|
ret = 1;
|
|
else
|
|
ret = emitter._events[type].length;
|
|
return ret;
|
|
};
|
|
|
|
},{"__browserify_process":66}],56:[function(require,module,exports){
|
|
var events = require('events');
|
|
|
|
exports.isArray = isArray;
|
|
exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'};
|
|
exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'};
|
|
|
|
|
|
exports.print = function () {};
|
|
exports.puts = function () {};
|
|
exports.debug = function() {};
|
|
|
|
exports.inspect = function(obj, showHidden, depth, colors) {
|
|
var seen = [];
|
|
|
|
var stylize = function(str, styleType) {
|
|
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
|
|
var styles =
|
|
{ 'bold' : [1, 22],
|
|
'italic' : [3, 23],
|
|
'underline' : [4, 24],
|
|
'inverse' : [7, 27],
|
|
'white' : [37, 39],
|
|
'grey' : [90, 39],
|
|
'black' : [30, 39],
|
|
'blue' : [34, 39],
|
|
'cyan' : [36, 39],
|
|
'green' : [32, 39],
|
|
'magenta' : [35, 39],
|
|
'red' : [31, 39],
|
|
'yellow' : [33, 39] };
|
|
|
|
var style =
|
|
{ 'special': 'cyan',
|
|
'number': 'blue',
|
|
'boolean': 'yellow',
|
|
'undefined': 'grey',
|
|
'null': 'bold',
|
|
'string': 'green',
|
|
'date': 'magenta',
|
|
// "name": intentionally not styling
|
|
'regexp': 'red' }[styleType];
|
|
|
|
if (style) {
|
|
return '\u001b[' + styles[style][0] + 'm' + str +
|
|
'\u001b[' + styles[style][1] + 'm';
|
|
} else {
|
|
return str;
|
|
}
|
|
};
|
|
if (! colors) {
|
|
stylize = function(str, styleType) { return str; };
|
|
}
|
|
|
|
function format(value, recurseTimes) {
|
|
// Provide a hook for user-specified inspect functions.
|
|
// Check that value is an object with an inspect function on it
|
|
if (value && typeof value.inspect === 'function' &&
|
|
// Filter out the util module, it's inspect function is special
|
|
value !== exports &&
|
|
// Also filter out any prototype objects using the circular check.
|
|
!(value.constructor && value.constructor.prototype === value)) {
|
|
return value.inspect(recurseTimes);
|
|
}
|
|
|
|
// Primitive types cannot have properties
|
|
switch (typeof value) {
|
|
case 'undefined':
|
|
return stylize('undefined', 'undefined');
|
|
|
|
case 'string':
|
|
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
|
|
.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"') + '\'';
|
|
return stylize(simple, 'string');
|
|
|
|
case 'number':
|
|
return stylize('' + value, 'number');
|
|
|
|
case 'boolean':
|
|
return stylize('' + value, 'boolean');
|
|
}
|
|
// For some reason typeof null is "object", so special case here.
|
|
if (value === null) {
|
|
return stylize('null', 'null');
|
|
}
|
|
|
|
// Look up the keys of the object.
|
|
var visible_keys = Object_keys(value);
|
|
var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys;
|
|
|
|
// Functions without properties can be shortcutted.
|
|
if (typeof value === 'function' && keys.length === 0) {
|
|
if (isRegExp(value)) {
|
|
return stylize('' + value, 'regexp');
|
|
} else {
|
|
var name = value.name ? ': ' + value.name : '';
|
|
return stylize('[Function' + name + ']', 'special');
|
|
}
|
|
}
|
|
|
|
// Dates without properties can be shortcutted
|
|
if (isDate(value) && keys.length === 0) {
|
|
return stylize(value.toUTCString(), 'date');
|
|
}
|
|
|
|
var base, type, braces;
|
|
// Determine the object type
|
|
if (isArray(value)) {
|
|
type = 'Array';
|
|
braces = ['[', ']'];
|
|
} else {
|
|
type = 'Object';
|
|
braces = ['{', '}'];
|
|
}
|
|
|
|
// Make functions say that they are functions
|
|
if (typeof value === 'function') {
|
|
var n = value.name ? ': ' + value.name : '';
|
|
base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
|
|
} else {
|
|
base = '';
|
|
}
|
|
|
|
// Make dates with properties first say the date
|
|
if (isDate(value)) {
|
|
base = ' ' + value.toUTCString();
|
|
}
|
|
|
|
if (keys.length === 0) {
|
|
return braces[0] + base + braces[1];
|
|
}
|
|
|
|
if (recurseTimes < 0) {
|
|
if (isRegExp(value)) {
|
|
return stylize('' + value, 'regexp');
|
|
} else {
|
|
return stylize('[Object]', 'special');
|
|
}
|
|
}
|
|
|
|
seen.push(value);
|
|
|
|
var output = keys.map(function(key) {
|
|
var name, str;
|
|
if (value.__lookupGetter__) {
|
|
if (value.__lookupGetter__(key)) {
|
|
if (value.__lookupSetter__(key)) {
|
|
str = stylize('[Getter/Setter]', 'special');
|
|
} else {
|
|
str = stylize('[Getter]', 'special');
|
|
}
|
|
} else {
|
|
if (value.__lookupSetter__(key)) {
|
|
str = stylize('[Setter]', 'special');
|
|
}
|
|
}
|
|
}
|
|
if (visible_keys.indexOf(key) < 0) {
|
|
name = '[' + key + ']';
|
|
}
|
|
if (!str) {
|
|
if (seen.indexOf(value[key]) < 0) {
|
|
if (recurseTimes === null) {
|
|
str = format(value[key]);
|
|
} else {
|
|
str = format(value[key], recurseTimes - 1);
|
|
}
|
|
if (str.indexOf('\n') > -1) {
|
|
if (isArray(value)) {
|
|
str = str.split('\n').map(function(line) {
|
|
return ' ' + line;
|
|
}).join('\n').substr(2);
|
|
} else {
|
|
str = '\n' + str.split('\n').map(function(line) {
|
|
return ' ' + line;
|
|
}).join('\n');
|
|
}
|
|
}
|
|
} else {
|
|
str = stylize('[Circular]', 'special');
|
|
}
|
|
}
|
|
if (typeof name === 'undefined') {
|
|
if (type === 'Array' && key.match(/^\d+$/)) {
|
|
return str;
|
|
}
|
|
name = JSON.stringify('' + key);
|
|
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
|
|
name = name.substr(1, name.length - 2);
|
|
name = stylize(name, 'name');
|
|
} else {
|
|
name = name.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"')
|
|
.replace(/(^"|"$)/g, "'");
|
|
name = stylize(name, 'string');
|
|
}
|
|
}
|
|
|
|
return name + ': ' + str;
|
|
});
|
|
|
|
seen.pop();
|
|
|
|
var numLinesEst = 0;
|
|
var length = output.reduce(function(prev, cur) {
|
|
numLinesEst++;
|
|
if (cur.indexOf('\n') >= 0) numLinesEst++;
|
|
return prev + cur.length + 1;
|
|
}, 0);
|
|
|
|
if (length > 50) {
|
|
output = braces[0] +
|
|
(base === '' ? '' : base + '\n ') +
|
|
' ' +
|
|
output.join(',\n ') +
|
|
' ' +
|
|
braces[1];
|
|
|
|
} else {
|
|
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
|
|
}
|
|
|
|
return output;
|
|
}
|
|
return format(obj, (typeof depth === 'undefined' ? 2 : depth));
|
|
};
|
|
|
|
|
|
function isArray(ar) {
|
|
return Array.isArray(ar) ||
|
|
(typeof ar === 'object' && Object.prototype.toString.call(ar) === '[object Array]');
|
|
}
|
|
|
|
|
|
function isRegExp(re) {
|
|
typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]';
|
|
}
|
|
|
|
|
|
function isDate(d) {
|
|
return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]';
|
|
}
|
|
|
|
function pad(n) {
|
|
return n < 10 ? '0' + n.toString(10) : n.toString(10);
|
|
}
|
|
|
|
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
|
|
'Oct', 'Nov', 'Dec'];
|
|
|
|
// 26 Feb 16:19:34
|
|
function timestamp() {
|
|
var d = new Date();
|
|
var time = [pad(d.getHours()),
|
|
pad(d.getMinutes()),
|
|
pad(d.getSeconds())].join(':');
|
|
return [d.getDate(), months[d.getMonth()], time].join(' ');
|
|
}
|
|
|
|
exports.log = function (msg) {};
|
|
|
|
exports.pump = null;
|
|
|
|
var Object_keys = Object.keys || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) res.push(key);
|
|
return res;
|
|
};
|
|
|
|
var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) {
|
|
if (Object.hasOwnProperty.call(obj, key)) res.push(key);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
var Object_create = Object.create || function (prototype, properties) {
|
|
// from es5-shim
|
|
var object;
|
|
if (prototype === null) {
|
|
object = { '__proto__' : null };
|
|
}
|
|
else {
|
|
if (typeof prototype !== 'object') {
|
|
throw new TypeError(
|
|
'typeof prototype[' + (typeof prototype) + '] != \'object\''
|
|
);
|
|
}
|
|
var Type = function () {};
|
|
Type.prototype = prototype;
|
|
object = new Type();
|
|
object.__proto__ = prototype;
|
|
}
|
|
if (typeof properties !== 'undefined' && Object.defineProperties) {
|
|
Object.defineProperties(object, properties);
|
|
}
|
|
return object;
|
|
};
|
|
|
|
exports.inherits = function(ctor, superCtor) {
|
|
ctor.super_ = superCtor;
|
|
ctor.prototype = Object_create(superCtor.prototype, {
|
|
constructor: {
|
|
value: ctor,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
};
|
|
|
|
var formatRegExp = /%[sdj%]/g;
|
|
exports.format = function(f) {
|
|
if (typeof f !== 'string') {
|
|
var objects = [];
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
objects.push(exports.inspect(arguments[i]));
|
|
}
|
|
return objects.join(' ');
|
|
}
|
|
|
|
var i = 1;
|
|
var args = arguments;
|
|
var len = args.length;
|
|
var str = String(f).replace(formatRegExp, function(x) {
|
|
if (x === '%%') return '%';
|
|
if (i >= len) return x;
|
|
switch (x) {
|
|
case '%s': return String(args[i++]);
|
|
case '%d': return Number(args[i++]);
|
|
case '%j': return JSON.stringify(args[i++]);
|
|
default:
|
|
return x;
|
|
}
|
|
});
|
|
for(var x = args[i]; i < len; x = args[++i]){
|
|
if (x === null || typeof x !== 'object') {
|
|
str += ' ' + x;
|
|
} else {
|
|
str += ' ' + exports.inspect(x);
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
},{"events":55}],57:[function(require,module,exports){
|
|
exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) {
|
|
var e, m,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
nBits = -7,
|
|
i = isBE ? 0 : (nBytes - 1),
|
|
d = isBE ? 1 : -1,
|
|
s = buffer[offset + i];
|
|
|
|
i += d;
|
|
|
|
e = s & ((1 << (-nBits)) - 1);
|
|
s >>= (-nBits);
|
|
nBits += eLen;
|
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
m = e & ((1 << (-nBits)) - 1);
|
|
e >>= (-nBits);
|
|
nBits += mLen;
|
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
if (e === 0) {
|
|
e = 1 - eBias;
|
|
} else if (e === eMax) {
|
|
return m ? NaN : ((s ? -1 : 1) * Infinity);
|
|
} else {
|
|
m = m + Math.pow(2, mLen);
|
|
e = e - eBias;
|
|
}
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
|
|
};
|
|
|
|
exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) {
|
|
var e, m, c,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
|
|
i = isBE ? (nBytes - 1) : 0,
|
|
d = isBE ? -1 : 1,
|
|
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
|
|
|
|
value = Math.abs(value);
|
|
|
|
if (isNaN(value) || value === Infinity) {
|
|
m = isNaN(value) ? 1 : 0;
|
|
e = eMax;
|
|
} else {
|
|
e = Math.floor(Math.log(value) / Math.LN2);
|
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
|
e--;
|
|
c *= 2;
|
|
}
|
|
if (e + eBias >= 1) {
|
|
value += rt / c;
|
|
} else {
|
|
value += rt * Math.pow(2, 1 - eBias);
|
|
}
|
|
if (value * c >= 2) {
|
|
e++;
|
|
c /= 2;
|
|
}
|
|
|
|
if (e + eBias >= eMax) {
|
|
m = 0;
|
|
e = eMax;
|
|
} else if (e + eBias >= 1) {
|
|
m = (value * c - 1) * Math.pow(2, mLen);
|
|
e = e + eBias;
|
|
} else {
|
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
|
e = 0;
|
|
}
|
|
}
|
|
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
|
|
|
|
e = (e << mLen) | m;
|
|
eLen += mLen;
|
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
|
|
|
|
buffer[offset + i - d] |= s * 128;
|
|
};
|
|
|
|
},{}],58:[function(require,module,exports){
|
|
var assert = require('assert');
|
|
exports.Buffer = Buffer;
|
|
exports.SlowBuffer = Buffer;
|
|
Buffer.poolSize = 8192;
|
|
exports.INSPECT_MAX_BYTES = 50;
|
|
|
|
function Buffer(subject, encoding, offset) {
|
|
if (!(this instanceof Buffer)) {
|
|
return new Buffer(subject, encoding, offset);
|
|
}
|
|
this.parent = this;
|
|
this.offset = 0;
|
|
|
|
var type;
|
|
|
|
// Are we slicing?
|
|
if (typeof offset === 'number') {
|
|
this.length = coerce(encoding);
|
|
this.offset = offset;
|
|
} else {
|
|
// Find the length
|
|
switch (type = typeof subject) {
|
|
case 'number':
|
|
this.length = coerce(subject);
|
|
break;
|
|
|
|
case 'string':
|
|
this.length = Buffer.byteLength(subject, encoding);
|
|
break;
|
|
|
|
case 'object': // Assume object is an array
|
|
this.length = coerce(subject.length);
|
|
break;
|
|
|
|
default:
|
|
throw new Error('First argument needs to be a number, ' +
|
|
'array or string.');
|
|
}
|
|
|
|
// Treat array-ish objects as a byte array.
|
|
if (isArrayIsh(subject)) {
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (subject instanceof Buffer) {
|
|
this[i] = subject.readUInt8(i);
|
|
}
|
|
else {
|
|
this[i] = subject[i];
|
|
}
|
|
}
|
|
} else if (type == 'string') {
|
|
// We are a string
|
|
this.length = this.write(subject, 0, encoding);
|
|
} else if (type === 'number') {
|
|
for (var i = 0; i < this.length; i++) {
|
|
this[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.get = function get(i) {
|
|
if (i < 0 || i >= this.length) throw new Error('oob');
|
|
return this[i];
|
|
};
|
|
|
|
Buffer.prototype.set = function set(i, v) {
|
|
if (i < 0 || i >= this.length) throw new Error('oob');
|
|
return this[i] = v;
|
|
};
|
|
|
|
Buffer.byteLength = function (str, encoding) {
|
|
switch (encoding || "utf8") {
|
|
case 'hex':
|
|
return str.length / 2;
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return utf8ToBytes(str).length;
|
|
|
|
case 'ascii':
|
|
case 'binary':
|
|
return str.length;
|
|
|
|
case 'base64':
|
|
return base64ToBytes(str).length;
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
Buffer.prototype.utf8Write = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return Buffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length);
|
|
};
|
|
|
|
Buffer.prototype.asciiWrite = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return Buffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length);
|
|
};
|
|
|
|
Buffer.prototype.binaryWrite = Buffer.prototype.asciiWrite;
|
|
|
|
Buffer.prototype.base64Write = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return Buffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length);
|
|
};
|
|
|
|
Buffer.prototype.base64Slice = function (start, end) {
|
|
var bytes = Array.prototype.slice.apply(this, arguments)
|
|
return require("base64-js").fromByteArray(bytes);
|
|
};
|
|
|
|
Buffer.prototype.utf8Slice = function () {
|
|
var bytes = Array.prototype.slice.apply(this, arguments);
|
|
var res = "";
|
|
var tmp = "";
|
|
var i = 0;
|
|
while (i < bytes.length) {
|
|
if (bytes[i] <= 0x7F) {
|
|
res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]);
|
|
tmp = "";
|
|
} else
|
|
tmp += "%" + bytes[i].toString(16);
|
|
|
|
i++;
|
|
}
|
|
|
|
return res + decodeUtf8Char(tmp);
|
|
}
|
|
|
|
Buffer.prototype.asciiSlice = function () {
|
|
var bytes = Array.prototype.slice.apply(this, arguments);
|
|
var ret = "";
|
|
for (var i = 0; i < bytes.length; i++)
|
|
ret += String.fromCharCode(bytes[i]);
|
|
return ret;
|
|
}
|
|
|
|
Buffer.prototype.binarySlice = Buffer.prototype.asciiSlice;
|
|
|
|
Buffer.prototype.inspect = function() {
|
|
var out = [],
|
|
len = this.length;
|
|
for (var i = 0; i < len; i++) {
|
|
out[i] = toHex(this[i]);
|
|
if (i == exports.INSPECT_MAX_BYTES) {
|
|
out[i + 1] = '...';
|
|
break;
|
|
}
|
|
}
|
|
return '<Buffer ' + out.join(' ') + '>';
|
|
};
|
|
|
|
|
|
Buffer.prototype.hexSlice = function(start, end) {
|
|
var len = this.length;
|
|
|
|
if (!start || start < 0) start = 0;
|
|
if (!end || end < 0 || end > len) end = len;
|
|
|
|
var out = '';
|
|
for (var i = start; i < end; i++) {
|
|
out += toHex(this[i]);
|
|
}
|
|
return out;
|
|
};
|
|
|
|
|
|
Buffer.prototype.toString = function(encoding, start, end) {
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
start = +start || 0;
|
|
if (typeof end == 'undefined') end = this.length;
|
|
|
|
// Fastpath empty strings
|
|
if (+end == start) {
|
|
return '';
|
|
}
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.hexSlice(start, end);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.utf8Slice(start, end);
|
|
|
|
case 'ascii':
|
|
return this.asciiSlice(start, end);
|
|
|
|
case 'binary':
|
|
return this.binarySlice(start, end);
|
|
|
|
case 'base64':
|
|
return this.base64Slice(start, end);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.ucs2Slice(start, end);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
Buffer.prototype.hexWrite = function(string, offset, length) {
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
|
|
// must be an even number of digits
|
|
var strLen = string.length;
|
|
if (strLen % 2) {
|
|
throw new Error('Invalid hex string');
|
|
}
|
|
if (length > strLen / 2) {
|
|
length = strLen / 2;
|
|
}
|
|
for (var i = 0; i < length; i++) {
|
|
var byte = parseInt(string.substr(i * 2, 2), 16);
|
|
if (isNaN(byte)) throw new Error('Invalid hex string');
|
|
this[offset + i] = byte;
|
|
}
|
|
Buffer._charsWritten = i * 2;
|
|
return i;
|
|
};
|
|
|
|
|
|
Buffer.prototype.write = function(string, offset, length, encoding) {
|
|
// Support both (string, offset, length, encoding)
|
|
// and the legacy (string, encoding, offset, length)
|
|
if (isFinite(offset)) {
|
|
if (!isFinite(length)) {
|
|
encoding = length;
|
|
length = undefined;
|
|
}
|
|
} else { // legacy
|
|
var swap = encoding;
|
|
encoding = offset;
|
|
offset = length;
|
|
length = swap;
|
|
}
|
|
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.hexWrite(string, offset, length);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.utf8Write(string, offset, length);
|
|
|
|
case 'ascii':
|
|
return this.asciiWrite(string, offset, length);
|
|
|
|
case 'binary':
|
|
return this.binaryWrite(string, offset, length);
|
|
|
|
case 'base64':
|
|
return this.base64Write(string, offset, length);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.ucs2Write(string, offset, length);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
// slice(start, end)
|
|
Buffer.prototype.slice = function(start, end) {
|
|
if (end === undefined) end = this.length;
|
|
|
|
if (end > this.length) {
|
|
throw new Error('oob');
|
|
}
|
|
if (start > end) {
|
|
throw new Error('oob');
|
|
}
|
|
|
|
return new Buffer(this, end - start, +start);
|
|
};
|
|
|
|
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
|
Buffer.prototype.copy = function(target, target_start, start, end) {
|
|
var source = this;
|
|
start || (start = 0);
|
|
if (end === undefined || isNaN(end)) {
|
|
end = this.length;
|
|
}
|
|
target_start || (target_start = 0);
|
|
|
|
if (end < start) throw new Error('sourceEnd < sourceStart');
|
|
|
|
// Copy 0 bytes; we're done
|
|
if (end === start) return 0;
|
|
if (target.length == 0 || source.length == 0) return 0;
|
|
|
|
if (target_start < 0 || target_start >= target.length) {
|
|
throw new Error('targetStart out of bounds');
|
|
}
|
|
|
|
if (start < 0 || start >= source.length) {
|
|
throw new Error('sourceStart out of bounds');
|
|
}
|
|
|
|
if (end < 0 || end > source.length) {
|
|
throw new Error('sourceEnd out of bounds');
|
|
}
|
|
|
|
// Are we oob?
|
|
if (end > this.length) {
|
|
end = this.length;
|
|
}
|
|
|
|
if (target.length - target_start < end - start) {
|
|
end = target.length - target_start + start;
|
|
}
|
|
|
|
var temp = [];
|
|
for (var i=start; i<end; i++) {
|
|
assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!");
|
|
temp.push(this[i]);
|
|
}
|
|
|
|
for (var i=target_start; i<target_start+temp.length; i++) {
|
|
target[i] = temp[i-target_start];
|
|
}
|
|
};
|
|
|
|
// fill(value, start=0, end=buffer.length)
|
|
Buffer.prototype.fill = function fill(value, start, end) {
|
|
value || (value = 0);
|
|
start || (start = 0);
|
|
end || (end = this.length);
|
|
|
|
if (typeof value === 'string') {
|
|
value = value.charCodeAt(0);
|
|
}
|
|
if (!(typeof value === 'number') || isNaN(value)) {
|
|
throw new Error('value is not a number');
|
|
}
|
|
|
|
if (end < start) throw new Error('end < start');
|
|
|
|
// Fill 0 bytes; we're done
|
|
if (end === start) return 0;
|
|
if (this.length == 0) return 0;
|
|
|
|
if (start < 0 || start >= this.length) {
|
|
throw new Error('start out of bounds');
|
|
}
|
|
|
|
if (end < 0 || end > this.length) {
|
|
throw new Error('end out of bounds');
|
|
}
|
|
|
|
for (var i = start; i < end; i++) {
|
|
this[i] = value;
|
|
}
|
|
}
|
|
|
|
// Static methods
|
|
Buffer.isBuffer = function isBuffer(b) {
|
|
return b instanceof Buffer || b instanceof Buffer;
|
|
};
|
|
|
|
Buffer.concat = function (list, totalLength) {
|
|
if (!isArray(list)) {
|
|
throw new Error("Usage: Buffer.concat(list, [totalLength])\n \
|
|
list should be an Array.");
|
|
}
|
|
|
|
if (list.length === 0) {
|
|
return new Buffer(0);
|
|
} else if (list.length === 1) {
|
|
return list[0];
|
|
}
|
|
|
|
if (typeof totalLength !== 'number') {
|
|
totalLength = 0;
|
|
for (var i = 0; i < list.length; i++) {
|
|
var buf = list[i];
|
|
totalLength += buf.length;
|
|
}
|
|
}
|
|
|
|
var buffer = new Buffer(totalLength);
|
|
var pos = 0;
|
|
for (var i = 0; i < list.length; i++) {
|
|
var buf = list[i];
|
|
buf.copy(buffer, pos);
|
|
pos += buf.length;
|
|
}
|
|
return buffer;
|
|
};
|
|
|
|
// helpers
|
|
|
|
function coerce(length) {
|
|
// Coerce length to a number (possibly NaN), round up
|
|
// in case it's fractional (e.g. 123.456) then do a
|
|
// double negate to coerce a NaN to 0. Easy, right?
|
|
length = ~~Math.ceil(+length);
|
|
return length < 0 ? 0 : length;
|
|
}
|
|
|
|
function isArray(subject) {
|
|
return (Array.isArray ||
|
|
function(subject){
|
|
return {}.toString.apply(subject) == '[object Array]'
|
|
})
|
|
(subject)
|
|
}
|
|
|
|
function isArrayIsh(subject) {
|
|
return isArray(subject) || Buffer.isBuffer(subject) ||
|
|
subject && typeof subject === 'object' &&
|
|
typeof subject.length === 'number';
|
|
}
|
|
|
|
function toHex(n) {
|
|
if (n < 16) return '0' + n.toString(16);
|
|
return n.toString(16);
|
|
}
|
|
|
|
function utf8ToBytes(str) {
|
|
var byteArray = [];
|
|
for (var i = 0; i < str.length; i++)
|
|
if (str.charCodeAt(i) <= 0x7F)
|
|
byteArray.push(str.charCodeAt(i));
|
|
else {
|
|
var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
|
|
for (var j = 0; j < h.length; j++)
|
|
byteArray.push(parseInt(h[j], 16));
|
|
}
|
|
|
|
return byteArray;
|
|
}
|
|
|
|
function asciiToBytes(str) {
|
|
var byteArray = []
|
|
for (var i = 0; i < str.length; i++ )
|
|
// Node's code seems to be doing this and not & 0x7F..
|
|
byteArray.push( str.charCodeAt(i) & 0xFF );
|
|
|
|
return byteArray;
|
|
}
|
|
|
|
function base64ToBytes(str) {
|
|
return require("base64-js").toByteArray(str);
|
|
}
|
|
|
|
function blitBuffer(src, dst, offset, length) {
|
|
var pos, i = 0;
|
|
while (i < length) {
|
|
if ((i+offset >= dst.length) || (i >= src.length))
|
|
break;
|
|
|
|
dst[i + offset] = src[i];
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
function decodeUtf8Char(str) {
|
|
try {
|
|
return decodeURIComponent(str);
|
|
} catch (err) {
|
|
return String.fromCharCode(0xFFFD); // UTF 8 invalid char
|
|
}
|
|
}
|
|
|
|
// read/write bit-twiddling
|
|
|
|
Buffer.prototype.readUInt8 = function(offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return;
|
|
|
|
return buffer[offset];
|
|
};
|
|
|
|
function readUInt16(buffer, offset, isBigEndian, noAssert) {
|
|
var val = 0;
|
|
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return 0;
|
|
|
|
if (isBigEndian) {
|
|
val = buffer[offset] << 8;
|
|
if (offset + 1 < buffer.length) {
|
|
val |= buffer[offset + 1];
|
|
}
|
|
} else {
|
|
val = buffer[offset];
|
|
if (offset + 1 < buffer.length) {
|
|
val |= buffer[offset + 1] << 8;
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Buffer.prototype.readUInt16LE = function(offset, noAssert) {
|
|
return readUInt16(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readUInt16BE = function(offset, noAssert) {
|
|
return readUInt16(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readUInt32(buffer, offset, isBigEndian, noAssert) {
|
|
var val = 0;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return 0;
|
|
|
|
if (isBigEndian) {
|
|
if (offset + 1 < buffer.length)
|
|
val = buffer[offset + 1] << 16;
|
|
if (offset + 2 < buffer.length)
|
|
val |= buffer[offset + 2] << 8;
|
|
if (offset + 3 < buffer.length)
|
|
val |= buffer[offset + 3];
|
|
val = val + (buffer[offset] << 24 >>> 0);
|
|
} else {
|
|
if (offset + 2 < buffer.length)
|
|
val = buffer[offset + 2] << 16;
|
|
if (offset + 1 < buffer.length)
|
|
val |= buffer[offset + 1] << 8;
|
|
val |= buffer[offset];
|
|
if (offset + 3 < buffer.length)
|
|
val = val + (buffer[offset + 3] << 24 >>> 0);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Buffer.prototype.readUInt32LE = function(offset, noAssert) {
|
|
return readUInt32(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readUInt32BE = function(offset, noAssert) {
|
|
return readUInt32(this, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* Signed integer types, yay team! A reminder on how two's complement actually
|
|
* works. The first bit is the signed bit, i.e. tells us whether or not the
|
|
* number should be positive or negative. If the two's complement value is
|
|
* positive, then we're done, as it's equivalent to the unsigned representation.
|
|
*
|
|
* Now if the number is positive, you're pretty much done, you can just leverage
|
|
* the unsigned translations and return those. Unfortunately, negative numbers
|
|
* aren't quite that straightforward.
|
|
*
|
|
* At first glance, one might be inclined to use the traditional formula to
|
|
* translate binary numbers between the positive and negative values in two's
|
|
* complement. (Though it doesn't quite work for the most negative value)
|
|
* Mainly:
|
|
* - invert all the bits
|
|
* - add one to the result
|
|
*
|
|
* Of course, this doesn't quite work in Javascript. Take for example the value
|
|
* of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
|
|
* course, Javascript will do the following:
|
|
*
|
|
* > ~0xff80
|
|
* -65409
|
|
*
|
|
* Whoh there, Javascript, that's not quite right. But wait, according to
|
|
* Javascript that's perfectly correct. When Javascript ends up seeing the
|
|
* constant 0xff80, it has no notion that it is actually a signed number. It
|
|
* assumes that we've input the unsigned value 0xff80. Thus, when it does the
|
|
* binary negation, it casts it into a signed value, (positive 0xff80). Then
|
|
* when you perform binary negation on that, it turns it into a negative number.
|
|
*
|
|
* Instead, we're going to have to use the following general formula, that works
|
|
* in a rather Javascript friendly way. I'm glad we don't support this kind of
|
|
* weird numbering scheme in the kernel.
|
|
*
|
|
* (BIT-MAX - (unsigned)val + 1) * -1
|
|
*
|
|
* The astute observer, may think that this doesn't make sense for 8-bit numbers
|
|
* (really it isn't necessary for them). However, when you get 16-bit numbers,
|
|
* you do. Let's go back to our prior example and see how this will look:
|
|
*
|
|
* (0xffff - 0xff80 + 1) * -1
|
|
* (0x007f + 1) * -1
|
|
* (0x0080) * -1
|
|
*/
|
|
Buffer.prototype.readInt8 = function(offset, noAssert) {
|
|
var buffer = this;
|
|
var neg;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return;
|
|
|
|
neg = buffer[offset] & 0x80;
|
|
if (!neg) {
|
|
return (buffer[offset]);
|
|
}
|
|
|
|
return ((0xff - buffer[offset] + 1) * -1);
|
|
};
|
|
|
|
function readInt16(buffer, offset, isBigEndian, noAssert) {
|
|
var neg, val;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
val = readUInt16(buffer, offset, isBigEndian, noAssert);
|
|
neg = val & 0x8000;
|
|
if (!neg) {
|
|
return val;
|
|
}
|
|
|
|
return (0xffff - val + 1) * -1;
|
|
}
|
|
|
|
Buffer.prototype.readInt16LE = function(offset, noAssert) {
|
|
return readInt16(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readInt16BE = function(offset, noAssert) {
|
|
return readInt16(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readInt32(buffer, offset, isBigEndian, noAssert) {
|
|
var neg, val;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
val = readUInt32(buffer, offset, isBigEndian, noAssert);
|
|
neg = val & 0x80000000;
|
|
if (!neg) {
|
|
return (val);
|
|
}
|
|
|
|
return (0xffffffff - val + 1) * -1;
|
|
}
|
|
|
|
Buffer.prototype.readInt32LE = function(offset, noAssert) {
|
|
return readInt32(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readInt32BE = function(offset, noAssert) {
|
|
return readInt32(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readFloat(buffer, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
|
|
23, 4);
|
|
}
|
|
|
|
Buffer.prototype.readFloatLE = function(offset, noAssert) {
|
|
return readFloat(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readFloatBE = function(offset, noAssert) {
|
|
return readFloat(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readDouble(buffer, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset + 7 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
|
|
52, 8);
|
|
}
|
|
|
|
Buffer.prototype.readDoubleLE = function(offset, noAssert) {
|
|
return readDouble(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readDoubleBE = function(offset, noAssert) {
|
|
return readDouble(this, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* We have to make sure that the value is a valid integer. This means that it is
|
|
* non-negative. It has no fractional component and that it does not exceed the
|
|
* maximum allowed value.
|
|
*
|
|
* value The number to check for validity
|
|
*
|
|
* max The maximum value
|
|
*/
|
|
function verifuint(value, max) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value >= 0,
|
|
'specified a negative value for writing an unsigned value');
|
|
|
|
assert.ok(value <= max, 'value is larger than maximum value for type');
|
|
|
|
assert.ok(Math.floor(value) === value, 'value has a fractional component');
|
|
}
|
|
|
|
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xff);
|
|
}
|
|
|
|
if (offset < buffer.length) {
|
|
buffer[offset] = value;
|
|
}
|
|
};
|
|
|
|
function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xffff);
|
|
}
|
|
|
|
for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) {
|
|
buffer[offset + i] =
|
|
(value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>>
|
|
(isBigEndian ? 1 - i : i) * 8;
|
|
}
|
|
|
|
}
|
|
|
|
Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
|
|
writeUInt16(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
|
|
writeUInt16(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xffffffff);
|
|
}
|
|
|
|
for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) {
|
|
buffer[offset + i] =
|
|
(value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff;
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
|
|
writeUInt32(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
|
|
writeUInt32(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* We now move onto our friends in the signed number category. Unlike unsigned
|
|
* numbers, we're going to have to worry a bit more about how we put values into
|
|
* arrays. Since we are only worrying about signed 32-bit values, we're in
|
|
* slightly better shape. Unfortunately, we really can't do our favorite binary
|
|
* & in this system. It really seems to do the wrong thing. For example:
|
|
*
|
|
* > -32 & 0xff
|
|
* 224
|
|
*
|
|
* What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
|
|
* this aren't treated as a signed number. Ultimately a bad thing.
|
|
*
|
|
* What we're going to want to do is basically create the unsigned equivalent of
|
|
* our representation and pass that off to the wuint* functions. To do that
|
|
* we're going to do the following:
|
|
*
|
|
* - if the value is positive
|
|
* we can pass it directly off to the equivalent wuint
|
|
* - if the value is negative
|
|
* we do the following computation:
|
|
* mb + val + 1, where
|
|
* mb is the maximum unsigned value in that byte size
|
|
* val is the Javascript negative integer
|
|
*
|
|
*
|
|
* As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
|
|
* you do out the computations:
|
|
*
|
|
* 0xffff - 128 + 1
|
|
* 0xffff - 127
|
|
* 0xff80
|
|
*
|
|
* You can then encode this value as the signed version. This is really rather
|
|
* hacky, but it should work and get the job done which is our goal here.
|
|
*/
|
|
|
|
/*
|
|
* A series of checks to make sure we actually have a signed 32-bit number
|
|
*/
|
|
function verifsint(value, max, min) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value <= max, 'value larger than maximum allowed value');
|
|
|
|
assert.ok(value >= min, 'value smaller than minimum allowed value');
|
|
|
|
assert.ok(Math.floor(value) === value, 'value has a fractional component');
|
|
}
|
|
|
|
function verifIEEE754(value, max, min) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value <= max, 'value larger than maximum allowed value');
|
|
|
|
assert.ok(value >= min, 'value smaller than minimum allowed value');
|
|
}
|
|
|
|
Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7f, -0x80);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
buffer.writeUInt8(value, offset, noAssert);
|
|
} else {
|
|
buffer.writeUInt8(0xff + value + 1, offset, noAssert);
|
|
}
|
|
};
|
|
|
|
function writeInt16(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7fff, -0x8000);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
writeUInt16(buffer, value, offset, isBigEndian, noAssert);
|
|
} else {
|
|
writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert);
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
|
|
writeInt16(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
|
|
writeInt16(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeInt32(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7fffffff, -0x80000000);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
writeUInt32(buffer, value, offset, isBigEndian, noAssert);
|
|
} else {
|
|
writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert);
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
|
|
writeInt32(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
|
|
writeInt32(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeFloat(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38);
|
|
}
|
|
|
|
require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
|
|
23, 4);
|
|
}
|
|
|
|
Buffer.prototype.writeFloatLE = function(value, offset, noAssert) {
|
|
writeFloat(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
|
|
writeFloat(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeDouble(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 7 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308);
|
|
}
|
|
|
|
require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
|
|
52, 8);
|
|
}
|
|
|
|
Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
|
|
writeDouble(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
|
|
writeDouble(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
},{"./buffer_ieee754":57,"assert":54,"base64-js":59}],59:[function(require,module,exports){
|
|
(function (exports) {
|
|
'use strict';
|
|
|
|
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
|
|
function b64ToByteArray(b64) {
|
|
var i, j, l, tmp, placeHolders, arr;
|
|
|
|
if (b64.length % 4 > 0) {
|
|
throw 'Invalid string. Length must be a multiple of 4';
|
|
}
|
|
|
|
// the number of equal signs (place holders)
|
|
// if there are two placeholders, than the two characters before it
|
|
// represent one byte
|
|
// if there is only one, then the three characters before it represent 2 bytes
|
|
// this is just a cheap hack to not do indexOf twice
|
|
placeHolders = b64.indexOf('=');
|
|
placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0;
|
|
|
|
// base64 is 4/3 + up to two characters of the original data
|
|
arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders);
|
|
|
|
// if there are placeholders, only get up to the last complete 4 chars
|
|
l = placeHolders > 0 ? b64.length - 4 : b64.length;
|
|
|
|
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
|
tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]);
|
|
arr.push((tmp & 0xFF0000) >> 16);
|
|
arr.push((tmp & 0xFF00) >> 8);
|
|
arr.push(tmp & 0xFF);
|
|
}
|
|
|
|
if (placeHolders === 2) {
|
|
tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4);
|
|
arr.push(tmp & 0xFF);
|
|
} else if (placeHolders === 1) {
|
|
tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2);
|
|
arr.push((tmp >> 8) & 0xFF);
|
|
arr.push(tmp & 0xFF);
|
|
}
|
|
|
|
return arr;
|
|
}
|
|
|
|
function uint8ToBase64(uint8) {
|
|
var i,
|
|
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
|
|
output = "",
|
|
temp, length;
|
|
|
|
function tripletToBase64 (num) {
|
|
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
|
|
};
|
|
|
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
|
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
|
|
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
|
|
output += tripletToBase64(temp);
|
|
}
|
|
|
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
|
switch (extraBytes) {
|
|
case 1:
|
|
temp = uint8[uint8.length - 1];
|
|
output += lookup[temp >> 2];
|
|
output += lookup[(temp << 4) & 0x3F];
|
|
output += '==';
|
|
break;
|
|
case 2:
|
|
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);
|
|
output += lookup[temp >> 10];
|
|
output += lookup[(temp >> 4) & 0x3F];
|
|
output += lookup[(temp << 2) & 0x3F];
|
|
output += '=';
|
|
break;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
module.exports.toByteArray = b64ToByteArray;
|
|
module.exports.fromByteArray = uint8ToBase64;
|
|
}());
|
|
|
|
},{}],60:[function(require,module,exports){
|
|
var Buffer = require('buffer').Buffer
|
|
var sha = require('./sha')
|
|
var sha256 = require('./sha256')
|
|
var rng = require('./rng')
|
|
var md5 = require('./md5')
|
|
|
|
var algorithms = {
|
|
sha1: {
|
|
hex: sha.hex_sha1,
|
|
base64: sha.b64_sha1,
|
|
binary: sha.str_sha1
|
|
},
|
|
sha256: {
|
|
hex: sha256.hex_sha256,
|
|
base64: sha256.b64_sha256,
|
|
binary: sha256.str_sha256
|
|
},
|
|
md5: {
|
|
hex: md5.hex_md5,
|
|
base64: md5.b64_md5,
|
|
binary: md5.bin_md5
|
|
}
|
|
}
|
|
|
|
var algorithmsHmac = {
|
|
sha1: {
|
|
hex: sha.hex_hmac_sha1,
|
|
base64: sha.b64_hmac_sha1,
|
|
binary: sha.str_hmac_sha1
|
|
},
|
|
sha256: {
|
|
hex: sha256.hex_hmac_sha256,
|
|
base64: sha256.b64_hmac_sha256,
|
|
binary: sha256.str_hmac_sha256
|
|
},
|
|
md5: {
|
|
hex: md5.hex_hmac_md5,
|
|
base64: md5.b64_hmac_md5,
|
|
binary: md5.bin_hmac_md5
|
|
}
|
|
}
|
|
|
|
|
|
function error () {
|
|
var m = [].slice.call(arguments).join(' ')
|
|
throw new Error([
|
|
m,
|
|
'we accept pull requests',
|
|
'http://github.com/dominictarr/crypto-browserify'
|
|
].join('\n'))
|
|
}
|
|
|
|
exports.createHash = function (alg) {
|
|
alg = alg || 'sha1'
|
|
if(!algorithms[alg])
|
|
error('algorithm:', alg, 'is not yet supported')
|
|
var s = ''
|
|
var _alg = algorithms[alg]
|
|
return {
|
|
update: function (data) {
|
|
s += data
|
|
return this
|
|
},
|
|
digest: function (enc) {
|
|
enc = enc || 'binary'
|
|
var fn
|
|
if(!(fn = _alg[enc]))
|
|
error('encoding:', enc , 'is not yet supported for algorithm', alg)
|
|
var r = fn(s)
|
|
s = null //not meant to use the hash after you've called digest.
|
|
return r
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.createHmac = function (alg, key) {
|
|
if (!algorithmsHmac[alg])
|
|
error('algorithm:', alg, 'is not yet supported')
|
|
if (typeof key != 'string')
|
|
key = key.toString('binary')
|
|
var s = ''
|
|
var _alg = algorithmsHmac[alg]
|
|
return {
|
|
update: function (data) {
|
|
s += data
|
|
return this
|
|
},
|
|
digest: function (enc) {
|
|
enc = enc || 'binary'
|
|
var fn
|
|
if (!(fn = _alg[enc]))
|
|
error('encoding:', enc, 'is not yet support for algorithm', alg)
|
|
var r = fn(key, s)
|
|
s = null
|
|
return r
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.randomBytes = function(size, callback) {
|
|
if (callback && callback.call) {
|
|
try {
|
|
callback.call(this, undefined, new Buffer(rng(size)));
|
|
} catch (err) { callback(err); }
|
|
} else {
|
|
return new Buffer(rng(size));
|
|
}
|
|
}
|
|
|
|
function each(a, f) {
|
|
for(var i in a)
|
|
f(a[i], i)
|
|
}
|
|
|
|
// the least I can do is make error messages for the rest of the node.js/crypto api.
|
|
each(['createCredentials'
|
|
, 'createCipher'
|
|
, 'createCipheriv'
|
|
, 'createDecipher'
|
|
, 'createDecipheriv'
|
|
, 'createSign'
|
|
, 'createVerify'
|
|
, 'createDiffieHellman'
|
|
, 'pbkdf2'], function (name) {
|
|
exports[name] = function () {
|
|
error('sorry,', name, 'is not implemented yet')
|
|
}
|
|
})
|
|
|
|
},{"./md5":61,"./rng":62,"./sha":63,"./sha256":64,"buffer":58}],61:[function(require,module,exports){
|
|
/*
|
|
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
|
* Digest Algorithm, as defined in RFC 1321.
|
|
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
* Distributed under the BSD License
|
|
* See http://pajhome.org.uk/crypt/md5 for more info.
|
|
*/
|
|
|
|
/*
|
|
* Configurable variables. You may need to tweak these to be compatible with
|
|
* the server-side, but the defaults work in most cases.
|
|
*/
|
|
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
|
var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */
|
|
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
|
|
|
/*
|
|
* These are the functions you'll usually want to call
|
|
* They take string arguments and return either hex or base-64 encoded strings
|
|
*/
|
|
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
|
|
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
|
|
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
|
|
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
|
|
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
|
|
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
|
|
|
|
/*
|
|
* Perform a simple self-test to see if the VM is working
|
|
*/
|
|
function md5_vm_test()
|
|
{
|
|
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
|
|
}
|
|
|
|
/*
|
|
* Calculate the MD5 of an array of little-endian words, and a bit length
|
|
*/
|
|
function core_md5(x, len)
|
|
{
|
|
/* append padding */
|
|
x[len >> 5] |= 0x80 << ((len) % 32);
|
|
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
|
|
|
var a = 1732584193;
|
|
var b = -271733879;
|
|
var c = -1732584194;
|
|
var d = 271733878;
|
|
|
|
for(var i = 0; i < x.length; i += 16)
|
|
{
|
|
var olda = a;
|
|
var oldb = b;
|
|
var oldc = c;
|
|
var oldd = d;
|
|
|
|
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
|
|
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
|
|
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
|
|
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
|
|
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
|
|
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
|
|
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
|
|
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
|
|
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
|
|
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
|
|
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
|
|
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
|
|
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
|
|
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
|
|
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
|
|
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
|
|
|
|
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
|
|
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
|
|
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
|
|
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
|
|
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
|
|
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
|
|
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
|
|
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
|
|
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
|
|
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
|
|
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
|
|
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
|
|
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
|
|
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
|
|
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
|
|
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
|
|
|
|
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
|
|
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
|
|
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
|
|
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
|
|
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
|
|
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
|
|
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
|
|
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
|
|
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
|
|
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
|
|
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
|
|
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
|
|
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
|
|
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
|
|
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
|
|
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
|
|
|
|
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
|
|
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
|
|
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
|
|
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
|
|
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
|
|
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
|
|
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
|
|
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
|
|
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
|
|
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
|
|
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
|
|
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
|
|
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
|
|
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
|
|
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
|
|
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
|
|
|
|
a = safe_add(a, olda);
|
|
b = safe_add(b, oldb);
|
|
c = safe_add(c, oldc);
|
|
d = safe_add(d, oldd);
|
|
}
|
|
return Array(a, b, c, d);
|
|
|
|
}
|
|
|
|
/*
|
|
* These functions implement the four basic operations the algorithm uses.
|
|
*/
|
|
function md5_cmn(q, a, b, x, s, t)
|
|
{
|
|
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
|
|
}
|
|
function md5_ff(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
|
}
|
|
function md5_gg(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
|
}
|
|
function md5_hh(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
|
|
}
|
|
function md5_ii(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
|
|
}
|
|
|
|
/*
|
|
* Calculate the HMAC-MD5, of a key and some data
|
|
*/
|
|
function core_hmac_md5(key, data)
|
|
{
|
|
var bkey = str2binl(key);
|
|
if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
|
|
|
|
var ipad = Array(16), opad = Array(16);
|
|
for(var i = 0; i < 16; i++)
|
|
{
|
|
ipad[i] = bkey[i] ^ 0x36363636;
|
|
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
|
}
|
|
|
|
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
|
|
return core_md5(opad.concat(hash), 512 + 128);
|
|
}
|
|
|
|
/*
|
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
|
* to work around bugs in some JS interpreters.
|
|
*/
|
|
function safe_add(x, y)
|
|
{
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
}
|
|
|
|
/*
|
|
* Bitwise rotate a 32-bit number to the left.
|
|
*/
|
|
function bit_rol(num, cnt)
|
|
{
|
|
return (num << cnt) | (num >>> (32 - cnt));
|
|
}
|
|
|
|
/*
|
|
* Convert a string to an array of little-endian words
|
|
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
|
|
*/
|
|
function str2binl(str)
|
|
{
|
|
var bin = Array();
|
|
var mask = (1 << chrsz) - 1;
|
|
for(var i = 0; i < str.length * chrsz; i += chrsz)
|
|
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
|
|
return bin;
|
|
}
|
|
|
|
/*
|
|
* Convert an array of little-endian words to a string
|
|
*/
|
|
function binl2str(bin)
|
|
{
|
|
var str = "";
|
|
var mask = (1 << chrsz) - 1;
|
|
for(var i = 0; i < bin.length * 32; i += chrsz)
|
|
str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
* Convert an array of little-endian words to a hex string.
|
|
*/
|
|
function binl2hex(binarray)
|
|
{
|
|
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
|
var str = "";
|
|
for(var i = 0; i < binarray.length * 4; i++)
|
|
{
|
|
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
|
|
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
* Convert an array of little-endian words to a base-64 string
|
|
*/
|
|
function binl2b64(binarray)
|
|
{
|
|
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
var str = "";
|
|
for(var i = 0; i < binarray.length * 4; i += 3)
|
|
{
|
|
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
|
|
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
|
|
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
|
|
for(var j = 0; j < 4; j++)
|
|
{
|
|
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
|
|
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
exports.hex_md5 = hex_md5;
|
|
exports.b64_md5 = b64_md5;
|
|
exports.bin_md5 = str_md5;
|
|
exports.hex_hmac_md5 = hex_hmac_md5;
|
|
exports.b64_hmac_md5 = b64_hmac_md5;
|
|
exports.bin_hmac_md5 = str_hmac_md5;
|
|
|
|
},{}],62:[function(require,module,exports){
|
|
// Original code adapted from Robert Kieffer.
|
|
// details at https://github.com/broofa/node-uuid
|
|
(function() {
|
|
var _global = this;
|
|
|
|
var mathRNG, whatwgRNG;
|
|
|
|
// NOTE: Math.random() does not guarantee "cryptographic quality"
|
|
mathRNG = function(size) {
|
|
var bytes = new Array(size);
|
|
var r;
|
|
|
|
for (var i = 0, r; i < size; i++) {
|
|
if ((i & 0x03) == 0) r = Math.random() * 0x100000000;
|
|
bytes[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
if (_global.crypto && crypto.getRandomValues) {
|
|
var _rnds = new Uint32Array(4);
|
|
whatwgRNG = function(size) {
|
|
var bytes = new Array(size);
|
|
crypto.getRandomValues(_rnds);
|
|
|
|
for (var c = 0 ; c < size; c++) {
|
|
bytes[c] = _rnds[c >> 2] >>> ((c & 0x03) * 8) & 0xff;
|
|
}
|
|
return bytes;
|
|
}
|
|
}
|
|
|
|
module.exports = whatwgRNG || mathRNG;
|
|
|
|
}())
|
|
|
|
},{}],63:[function(require,module,exports){
|
|
/*
|
|
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
|
* in FIPS PUB 180-1
|
|
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
* Distributed under the BSD License
|
|
* See http://pajhome.org.uk/crypt/md5 for details.
|
|
*/
|
|
|
|
exports.hex_sha1 = hex_sha1;
|
|
exports.b64_sha1 = b64_sha1;
|
|
exports.str_sha1 = str_sha1;
|
|
exports.hex_hmac_sha1 = hex_hmac_sha1;
|
|
exports.b64_hmac_sha1 = b64_hmac_sha1;
|
|
exports.str_hmac_sha1 = str_hmac_sha1;
|
|
|
|
/*
|
|
* Configurable variables. You may need to tweak these to be compatible with
|
|
* the server-side, but the defaults work in most cases.
|
|
*/
|
|
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
|
var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */
|
|
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
|
|
|
/*
|
|
* These are the functions you'll usually want to call
|
|
* They take string arguments and return either hex or base-64 encoded strings
|
|
*/
|
|
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
|
|
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
|
|
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
|
|
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
|
|
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
|
|
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
|
|
|
|
/*
|
|
* Perform a simple self-test to see if the VM is working
|
|
*/
|
|
function sha1_vm_test()
|
|
{
|
|
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
|
|
}
|
|
|
|
/*
|
|
* Calculate the SHA-1 of an array of big-endian words, and a bit length
|
|
*/
|
|
function core_sha1(x, len)
|
|
{
|
|
/* append padding */
|
|
x[len >> 5] |= 0x80 << (24 - len % 32);
|
|
x[((len + 64 >> 9) << 4) + 15] = len;
|
|
|
|
var w = Array(80);
|
|
var a = 1732584193;
|
|
var b = -271733879;
|
|
var c = -1732584194;
|
|
var d = 271733878;
|
|
var e = -1009589776;
|
|
|
|
for(var i = 0; i < x.length; i += 16)
|
|
{
|
|
var olda = a;
|
|
var oldb = b;
|
|
var oldc = c;
|
|
var oldd = d;
|
|
var olde = e;
|
|
|
|
for(var j = 0; j < 80; j++)
|
|
{
|
|
if(j < 16) w[j] = x[i + j];
|
|
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
|
|
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
|
|
safe_add(safe_add(e, w[j]), sha1_kt(j)));
|
|
e = d;
|
|
d = c;
|
|
c = rol(b, 30);
|
|
b = a;
|
|
a = t;
|
|
}
|
|
|
|
a = safe_add(a, olda);
|
|
b = safe_add(b, oldb);
|
|
c = safe_add(c, oldc);
|
|
d = safe_add(d, oldd);
|
|
e = safe_add(e, olde);
|
|
}
|
|
return Array(a, b, c, d, e);
|
|
|
|
}
|
|
|
|
/*
|
|
* Perform the appropriate triplet combination function for the current
|
|
* iteration
|
|
*/
|
|
function sha1_ft(t, b, c, d)
|
|
{
|
|
if(t < 20) return (b & c) | ((~b) & d);
|
|
if(t < 40) return b ^ c ^ d;
|
|
if(t < 60) return (b & c) | (b & d) | (c & d);
|
|
return b ^ c ^ d;
|
|
}
|
|
|
|
/*
|
|
* Determine the appropriate additive constant for the current iteration
|
|
*/
|
|
function sha1_kt(t)
|
|
{
|
|
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
|
|
(t < 60) ? -1894007588 : -899497514;
|
|
}
|
|
|
|
/*
|
|
* Calculate the HMAC-SHA1 of a key and some data
|
|
*/
|
|
function core_hmac_sha1(key, data)
|
|
{
|
|
var bkey = str2binb(key);
|
|
if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
|
|
|
|
var ipad = Array(16), opad = Array(16);
|
|
for(var i = 0; i < 16; i++)
|
|
{
|
|
ipad[i] = bkey[i] ^ 0x36363636;
|
|
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
|
}
|
|
|
|
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
|
|
return core_sha1(opad.concat(hash), 512 + 160);
|
|
}
|
|
|
|
/*
|
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
|
* to work around bugs in some JS interpreters.
|
|
*/
|
|
function safe_add(x, y)
|
|
{
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
}
|
|
|
|
/*
|
|
* Bitwise rotate a 32-bit number to the left.
|
|
*/
|
|
function rol(num, cnt)
|
|
{
|
|
return (num << cnt) | (num >>> (32 - cnt));
|
|
}
|
|
|
|
/*
|
|
* Convert an 8-bit or 16-bit string to an array of big-endian words
|
|
* In 8-bit function, characters >255 have their hi-byte silently ignored.
|
|
*/
|
|
function str2binb(str)
|
|
{
|
|
var bin = Array();
|
|
var mask = (1 << chrsz) - 1;
|
|
for(var i = 0; i < str.length * chrsz; i += chrsz)
|
|
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
|
|
return bin;
|
|
}
|
|
|
|
/*
|
|
* Convert an array of big-endian words to a string
|
|
*/
|
|
function binb2str(bin)
|
|
{
|
|
var str = "";
|
|
var mask = (1 << chrsz) - 1;
|
|
for(var i = 0; i < bin.length * 32; i += chrsz)
|
|
str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
* Convert an array of big-endian words to a hex string.
|
|
*/
|
|
function binb2hex(binarray)
|
|
{
|
|
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
|
var str = "";
|
|
for(var i = 0; i < binarray.length * 4; i++)
|
|
{
|
|
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
|
|
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
* Convert an array of big-endian words to a base-64 string
|
|
*/
|
|
function binb2b64(binarray)
|
|
{
|
|
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
var str = "";
|
|
for(var i = 0; i < binarray.length * 4; i += 3)
|
|
{
|
|
var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
|
|
| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
|
|
| ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
|
|
for(var j = 0; j < 4; j++)
|
|
{
|
|
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
|
|
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
},{}],64:[function(require,module,exports){
|
|
|
|
/**
|
|
* A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
|
|
* in FIPS 180-2
|
|
* Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
*
|
|
*/
|
|
|
|
exports.hex_sha256 = hex_sha256;
|
|
exports.b64_sha256 = b64_sha256;
|
|
exports.str_sha256 = str_sha256;
|
|
exports.hex_hmac_sha256 = hex_hmac_sha256;
|
|
exports.b64_hmac_sha256 = b64_hmac_sha256;
|
|
exports.str_hmac_sha256 = str_hmac_sha256;
|
|
|
|
/*
|
|
* Configurable variables. You may need to tweak these to be compatible with
|
|
* the server-side, but the defaults work in most cases.
|
|
*/
|
|
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
|
var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */
|
|
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
|
|
|
/*
|
|
* These are the functions you'll usually want to call
|
|
* They take string arguments and return either hex or base-64 encoded strings
|
|
*/
|
|
function hex_sha256(s){return binb2hex(core_sha256(str2binb(s),s.length * chrsz));}
|
|
function b64_sha256(s){return binb2b64(core_sha256(str2binb(s),s.length * chrsz));}
|
|
function str_sha256(s){return binb2str(core_sha256(str2binb(s),s.length * chrsz));}
|
|
function hex_hmac_sha256(key, data){ return binb2hex(core_hmac_sha256(key, data));}
|
|
function b64_hmac_sha256(key, data){ return binb2b64(core_hmac_sha256(key, data));}
|
|
function str_hmac_sha256(key, data){ return binb2str(core_hmac_sha256(key, data));}
|
|
|
|
var safe_add = function(x, y) {
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
};
|
|
|
|
var S = function(X, n) {
|
|
return (X >>> n) | (X << (32 - n));
|
|
};
|
|
|
|
var R = function(X, n) {
|
|
return (X >>> n);
|
|
};
|
|
|
|
var Ch = function(x, y, z) {
|
|
return ((x & y) ^ ((~x) & z));
|
|
};
|
|
|
|
var Maj = function(x, y, z) {
|
|
return ((x & y) ^ (x & z) ^ (y & z));
|
|
};
|
|
|
|
var Sigma0256 = function(x) {
|
|
return (S(x, 2) ^ S(x, 13) ^ S(x, 22));
|
|
};
|
|
|
|
var Sigma1256 = function(x) {
|
|
return (S(x, 6) ^ S(x, 11) ^ S(x, 25));
|
|
};
|
|
|
|
var Gamma0256 = function(x) {
|
|
return (S(x, 7) ^ S(x, 18) ^ R(x, 3));
|
|
};
|
|
|
|
var Gamma1256 = function(x) {
|
|
return (S(x, 17) ^ S(x, 19) ^ R(x, 10));
|
|
};
|
|
|
|
var core_sha256 = function(m, l) {
|
|
var K = new Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2);
|
|
var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
|
|
var W = new Array(64);
|
|
var a, b, c, d, e, f, g, h, i, j;
|
|
var T1, T2;
|
|
/* append padding */
|
|
m[l >> 5] |= 0x80 << (24 - l % 32);
|
|
m[((l + 64 >> 9) << 4) + 15] = l;
|
|
for (var i = 0; i < m.length; i += 16) {
|
|
a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
|
|
for (var j = 0; j < 64; j++) {
|
|
if (j < 16) {
|
|
W[j] = m[j + i];
|
|
} else {
|
|
W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
|
|
}
|
|
T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
|
|
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
|
|
h = g; g = f; f = e; e = safe_add(d, T1); d = c; c = b; b = a; a = safe_add(T1, T2);
|
|
}
|
|
HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]); HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]);
|
|
HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]); HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
|
|
}
|
|
return HASH;
|
|
};
|
|
|
|
var str2binb = function(str) {
|
|
var bin = Array();
|
|
var mask = (1 << chrsz) - 1;
|
|
for (var i = 0; i < str.length * chrsz; i += chrsz) {
|
|
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i % 32);
|
|
}
|
|
return bin;
|
|
};
|
|
|
|
/*
|
|
* Convert an array of big-endian words to a string
|
|
*/
|
|
function binb2str(bin)
|
|
{
|
|
var str = "";
|
|
var mask = (1 << chrsz) - 1;
|
|
for (var i = 0; i < bin.length * 32; i += chrsz)
|
|
str += String.fromCharCode((bin[i >> 5] >>> (32 - chrsz - i % 32)) & mask);
|
|
return str;
|
|
}
|
|
|
|
var hex2binb = function(a) {
|
|
var b = [], length = a.length, i, num;
|
|
for (i = 0; i < length; i += 2) {
|
|
num = parseInt(a.substr(i, 2), 16);
|
|
if (!isNaN(num)) {
|
|
b[i >> 3] |= num << (24 - (4 * (i % 8)));
|
|
} else {
|
|
return "INVALID HEX STRING";
|
|
}
|
|
}
|
|
return b;
|
|
};
|
|
|
|
var binb2hex = function(binarray) {
|
|
//var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
|
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
|
var str = "";
|
|
for (var i = 0; i < binarray.length * 4; i++) {
|
|
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
|
|
}
|
|
return str;
|
|
};
|
|
|
|
var binb2b64 = function(a) {
|
|
var b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/", str = "", length = a.length * 4, i, j, triplet;
|
|
var b64pad = "=";
|
|
for (i = 0; i < length; i += 3) {
|
|
triplet = (((a[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((a[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | ((a[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF);
|
|
for (j = 0; j < 4; j += 1) {
|
|
if (i * 8 + j * 6 <= a.length * 32) {
|
|
str += b.charAt((triplet >> 6 * (3 - j)) & 0x3F);
|
|
} else {
|
|
str += b64pad;
|
|
}
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
var core_hmac_sha256 = function(key, data) {
|
|
var bkey = str2binb(key);
|
|
if (bkey.length > 16) {
|
|
bkey = core_sha256(bkey, key.length * chrsz);
|
|
}
|
|
var ipad = Array(16), opad = Array(16);
|
|
for (var i = 0; i < 16; i++) {
|
|
ipad[i] = bkey[i] ^ 0x36363636;
|
|
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
|
}
|
|
var hash = core_sha256(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
|
|
return core_sha256(opad.concat(hash), 512 + 256);
|
|
};
|
|
|
|
|
|
},{}],65:[function(require,module,exports){
|
|
require=(function(e,t,n,r){function i(r){if(!n[r]){if(!t[r]){if(e)return e(r);throw new Error("Cannot find module '"+r+"'")}var s=n[r]={exports:{}};t[r][0](function(e){var n=t[r][1][e];return i(n?n:e)},s,s.exports)}return n[r].exports}for(var s=0;s<r.length;s++)i(r[s]);return i})(typeof require!=="undefined"&&require,{1:[function(require,module,exports){
|
|
// UTILITY
|
|
var util = require('util');
|
|
var Buffer = require("buffer").Buffer;
|
|
var pSlice = Array.prototype.slice;
|
|
|
|
function objectKeys(object) {
|
|
if (Object.keys) return Object.keys(object);
|
|
var result = [];
|
|
for (var name in object) {
|
|
if (Object.prototype.hasOwnProperty.call(object, name)) {
|
|
result.push(name);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// 1. The assert module provides functions that throw
|
|
// AssertionError's when particular conditions are not met. The
|
|
// assert module must conform to the following interface.
|
|
|
|
var assert = module.exports = ok;
|
|
|
|
// 2. The AssertionError is defined in assert.
|
|
// new assert.AssertionError({ message: message,
|
|
// actual: actual,
|
|
// expected: expected })
|
|
|
|
assert.AssertionError = function AssertionError(options) {
|
|
this.name = 'AssertionError';
|
|
this.message = options.message;
|
|
this.actual = options.actual;
|
|
this.expected = options.expected;
|
|
this.operator = options.operator;
|
|
var stackStartFunction = options.stackStartFunction || fail;
|
|
|
|
if (Error.captureStackTrace) {
|
|
Error.captureStackTrace(this, stackStartFunction);
|
|
}
|
|
};
|
|
util.inherits(assert.AssertionError, Error);
|
|
|
|
function replacer(key, value) {
|
|
if (value === undefined) {
|
|
return '' + value;
|
|
}
|
|
if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) {
|
|
return value.toString();
|
|
}
|
|
if (typeof value === 'function' || value instanceof RegExp) {
|
|
return value.toString();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function truncate(s, n) {
|
|
if (typeof s == 'string') {
|
|
return s.length < n ? s : s.slice(0, n);
|
|
} else {
|
|
return s;
|
|
}
|
|
}
|
|
|
|
assert.AssertionError.prototype.toString = function() {
|
|
if (this.message) {
|
|
return [this.name + ':', this.message].join(' ');
|
|
} else {
|
|
return [
|
|
this.name + ':',
|
|
truncate(JSON.stringify(this.actual, replacer), 128),
|
|
this.operator,
|
|
truncate(JSON.stringify(this.expected, replacer), 128)
|
|
].join(' ');
|
|
}
|
|
};
|
|
|
|
// assert.AssertionError instanceof Error
|
|
|
|
assert.AssertionError.__proto__ = Error.prototype;
|
|
|
|
// At present only the three keys mentioned above are used and
|
|
// understood by the spec. Implementations or sub modules can pass
|
|
// other keys to the AssertionError's constructor - they will be
|
|
// ignored.
|
|
|
|
// 3. All of the following functions must throw an AssertionError
|
|
// when a corresponding condition is not met, with a message that
|
|
// may be undefined if not provided. All assertion methods provide
|
|
// both the actual and expected values to the assertion error for
|
|
// display purposes.
|
|
|
|
function fail(actual, expected, message, operator, stackStartFunction) {
|
|
throw new assert.AssertionError({
|
|
message: message,
|
|
actual: actual,
|
|
expected: expected,
|
|
operator: operator,
|
|
stackStartFunction: stackStartFunction
|
|
});
|
|
}
|
|
|
|
// EXTENSION! allows for well behaved errors defined elsewhere.
|
|
assert.fail = fail;
|
|
|
|
// 4. Pure assertion tests whether a value is truthy, as determined
|
|
// by !!guard.
|
|
// assert.ok(guard, message_opt);
|
|
// This statement is equivalent to assert.equal(true, guard,
|
|
// message_opt);. To test strictly for the value true, use
|
|
// assert.strictEqual(true, guard, message_opt);.
|
|
|
|
function ok(value, message) {
|
|
if (!!!value) fail(value, true, message, '==', assert.ok);
|
|
}
|
|
assert.ok = ok;
|
|
|
|
// 5. The equality assertion tests shallow, coercive equality with
|
|
// ==.
|
|
// assert.equal(actual, expected, message_opt);
|
|
|
|
assert.equal = function equal(actual, expected, message) {
|
|
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
|
|
};
|
|
|
|
// 6. The non-equality assertion tests for whether two objects are not equal
|
|
// with != assert.notEqual(actual, expected, message_opt);
|
|
|
|
assert.notEqual = function notEqual(actual, expected, message) {
|
|
if (actual == expected) {
|
|
fail(actual, expected, message, '!=', assert.notEqual);
|
|
}
|
|
};
|
|
|
|
// 7. The equivalence assertion tests a deep equality relation.
|
|
// assert.deepEqual(actual, expected, message_opt);
|
|
|
|
assert.deepEqual = function deepEqual(actual, expected, message) {
|
|
if (!_deepEqual(actual, expected)) {
|
|
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
|
|
}
|
|
};
|
|
|
|
function _deepEqual(actual, expected) {
|
|
// 7.1. All identical values are equivalent, as determined by ===.
|
|
if (actual === expected) {
|
|
return true;
|
|
|
|
} else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
|
|
if (actual.length != expected.length) return false;
|
|
|
|
for (var i = 0; i < actual.length; i++) {
|
|
if (actual[i] !== expected[i]) return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
// 7.2. If the expected value is a Date object, the actual value is
|
|
// equivalent if it is also a Date object that refers to the same time.
|
|
} else if (actual instanceof Date && expected instanceof Date) {
|
|
return actual.getTime() === expected.getTime();
|
|
|
|
// 7.3. Other pairs that do not both pass typeof value == 'object',
|
|
// equivalence is determined by ==.
|
|
} else if (typeof actual != 'object' && typeof expected != 'object') {
|
|
return actual == expected;
|
|
|
|
// 7.4. For all other Object pairs, including Array objects, equivalence is
|
|
// determined by having the same number of owned properties (as verified
|
|
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
|
// (although not necessarily the same order), equivalent values for every
|
|
// corresponding key, and an identical 'prototype' property. Note: this
|
|
// accounts for both named and indexed properties on Arrays.
|
|
} else {
|
|
return objEquiv(actual, expected);
|
|
}
|
|
}
|
|
|
|
function isUndefinedOrNull(value) {
|
|
return value === null || value === undefined;
|
|
}
|
|
|
|
function isArguments(object) {
|
|
return Object.prototype.toString.call(object) == '[object Arguments]';
|
|
}
|
|
|
|
function objEquiv(a, b) {
|
|
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
|
|
return false;
|
|
// an identical 'prototype' property.
|
|
if (a.prototype !== b.prototype) return false;
|
|
//~~~I've managed to break Object.keys through screwy arguments passing.
|
|
// Converting to array solves the problem.
|
|
if (isArguments(a)) {
|
|
if (!isArguments(b)) {
|
|
return false;
|
|
}
|
|
a = pSlice.call(a);
|
|
b = pSlice.call(b);
|
|
return _deepEqual(a, b);
|
|
}
|
|
try {
|
|
var ka = objectKeys(a),
|
|
kb = objectKeys(b),
|
|
key, i;
|
|
} catch (e) {//happens when one is a string literal and the other isn't
|
|
return false;
|
|
}
|
|
// having the same number of owned properties (keys incorporates
|
|
// hasOwnProperty)
|
|
if (ka.length != kb.length)
|
|
return false;
|
|
//the same set of keys (although not necessarily the same order),
|
|
ka.sort();
|
|
kb.sort();
|
|
//~~~cheap key test
|
|
for (i = ka.length - 1; i >= 0; i--) {
|
|
if (ka[i] != kb[i])
|
|
return false;
|
|
}
|
|
//equivalent values for every corresponding key, and
|
|
//~~~possibly expensive deep test
|
|
for (i = ka.length - 1; i >= 0; i--) {
|
|
key = ka[i];
|
|
if (!_deepEqual(a[key], b[key])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// 8. The non-equivalence assertion tests for any deep inequality.
|
|
// assert.notDeepEqual(actual, expected, message_opt);
|
|
|
|
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
|
if (_deepEqual(actual, expected)) {
|
|
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
|
|
}
|
|
};
|
|
|
|
// 9. The strict equality assertion tests strict equality, as determined by ===.
|
|
// assert.strictEqual(actual, expected, message_opt);
|
|
|
|
assert.strictEqual = function strictEqual(actual, expected, message) {
|
|
if (actual !== expected) {
|
|
fail(actual, expected, message, '===', assert.strictEqual);
|
|
}
|
|
};
|
|
|
|
// 10. The strict non-equality assertion tests for strict inequality, as
|
|
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
|
|
|
|
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
|
if (actual === expected) {
|
|
fail(actual, expected, message, '!==', assert.notStrictEqual);
|
|
}
|
|
};
|
|
|
|
function expectedException(actual, expected) {
|
|
if (!actual || !expected) {
|
|
return false;
|
|
}
|
|
|
|
if (expected instanceof RegExp) {
|
|
return expected.test(actual);
|
|
} else if (actual instanceof expected) {
|
|
return true;
|
|
} else if (expected.call({}, actual) === true) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function _throws(shouldThrow, block, expected, message) {
|
|
var actual;
|
|
|
|
if (typeof expected === 'string') {
|
|
message = expected;
|
|
expected = null;
|
|
}
|
|
|
|
try {
|
|
block();
|
|
} catch (e) {
|
|
actual = e;
|
|
}
|
|
|
|
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
|
|
(message ? ' ' + message : '.');
|
|
|
|
if (shouldThrow && !actual) {
|
|
fail('Missing expected exception' + message);
|
|
}
|
|
|
|
if (!shouldThrow && expectedException(actual, expected)) {
|
|
fail('Got unwanted exception' + message);
|
|
}
|
|
|
|
if ((shouldThrow && actual && expected &&
|
|
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
|
|
throw actual;
|
|
}
|
|
}
|
|
|
|
// 11. Expected to throw an error:
|
|
// assert.throws(block, Error_opt, message_opt);
|
|
|
|
assert.throws = function(block, /*optional*/error, /*optional*/message) {
|
|
_throws.apply(this, [true].concat(pSlice.call(arguments)));
|
|
};
|
|
|
|
// EXTENSION! This is annoying to write outside this module.
|
|
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
|
|
_throws.apply(this, [false].concat(pSlice.call(arguments)));
|
|
};
|
|
|
|
assert.ifError = function(err) { if (err) {throw err;}};
|
|
|
|
},{"util":2,"buffer":3}],2:[function(require,module,exports){
|
|
var events = require('events');
|
|
|
|
exports.isArray = isArray;
|
|
exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'};
|
|
exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'};
|
|
|
|
|
|
exports.print = function () {};
|
|
exports.puts = function () {};
|
|
exports.debug = function() {};
|
|
|
|
exports.inspect = function(obj, showHidden, depth, colors) {
|
|
var seen = [];
|
|
|
|
var stylize = function(str, styleType) {
|
|
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
|
|
var styles =
|
|
{ 'bold' : [1, 22],
|
|
'italic' : [3, 23],
|
|
'underline' : [4, 24],
|
|
'inverse' : [7, 27],
|
|
'white' : [37, 39],
|
|
'grey' : [90, 39],
|
|
'black' : [30, 39],
|
|
'blue' : [34, 39],
|
|
'cyan' : [36, 39],
|
|
'green' : [32, 39],
|
|
'magenta' : [35, 39],
|
|
'red' : [31, 39],
|
|
'yellow' : [33, 39] };
|
|
|
|
var style =
|
|
{ 'special': 'cyan',
|
|
'number': 'blue',
|
|
'boolean': 'yellow',
|
|
'undefined': 'grey',
|
|
'null': 'bold',
|
|
'string': 'green',
|
|
'date': 'magenta',
|
|
// "name": intentionally not styling
|
|
'regexp': 'red' }[styleType];
|
|
|
|
if (style) {
|
|
return '\033[' + styles[style][0] + 'm' + str +
|
|
'\033[' + styles[style][1] + 'm';
|
|
} else {
|
|
return str;
|
|
}
|
|
};
|
|
if (! colors) {
|
|
stylize = function(str, styleType) { return str; };
|
|
}
|
|
|
|
function format(value, recurseTimes) {
|
|
// Provide a hook for user-specified inspect functions.
|
|
// Check that value is an object with an inspect function on it
|
|
if (value && typeof value.inspect === 'function' &&
|
|
// Filter out the util module, it's inspect function is special
|
|
value !== exports &&
|
|
// Also filter out any prototype objects using the circular check.
|
|
!(value.constructor && value.constructor.prototype === value)) {
|
|
return value.inspect(recurseTimes);
|
|
}
|
|
|
|
// Primitive types cannot have properties
|
|
switch (typeof value) {
|
|
case 'undefined':
|
|
return stylize('undefined', 'undefined');
|
|
|
|
case 'string':
|
|
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
|
|
.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"') + '\'';
|
|
return stylize(simple, 'string');
|
|
|
|
case 'number':
|
|
return stylize('' + value, 'number');
|
|
|
|
case 'boolean':
|
|
return stylize('' + value, 'boolean');
|
|
}
|
|
// For some reason typeof null is "object", so special case here.
|
|
if (value === null) {
|
|
return stylize('null', 'null');
|
|
}
|
|
|
|
// Look up the keys of the object.
|
|
var visible_keys = Object_keys(value);
|
|
var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys;
|
|
|
|
// Functions without properties can be shortcutted.
|
|
if (typeof value === 'function' && keys.length === 0) {
|
|
if (isRegExp(value)) {
|
|
return stylize('' + value, 'regexp');
|
|
} else {
|
|
var name = value.name ? ': ' + value.name : '';
|
|
return stylize('[Function' + name + ']', 'special');
|
|
}
|
|
}
|
|
|
|
// Dates without properties can be shortcutted
|
|
if (isDate(value) && keys.length === 0) {
|
|
return stylize(value.toUTCString(), 'date');
|
|
}
|
|
|
|
var base, type, braces;
|
|
// Determine the object type
|
|
if (isArray(value)) {
|
|
type = 'Array';
|
|
braces = ['[', ']'];
|
|
} else {
|
|
type = 'Object';
|
|
braces = ['{', '}'];
|
|
}
|
|
|
|
// Make functions say that they are functions
|
|
if (typeof value === 'function') {
|
|
var n = value.name ? ': ' + value.name : '';
|
|
base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
|
|
} else {
|
|
base = '';
|
|
}
|
|
|
|
// Make dates with properties first say the date
|
|
if (isDate(value)) {
|
|
base = ' ' + value.toUTCString();
|
|
}
|
|
|
|
if (keys.length === 0) {
|
|
return braces[0] + base + braces[1];
|
|
}
|
|
|
|
if (recurseTimes < 0) {
|
|
if (isRegExp(value)) {
|
|
return stylize('' + value, 'regexp');
|
|
} else {
|
|
return stylize('[Object]', 'special');
|
|
}
|
|
}
|
|
|
|
seen.push(value);
|
|
|
|
var output = keys.map(function(key) {
|
|
var name, str;
|
|
if (value.__lookupGetter__) {
|
|
if (value.__lookupGetter__(key)) {
|
|
if (value.__lookupSetter__(key)) {
|
|
str = stylize('[Getter/Setter]', 'special');
|
|
} else {
|
|
str = stylize('[Getter]', 'special');
|
|
}
|
|
} else {
|
|
if (value.__lookupSetter__(key)) {
|
|
str = stylize('[Setter]', 'special');
|
|
}
|
|
}
|
|
}
|
|
if (visible_keys.indexOf(key) < 0) {
|
|
name = '[' + key + ']';
|
|
}
|
|
if (!str) {
|
|
if (seen.indexOf(value[key]) < 0) {
|
|
if (recurseTimes === null) {
|
|
str = format(value[key]);
|
|
} else {
|
|
str = format(value[key], recurseTimes - 1);
|
|
}
|
|
if (str.indexOf('\n') > -1) {
|
|
if (isArray(value)) {
|
|
str = str.split('\n').map(function(line) {
|
|
return ' ' + line;
|
|
}).join('\n').substr(2);
|
|
} else {
|
|
str = '\n' + str.split('\n').map(function(line) {
|
|
return ' ' + line;
|
|
}).join('\n');
|
|
}
|
|
}
|
|
} else {
|
|
str = stylize('[Circular]', 'special');
|
|
}
|
|
}
|
|
if (typeof name === 'undefined') {
|
|
if (type === 'Array' && key.match(/^\d+$/)) {
|
|
return str;
|
|
}
|
|
name = JSON.stringify('' + key);
|
|
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
|
|
name = name.substr(1, name.length - 2);
|
|
name = stylize(name, 'name');
|
|
} else {
|
|
name = name.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"')
|
|
.replace(/(^"|"$)/g, "'");
|
|
name = stylize(name, 'string');
|
|
}
|
|
}
|
|
|
|
return name + ': ' + str;
|
|
});
|
|
|
|
seen.pop();
|
|
|
|
var numLinesEst = 0;
|
|
var length = output.reduce(function(prev, cur) {
|
|
numLinesEst++;
|
|
if (cur.indexOf('\n') >= 0) numLinesEst++;
|
|
return prev + cur.length + 1;
|
|
}, 0);
|
|
|
|
if (length > 50) {
|
|
output = braces[0] +
|
|
(base === '' ? '' : base + '\n ') +
|
|
' ' +
|
|
output.join(',\n ') +
|
|
' ' +
|
|
braces[1];
|
|
|
|
} else {
|
|
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
|
|
}
|
|
|
|
return output;
|
|
}
|
|
return format(obj, (typeof depth === 'undefined' ? 2 : depth));
|
|
};
|
|
|
|
|
|
function isArray(ar) {
|
|
return ar instanceof Array ||
|
|
Array.isArray(ar) ||
|
|
(ar && ar !== Object.prototype && isArray(ar.__proto__));
|
|
}
|
|
|
|
|
|
function isRegExp(re) {
|
|
return re instanceof RegExp ||
|
|
(typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]');
|
|
}
|
|
|
|
|
|
function isDate(d) {
|
|
if (d instanceof Date) return true;
|
|
if (typeof d !== 'object') return false;
|
|
var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype);
|
|
var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__);
|
|
return JSON.stringify(proto) === JSON.stringify(properties);
|
|
}
|
|
|
|
function pad(n) {
|
|
return n < 10 ? '0' + n.toString(10) : n.toString(10);
|
|
}
|
|
|
|
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
|
|
'Oct', 'Nov', 'Dec'];
|
|
|
|
// 26 Feb 16:19:34
|
|
function timestamp() {
|
|
var d = new Date();
|
|
var time = [pad(d.getHours()),
|
|
pad(d.getMinutes()),
|
|
pad(d.getSeconds())].join(':');
|
|
return [d.getDate(), months[d.getMonth()], time].join(' ');
|
|
}
|
|
|
|
exports.log = function (msg) {};
|
|
|
|
exports.pump = null;
|
|
|
|
var Object_keys = Object.keys || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) res.push(key);
|
|
return res;
|
|
};
|
|
|
|
var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) {
|
|
if (Object.hasOwnProperty.call(obj, key)) res.push(key);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
var Object_create = Object.create || function (prototype, properties) {
|
|
// from es5-shim
|
|
var object;
|
|
if (prototype === null) {
|
|
object = { '__proto__' : null };
|
|
}
|
|
else {
|
|
if (typeof prototype !== 'object') {
|
|
throw new TypeError(
|
|
'typeof prototype[' + (typeof prototype) + '] != \'object\''
|
|
);
|
|
}
|
|
var Type = function () {};
|
|
Type.prototype = prototype;
|
|
object = new Type();
|
|
object.__proto__ = prototype;
|
|
}
|
|
if (typeof properties !== 'undefined' && Object.defineProperties) {
|
|
Object.defineProperties(object, properties);
|
|
}
|
|
return object;
|
|
};
|
|
|
|
exports.inherits = function(ctor, superCtor) {
|
|
ctor.super_ = superCtor;
|
|
ctor.prototype = Object_create(superCtor.prototype, {
|
|
constructor: {
|
|
value: ctor,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
};
|
|
|
|
var formatRegExp = /%[sdj%]/g;
|
|
exports.format = function(f) {
|
|
if (typeof f !== 'string') {
|
|
var objects = [];
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
objects.push(exports.inspect(arguments[i]));
|
|
}
|
|
return objects.join(' ');
|
|
}
|
|
|
|
var i = 1;
|
|
var args = arguments;
|
|
var len = args.length;
|
|
var str = String(f).replace(formatRegExp, function(x) {
|
|
if (x === '%%') return '%';
|
|
if (i >= len) return x;
|
|
switch (x) {
|
|
case '%s': return String(args[i++]);
|
|
case '%d': return Number(args[i++]);
|
|
case '%j': return JSON.stringify(args[i++]);
|
|
default:
|
|
return x;
|
|
}
|
|
});
|
|
for(var x = args[i]; i < len; x = args[++i]){
|
|
if (x === null || typeof x !== 'object') {
|
|
str += ' ' + x;
|
|
} else {
|
|
str += ' ' + exports.inspect(x);
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
},{"events":4}],5:[function(require,module,exports){
|
|
exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) {
|
|
var e, m,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
nBits = -7,
|
|
i = isBE ? 0 : (nBytes - 1),
|
|
d = isBE ? 1 : -1,
|
|
s = buffer[offset + i];
|
|
|
|
i += d;
|
|
|
|
e = s & ((1 << (-nBits)) - 1);
|
|
s >>= (-nBits);
|
|
nBits += eLen;
|
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
m = e & ((1 << (-nBits)) - 1);
|
|
e >>= (-nBits);
|
|
nBits += mLen;
|
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
if (e === 0) {
|
|
e = 1 - eBias;
|
|
} else if (e === eMax) {
|
|
return m ? NaN : ((s ? -1 : 1) * Infinity);
|
|
} else {
|
|
m = m + Math.pow(2, mLen);
|
|
e = e - eBias;
|
|
}
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
|
|
};
|
|
|
|
exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) {
|
|
var e, m, c,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
|
|
i = isBE ? (nBytes - 1) : 0,
|
|
d = isBE ? -1 : 1,
|
|
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
|
|
|
|
value = Math.abs(value);
|
|
|
|
if (isNaN(value) || value === Infinity) {
|
|
m = isNaN(value) ? 1 : 0;
|
|
e = eMax;
|
|
} else {
|
|
e = Math.floor(Math.log(value) / Math.LN2);
|
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
|
e--;
|
|
c *= 2;
|
|
}
|
|
if (e + eBias >= 1) {
|
|
value += rt / c;
|
|
} else {
|
|
value += rt * Math.pow(2, 1 - eBias);
|
|
}
|
|
if (value * c >= 2) {
|
|
e++;
|
|
c /= 2;
|
|
}
|
|
|
|
if (e + eBias >= eMax) {
|
|
m = 0;
|
|
e = eMax;
|
|
} else if (e + eBias >= 1) {
|
|
m = (value * c - 1) * Math.pow(2, mLen);
|
|
e = e + eBias;
|
|
} else {
|
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
|
e = 0;
|
|
}
|
|
}
|
|
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
|
|
|
|
e = (e << mLen) | m;
|
|
eLen += mLen;
|
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
|
|
|
|
buffer[offset + i - d] |= s * 128;
|
|
};
|
|
|
|
},{}],6:[function(require,module,exports){
|
|
// shim for using process in browser
|
|
|
|
var process = module.exports = {};
|
|
|
|
process.nextTick = (function () {
|
|
var canSetImmediate = typeof window !== 'undefined'
|
|
&& window.setImmediate;
|
|
var canPost = typeof window !== 'undefined'
|
|
&& window.postMessage && window.addEventListener
|
|
;
|
|
|
|
if (canSetImmediate) {
|
|
return function (f) { return window.setImmediate(f) };
|
|
}
|
|
|
|
if (canPost) {
|
|
var queue = [];
|
|
window.addEventListener('message', function (ev) {
|
|
if (ev.source === window && ev.data === 'process-tick') {
|
|
ev.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
return function nextTick(fn) {
|
|
queue.push(fn);
|
|
window.postMessage('process-tick', '*');
|
|
};
|
|
}
|
|
|
|
return function nextTick(fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
})();
|
|
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
}
|
|
|
|
// TODO(shtylman)
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
|
|
},{}],4:[function(require,module,exports){
|
|
(function(process){if (!process.EventEmitter) process.EventEmitter = function () {};
|
|
|
|
var EventEmitter = exports.EventEmitter = process.EventEmitter;
|
|
var isArray = typeof Array.isArray === 'function'
|
|
? Array.isArray
|
|
: function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]'
|
|
}
|
|
;
|
|
function indexOf (xs, x) {
|
|
if (xs.indexOf) return xs.indexOf(x);
|
|
for (var i = 0; i < xs.length; i++) {
|
|
if (x === xs[i]) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// By default EventEmitters will print a warning if more than
|
|
// 10 listeners are added to it. This is a useful default which
|
|
// helps finding memory leaks.
|
|
//
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
// that to be increased. Set to zero for unlimited.
|
|
var defaultMaxListeners = 10;
|
|
EventEmitter.prototype.setMaxListeners = function(n) {
|
|
if (!this._events) this._events = {};
|
|
this._events.maxListeners = n;
|
|
};
|
|
|
|
|
|
EventEmitter.prototype.emit = function(type) {
|
|
// If there is no 'error' event listener then throw.
|
|
if (type === 'error') {
|
|
if (!this._events || !this._events.error ||
|
|
(isArray(this._events.error) && !this._events.error.length))
|
|
{
|
|
if (arguments[1] instanceof Error) {
|
|
throw arguments[1]; // Unhandled 'error' event
|
|
} else {
|
|
throw new Error("Uncaught, unspecified 'error' event.");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!this._events) return false;
|
|
var handler = this._events[type];
|
|
if (!handler) return false;
|
|
|
|
if (typeof handler == 'function') {
|
|
switch (arguments.length) {
|
|
// fast cases
|
|
case 1:
|
|
handler.call(this);
|
|
break;
|
|
case 2:
|
|
handler.call(this, arguments[1]);
|
|
break;
|
|
case 3:
|
|
handler.call(this, arguments[1], arguments[2]);
|
|
break;
|
|
// slower
|
|
default:
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
handler.apply(this, args);
|
|
}
|
|
return true;
|
|
|
|
} else if (isArray(handler)) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
var listeners = handler.slice();
|
|
for (var i = 0, l = listeners.length; i < l; i++) {
|
|
listeners[i].apply(this, args);
|
|
}
|
|
return true;
|
|
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// EventEmitter is defined in src/node_events.cc
|
|
// EventEmitter.prototype.emit() is also defined there.
|
|
EventEmitter.prototype.addListener = function(type, listener) {
|
|
if ('function' !== typeof listener) {
|
|
throw new Error('addListener only takes instances of Function');
|
|
}
|
|
|
|
if (!this._events) this._events = {};
|
|
|
|
// To avoid recursion in the case that type == "newListeners"! Before
|
|
// adding it to the listeners, first emit "newListeners".
|
|
this.emit('newListener', type, listener);
|
|
|
|
if (!this._events[type]) {
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
this._events[type] = listener;
|
|
} else if (isArray(this._events[type])) {
|
|
|
|
// Check for listener leak
|
|
if (!this._events[type].warned) {
|
|
var m;
|
|
if (this._events.maxListeners !== undefined) {
|
|
m = this._events.maxListeners;
|
|
} else {
|
|
m = defaultMaxListeners;
|
|
}
|
|
|
|
if (m && m > 0 && this._events[type].length > m) {
|
|
this._events[type].warned = true;
|
|
console.error('(node) warning: possible EventEmitter memory ' +
|
|
'leak detected. %d listeners added. ' +
|
|
'Use emitter.setMaxListeners() to increase limit.',
|
|
this._events[type].length);
|
|
console.trace();
|
|
}
|
|
}
|
|
|
|
// If we've already got an array, just append.
|
|
this._events[type].push(listener);
|
|
} else {
|
|
// Adding the second element, need to change to array.
|
|
this._events[type] = [this._events[type], listener];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
|
|
|
EventEmitter.prototype.once = function(type, listener) {
|
|
var self = this;
|
|
self.on(type, function g() {
|
|
self.removeListener(type, g);
|
|
listener.apply(this, arguments);
|
|
});
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeListener = function(type, listener) {
|
|
if ('function' !== typeof listener) {
|
|
throw new Error('removeListener only takes instances of Function');
|
|
}
|
|
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (!this._events || !this._events[type]) return this;
|
|
|
|
var list = this._events[type];
|
|
|
|
if (isArray(list)) {
|
|
var i = indexOf(list, listener);
|
|
if (i < 0) return this;
|
|
list.splice(i, 1);
|
|
if (list.length == 0)
|
|
delete this._events[type];
|
|
} else if (this._events[type] === listener) {
|
|
delete this._events[type];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) {
|
|
if (arguments.length === 0) {
|
|
this._events = {};
|
|
return this;
|
|
}
|
|
|
|
// does not use listeners(), so no side effect of creating _events[type]
|
|
if (type && this._events && this._events[type]) this._events[type] = null;
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.listeners = function(type) {
|
|
if (!this._events) this._events = {};
|
|
if (!this._events[type]) this._events[type] = [];
|
|
if (!isArray(this._events[type])) {
|
|
this._events[type] = [this._events[type]];
|
|
}
|
|
return this._events[type];
|
|
};
|
|
|
|
})(require("__browserify_process"))
|
|
},{"__browserify_process":6}],"buffer-browserify":[function(require,module,exports){
|
|
module.exports=require('q9TxCC');
|
|
},{}],"q9TxCC":[function(require,module,exports){
|
|
function SlowBuffer (size) {
|
|
this.length = size;
|
|
};
|
|
|
|
var assert = require('assert');
|
|
|
|
exports.INSPECT_MAX_BYTES = 50;
|
|
|
|
|
|
function toHex(n) {
|
|
if (n < 16) return '0' + n.toString(16);
|
|
return n.toString(16);
|
|
}
|
|
|
|
function utf8ToBytes(str) {
|
|
var byteArray = [];
|
|
for (var i = 0; i < str.length; i++)
|
|
if (str.charCodeAt(i) <= 0x7F)
|
|
byteArray.push(str.charCodeAt(i));
|
|
else {
|
|
var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
|
|
for (var j = 0; j < h.length; j++)
|
|
byteArray.push(parseInt(h[j], 16));
|
|
}
|
|
|
|
return byteArray;
|
|
}
|
|
|
|
function asciiToBytes(str) {
|
|
var byteArray = []
|
|
for (var i = 0; i < str.length; i++ )
|
|
// Node's code seems to be doing this and not & 0x7F..
|
|
byteArray.push( str.charCodeAt(i) & 0xFF );
|
|
|
|
return byteArray;
|
|
}
|
|
|
|
function base64ToBytes(str) {
|
|
return require("base64-js").toByteArray(str);
|
|
}
|
|
|
|
SlowBuffer.byteLength = function (str, encoding) {
|
|
switch (encoding || "utf8") {
|
|
case 'hex':
|
|
return str.length / 2;
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return utf8ToBytes(str).length;
|
|
|
|
case 'ascii':
|
|
case 'binary':
|
|
return str.length;
|
|
|
|
case 'base64':
|
|
return base64ToBytes(str).length;
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
function blitBuffer(src, dst, offset, length) {
|
|
var pos, i = 0;
|
|
while (i < length) {
|
|
if ((i+offset >= dst.length) || (i >= src.length))
|
|
break;
|
|
|
|
dst[i + offset] = src[i];
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
SlowBuffer.prototype.utf8Write = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return SlowBuffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length);
|
|
};
|
|
|
|
SlowBuffer.prototype.asciiWrite = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return SlowBuffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length);
|
|
};
|
|
|
|
SlowBuffer.prototype.binaryWrite = SlowBuffer.prototype.asciiWrite;
|
|
|
|
SlowBuffer.prototype.base64Write = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length);
|
|
};
|
|
|
|
SlowBuffer.prototype.base64Slice = function (start, end) {
|
|
var bytes = Array.prototype.slice.apply(this, arguments)
|
|
return require("base64-js").fromByteArray(bytes);
|
|
}
|
|
|
|
function decodeUtf8Char(str) {
|
|
try {
|
|
return decodeURIComponent(str);
|
|
} catch (err) {
|
|
return String.fromCharCode(0xFFFD); // UTF 8 invalid char
|
|
}
|
|
}
|
|
|
|
SlowBuffer.prototype.utf8Slice = function () {
|
|
var bytes = Array.prototype.slice.apply(this, arguments);
|
|
var res = "";
|
|
var tmp = "";
|
|
var i = 0;
|
|
while (i < bytes.length) {
|
|
if (bytes[i] <= 0x7F) {
|
|
res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]);
|
|
tmp = "";
|
|
} else
|
|
tmp += "%" + bytes[i].toString(16);
|
|
|
|
i++;
|
|
}
|
|
|
|
return res + decodeUtf8Char(tmp);
|
|
}
|
|
|
|
SlowBuffer.prototype.asciiSlice = function () {
|
|
var bytes = Array.prototype.slice.apply(this, arguments);
|
|
var ret = "";
|
|
for (var i = 0; i < bytes.length; i++)
|
|
ret += String.fromCharCode(bytes[i]);
|
|
return ret;
|
|
}
|
|
|
|
SlowBuffer.prototype.binarySlice = SlowBuffer.prototype.asciiSlice;
|
|
|
|
SlowBuffer.prototype.inspect = function() {
|
|
var out = [],
|
|
len = this.length;
|
|
for (var i = 0; i < len; i++) {
|
|
out[i] = toHex(this[i]);
|
|
if (i == exports.INSPECT_MAX_BYTES) {
|
|
out[i + 1] = '...';
|
|
break;
|
|
}
|
|
}
|
|
return '<SlowBuffer ' + out.join(' ') + '>';
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.hexSlice = function(start, end) {
|
|
var len = this.length;
|
|
|
|
if (!start || start < 0) start = 0;
|
|
if (!end || end < 0 || end > len) end = len;
|
|
|
|
var out = '';
|
|
for (var i = start; i < end; i++) {
|
|
out += toHex(this[i]);
|
|
}
|
|
return out;
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.toString = function(encoding, start, end) {
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
start = +start || 0;
|
|
if (typeof end == 'undefined') end = this.length;
|
|
|
|
// Fastpath empty strings
|
|
if (+end == start) {
|
|
return '';
|
|
}
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.hexSlice(start, end);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.utf8Slice(start, end);
|
|
|
|
case 'ascii':
|
|
return this.asciiSlice(start, end);
|
|
|
|
case 'binary':
|
|
return this.binarySlice(start, end);
|
|
|
|
case 'base64':
|
|
return this.base64Slice(start, end);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.ucs2Slice(start, end);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.hexWrite = function(string, offset, length) {
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
|
|
// must be an even number of digits
|
|
var strLen = string.length;
|
|
if (strLen % 2) {
|
|
throw new Error('Invalid hex string');
|
|
}
|
|
if (length > strLen / 2) {
|
|
length = strLen / 2;
|
|
}
|
|
for (var i = 0; i < length; i++) {
|
|
var byte = parseInt(string.substr(i * 2, 2), 16);
|
|
if (isNaN(byte)) throw new Error('Invalid hex string');
|
|
this[offset + i] = byte;
|
|
}
|
|
SlowBuffer._charsWritten = i * 2;
|
|
return i;
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.write = function(string, offset, length, encoding) {
|
|
// Support both (string, offset, length, encoding)
|
|
// and the legacy (string, encoding, offset, length)
|
|
if (isFinite(offset)) {
|
|
if (!isFinite(length)) {
|
|
encoding = length;
|
|
length = undefined;
|
|
}
|
|
} else { // legacy
|
|
var swap = encoding;
|
|
encoding = offset;
|
|
offset = length;
|
|
length = swap;
|
|
}
|
|
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.hexWrite(string, offset, length);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.utf8Write(string, offset, length);
|
|
|
|
case 'ascii':
|
|
return this.asciiWrite(string, offset, length);
|
|
|
|
case 'binary':
|
|
return this.binaryWrite(string, offset, length);
|
|
|
|
case 'base64':
|
|
return this.base64Write(string, offset, length);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.ucs2Write(string, offset, length);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
// slice(start, end)
|
|
SlowBuffer.prototype.slice = function(start, end) {
|
|
if (end === undefined) end = this.length;
|
|
|
|
if (end > this.length) {
|
|
throw new Error('oob');
|
|
}
|
|
if (start > end) {
|
|
throw new Error('oob');
|
|
}
|
|
|
|
return new Buffer(this, end - start, +start);
|
|
};
|
|
|
|
SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) {
|
|
var temp = [];
|
|
for (var i=sourcestart; i<sourceend; i++) {
|
|
assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!");
|
|
temp.push(this[i]);
|
|
}
|
|
|
|
for (var i=targetstart; i<targetstart+temp.length; i++) {
|
|
target[i] = temp[i-targetstart];
|
|
}
|
|
};
|
|
|
|
SlowBuffer.prototype.fill = function(value, start, end) {
|
|
if (end > this.length) {
|
|
throw new Error('oob');
|
|
}
|
|
if (start > end) {
|
|
throw new Error('oob');
|
|
}
|
|
|
|
for (var i = start; i < end; i++) {
|
|
this[i] = value;
|
|
}
|
|
}
|
|
|
|
function coerce(length) {
|
|
// Coerce length to a number (possibly NaN), round up
|
|
// in case it's fractional (e.g. 123.456) then do a
|
|
// double negate to coerce a NaN to 0. Easy, right?
|
|
length = ~~Math.ceil(+length);
|
|
return length < 0 ? 0 : length;
|
|
}
|
|
|
|
|
|
// Buffer
|
|
|
|
function Buffer(subject, encoding, offset) {
|
|
if (!(this instanceof Buffer)) {
|
|
return new Buffer(subject, encoding, offset);
|
|
}
|
|
|
|
var type;
|
|
|
|
// Are we slicing?
|
|
if (typeof offset === 'number') {
|
|
this.length = coerce(encoding);
|
|
this.parent = subject;
|
|
this.offset = offset;
|
|
} else {
|
|
// Find the length
|
|
switch (type = typeof subject) {
|
|
case 'number':
|
|
this.length = coerce(subject);
|
|
break;
|
|
|
|
case 'string':
|
|
this.length = Buffer.byteLength(subject, encoding);
|
|
break;
|
|
|
|
case 'object': // Assume object is an array
|
|
this.length = coerce(subject.length);
|
|
break;
|
|
|
|
default:
|
|
throw new Error('First argument needs to be a number, ' +
|
|
'array or string.');
|
|
}
|
|
|
|
if (this.length > Buffer.poolSize) {
|
|
// Big buffer, just alloc one.
|
|
this.parent = new SlowBuffer(this.length);
|
|
this.offset = 0;
|
|
|
|
} else {
|
|
// Small buffer.
|
|
if (!pool || pool.length - pool.used < this.length) allocPool();
|
|
this.parent = pool;
|
|
this.offset = pool.used;
|
|
pool.used += this.length;
|
|
}
|
|
|
|
// Treat array-ish objects as a byte array.
|
|
if (isArrayIsh(subject)) {
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (subject instanceof Buffer) {
|
|
this.parent[i + this.offset] = subject.readUInt8(i);
|
|
}
|
|
else {
|
|
this.parent[i + this.offset] = subject[i];
|
|
}
|
|
}
|
|
} else if (type == 'string') {
|
|
// We are a string
|
|
this.length = this.write(subject, 0, encoding);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function isArrayIsh(subject) {
|
|
return Array.isArray(subject) || Buffer.isBuffer(subject) ||
|
|
subject && typeof subject === 'object' &&
|
|
typeof subject.length === 'number';
|
|
}
|
|
|
|
exports.SlowBuffer = SlowBuffer;
|
|
exports.Buffer = Buffer;
|
|
|
|
Buffer.poolSize = 8 * 1024;
|
|
var pool;
|
|
|
|
function allocPool() {
|
|
pool = new SlowBuffer(Buffer.poolSize);
|
|
pool.used = 0;
|
|
}
|
|
|
|
|
|
// Static methods
|
|
Buffer.isBuffer = function isBuffer(b) {
|
|
return b instanceof Buffer || b instanceof SlowBuffer;
|
|
};
|
|
|
|
Buffer.concat = function (list, totalLength) {
|
|
if (!Array.isArray(list)) {
|
|
throw new Error("Usage: Buffer.concat(list, [totalLength])\n \
|
|
list should be an Array.");
|
|
}
|
|
|
|
if (list.length === 0) {
|
|
return new Buffer(0);
|
|
} else if (list.length === 1) {
|
|
return list[0];
|
|
}
|
|
|
|
if (typeof totalLength !== 'number') {
|
|
totalLength = 0;
|
|
for (var i = 0; i < list.length; i++) {
|
|
var buf = list[i];
|
|
totalLength += buf.length;
|
|
}
|
|
}
|
|
|
|
var buffer = new Buffer(totalLength);
|
|
var pos = 0;
|
|
for (var i = 0; i < list.length; i++) {
|
|
var buf = list[i];
|
|
buf.copy(buffer, pos);
|
|
pos += buf.length;
|
|
}
|
|
return buffer;
|
|
};
|
|
|
|
// Inspect
|
|
Buffer.prototype.inspect = function inspect() {
|
|
var out = [],
|
|
len = this.length;
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
out[i] = toHex(this.parent[i + this.offset]);
|
|
if (i == exports.INSPECT_MAX_BYTES) {
|
|
out[i + 1] = '...';
|
|
break;
|
|
}
|
|
}
|
|
|
|
return '<Buffer ' + out.join(' ') + '>';
|
|
};
|
|
|
|
|
|
Buffer.prototype.get = function get(i) {
|
|
if (i < 0 || i >= this.length) throw new Error('oob');
|
|
return this.parent[this.offset + i];
|
|
};
|
|
|
|
|
|
Buffer.prototype.set = function set(i, v) {
|
|
if (i < 0 || i >= this.length) throw new Error('oob');
|
|
return this.parent[this.offset + i] = v;
|
|
};
|
|
|
|
|
|
// write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8')
|
|
Buffer.prototype.write = function(string, offset, length, encoding) {
|
|
// Support both (string, offset, length, encoding)
|
|
// and the legacy (string, encoding, offset, length)
|
|
if (isFinite(offset)) {
|
|
if (!isFinite(length)) {
|
|
encoding = length;
|
|
length = undefined;
|
|
}
|
|
} else { // legacy
|
|
var swap = encoding;
|
|
encoding = offset;
|
|
offset = length;
|
|
length = swap;
|
|
}
|
|
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
var ret;
|
|
switch (encoding) {
|
|
case 'hex':
|
|
ret = this.parent.hexWrite(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
ret = this.parent.utf8Write(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'ascii':
|
|
ret = this.parent.asciiWrite(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'binary':
|
|
ret = this.parent.binaryWrite(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'base64':
|
|
// Warning: maxLength not taken into account in base64Write
|
|
ret = this.parent.base64Write(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
ret = this.parent.ucs2Write(string, this.offset + offset, length);
|
|
break;
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
|
|
Buffer._charsWritten = SlowBuffer._charsWritten;
|
|
|
|
return ret;
|
|
};
|
|
|
|
|
|
// toString(encoding, start=0, end=buffer.length)
|
|
Buffer.prototype.toString = function(encoding, start, end) {
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
if (typeof start == 'undefined' || start < 0) {
|
|
start = 0;
|
|
} else if (start > this.length) {
|
|
start = this.length;
|
|
}
|
|
|
|
if (typeof end == 'undefined' || end > this.length) {
|
|
end = this.length;
|
|
} else if (end < 0) {
|
|
end = 0;
|
|
}
|
|
|
|
start = start + this.offset;
|
|
end = end + this.offset;
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.parent.hexSlice(start, end);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.parent.utf8Slice(start, end);
|
|
|
|
case 'ascii':
|
|
return this.parent.asciiSlice(start, end);
|
|
|
|
case 'binary':
|
|
return this.parent.binarySlice(start, end);
|
|
|
|
case 'base64':
|
|
return this.parent.base64Slice(start, end);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.parent.ucs2Slice(start, end);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
// byteLength
|
|
Buffer.byteLength = SlowBuffer.byteLength;
|
|
|
|
|
|
// fill(value, start=0, end=buffer.length)
|
|
Buffer.prototype.fill = function fill(value, start, end) {
|
|
value || (value = 0);
|
|
start || (start = 0);
|
|
end || (end = this.length);
|
|
|
|
if (typeof value === 'string') {
|
|
value = value.charCodeAt(0);
|
|
}
|
|
if (!(typeof value === 'number') || isNaN(value)) {
|
|
throw new Error('value is not a number');
|
|
}
|
|
|
|
if (end < start) throw new Error('end < start');
|
|
|
|
// Fill 0 bytes; we're done
|
|
if (end === start) return 0;
|
|
if (this.length == 0) return 0;
|
|
|
|
if (start < 0 || start >= this.length) {
|
|
throw new Error('start out of bounds');
|
|
}
|
|
|
|
if (end < 0 || end > this.length) {
|
|
throw new Error('end out of bounds');
|
|
}
|
|
|
|
return this.parent.fill(value,
|
|
start + this.offset,
|
|
end + this.offset);
|
|
};
|
|
|
|
|
|
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
|
Buffer.prototype.copy = function(target, target_start, start, end) {
|
|
var source = this;
|
|
start || (start = 0);
|
|
end || (end = this.length);
|
|
target_start || (target_start = 0);
|
|
|
|
if (end < start) throw new Error('sourceEnd < sourceStart');
|
|
|
|
// Copy 0 bytes; we're done
|
|
if (end === start) return 0;
|
|
if (target.length == 0 || source.length == 0) return 0;
|
|
|
|
if (target_start < 0 || target_start >= target.length) {
|
|
throw new Error('targetStart out of bounds');
|
|
}
|
|
|
|
if (start < 0 || start >= source.length) {
|
|
throw new Error('sourceStart out of bounds');
|
|
}
|
|
|
|
if (end < 0 || end > source.length) {
|
|
throw new Error('sourceEnd out of bounds');
|
|
}
|
|
|
|
// Are we oob?
|
|
if (end > this.length) {
|
|
end = this.length;
|
|
}
|
|
|
|
if (target.length - target_start < end - start) {
|
|
end = target.length - target_start + start;
|
|
}
|
|
|
|
return this.parent.copy(target.parent,
|
|
target_start + target.offset,
|
|
start + this.offset,
|
|
end + this.offset);
|
|
};
|
|
|
|
|
|
// slice(start, end)
|
|
Buffer.prototype.slice = function(start, end) {
|
|
if (end === undefined) end = this.length;
|
|
if (end > this.length) throw new Error('oob');
|
|
if (start > end) throw new Error('oob');
|
|
|
|
return new Buffer(this.parent, end - start, +start + this.offset);
|
|
};
|
|
|
|
|
|
// Legacy methods for backwards compatibility.
|
|
|
|
Buffer.prototype.utf8Slice = function(start, end) {
|
|
return this.toString('utf8', start, end);
|
|
};
|
|
|
|
Buffer.prototype.binarySlice = function(start, end) {
|
|
return this.toString('binary', start, end);
|
|
};
|
|
|
|
Buffer.prototype.asciiSlice = function(start, end) {
|
|
return this.toString('ascii', start, end);
|
|
};
|
|
|
|
Buffer.prototype.utf8Write = function(string, offset) {
|
|
return this.write(string, offset, 'utf8');
|
|
};
|
|
|
|
Buffer.prototype.binaryWrite = function(string, offset) {
|
|
return this.write(string, offset, 'binary');
|
|
};
|
|
|
|
Buffer.prototype.asciiWrite = function(string, offset) {
|
|
return this.write(string, offset, 'ascii');
|
|
};
|
|
|
|
Buffer.prototype.readUInt8 = function(offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return;
|
|
|
|
return buffer.parent[buffer.offset + offset];
|
|
};
|
|
|
|
function readUInt16(buffer, offset, isBigEndian, noAssert) {
|
|
var val = 0;
|
|
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return 0;
|
|
|
|
if (isBigEndian) {
|
|
val = buffer.parent[buffer.offset + offset] << 8;
|
|
if (offset + 1 < buffer.length) {
|
|
val |= buffer.parent[buffer.offset + offset + 1];
|
|
}
|
|
} else {
|
|
val = buffer.parent[buffer.offset + offset];
|
|
if (offset + 1 < buffer.length) {
|
|
val |= buffer.parent[buffer.offset + offset + 1] << 8;
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Buffer.prototype.readUInt16LE = function(offset, noAssert) {
|
|
return readUInt16(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readUInt16BE = function(offset, noAssert) {
|
|
return readUInt16(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readUInt32(buffer, offset, isBigEndian, noAssert) {
|
|
var val = 0;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return 0;
|
|
|
|
if (isBigEndian) {
|
|
if (offset + 1 < buffer.length)
|
|
val = buffer.parent[buffer.offset + offset + 1] << 16;
|
|
if (offset + 2 < buffer.length)
|
|
val |= buffer.parent[buffer.offset + offset + 2] << 8;
|
|
if (offset + 3 < buffer.length)
|
|
val |= buffer.parent[buffer.offset + offset + 3];
|
|
val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0);
|
|
} else {
|
|
if (offset + 2 < buffer.length)
|
|
val = buffer.parent[buffer.offset + offset + 2] << 16;
|
|
if (offset + 1 < buffer.length)
|
|
val |= buffer.parent[buffer.offset + offset + 1] << 8;
|
|
val |= buffer.parent[buffer.offset + offset];
|
|
if (offset + 3 < buffer.length)
|
|
val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Buffer.prototype.readUInt32LE = function(offset, noAssert) {
|
|
return readUInt32(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readUInt32BE = function(offset, noAssert) {
|
|
return readUInt32(this, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* Signed integer types, yay team! A reminder on how two's complement actually
|
|
* works. The first bit is the signed bit, i.e. tells us whether or not the
|
|
* number should be positive or negative. If the two's complement value is
|
|
* positive, then we're done, as it's equivalent to the unsigned representation.
|
|
*
|
|
* Now if the number is positive, you're pretty much done, you can just leverage
|
|
* the unsigned translations and return those. Unfortunately, negative numbers
|
|
* aren't quite that straightforward.
|
|
*
|
|
* At first glance, one might be inclined to use the traditional formula to
|
|
* translate binary numbers between the positive and negative values in two's
|
|
* complement. (Though it doesn't quite work for the most negative value)
|
|
* Mainly:
|
|
* - invert all the bits
|
|
* - add one to the result
|
|
*
|
|
* Of course, this doesn't quite work in Javascript. Take for example the value
|
|
* of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
|
|
* course, Javascript will do the following:
|
|
*
|
|
* > ~0xff80
|
|
* -65409
|
|
*
|
|
* Whoh there, Javascript, that's not quite right. But wait, according to
|
|
* Javascript that's perfectly correct. When Javascript ends up seeing the
|
|
* constant 0xff80, it has no notion that it is actually a signed number. It
|
|
* assumes that we've input the unsigned value 0xff80. Thus, when it does the
|
|
* binary negation, it casts it into a signed value, (positive 0xff80). Then
|
|
* when you perform binary negation on that, it turns it into a negative number.
|
|
*
|
|
* Instead, we're going to have to use the following general formula, that works
|
|
* in a rather Javascript friendly way. I'm glad we don't support this kind of
|
|
* weird numbering scheme in the kernel.
|
|
*
|
|
* (BIT-MAX - (unsigned)val + 1) * -1
|
|
*
|
|
* The astute observer, may think that this doesn't make sense for 8-bit numbers
|
|
* (really it isn't necessary for them). However, when you get 16-bit numbers,
|
|
* you do. Let's go back to our prior example and see how this will look:
|
|
*
|
|
* (0xffff - 0xff80 + 1) * -1
|
|
* (0x007f + 1) * -1
|
|
* (0x0080) * -1
|
|
*/
|
|
Buffer.prototype.readInt8 = function(offset, noAssert) {
|
|
var buffer = this;
|
|
var neg;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (offset >= buffer.length) return;
|
|
|
|
neg = buffer.parent[buffer.offset + offset] & 0x80;
|
|
if (!neg) {
|
|
return (buffer.parent[buffer.offset + offset]);
|
|
}
|
|
|
|
return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1);
|
|
};
|
|
|
|
function readInt16(buffer, offset, isBigEndian, noAssert) {
|
|
var neg, val;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
val = readUInt16(buffer, offset, isBigEndian, noAssert);
|
|
neg = val & 0x8000;
|
|
if (!neg) {
|
|
return val;
|
|
}
|
|
|
|
return (0xffff - val + 1) * -1;
|
|
}
|
|
|
|
Buffer.prototype.readInt16LE = function(offset, noAssert) {
|
|
return readInt16(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readInt16BE = function(offset, noAssert) {
|
|
return readInt16(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readInt32(buffer, offset, isBigEndian, noAssert) {
|
|
var neg, val;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
val = readUInt32(buffer, offset, isBigEndian, noAssert);
|
|
neg = val & 0x80000000;
|
|
if (!neg) {
|
|
return (val);
|
|
}
|
|
|
|
return (0xffffffff - val + 1) * -1;
|
|
}
|
|
|
|
Buffer.prototype.readInt32LE = function(offset, noAssert) {
|
|
return readInt32(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readInt32BE = function(offset, noAssert) {
|
|
return readInt32(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readFloat(buffer, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
|
|
23, 4);
|
|
}
|
|
|
|
Buffer.prototype.readFloatLE = function(offset, noAssert) {
|
|
return readFloat(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readFloatBE = function(offset, noAssert) {
|
|
return readFloat(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readDouble(buffer, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset + 7 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
|
|
52, 8);
|
|
}
|
|
|
|
Buffer.prototype.readDoubleLE = function(offset, noAssert) {
|
|
return readDouble(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readDoubleBE = function(offset, noAssert) {
|
|
return readDouble(this, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* We have to make sure that the value is a valid integer. This means that it is
|
|
* non-negative. It has no fractional component and that it does not exceed the
|
|
* maximum allowed value.
|
|
*
|
|
* value The number to check for validity
|
|
*
|
|
* max The maximum value
|
|
*/
|
|
function verifuint(value, max) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value >= 0,
|
|
'specified a negative value for writing an unsigned value');
|
|
|
|
assert.ok(value <= max, 'value is larger than maximum value for type');
|
|
|
|
assert.ok(Math.floor(value) === value, 'value has a fractional component');
|
|
}
|
|
|
|
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xff);
|
|
}
|
|
|
|
if (offset < buffer.length) {
|
|
buffer.parent[buffer.offset + offset] = value;
|
|
}
|
|
};
|
|
|
|
function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xffff);
|
|
}
|
|
|
|
for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) {
|
|
buffer.parent[buffer.offset + offset + i] =
|
|
(value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>>
|
|
(isBigEndian ? 1 - i : i) * 8;
|
|
}
|
|
|
|
}
|
|
|
|
Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
|
|
writeUInt16(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
|
|
writeUInt16(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xffffffff);
|
|
}
|
|
|
|
for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) {
|
|
buffer.parent[buffer.offset + offset + i] =
|
|
(value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff;
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
|
|
writeUInt32(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
|
|
writeUInt32(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* We now move onto our friends in the signed number category. Unlike unsigned
|
|
* numbers, we're going to have to worry a bit more about how we put values into
|
|
* arrays. Since we are only worrying about signed 32-bit values, we're in
|
|
* slightly better shape. Unfortunately, we really can't do our favorite binary
|
|
* & in this system. It really seems to do the wrong thing. For example:
|
|
*
|
|
* > -32 & 0xff
|
|
* 224
|
|
*
|
|
* What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
|
|
* this aren't treated as a signed number. Ultimately a bad thing.
|
|
*
|
|
* What we're going to want to do is basically create the unsigned equivalent of
|
|
* our representation and pass that off to the wuint* functions. To do that
|
|
* we're going to do the following:
|
|
*
|
|
* - if the value is positive
|
|
* we can pass it directly off to the equivalent wuint
|
|
* - if the value is negative
|
|
* we do the following computation:
|
|
* mb + val + 1, where
|
|
* mb is the maximum unsigned value in that byte size
|
|
* val is the Javascript negative integer
|
|
*
|
|
*
|
|
* As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
|
|
* you do out the computations:
|
|
*
|
|
* 0xffff - 128 + 1
|
|
* 0xffff - 127
|
|
* 0xff80
|
|
*
|
|
* You can then encode this value as the signed version. This is really rather
|
|
* hacky, but it should work and get the job done which is our goal here.
|
|
*/
|
|
|
|
/*
|
|
* A series of checks to make sure we actually have a signed 32-bit number
|
|
*/
|
|
function verifsint(value, max, min) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value <= max, 'value larger than maximum allowed value');
|
|
|
|
assert.ok(value >= min, 'value smaller than minimum allowed value');
|
|
|
|
assert.ok(Math.floor(value) === value, 'value has a fractional component');
|
|
}
|
|
|
|
function verifIEEE754(value, max, min) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value <= max, 'value larger than maximum allowed value');
|
|
|
|
assert.ok(value >= min, 'value smaller than minimum allowed value');
|
|
}
|
|
|
|
Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7f, -0x80);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
buffer.writeUInt8(value, offset, noAssert);
|
|
} else {
|
|
buffer.writeUInt8(0xff + value + 1, offset, noAssert);
|
|
}
|
|
};
|
|
|
|
function writeInt16(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7fff, -0x8000);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
writeUInt16(buffer, value, offset, isBigEndian, noAssert);
|
|
} else {
|
|
writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert);
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
|
|
writeInt16(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
|
|
writeInt16(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeInt32(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7fffffff, -0x80000000);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
writeUInt32(buffer, value, offset, isBigEndian, noAssert);
|
|
} else {
|
|
writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert);
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
|
|
writeInt32(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
|
|
writeInt32(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeFloat(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38);
|
|
}
|
|
|
|
require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
|
|
23, 4);
|
|
}
|
|
|
|
Buffer.prototype.writeFloatLE = function(value, offset, noAssert) {
|
|
writeFloat(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
|
|
writeFloat(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeDouble(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 7 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308);
|
|
}
|
|
|
|
require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
|
|
52, 8);
|
|
}
|
|
|
|
Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
|
|
writeDouble(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
|
|
writeDouble(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8;
|
|
SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE;
|
|
SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE;
|
|
SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE;
|
|
SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE;
|
|
SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8;
|
|
SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE;
|
|
SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE;
|
|
SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE;
|
|
SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE;
|
|
SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE;
|
|
SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE;
|
|
SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE;
|
|
SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE;
|
|
SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8;
|
|
SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE;
|
|
SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE;
|
|
SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE;
|
|
SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE;
|
|
SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8;
|
|
SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE;
|
|
SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE;
|
|
SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE;
|
|
SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE;
|
|
SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE;
|
|
SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE;
|
|
SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE;
|
|
SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE;
|
|
|
|
},{"assert":1,"./buffer_ieee754":5,"base64-js":7}],7:[function(require,module,exports){
|
|
(function (exports) {
|
|
'use strict';
|
|
|
|
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
|
|
function b64ToByteArray(b64) {
|
|
var i, j, l, tmp, placeHolders, arr;
|
|
|
|
if (b64.length % 4 > 0) {
|
|
throw 'Invalid string. Length must be a multiple of 4';
|
|
}
|
|
|
|
// the number of equal signs (place holders)
|
|
// if there are two placeholders, than the two characters before it
|
|
// represent one byte
|
|
// if there is only one, then the three characters before it represent 2 bytes
|
|
// this is just a cheap hack to not do indexOf twice
|
|
placeHolders = b64.indexOf('=');
|
|
placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0;
|
|
|
|
// base64 is 4/3 + up to two characters of the original data
|
|
arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders);
|
|
|
|
// if there are placeholders, only get up to the last complete 4 chars
|
|
l = placeHolders > 0 ? b64.length - 4 : b64.length;
|
|
|
|
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
|
tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]);
|
|
arr.push((tmp & 0xFF0000) >> 16);
|
|
arr.push((tmp & 0xFF00) >> 8);
|
|
arr.push(tmp & 0xFF);
|
|
}
|
|
|
|
if (placeHolders === 2) {
|
|
tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4);
|
|
arr.push(tmp & 0xFF);
|
|
} else if (placeHolders === 1) {
|
|
tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2);
|
|
arr.push((tmp >> 8) & 0xFF);
|
|
arr.push(tmp & 0xFF);
|
|
}
|
|
|
|
return arr;
|
|
}
|
|
|
|
function uint8ToBase64(uint8) {
|
|
var i,
|
|
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
|
|
output = "",
|
|
temp, length;
|
|
|
|
function tripletToBase64 (num) {
|
|
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
|
|
};
|
|
|
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
|
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
|
|
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
|
|
output += tripletToBase64(temp);
|
|
}
|
|
|
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
|
switch (extraBytes) {
|
|
case 1:
|
|
temp = uint8[uint8.length - 1];
|
|
output += lookup[temp >> 2];
|
|
output += lookup[(temp << 4) & 0x3F];
|
|
output += '==';
|
|
break;
|
|
case 2:
|
|
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);
|
|
output += lookup[temp >> 10];
|
|
output += lookup[(temp >> 4) & 0x3F];
|
|
output += lookup[(temp << 2) & 0x3F];
|
|
output += '=';
|
|
break;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
module.exports.toByteArray = b64ToByteArray;
|
|
module.exports.fromByteArray = uint8ToBase64;
|
|
}());
|
|
|
|
},{}],8:[function(require,module,exports){
|
|
exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) {
|
|
var e, m,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
nBits = -7,
|
|
i = isBE ? 0 : (nBytes - 1),
|
|
d = isBE ? 1 : -1,
|
|
s = buffer[offset + i];
|
|
|
|
i += d;
|
|
|
|
e = s & ((1 << (-nBits)) - 1);
|
|
s >>= (-nBits);
|
|
nBits += eLen;
|
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
m = e & ((1 << (-nBits)) - 1);
|
|
e >>= (-nBits);
|
|
nBits += mLen;
|
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
if (e === 0) {
|
|
e = 1 - eBias;
|
|
} else if (e === eMax) {
|
|
return m ? NaN : ((s ? -1 : 1) * Infinity);
|
|
} else {
|
|
m = m + Math.pow(2, mLen);
|
|
e = e - eBias;
|
|
}
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
|
|
};
|
|
|
|
exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) {
|
|
var e, m, c,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
|
|
i = isBE ? (nBytes - 1) : 0,
|
|
d = isBE ? -1 : 1,
|
|
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
|
|
|
|
value = Math.abs(value);
|
|
|
|
if (isNaN(value) || value === Infinity) {
|
|
m = isNaN(value) ? 1 : 0;
|
|
e = eMax;
|
|
} else {
|
|
e = Math.floor(Math.log(value) / Math.LN2);
|
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
|
e--;
|
|
c *= 2;
|
|
}
|
|
if (e + eBias >= 1) {
|
|
value += rt / c;
|
|
} else {
|
|
value += rt * Math.pow(2, 1 - eBias);
|
|
}
|
|
if (value * c >= 2) {
|
|
e++;
|
|
c /= 2;
|
|
}
|
|
|
|
if (e + eBias >= eMax) {
|
|
m = 0;
|
|
e = eMax;
|
|
} else if (e + eBias >= 1) {
|
|
m = (value * c - 1) * Math.pow(2, mLen);
|
|
e = e + eBias;
|
|
} else {
|
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
|
e = 0;
|
|
}
|
|
}
|
|
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
|
|
|
|
e = (e << mLen) | m;
|
|
eLen += mLen;
|
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
|
|
|
|
buffer[offset + i - d] |= s * 128;
|
|
};
|
|
|
|
},{}],3:[function(require,module,exports){
|
|
function SlowBuffer (size) {
|
|
this.length = size;
|
|
};
|
|
|
|
var assert = require('assert');
|
|
|
|
exports.INSPECT_MAX_BYTES = 50;
|
|
|
|
|
|
function toHex(n) {
|
|
if (n < 16) return '0' + n.toString(16);
|
|
return n.toString(16);
|
|
}
|
|
|
|
function utf8ToBytes(str) {
|
|
var byteArray = [];
|
|
for (var i = 0; i < str.length; i++)
|
|
if (str.charCodeAt(i) <= 0x7F)
|
|
byteArray.push(str.charCodeAt(i));
|
|
else {
|
|
var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
|
|
for (var j = 0; j < h.length; j++)
|
|
byteArray.push(parseInt(h[j], 16));
|
|
}
|
|
|
|
return byteArray;
|
|
}
|
|
|
|
function asciiToBytes(str) {
|
|
var byteArray = []
|
|
for (var i = 0; i < str.length; i++ )
|
|
// Node's code seems to be doing this and not & 0x7F..
|
|
byteArray.push( str.charCodeAt(i) & 0xFF );
|
|
|
|
return byteArray;
|
|
}
|
|
|
|
function base64ToBytes(str) {
|
|
return require("base64-js").toByteArray(str);
|
|
}
|
|
|
|
SlowBuffer.byteLength = function (str, encoding) {
|
|
switch (encoding || "utf8") {
|
|
case 'hex':
|
|
return str.length / 2;
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return utf8ToBytes(str).length;
|
|
|
|
case 'ascii':
|
|
return str.length;
|
|
|
|
case 'base64':
|
|
return base64ToBytes(str).length;
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
function blitBuffer(src, dst, offset, length) {
|
|
var pos, i = 0;
|
|
while (i < length) {
|
|
if ((i+offset >= dst.length) || (i >= src.length))
|
|
break;
|
|
|
|
dst[i + offset] = src[i];
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
SlowBuffer.prototype.utf8Write = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return SlowBuffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length);
|
|
};
|
|
|
|
SlowBuffer.prototype.asciiWrite = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return SlowBuffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length);
|
|
};
|
|
|
|
SlowBuffer.prototype.base64Write = function (string, offset, length) {
|
|
var bytes, pos;
|
|
return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length);
|
|
};
|
|
|
|
SlowBuffer.prototype.base64Slice = function (start, end) {
|
|
var bytes = Array.prototype.slice.apply(this, arguments)
|
|
return require("base64-js").fromByteArray(bytes);
|
|
}
|
|
|
|
function decodeUtf8Char(str) {
|
|
try {
|
|
return decodeURIComponent(str);
|
|
} catch (err) {
|
|
return String.fromCharCode(0xFFFD); // UTF 8 invalid char
|
|
}
|
|
}
|
|
|
|
SlowBuffer.prototype.utf8Slice = function () {
|
|
var bytes = Array.prototype.slice.apply(this, arguments);
|
|
var res = "";
|
|
var tmp = "";
|
|
var i = 0;
|
|
while (i < bytes.length) {
|
|
if (bytes[i] <= 0x7F) {
|
|
res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]);
|
|
tmp = "";
|
|
} else
|
|
tmp += "%" + bytes[i].toString(16);
|
|
|
|
i++;
|
|
}
|
|
|
|
return res + decodeUtf8Char(tmp);
|
|
}
|
|
|
|
SlowBuffer.prototype.asciiSlice = function () {
|
|
var bytes = Array.prototype.slice.apply(this, arguments);
|
|
var ret = "";
|
|
for (var i = 0; i < bytes.length; i++)
|
|
ret += String.fromCharCode(bytes[i]);
|
|
return ret;
|
|
}
|
|
|
|
SlowBuffer.prototype.inspect = function() {
|
|
var out = [],
|
|
len = this.length;
|
|
for (var i = 0; i < len; i++) {
|
|
out[i] = toHex(this[i]);
|
|
if (i == exports.INSPECT_MAX_BYTES) {
|
|
out[i + 1] = '...';
|
|
break;
|
|
}
|
|
}
|
|
return '<SlowBuffer ' + out.join(' ') + '>';
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.hexSlice = function(start, end) {
|
|
var len = this.length;
|
|
|
|
if (!start || start < 0) start = 0;
|
|
if (!end || end < 0 || end > len) end = len;
|
|
|
|
var out = '';
|
|
for (var i = start; i < end; i++) {
|
|
out += toHex(this[i]);
|
|
}
|
|
return out;
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.toString = function(encoding, start, end) {
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
start = +start || 0;
|
|
if (typeof end == 'undefined') end = this.length;
|
|
|
|
// Fastpath empty strings
|
|
if (+end == start) {
|
|
return '';
|
|
}
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.hexSlice(start, end);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.utf8Slice(start, end);
|
|
|
|
case 'ascii':
|
|
return this.asciiSlice(start, end);
|
|
|
|
case 'binary':
|
|
return this.binarySlice(start, end);
|
|
|
|
case 'base64':
|
|
return this.base64Slice(start, end);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.ucs2Slice(start, end);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.hexWrite = function(string, offset, length) {
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
|
|
// must be an even number of digits
|
|
var strLen = string.length;
|
|
if (strLen % 2) {
|
|
throw new Error('Invalid hex string');
|
|
}
|
|
if (length > strLen / 2) {
|
|
length = strLen / 2;
|
|
}
|
|
for (var i = 0; i < length; i++) {
|
|
var byte = parseInt(string.substr(i * 2, 2), 16);
|
|
if (isNaN(byte)) throw new Error('Invalid hex string');
|
|
this[offset + i] = byte;
|
|
}
|
|
SlowBuffer._charsWritten = i * 2;
|
|
return i;
|
|
};
|
|
|
|
|
|
SlowBuffer.prototype.write = function(string, offset, length, encoding) {
|
|
// Support both (string, offset, length, encoding)
|
|
// and the legacy (string, encoding, offset, length)
|
|
if (isFinite(offset)) {
|
|
if (!isFinite(length)) {
|
|
encoding = length;
|
|
length = undefined;
|
|
}
|
|
} else { // legacy
|
|
var swap = encoding;
|
|
encoding = offset;
|
|
offset = length;
|
|
length = swap;
|
|
}
|
|
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.hexWrite(string, offset, length);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.utf8Write(string, offset, length);
|
|
|
|
case 'ascii':
|
|
return this.asciiWrite(string, offset, length);
|
|
|
|
case 'binary':
|
|
return this.binaryWrite(string, offset, length);
|
|
|
|
case 'base64':
|
|
return this.base64Write(string, offset, length);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.ucs2Write(string, offset, length);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
// slice(start, end)
|
|
SlowBuffer.prototype.slice = function(start, end) {
|
|
if (end === undefined) end = this.length;
|
|
|
|
if (end > this.length) {
|
|
throw new Error('oob');
|
|
}
|
|
if (start > end) {
|
|
throw new Error('oob');
|
|
}
|
|
|
|
return new Buffer(this, end - start, +start);
|
|
};
|
|
|
|
SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) {
|
|
var temp = [];
|
|
for (var i=sourcestart; i<sourceend; i++) {
|
|
assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!");
|
|
temp.push(this[i]);
|
|
}
|
|
|
|
for (var i=targetstart; i<targetstart+temp.length; i++) {
|
|
target[i] = temp[i-targetstart];
|
|
}
|
|
};
|
|
|
|
function coerce(length) {
|
|
// Coerce length to a number (possibly NaN), round up
|
|
// in case it's fractional (e.g. 123.456) then do a
|
|
// double negate to coerce a NaN to 0. Easy, right?
|
|
length = ~~Math.ceil(+length);
|
|
return length < 0 ? 0 : length;
|
|
}
|
|
|
|
|
|
// Buffer
|
|
|
|
function Buffer(subject, encoding, offset) {
|
|
if (!(this instanceof Buffer)) {
|
|
return new Buffer(subject, encoding, offset);
|
|
}
|
|
|
|
var type;
|
|
|
|
// Are we slicing?
|
|
if (typeof offset === 'number') {
|
|
this.length = coerce(encoding);
|
|
this.parent = subject;
|
|
this.offset = offset;
|
|
} else {
|
|
// Find the length
|
|
switch (type = typeof subject) {
|
|
case 'number':
|
|
this.length = coerce(subject);
|
|
break;
|
|
|
|
case 'string':
|
|
this.length = Buffer.byteLength(subject, encoding);
|
|
break;
|
|
|
|
case 'object': // Assume object is an array
|
|
this.length = coerce(subject.length);
|
|
break;
|
|
|
|
default:
|
|
throw new Error('First argument needs to be a number, ' +
|
|
'array or string.');
|
|
}
|
|
|
|
if (this.length > Buffer.poolSize) {
|
|
// Big buffer, just alloc one.
|
|
this.parent = new SlowBuffer(this.length);
|
|
this.offset = 0;
|
|
|
|
} else {
|
|
// Small buffer.
|
|
if (!pool || pool.length - pool.used < this.length) allocPool();
|
|
this.parent = pool;
|
|
this.offset = pool.used;
|
|
pool.used += this.length;
|
|
}
|
|
|
|
// Treat array-ish objects as a byte array.
|
|
if (isArrayIsh(subject)) {
|
|
for (var i = 0; i < this.length; i++) {
|
|
this.parent[i + this.offset] = subject[i];
|
|
}
|
|
} else if (type == 'string') {
|
|
// We are a string
|
|
this.length = this.write(subject, 0, encoding);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function isArrayIsh(subject) {
|
|
return Array.isArray(subject) || Buffer.isBuffer(subject) ||
|
|
subject && typeof subject === 'object' &&
|
|
typeof subject.length === 'number';
|
|
}
|
|
|
|
exports.SlowBuffer = SlowBuffer;
|
|
exports.Buffer = Buffer;
|
|
|
|
Buffer.poolSize = 8 * 1024;
|
|
var pool;
|
|
|
|
function allocPool() {
|
|
pool = new SlowBuffer(Buffer.poolSize);
|
|
pool.used = 0;
|
|
}
|
|
|
|
|
|
// Static methods
|
|
Buffer.isBuffer = function isBuffer(b) {
|
|
return b instanceof Buffer || b instanceof SlowBuffer;
|
|
};
|
|
|
|
Buffer.concat = function (list, totalLength) {
|
|
if (!Array.isArray(list)) {
|
|
throw new Error("Usage: Buffer.concat(list, [totalLength])\n \
|
|
list should be an Array.");
|
|
}
|
|
|
|
if (list.length === 0) {
|
|
return new Buffer(0);
|
|
} else if (list.length === 1) {
|
|
return list[0];
|
|
}
|
|
|
|
if (typeof totalLength !== 'number') {
|
|
totalLength = 0;
|
|
for (var i = 0; i < list.length; i++) {
|
|
var buf = list[i];
|
|
totalLength += buf.length;
|
|
}
|
|
}
|
|
|
|
var buffer = new Buffer(totalLength);
|
|
var pos = 0;
|
|
for (var i = 0; i < list.length; i++) {
|
|
var buf = list[i];
|
|
buf.copy(buffer, pos);
|
|
pos += buf.length;
|
|
}
|
|
return buffer;
|
|
};
|
|
|
|
// Inspect
|
|
Buffer.prototype.inspect = function inspect() {
|
|
var out = [],
|
|
len = this.length;
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
out[i] = toHex(this.parent[i + this.offset]);
|
|
if (i == exports.INSPECT_MAX_BYTES) {
|
|
out[i + 1] = '...';
|
|
break;
|
|
}
|
|
}
|
|
|
|
return '<Buffer ' + out.join(' ') + '>';
|
|
};
|
|
|
|
|
|
Buffer.prototype.get = function get(i) {
|
|
if (i < 0 || i >= this.length) throw new Error('oob');
|
|
return this.parent[this.offset + i];
|
|
};
|
|
|
|
|
|
Buffer.prototype.set = function set(i, v) {
|
|
if (i < 0 || i >= this.length) throw new Error('oob');
|
|
return this.parent[this.offset + i] = v;
|
|
};
|
|
|
|
|
|
// write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8')
|
|
Buffer.prototype.write = function(string, offset, length, encoding) {
|
|
// Support both (string, offset, length, encoding)
|
|
// and the legacy (string, encoding, offset, length)
|
|
if (isFinite(offset)) {
|
|
if (!isFinite(length)) {
|
|
encoding = length;
|
|
length = undefined;
|
|
}
|
|
} else { // legacy
|
|
var swap = encoding;
|
|
encoding = offset;
|
|
offset = length;
|
|
length = swap;
|
|
}
|
|
|
|
offset = +offset || 0;
|
|
var remaining = this.length - offset;
|
|
if (!length) {
|
|
length = remaining;
|
|
} else {
|
|
length = +length;
|
|
if (length > remaining) {
|
|
length = remaining;
|
|
}
|
|
}
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
var ret;
|
|
switch (encoding) {
|
|
case 'hex':
|
|
ret = this.parent.hexWrite(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
ret = this.parent.utf8Write(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'ascii':
|
|
ret = this.parent.asciiWrite(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'binary':
|
|
ret = this.parent.binaryWrite(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'base64':
|
|
// Warning: maxLength not taken into account in base64Write
|
|
ret = this.parent.base64Write(string, this.offset + offset, length);
|
|
break;
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
ret = this.parent.ucs2Write(string, this.offset + offset, length);
|
|
break;
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
|
|
Buffer._charsWritten = SlowBuffer._charsWritten;
|
|
|
|
return ret;
|
|
};
|
|
|
|
|
|
// toString(encoding, start=0, end=buffer.length)
|
|
Buffer.prototype.toString = function(encoding, start, end) {
|
|
encoding = String(encoding || 'utf8').toLowerCase();
|
|
|
|
if (typeof start == 'undefined' || start < 0) {
|
|
start = 0;
|
|
} else if (start > this.length) {
|
|
start = this.length;
|
|
}
|
|
|
|
if (typeof end == 'undefined' || end > this.length) {
|
|
end = this.length;
|
|
} else if (end < 0) {
|
|
end = 0;
|
|
}
|
|
|
|
start = start + this.offset;
|
|
end = end + this.offset;
|
|
|
|
switch (encoding) {
|
|
case 'hex':
|
|
return this.parent.hexSlice(start, end);
|
|
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return this.parent.utf8Slice(start, end);
|
|
|
|
case 'ascii':
|
|
return this.parent.asciiSlice(start, end);
|
|
|
|
case 'binary':
|
|
return this.parent.binarySlice(start, end);
|
|
|
|
case 'base64':
|
|
return this.parent.base64Slice(start, end);
|
|
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
return this.parent.ucs2Slice(start, end);
|
|
|
|
default:
|
|
throw new Error('Unknown encoding');
|
|
}
|
|
};
|
|
|
|
|
|
// byteLength
|
|
Buffer.byteLength = SlowBuffer.byteLength;
|
|
|
|
|
|
// fill(value, start=0, end=buffer.length)
|
|
Buffer.prototype.fill = function fill(value, start, end) {
|
|
value || (value = 0);
|
|
start || (start = 0);
|
|
end || (end = this.length);
|
|
|
|
if (typeof value === 'string') {
|
|
value = value.charCodeAt(0);
|
|
}
|
|
if (!(typeof value === 'number') || isNaN(value)) {
|
|
throw new Error('value is not a number');
|
|
}
|
|
|
|
if (end < start) throw new Error('end < start');
|
|
|
|
// Fill 0 bytes; we're done
|
|
if (end === start) return 0;
|
|
if (this.length == 0) return 0;
|
|
|
|
if (start < 0 || start >= this.length) {
|
|
throw new Error('start out of bounds');
|
|
}
|
|
|
|
if (end < 0 || end > this.length) {
|
|
throw new Error('end out of bounds');
|
|
}
|
|
|
|
return this.parent.fill(value,
|
|
start + this.offset,
|
|
end + this.offset);
|
|
};
|
|
|
|
|
|
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
|
Buffer.prototype.copy = function(target, target_start, start, end) {
|
|
var source = this;
|
|
start || (start = 0);
|
|
end || (end = this.length);
|
|
target_start || (target_start = 0);
|
|
|
|
if (end < start) throw new Error('sourceEnd < sourceStart');
|
|
|
|
// Copy 0 bytes; we're done
|
|
if (end === start) return 0;
|
|
if (target.length == 0 || source.length == 0) return 0;
|
|
|
|
if (target_start < 0 || target_start >= target.length) {
|
|
throw new Error('targetStart out of bounds');
|
|
}
|
|
|
|
if (start < 0 || start >= source.length) {
|
|
throw new Error('sourceStart out of bounds');
|
|
}
|
|
|
|
if (end < 0 || end > source.length) {
|
|
throw new Error('sourceEnd out of bounds');
|
|
}
|
|
|
|
// Are we oob?
|
|
if (end > this.length) {
|
|
end = this.length;
|
|
}
|
|
|
|
if (target.length - target_start < end - start) {
|
|
end = target.length - target_start + start;
|
|
}
|
|
|
|
return this.parent.copy(target.parent,
|
|
target_start + target.offset,
|
|
start + this.offset,
|
|
end + this.offset);
|
|
};
|
|
|
|
|
|
// slice(start, end)
|
|
Buffer.prototype.slice = function(start, end) {
|
|
if (end === undefined) end = this.length;
|
|
if (end > this.length) throw new Error('oob');
|
|
if (start > end) throw new Error('oob');
|
|
|
|
return new Buffer(this.parent, end - start, +start + this.offset);
|
|
};
|
|
|
|
|
|
// Legacy methods for backwards compatibility.
|
|
|
|
Buffer.prototype.utf8Slice = function(start, end) {
|
|
return this.toString('utf8', start, end);
|
|
};
|
|
|
|
Buffer.prototype.binarySlice = function(start, end) {
|
|
return this.toString('binary', start, end);
|
|
};
|
|
|
|
Buffer.prototype.asciiSlice = function(start, end) {
|
|
return this.toString('ascii', start, end);
|
|
};
|
|
|
|
Buffer.prototype.utf8Write = function(string, offset) {
|
|
return this.write(string, offset, 'utf8');
|
|
};
|
|
|
|
Buffer.prototype.binaryWrite = function(string, offset) {
|
|
return this.write(string, offset, 'binary');
|
|
};
|
|
|
|
Buffer.prototype.asciiWrite = function(string, offset) {
|
|
return this.write(string, offset, 'ascii');
|
|
};
|
|
|
|
Buffer.prototype.readUInt8 = function(offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return buffer.parent[buffer.offset + offset];
|
|
};
|
|
|
|
function readUInt16(buffer, offset, isBigEndian, noAssert) {
|
|
var val = 0;
|
|
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (isBigEndian) {
|
|
val = buffer.parent[buffer.offset + offset] << 8;
|
|
val |= buffer.parent[buffer.offset + offset + 1];
|
|
} else {
|
|
val = buffer.parent[buffer.offset + offset];
|
|
val |= buffer.parent[buffer.offset + offset + 1] << 8;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Buffer.prototype.readUInt16LE = function(offset, noAssert) {
|
|
return readUInt16(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readUInt16BE = function(offset, noAssert) {
|
|
return readUInt16(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readUInt32(buffer, offset, isBigEndian, noAssert) {
|
|
var val = 0;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
if (isBigEndian) {
|
|
val = buffer.parent[buffer.offset + offset + 1] << 16;
|
|
val |= buffer.parent[buffer.offset + offset + 2] << 8;
|
|
val |= buffer.parent[buffer.offset + offset + 3];
|
|
val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0);
|
|
} else {
|
|
val = buffer.parent[buffer.offset + offset + 2] << 16;
|
|
val |= buffer.parent[buffer.offset + offset + 1] << 8;
|
|
val |= buffer.parent[buffer.offset + offset];
|
|
val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0);
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Buffer.prototype.readUInt32LE = function(offset, noAssert) {
|
|
return readUInt32(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readUInt32BE = function(offset, noAssert) {
|
|
return readUInt32(this, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* Signed integer types, yay team! A reminder on how two's complement actually
|
|
* works. The first bit is the signed bit, i.e. tells us whether or not the
|
|
* number should be positive or negative. If the two's complement value is
|
|
* positive, then we're done, as it's equivalent to the unsigned representation.
|
|
*
|
|
* Now if the number is positive, you're pretty much done, you can just leverage
|
|
* the unsigned translations and return those. Unfortunately, negative numbers
|
|
* aren't quite that straightforward.
|
|
*
|
|
* At first glance, one might be inclined to use the traditional formula to
|
|
* translate binary numbers between the positive and negative values in two's
|
|
* complement. (Though it doesn't quite work for the most negative value)
|
|
* Mainly:
|
|
* - invert all the bits
|
|
* - add one to the result
|
|
*
|
|
* Of course, this doesn't quite work in Javascript. Take for example the value
|
|
* of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
|
|
* course, Javascript will do the following:
|
|
*
|
|
* > ~0xff80
|
|
* -65409
|
|
*
|
|
* Whoh there, Javascript, that's not quite right. But wait, according to
|
|
* Javascript that's perfectly correct. When Javascript ends up seeing the
|
|
* constant 0xff80, it has no notion that it is actually a signed number. It
|
|
* assumes that we've input the unsigned value 0xff80. Thus, when it does the
|
|
* binary negation, it casts it into a signed value, (positive 0xff80). Then
|
|
* when you perform binary negation on that, it turns it into a negative number.
|
|
*
|
|
* Instead, we're going to have to use the following general formula, that works
|
|
* in a rather Javascript friendly way. I'm glad we don't support this kind of
|
|
* weird numbering scheme in the kernel.
|
|
*
|
|
* (BIT-MAX - (unsigned)val + 1) * -1
|
|
*
|
|
* The astute observer, may think that this doesn't make sense for 8-bit numbers
|
|
* (really it isn't necessary for them). However, when you get 16-bit numbers,
|
|
* you do. Let's go back to our prior example and see how this will look:
|
|
*
|
|
* (0xffff - 0xff80 + 1) * -1
|
|
* (0x007f + 1) * -1
|
|
* (0x0080) * -1
|
|
*/
|
|
Buffer.prototype.readInt8 = function(offset, noAssert) {
|
|
var buffer = this;
|
|
var neg;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
neg = buffer.parent[buffer.offset + offset] & 0x80;
|
|
if (!neg) {
|
|
return (buffer.parent[buffer.offset + offset]);
|
|
}
|
|
|
|
return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1);
|
|
};
|
|
|
|
function readInt16(buffer, offset, isBigEndian, noAssert) {
|
|
var neg, val;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
val = readUInt16(buffer, offset, isBigEndian, noAssert);
|
|
neg = val & 0x8000;
|
|
if (!neg) {
|
|
return val;
|
|
}
|
|
|
|
return (0xffff - val + 1) * -1;
|
|
}
|
|
|
|
Buffer.prototype.readInt16LE = function(offset, noAssert) {
|
|
return readInt16(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readInt16BE = function(offset, noAssert) {
|
|
return readInt16(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readInt32(buffer, offset, isBigEndian, noAssert) {
|
|
var neg, val;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
val = readUInt32(buffer, offset, isBigEndian, noAssert);
|
|
neg = val & 0x80000000;
|
|
if (!neg) {
|
|
return (val);
|
|
}
|
|
|
|
return (0xffffffff - val + 1) * -1;
|
|
}
|
|
|
|
Buffer.prototype.readInt32LE = function(offset, noAssert) {
|
|
return readInt32(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readInt32BE = function(offset, noAssert) {
|
|
return readInt32(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readFloat(buffer, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
|
|
23, 4);
|
|
}
|
|
|
|
Buffer.prototype.readFloatLE = function(offset, noAssert) {
|
|
return readFloat(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readFloatBE = function(offset, noAssert) {
|
|
return readFloat(this, offset, true, noAssert);
|
|
};
|
|
|
|
function readDouble(buffer, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset + 7 < buffer.length,
|
|
'Trying to read beyond buffer length');
|
|
}
|
|
|
|
return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
|
|
52, 8);
|
|
}
|
|
|
|
Buffer.prototype.readDoubleLE = function(offset, noAssert) {
|
|
return readDouble(this, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.readDoubleBE = function(offset, noAssert) {
|
|
return readDouble(this, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* We have to make sure that the value is a valid integer. This means that it is
|
|
* non-negative. It has no fractional component and that it does not exceed the
|
|
* maximum allowed value.
|
|
*
|
|
* value The number to check for validity
|
|
*
|
|
* max The maximum value
|
|
*/
|
|
function verifuint(value, max) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value >= 0,
|
|
'specified a negative value for writing an unsigned value');
|
|
|
|
assert.ok(value <= max, 'value is larger than maximum value for type');
|
|
|
|
assert.ok(Math.floor(value) === value, 'value has a fractional component');
|
|
}
|
|
|
|
Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xff);
|
|
}
|
|
|
|
buffer.parent[buffer.offset + offset] = value;
|
|
};
|
|
|
|
function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xffff);
|
|
}
|
|
|
|
if (isBigEndian) {
|
|
buffer.parent[buffer.offset + offset] = (value & 0xff00) >>> 8;
|
|
buffer.parent[buffer.offset + offset + 1] = value & 0x00ff;
|
|
} else {
|
|
buffer.parent[buffer.offset + offset + 1] = (value & 0xff00) >>> 8;
|
|
buffer.parent[buffer.offset + offset] = value & 0x00ff;
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
|
|
writeUInt16(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
|
|
writeUInt16(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'trying to write beyond buffer length');
|
|
|
|
verifuint(value, 0xffffffff);
|
|
}
|
|
|
|
if (isBigEndian) {
|
|
buffer.parent[buffer.offset + offset] = (value >>> 24) & 0xff;
|
|
buffer.parent[buffer.offset + offset + 1] = (value >>> 16) & 0xff;
|
|
buffer.parent[buffer.offset + offset + 2] = (value >>> 8) & 0xff;
|
|
buffer.parent[buffer.offset + offset + 3] = value & 0xff;
|
|
} else {
|
|
buffer.parent[buffer.offset + offset + 3] = (value >>> 24) & 0xff;
|
|
buffer.parent[buffer.offset + offset + 2] = (value >>> 16) & 0xff;
|
|
buffer.parent[buffer.offset + offset + 1] = (value >>> 8) & 0xff;
|
|
buffer.parent[buffer.offset + offset] = value & 0xff;
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
|
|
writeUInt32(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
|
|
writeUInt32(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
|
|
/*
|
|
* We now move onto our friends in the signed number category. Unlike unsigned
|
|
* numbers, we're going to have to worry a bit more about how we put values into
|
|
* arrays. Since we are only worrying about signed 32-bit values, we're in
|
|
* slightly better shape. Unfortunately, we really can't do our favorite binary
|
|
* & in this system. It really seems to do the wrong thing. For example:
|
|
*
|
|
* > -32 & 0xff
|
|
* 224
|
|
*
|
|
* What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
|
|
* this aren't treated as a signed number. Ultimately a bad thing.
|
|
*
|
|
* What we're going to want to do is basically create the unsigned equivalent of
|
|
* our representation and pass that off to the wuint* functions. To do that
|
|
* we're going to do the following:
|
|
*
|
|
* - if the value is positive
|
|
* we can pass it directly off to the equivalent wuint
|
|
* - if the value is negative
|
|
* we do the following computation:
|
|
* mb + val + 1, where
|
|
* mb is the maximum unsigned value in that byte size
|
|
* val is the Javascript negative integer
|
|
*
|
|
*
|
|
* As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
|
|
* you do out the computations:
|
|
*
|
|
* 0xffff - 128 + 1
|
|
* 0xffff - 127
|
|
* 0xff80
|
|
*
|
|
* You can then encode this value as the signed version. This is really rather
|
|
* hacky, but it should work and get the job done which is our goal here.
|
|
*/
|
|
|
|
/*
|
|
* A series of checks to make sure we actually have a signed 32-bit number
|
|
*/
|
|
function verifsint(value, max, min) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value <= max, 'value larger than maximum allowed value');
|
|
|
|
assert.ok(value >= min, 'value smaller than minimum allowed value');
|
|
|
|
assert.ok(Math.floor(value) === value, 'value has a fractional component');
|
|
}
|
|
|
|
function verifIEEE754(value, max, min) {
|
|
assert.ok(typeof (value) == 'number',
|
|
'cannot write a non-number as a number');
|
|
|
|
assert.ok(value <= max, 'value larger than maximum allowed value');
|
|
|
|
assert.ok(value >= min, 'value smaller than minimum allowed value');
|
|
}
|
|
|
|
Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
|
|
var buffer = this;
|
|
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7f, -0x80);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
buffer.writeUInt8(value, offset, noAssert);
|
|
} else {
|
|
buffer.writeUInt8(0xff + value + 1, offset, noAssert);
|
|
}
|
|
};
|
|
|
|
function writeInt16(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 1 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7fff, -0x8000);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
writeUInt16(buffer, value, offset, isBigEndian, noAssert);
|
|
} else {
|
|
writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert);
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
|
|
writeInt16(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
|
|
writeInt16(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeInt32(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifsint(value, 0x7fffffff, -0x80000000);
|
|
}
|
|
|
|
if (value >= 0) {
|
|
writeUInt32(buffer, value, offset, isBigEndian, noAssert);
|
|
} else {
|
|
writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert);
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
|
|
writeInt32(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
|
|
writeInt32(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeFloat(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 3 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38);
|
|
}
|
|
|
|
require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
|
|
23, 4);
|
|
}
|
|
|
|
Buffer.prototype.writeFloatLE = function(value, offset, noAssert) {
|
|
writeFloat(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
|
|
writeFloat(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
function writeDouble(buffer, value, offset, isBigEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert.ok(value !== undefined && value !== null,
|
|
'missing value');
|
|
|
|
assert.ok(typeof (isBigEndian) === 'boolean',
|
|
'missing or invalid endian');
|
|
|
|
assert.ok(offset !== undefined && offset !== null,
|
|
'missing offset');
|
|
|
|
assert.ok(offset + 7 < buffer.length,
|
|
'Trying to write beyond buffer length');
|
|
|
|
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308);
|
|
}
|
|
|
|
require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
|
|
52, 8);
|
|
}
|
|
|
|
Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
|
|
writeDouble(this, value, offset, false, noAssert);
|
|
};
|
|
|
|
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
|
|
writeDouble(this, value, offset, true, noAssert);
|
|
};
|
|
|
|
SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8;
|
|
SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE;
|
|
SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE;
|
|
SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE;
|
|
SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE;
|
|
SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8;
|
|
SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE;
|
|
SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE;
|
|
SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE;
|
|
SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE;
|
|
SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE;
|
|
SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE;
|
|
SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE;
|
|
SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE;
|
|
SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8;
|
|
SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE;
|
|
SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE;
|
|
SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE;
|
|
SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE;
|
|
SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8;
|
|
SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE;
|
|
SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE;
|
|
SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE;
|
|
SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE;
|
|
SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE;
|
|
SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE;
|
|
SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE;
|
|
SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE;
|
|
|
|
},{"assert":1,"./buffer_ieee754":8,"base64-js":9}],9:[function(require,module,exports){
|
|
(function (exports) {
|
|
'use strict';
|
|
|
|
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
|
|
function b64ToByteArray(b64) {
|
|
var i, j, l, tmp, placeHolders, arr;
|
|
|
|
if (b64.length % 4 > 0) {
|
|
throw 'Invalid string. Length must be a multiple of 4';
|
|
}
|
|
|
|
// the number of equal signs (place holders)
|
|
// if there are two placeholders, than the two characters before it
|
|
// represent one byte
|
|
// if there is only one, then the three characters before it represent 2 bytes
|
|
// this is just a cheap hack to not do indexOf twice
|
|
placeHolders = b64.indexOf('=');
|
|
placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0;
|
|
|
|
// base64 is 4/3 + up to two characters of the original data
|
|
arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders);
|
|
|
|
// if there are placeholders, only get up to the last complete 4 chars
|
|
l = placeHolders > 0 ? b64.length - 4 : b64.length;
|
|
|
|
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
|
tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]);
|
|
arr.push((tmp & 0xFF0000) >> 16);
|
|
arr.push((tmp & 0xFF00) >> 8);
|
|
arr.push(tmp & 0xFF);
|
|
}
|
|
|
|
if (placeHolders === 2) {
|
|
tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4);
|
|
arr.push(tmp & 0xFF);
|
|
} else if (placeHolders === 1) {
|
|
tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2);
|
|
arr.push((tmp >> 8) & 0xFF);
|
|
arr.push(tmp & 0xFF);
|
|
}
|
|
|
|
return arr;
|
|
}
|
|
|
|
function uint8ToBase64(uint8) {
|
|
var i,
|
|
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
|
|
output = "",
|
|
temp, length;
|
|
|
|
function tripletToBase64 (num) {
|
|
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
|
|
};
|
|
|
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
|
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
|
|
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
|
|
output += tripletToBase64(temp);
|
|
}
|
|
|
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
|
switch (extraBytes) {
|
|
case 1:
|
|
temp = uint8[uint8.length - 1];
|
|
output += lookup[temp >> 2];
|
|
output += lookup[(temp << 4) & 0x3F];
|
|
output += '==';
|
|
break;
|
|
case 2:
|
|
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);
|
|
output += lookup[temp >> 10];
|
|
output += lookup[(temp >> 4) & 0x3F];
|
|
output += lookup[(temp << 2) & 0x3F];
|
|
output += '=';
|
|
break;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
module.exports.toByteArray = b64ToByteArray;
|
|
module.exports.fromByteArray = uint8ToBase64;
|
|
}());
|
|
|
|
},{}]},{},[])
|
|
;;module.exports=require("buffer-browserify")
|
|
|
|
},{}],66:[function(require,module,exports){
|
|
// shim for using process in browser
|
|
|
|
var process = module.exports = {};
|
|
|
|
process.nextTick = (function () {
|
|
var canSetImmediate = typeof window !== 'undefined'
|
|
&& window.setImmediate;
|
|
var canPost = typeof window !== 'undefined'
|
|
&& window.postMessage && window.addEventListener
|
|
;
|
|
|
|
if (canSetImmediate) {
|
|
return function (f) { return window.setImmediate(f) };
|
|
}
|
|
|
|
if (canPost) {
|
|
var queue = [];
|
|
window.addEventListener('message', function (ev) {
|
|
if (ev.source === window && ev.data === 'process-tick') {
|
|
ev.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
return function nextTick(fn) {
|
|
queue.push(fn);
|
|
window.postMessage('process-tick', '*');
|
|
};
|
|
}
|
|
|
|
return function nextTick(fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
})();
|
|
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
}
|
|
|
|
// TODO(shtylman)
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
|
|
},{}],67:[function(require,module,exports){
|
|
var _ = require('./vendor/lodash');
|
|
var async = require('async');
|
|
var jxt = require('jxt');
|
|
var request = require('xhr');
|
|
var parser = new DOMParser();
|
|
|
|
|
|
function XRD(data, xml) {
|
|
return jxt.init(this, xml, data);
|
|
}
|
|
XRD.prototype = {
|
|
constructor: {
|
|
value: XRD
|
|
},
|
|
NS: 'http://docs.oasis-open.org/ns/xri/xrd-1.0',
|
|
EL: 'XRD',
|
|
toString: jxt.toString,
|
|
toJSON: jxt.toJSON,
|
|
get subject() {
|
|
return jxt.getSubText(this.xml, this.NS, 'Subject');
|
|
},
|
|
get expires() {
|
|
return new Date(jxt.getSubText(this.xml, this.NS, 'Expires'));
|
|
},
|
|
get aliases() {
|
|
return jxt.getMultiSubText(this.xml, this.NS, 'Alias');
|
|
},
|
|
get properties() {
|
|
var results = {};
|
|
var props = jxt.find(this.xml, this.NS, 'Property');
|
|
_.each(props, function (property) {
|
|
var type = jxt.getAttribute(property, 'type');
|
|
results[type] = property.textContent;
|
|
});
|
|
return results;
|
|
},
|
|
get links() {
|
|
var results = [];
|
|
var links = jxt.find(this.xml, this.NS, 'Link');
|
|
_.each(links, function (link) {
|
|
var item = {
|
|
rel: jxt.getAttribute(link, 'rel'),
|
|
href: jxt.getAttribute(link, 'href'),
|
|
type: jxt.getAttribute(link, 'type'),
|
|
template: jxt.getAttribute(link, 'template'),
|
|
titles: jxt.getSubLangText(link, this.NS, 'Title', 'default'),
|
|
properties: {}
|
|
};
|
|
var props = jxt.find(link, this.NS, 'Property');
|
|
_.each(props, function (property) {
|
|
var type = jxt.getAttribute(property, 'type');
|
|
item.properties[type] = property.textContent;
|
|
});
|
|
results.push(item);
|
|
});
|
|
return results;
|
|
}
|
|
};
|
|
|
|
|
|
module.exports = function (opts, cb) {
|
|
if (typeof opts === 'string') {
|
|
opts = {host: opts};
|
|
}
|
|
|
|
opts = _.extend({
|
|
ssl: true,
|
|
json: true
|
|
}, opts);
|
|
|
|
var scheme = opts.ssl ? 'https://' : 'http://';
|
|
|
|
async.parallel({
|
|
json: function (jsonCb) {
|
|
if (!opts.json) return jsonCb(null, {});
|
|
request({
|
|
uri: scheme + opts.host + '/.well-known/host-meta.json'
|
|
}, function (err, resp, body) {
|
|
if (err) return jsonCb();
|
|
try {
|
|
jsonCb('completed', JSON.parse(body));
|
|
} catch (e) {
|
|
jsonCb(null, {});
|
|
}
|
|
});
|
|
},
|
|
xrd: function (xrdCb) {
|
|
request({
|
|
uri: scheme + opts.host + '/.well-known/host-meta'
|
|
}, function (err, resp) {
|
|
if (err) return xrdCb(null, {});
|
|
try {
|
|
var body = parser.parseFromString(resp.body, 'application/xml').childNodes[0];
|
|
var xrd = new XRD({}, body);
|
|
xrdCb('completed', xrd.toJSON());
|
|
} catch (e) {
|
|
xrdCb(null, {});
|
|
}
|
|
});
|
|
}
|
|
}, function (completed, data) {
|
|
if (completed) {
|
|
if (Object.keys(data.json).length) {
|
|
return cb(false, data.json);
|
|
} else if (Object.keys(data.xrd).length) {
|
|
return cb(false, data.xrd);
|
|
}
|
|
}
|
|
cb('no-host-meta', {});
|
|
});
|
|
};
|
|
|
|
},{"./vendor/lodash":73,"async":53,"jxt":68,"xhr":70}],68:[function(require,module,exports){
|
|
var _ = require('./vendor/lodash');
|
|
var serializer = new XMLSerializer();
|
|
var XML_NS = 'http://www.w3.org/XML/1998/namespace';
|
|
var TOP_LEVEL_LOOKUP = {};
|
|
var LOOKUP = {};
|
|
var LOOKUP_EXT = {};
|
|
|
|
|
|
var find = exports.find = function (xml, NS, selector) {
|
|
var children = xml.querySelectorAll(selector);
|
|
return _.filter(children, function (child) {
|
|
return child.namespaceURI === NS && child.parentNode == xml;
|
|
});
|
|
};
|
|
|
|
exports.findOrCreate = function (xml, NS, selector) {
|
|
var existing = find(xml, NS, selector);
|
|
if (existing.length) {
|
|
return existing[0];
|
|
} else {
|
|
var created = document.createElementNS(NS, selector);
|
|
xml.appendChild(created);
|
|
return created;
|
|
}
|
|
};
|
|
|
|
exports.init = function (self, xml, data) {
|
|
self.xml = xml || document.createElementNS(self.NS, self.EL);
|
|
if (!self.xml.parentNode || self.xml.parentNode.namespaceURI !== self.NS) {
|
|
self.xml.setAttribute('xmlns', self.NS);
|
|
}
|
|
|
|
self._extensions = {};
|
|
_.each(self.xml.childNodes, function (child) {
|
|
var childName = child.namespaceURI + '|' + child.localName;
|
|
var ChildJXT = LOOKUP[childName];
|
|
if (ChildJXT !== undefined) {
|
|
var name = ChildJXT.prototype._name;
|
|
self._extensions[name] = new ChildJXT(null, child);
|
|
self._extensions[name].parent = self;
|
|
}
|
|
});
|
|
|
|
_.extend(self, data);
|
|
return self;
|
|
};
|
|
|
|
exports.getSubText = function (xml, NS, element) {
|
|
var subs = find(xml, NS, element);
|
|
if (!subs) {
|
|
return '';
|
|
}
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
return subs[i].textContent || '';
|
|
}
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
exports.getMultiSubText = function (xml, NS, element, extractor) {
|
|
var subs = find(xml, NS, element);
|
|
var results = [];
|
|
extractor = extractor || function (sub) {
|
|
return sub.textContent || '';
|
|
};
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
results.push(extractor(subs[i]));
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
exports.getSubLangText = function (xml, NS, element, defaultLang) {
|
|
var subs = find(xml, NS, element);
|
|
if (!subs) {
|
|
return {};
|
|
}
|
|
|
|
var lang, sub;
|
|
var results = {};
|
|
var langs = [];
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
sub = subs[i];
|
|
if (sub.namespaceURI === NS) {
|
|
lang = sub.getAttributeNS(XML_NS, 'lang') || defaultLang;
|
|
langs.push(lang);
|
|
results[lang] = sub.textContent || '';
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
|
|
exports.setSubText = function (xml, NS, element, value) {
|
|
var subs = find(xml, NS, element);
|
|
if (!subs.length) {
|
|
if (value) {
|
|
var sub = document.createElementNS(NS, element);
|
|
sub.textContent = value;
|
|
xml.appendChild(sub);
|
|
}
|
|
} else {
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
if (value) {
|
|
subs[i].textContent = value;
|
|
return;
|
|
} else {
|
|
xml.removeChild(subs[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.setMultiSubText = function (xml, NS, element, value, builder) {
|
|
var subs = find(xml, NS, element);
|
|
var values = [];
|
|
builder = builder || function (value) {
|
|
var sub = document.createElementNS(NS, element);
|
|
sub.textContent = value;
|
|
xml.appendChild(sub);
|
|
};
|
|
if (typeof value === 'string') {
|
|
values = (value || '').split('\n');
|
|
} else {
|
|
values = value;
|
|
}
|
|
_.forEach(subs, function (sub) {
|
|
xml.removeChild(sub);
|
|
});
|
|
_.forEach(values, function (val) {
|
|
if (val) {
|
|
builder(val);
|
|
}
|
|
});
|
|
};
|
|
|
|
exports.setSubLangText = function (xml, NS, element, value, defaultLang) {
|
|
var sub, lang;
|
|
var subs = find(xml, NS, element);
|
|
if (subs.length) {
|
|
for (var i = 0; i < subs.length; i++) {
|
|
sub = subs[i];
|
|
if (sub.namespaceURI === NS) {
|
|
xml.removeChild(sub);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof value === 'string') {
|
|
sub = document.createElementNS(NS, element);
|
|
sub.textContent = value;
|
|
xml.appendChild(sub);
|
|
} else if (typeof value === 'object') {
|
|
for (lang in value) {
|
|
if (value.hasOwnProperty(lang)) {
|
|
sub = document.createElementNS(NS, element);
|
|
if (lang !== defaultLang) {
|
|
sub.setAttributeNS(XML_NS, 'lang', lang);
|
|
}
|
|
sub.textContent = value[lang];
|
|
xml.appendChild(sub);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.getAttribute = function (xml, attr, defaultVal) {
|
|
return xml.getAttribute(attr) || defaultVal || '';
|
|
};
|
|
|
|
exports.setAttribute = function (xml, attr, value, force) {
|
|
if (value || force) {
|
|
xml.setAttribute(attr, value);
|
|
} else {
|
|
xml.removeAttribute(attr);
|
|
}
|
|
};
|
|
|
|
exports.getBoolAttribute = function (xml, attr, defaultVal) {
|
|
var val = xml.getAttribute(attr) || defaultVal || '';
|
|
return val === 'true' || val === '1';
|
|
};
|
|
|
|
exports.setBoolAttribute = function (xml, attr, value) {
|
|
if (value) {
|
|
xml.setAttribute(attr, '1');
|
|
} else {
|
|
xml.removeAttribute(attr);
|
|
}
|
|
};
|
|
|
|
exports.getSubAttribute = function (xml, NS, sub, attr, defaultVal) {
|
|
var subs = find(xml, NS, sub);
|
|
if (!subs) {
|
|
return '';
|
|
}
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
return subs[i].getAttribute(attr) || defaultVal || '';
|
|
}
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
exports.setSubAttribute = function (xml, NS, sub, attr, value) {
|
|
var subs = find(xml, NS, sub);
|
|
if (!subs.length) {
|
|
if (value) {
|
|
sub = document.createElementNS(NS, sub);
|
|
sub.setAttribute(attr, value);
|
|
xml.appendChild(sub);
|
|
}
|
|
} else {
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
if (value) {
|
|
subs[i].setAttribute(attr, value);
|
|
return;
|
|
} else {
|
|
subs[i].removeAttribute(attr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.toString = function () {
|
|
return serializer.serializeToString(this.xml);
|
|
};
|
|
|
|
exports.toJSON = function () {
|
|
var prop;
|
|
var result = {};
|
|
var exclude = {
|
|
constructor: true,
|
|
NS: true,
|
|
EL: true,
|
|
toString: true,
|
|
toJSON: true,
|
|
_extensions: true,
|
|
prototype: true,
|
|
xml: true,
|
|
parent: true,
|
|
_name: true
|
|
};
|
|
for (prop in this._extensions) {
|
|
if (this._extensions[prop].toJSON) {
|
|
result[prop] = this._extensions[prop].toJSON();
|
|
}
|
|
}
|
|
for (prop in this) {
|
|
if (!exclude[prop] && !((LOOKUP_EXT[this.NS + '|' + this.EL] || {})[prop]) && !this._extensions[prop] && prop[0] !== '_') {
|
|
var val = this[prop];
|
|
if (typeof val == 'function') continue;
|
|
var type = Object.prototype.toString.call(val);
|
|
if (type.indexOf('Object') >= 0) {
|
|
if (Object.keys(val).length > 0) {
|
|
result[prop] = val;
|
|
}
|
|
} else if (type.indexOf('Array') >= 0) {
|
|
if (val.length > 0) {
|
|
result[prop] = val;
|
|
}
|
|
} else if (!!val) {
|
|
result[prop] = val;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
exports.extend = function (ParentJXT, ChildJXT) {
|
|
var parentName = ParentJXT.prototype.NS + '|' + ParentJXT.prototype.EL;
|
|
var name = ChildJXT.prototype._name;
|
|
var qName = ChildJXT.prototype.NS + '|' + ChildJXT.prototype.EL;
|
|
|
|
LOOKUP[qName] = ChildJXT;
|
|
if (!LOOKUP_EXT[qName]) {
|
|
LOOKUP_EXT[qName] = {};
|
|
}
|
|
if (!LOOKUP_EXT[parentName]) {
|
|
LOOKUP_EXT[parentName] = {};
|
|
}
|
|
LOOKUP_EXT[parentName][name] = ChildJXT;
|
|
|
|
ParentJXT.prototype.__defineGetter__(name, function () {
|
|
if (!this._extensions[name]) {
|
|
var existing = exports.find(this.xml, ChildJXT.prototype.NS, ChildJXT.prototype.EL);
|
|
if (!existing.length) {
|
|
this._extensions[name] = new ChildJXT();
|
|
this.xml.appendChild(this._extensions[name].xml);
|
|
} else {
|
|
this._extensions[name] = new ChildJXT(null, existing[0]);
|
|
}
|
|
this._extensions[name].parent = this;
|
|
}
|
|
return this._extensions[name];
|
|
});
|
|
ParentJXT.prototype.__defineSetter__(name, function (value) {
|
|
var child = this[name];
|
|
_.extend(child, value);
|
|
});
|
|
};
|
|
|
|
exports.topLevel = function (JXT) {
|
|
var name = JXT.prototype.NS + '|' + JXT.prototype.EL;
|
|
LOOKUP[name] = JXT;
|
|
TOP_LEVEL_LOOKUP[name] = JXT;
|
|
};
|
|
|
|
exports.build = function (xml) {
|
|
var JXT = TOP_LEVEL_LOOKUP[xml.namespaceURI + '|' + xml.localName];
|
|
if (JXT) {
|
|
return new JXT(null, xml);
|
|
}
|
|
};
|
|
|
|
exports.XML_NS = XML_NS;
|
|
exports.TOP_LEVEL_LOOKUP = TOP_LEVEL_LOOKUP;
|
|
exports.LOOKUP_EXT = LOOKUP_EXT;
|
|
exports.LOOKUP = LOOKUP;
|
|
|
|
},{"./vendor/lodash":69}],69:[function(require,module,exports){
|
|
var global=self;/**
|
|
* @license
|
|
* Lo-Dash 1.3.1 (Custom Build) lodash.com/license
|
|
* Build: `lodash include="each,extend,filter"`
|
|
* Underscore.js 1.4.4 underscorejs.org/LICENSE
|
|
*/
|
|
;!function(t){function r(t){return typeof t.toString!="function"&&typeof(t+"")=="string"}function e(t){t.length=0,g.length<y&&g.push(t)}function n(t){var r=t.k;r&&n(r),t.b=t.k=t.object=t.number=t.string=null,h.length<y&&h.push(t)}function o(){}function u(){var t=h.pop()||{a:"",b:null,c:"",k:null,"false":!1,d:"",e:"",f:"","null":!1,number:null,object:null,push:null,g:null,string:null,h:"","true":!1,undefined:!1,i:!1,j:!1};t.g=v,t.b=t.c=t.f=t.h="",t.e="r",t.i=!0,t.j=!!X;for(var r,e=0;r=arguments[e];e++)for(var u in r)t[u]=r[u];
|
|
e=t.a,t.d=/^[^,]+/.exec(e)[0],r=Function,e="return function("+e+"){",u="var m,r="+t.d+",C="+t.e+";if(!r)return C;"+t.h+";",t.b?(u+="var s=r.length;m=-1;if("+t.b+"){",K.unindexedChars&&(u+="if(q(r)){r=r.split('')}"),u+="while(++m<s){"+t.f+";}}else{"):K.nonEnumArgs&&(u+="var s=r.length;m=-1;if(s&&n(r)){while(++m<s){m+='';"+t.f+";}}else{"),K.enumPrototypes&&(u+="var E=typeof r=='function';"),K.enumErrorProps&&(u+="var D=r===j||r instanceof Error;");var c=[];if(K.enumPrototypes&&c.push('!(E&&m=="prototype")'),K.enumErrorProps&&c.push('!(D&&(m=="message"||m=="name"))'),t.i&&t.j)u+="var A=-1,B=z[typeof r]&&t(r),s=B?B.length:0;while(++A<s){m=B[A];",c.length&&(u+="if("+c.join("&&")+"){"),u+=t.f+";",c.length&&(u+="}"),u+="}";
|
|
else if(u+="for(m in r){",t.i&&c.push("l.call(r, m)"),c.length&&(u+="if("+c.join("&&")+"){"),u+=t.f+";",c.length&&(u+="}"),u+="}",K.nonEnumShadows){for(u+="if(r!==y){var h=r.constructor,p=r===(h&&h.prototype),e=r===H?G:r===j?i:J.call(r),v=w[e];",k=0;7>k;k++)u+="m='"+t.g[k]+"';if((!(p&&v[m])&&l.call(r,m))",t.i||(u+="||(!v[m]&&r[m]!==y[m])"),u+="){"+t.f+"}";u+="}"}return(t.b||K.nonEnumArgs)&&(u+="}"),u+=t.c+";return C",r=r("i,j,l,n,o,q,t,u,y,z,w,G,H,J",e+u+"}"),n(t),r(_,z,R,a,U,l,X,o,D,P,V,A,N,M)}function a(t){return M.call(t)==j
|
|
}function c(t,n,u,i,l,s){var p=u===b;if(typeof u=="function"&&!p){u=o.createCallback(u,i,2);var m=u(t,n);if(typeof m!="undefined")return!!m}if(t===n)return 0!==t||1/t==1/n;var h=typeof t,y=typeof n;if(t===t&&(!t||"function"!=h&&"object"!=h)&&(!n||"function"!=y&&"object"!=y))return!1;if(null==t||null==n)return t===n;if(y=M.call(t),h=M.call(n),y==j&&(y=w),h==j&&(h=w),y!=h)return!1;switch(y){case O:case E:return+t==+n;case x:return t!=+t?n!=+n:0==t?1/t==1/n:t==+n;case S:case A:return t==n+""}if(h=y==C,!h){if(R.call(t,"__wrapped__")||R.call(n,"__wrapped__"))return c(t.__wrapped__||t,n.__wrapped__||n,u,i,l,s);
|
|
if(y!=w||!K.nodeClass&&(r(t)||r(n)))return!1;var y=!K.argsObject&&a(t)?Object:t.constructor,d=!K.argsObject&&a(n)?Object:n.constructor;if(y!=d&&(!f(y)||!(y instanceof y&&f(d)&&d instanceof d)))return!1}for(d=!l,l||(l=g.pop()||[]),s||(s=g.pop()||[]),y=l.length;y--;)if(l[y]==t)return s[y]==n;var v=0,m=!0;if(l.push(t),s.push(n),h){if(y=t.length,v=n.length,m=v==t.length,!m&&!p)return m;for(;v--;)if(h=y,d=n[v],p)for(;h--&&!(m=c(t[h],d,u,i,l,s)););else if(!(m=c(t[v],d,u,i,l,s)))break;return m}return Z(n,function(r,e,n){return R.call(n,e)?(v++,m=R.call(t,e)&&c(t[e],r,u,i,l,s)):void 0
|
|
}),m&&!p&&Z(t,function(t,r,e){return R.call(e,r)?m=-1<--v:void 0}),d&&(e(l),e(s)),m}function f(t){return typeof t=="function"}function i(t){return!(!t||!P[typeof t])}function l(t){return typeof t=="string"||M.call(t)==A}function s(t,r,e){var n=[];if(r=o.createCallback(r,e),U(t)){e=-1;for(var u=t.length;++e<u;){var a=t[e];r(a,e,t)&&n.push(a)}}else Y(t,function(t,e,o){r(t,e,o)&&n.push(t)});return n}function p(t,r,e){if(r&&typeof e=="undefined"&&U(t)){e=-1;for(var n=t.length;++e<n&&false!==r(t[e],e,t););}else Y(t,r,e);
|
|
return t}function m(t){return t}var g=[],h=[],b={},y=40,d=(d=/\bthis\b/)&&d.test(function(){return this})&&d,v="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),j="[object Arguments]",C="[object Array]",O="[object Boolean]",E="[object Date]",_="[object Error]",x="[object Number]",w="[object Object]",S="[object RegExp]",A="[object String]",P={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},I=P[typeof exports]&&exports,B=P[typeof module]&&module&&module.exports==I&&module,F=P[typeof global]&&global;
|
|
!F||F.global!==F&&F.window!==F||(t=F);var z=Error.prototype,D=Object.prototype,N=String.prototype,F=RegExp("^"+(D.valueOf+"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),q=Function.prototype.toString,R=D.hasOwnProperty,$=D.propertyIsEnumerable,M=D.toString,T=F.test(T=M.bind)&&T,G=F.test(G=Object.create)&&G,H=F.test(H=Array.isArray)&&H,J=F.test(J=Object.keys)&&J,G=F.test(t.attachEvent),L=T&&!/\n|true/.test(T+G),V={};V[C]=V[E]=V[x]={constructor:!0,toLocaleString:!0,toString:!0,valueOf:!0},V[O]=V[A]={constructor:!0,toString:!0,valueOf:!0},V[_]=V["[object Function]"]=V[S]={constructor:!0,toString:!0},V[w]={constructor:!0},function(){for(var t=v.length;t--;){var r,e=v[t];
|
|
for(r in V)R.call(V,r)&&!R.call(V[r],e)&&(V[r][e]=!1)}}();var K=o.support={};!function(){var t=function(){this.x=1},r=[];t.prototype={valueOf:1,y:1};for(var e in new t)r.push(e);for(e in arguments);K.argsObject=arguments.constructor==Object&&!(arguments instanceof Array),K.argsClass=a(arguments),K.enumErrorProps=$.call(z,"message")||$.call(z,"name"),K.enumPrototypes=$.call(t,"prototype"),K.fastBind=T&&!L,K.nonEnumArgs=0!=e,K.nonEnumShadows=!/valueOf/.test(r),K.unindexedChars="xx"!="x"[0]+Object("x")[0];
|
|
try{K.nodeClass=!(M.call(document)==w&&!({toString:0}+""))}catch(n){K.nodeClass=!0}}(1);var Q={a:"x,F,k",h:"var a=arguments,b=0,c=typeof k=='number'?2:a.length;while(++b<c){r=a[b];if(r&&z[typeof r]){",f:"if(typeof C[m]=='undefined')C[m]=r[m]",c:"}}"},G={a:"f,d,I",h:"d=d&&typeof I=='undefined'?d:u.createCallback(d,I)",b:"typeof s=='number'",f:"if(d(r[m],m,f)===false)return C"},F={h:"if(!z[typeof r])return C;"+G.h,b:!1};K.argsClass||(a=function(t){return t?R.call(t,"callee"):!1});var U=H||function(t){return t?typeof t=="object"&&M.call(t)==C:!1
|
|
},W=u({a:"x",e:"[]",h:"if(!(z[typeof x]))return C",f:"C.push(m)"}),X=J?function(t){return i(t)?K.enumPrototypes&&typeof t=="function"||K.nonEnumArgs&&t.length&&a(t)?W(t):J(t):[]}:W,Y=u(G),H=u(Q,{h:Q.h.replace(";",";if(c>3&&typeof a[c-2]=='function'){var d=u.createCallback(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){d=a[--c]}"),f:"C[m]=d?d(C[m],r[m]):r[m]"}),Z=u(G,F,{i:!1});f(/x/)&&(f=function(t){return typeof t=="function"&&"[object Function]"==M.call(t)}),o.assign=H,o.createCallback=function(t,r,e){if(null==t)return m;
|
|
var n=typeof t;if("function"!=n){if("object"!=n)return function(r){return r[t]};var o=X(t);return function(r){for(var e=o.length,n=!1;e--&&(n=c(r[o[e]],t[o[e]],b)););return n}}return typeof r=="undefined"||d&&!d.test(q.call(t))?t:1===e?function(e){return t.call(r,e)}:2===e?function(e,n){return t.call(r,e,n)}:4===e?function(e,n,o,u){return t.call(r,e,n,o,u)}:function(e,n,o){return t.call(r,e,n,o)}},o.filter=s,o.forEach=p,o.forIn=Z,o.keys=X,o.each=p,o.extend=H,o.select=s,o.identity=m,o.isArguments=a,o.isArray=U,o.isEqual=c,o.isFunction=f,o.isObject=i,o.isString=l,o.VERSION="1.3.1",typeof define=="function"&&typeof define.amd=="object"&&define.amd?(t._=o, define(function(){return o
|
|
})):I&&!I.nodeType?B?(B.exports=o)._=o:I._=o:t._=o}(this);
|
|
},{}],70:[function(require,module,exports){
|
|
var window = require("global/window")
|
|
var once = require("once")
|
|
|
|
var messages = {
|
|
"0": "Internal XMLHttpRequest Error",
|
|
"4": "4xx Client Error",
|
|
"5": "5xx Server Error"
|
|
}
|
|
|
|
var XHR = window.XMLHttpRequest || noop
|
|
var XDR = "withCredentials" in (new XHR()) ?
|
|
window.XMLHttpRequest : window.XDomainRequest
|
|
|
|
module.exports = createXHR
|
|
|
|
function createXHR(options, callback) {
|
|
if (typeof options === "string") {
|
|
options = { uri: options }
|
|
}
|
|
|
|
options = options || {}
|
|
callback = once(callback)
|
|
|
|
var xhr
|
|
|
|
if (options.cors) {
|
|
xhr = new XDR()
|
|
xhr.withCredentials = true
|
|
} else {
|
|
xhr = new XHR()
|
|
}
|
|
|
|
var uri = xhr.url = options.uri
|
|
var method = xhr.method = options.method || "GET"
|
|
var body = options.body || options.data
|
|
var headers = xhr.headers = options.headers || {}
|
|
var isJson = false
|
|
|
|
if ("json" in options) {
|
|
isJson = true
|
|
headers["Content-Type"] = "application/json"
|
|
body = JSON.stringify(options.json)
|
|
}
|
|
|
|
xhr.onreadystatechange = readystatechange
|
|
xhr.onload = load
|
|
xhr.onerror = error
|
|
// IE9 must have onprogress be set to a unique function.
|
|
xhr.onprogress = function () {
|
|
// IE must die
|
|
}
|
|
// hate IE
|
|
xhr.ontimeout = noop
|
|
xhr.open(method, uri)
|
|
xhr.timeout = "timeout" in options ? options.timeout : 5000
|
|
|
|
if ( xhr.setRequestHeader) {
|
|
Object.keys(headers).forEach(function (key) {
|
|
xhr.setRequestHeader(key, headers[key])
|
|
})
|
|
}
|
|
|
|
xhr.send(body)
|
|
|
|
return xhr
|
|
|
|
function readystatechange() {
|
|
if (xhr.readyState === 4) {
|
|
load()
|
|
}
|
|
}
|
|
|
|
function load() {
|
|
var error = null
|
|
var status = xhr.statusCode = xhr.status
|
|
var body = xhr.body = xhr.response ||
|
|
xhr.responseText || xhr.responseXML
|
|
|
|
if (status === 0 || (status >= 400 && status < 600)) {
|
|
var message = xhr.responseText ||
|
|
messages[String(xhr.status).charAt(0)]
|
|
error = new Error(message)
|
|
|
|
error.statusCode = xhr.status
|
|
}
|
|
|
|
if (isJson) {
|
|
try {
|
|
body = xhr.body = JSON.parse(body)
|
|
} catch (e) {}
|
|
}
|
|
|
|
callback(error, xhr, body)
|
|
}
|
|
|
|
function error(evt) {
|
|
callback(evt, xhr)
|
|
}
|
|
}
|
|
|
|
|
|
function noop() {}
|
|
|
|
},{"global/window":71,"once":72}],71:[function(require,module,exports){
|
|
var global=self;if (typeof window !== "undefined") {
|
|
module.exports = window
|
|
} else if (typeof global !== "undefined") {
|
|
module.exports = global
|
|
} else {
|
|
module.exports = {}
|
|
}
|
|
|
|
},{}],72:[function(require,module,exports){
|
|
module.exports = once
|
|
|
|
once.proto = once(function () {
|
|
Object.defineProperty(Function.prototype, 'once', {
|
|
value: function () {
|
|
return once(this)
|
|
},
|
|
configurable: true
|
|
})
|
|
})
|
|
|
|
function once (fn) {
|
|
var called = false
|
|
return function () {
|
|
if (called) return
|
|
called = true
|
|
return fn.apply(this, arguments)
|
|
}
|
|
}
|
|
|
|
},{}],73:[function(require,module,exports){
|
|
var global=self;/**
|
|
* @license
|
|
* Lo-Dash 1.3.1 (Custom Build) lodash.com/license
|
|
* Build: `lodash include="each,extend"`
|
|
* Underscore.js 1.4.4 underscorejs.org/LICENSE
|
|
*/
|
|
;!function(t){function r(t){return typeof t.toString!="function"&&typeof(t+"")=="string"}function e(t){t.length=0,m.length<y&&m.push(t)}function n(t){var r=t.k;r&&n(r),t.b=t.k=t.object=t.number=t.string=null,g.length<y&&g.push(t)}function o(){}function u(){var t=g.pop()||{a:"",b:null,c:"",k:null,"false":!1,d:"",e:"",f:"","null":!1,number:null,object:null,push:null,g:null,string:null,h:"","true":!1,undefined:!1,i:!1,j:!1};t.g=d,t.b=t.c=t.f=t.h="",t.e="r",t.i=!0,t.j=!!W;for(var r,e=0;r=arguments[e];e++)for(var u in r)t[u]=r[u];
|
|
e=t.a,t.d=/^[^,]+/.exec(e)[0],r=Function,e="return function("+e+"){",u="var m,r="+t.d+",C="+t.e+";if(!r)return C;"+t.h+";",t.b?(u+="var s=r.length;m=-1;if("+t.b+"){",V.unindexedChars&&(u+="if(q(r)){r=r.split('')}"),u+="while(++m<s){"+t.f+";}}else{"):V.nonEnumArgs&&(u+="var s=r.length;m=-1;if(s&&n(r)){while(++m<s){m+='';"+t.f+";}}else{"),V.enumPrototypes&&(u+="var E=typeof r=='function';"),V.enumErrorProps&&(u+="var D=r===j||r instanceof Error;");var c=[];if(V.enumPrototypes&&c.push('!(E&&m=="prototype")'),V.enumErrorProps&&c.push('!(D&&(m=="message"||m=="name"))'),t.i&&t.j)u+="var A=-1,B=z[typeof r]&&t(r),s=B?B.length:0;while(++A<s){m=B[A];",c.length&&(u+="if("+c.join("&&")+"){"),u+=t.f+";",c.length&&(u+="}"),u+="}";
|
|
else if(u+="for(m in r){",t.i&&c.push("l.call(r, m)"),c.length&&(u+="if("+c.join("&&")+"){"),u+=t.f+";",c.length&&(u+="}"),u+="}",V.nonEnumShadows){for(u+="if(r!==y){var h=r.constructor,p=r===(h&&h.prototype),e=r===H?G:r===j?i:J.call(r),v=w[e];",k=0;7>k;k++)u+="m='"+t.g[k]+"';if((!(p&&v[m])&&l.call(r,m))",t.i||(u+="||(!v[m]&&r[m]!==y[m])"),u+="){"+t.f+"}";u+="}"}return(t.b||V.nonEnumArgs)&&(u+="}"),u+=t.c+";return C",r=r("i,j,l,n,o,q,t,u,y,z,w,G,H,J",e+u+"}"),n(t),r(E,F,q,a,Q,l,W,o,z,A,L,S,D,$)}function a(t){return $.call(t)==v
|
|
}function c(t,n,u,i,l,s){var p=u===h;if(typeof u=="function"&&!p){u=o.createCallback(u,i,2);var g=u(t,n);if(typeof g!="undefined")return!!g}if(t===n)return 0!==t||1/t==1/n;var y=typeof t,b=typeof n;if(t===t&&(!t||"function"!=y&&"object"!=y)&&(!n||"function"!=b&&"object"!=b))return!1;if(null==t||null==n)return t===n;if(b=$.call(t),y=$.call(n),b==v&&(b=x),y==v&&(y=x),b!=y)return!1;switch(b){case O:case C:return+t==+n;case _:return t!=+t?n!=+n:0==t?1/t==1/n:t==+n;case w:case S:return t==n+""}if(y=b==j,!y){if(q.call(t,"__wrapped__")||q.call(n,"__wrapped__"))return c(t.__wrapped__||t,n.__wrapped__||n,u,i,l,s);
|
|
if(b!=x||!V.nodeClass&&(r(t)||r(n)))return!1;var b=!V.argsObject&&a(t)?Object:t.constructor,d=!V.argsObject&&a(n)?Object:n.constructor;if(b!=d&&(!f(b)||!(b instanceof b&&f(d)&&d instanceof d)))return!1}for(d=!l,l||(l=m.pop()||[]),s||(s=m.pop()||[]),b=l.length;b--;)if(l[b]==t)return s[b]==n;var E=0,g=!0;if(l.push(t),s.push(n),y){if(b=t.length,E=n.length,g=E==t.length,!g&&!p)return g;for(;E--;)if(y=b,d=n[E],p)for(;y--&&!(g=c(t[y],d,u,i,l,s)););else if(!(g=c(t[E],d,u,i,l,s)))break;return g}return Y(n,function(r,e,n){return q.call(n,e)?(E++,g=q.call(t,e)&&c(t[e],r,u,i,l,s)):void 0
|
|
}),g&&!p&&Y(t,function(t,r,e){return q.call(e,r)?g=-1<--E:void 0}),d&&(e(l),e(s)),g}function f(t){return typeof t=="function"}function i(t){return!(!t||!A[typeof t])}function l(t){return typeof t=="string"||$.call(t)==S}function s(t,r,e){if(r&&typeof e=="undefined"&&Q(t)){e=-1;for(var n=t.length;++e<n&&false!==r(t[e],e,t););}else X(t,r,e);return t}function p(t){return t}var m=[],g=[],h={},y=40,b=(b=/\bthis\b/)&&b.test(function(){return this})&&b,d="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),v="[object Arguments]",j="[object Array]",O="[object Boolean]",C="[object Date]",E="[object Error]",_="[object Number]",x="[object Object]",w="[object RegExp]",S="[object String]",A={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},P=A[typeof exports]&&exports,I=A[typeof module]&&module&&module.exports==P&&module,B=A[typeof global]&&global;
|
|
!B||B.global!==B&&B.window!==B||(t=B);var F=Error.prototype,z=Object.prototype,D=String.prototype,B=RegExp("^"+(z.valueOf+"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),N=Function.prototype.toString,q=z.hasOwnProperty,R=z.propertyIsEnumerable,$=z.toString,M=B.test(M=$.bind)&&M,T=B.test(T=Object.create)&&T,G=B.test(G=Array.isArray)&&G,H=B.test(H=Object.keys)&&H,T=B.test(t.attachEvent),J=M&&!/\n|true/.test(M+T),L={};L[j]=L[C]=L[_]={constructor:!0,toLocaleString:!0,toString:!0,valueOf:!0},L[O]=L[S]={constructor:!0,toString:!0,valueOf:!0},L[E]=L["[object Function]"]=L[w]={constructor:!0,toString:!0},L[x]={constructor:!0},function(){for(var t=d.length;t--;){var r,e=d[t];
|
|
for(r in L)q.call(L,r)&&!q.call(L[r],e)&&(L[r][e]=!1)}}();var V=o.support={};!function(){var t=function(){this.x=1},r=[];t.prototype={valueOf:1,y:1};for(var e in new t)r.push(e);for(e in arguments);V.argsObject=arguments.constructor==Object&&!(arguments instanceof Array),V.argsClass=a(arguments),V.enumErrorProps=R.call(F,"message")||R.call(F,"name"),V.enumPrototypes=R.call(t,"prototype"),V.fastBind=M&&!J,V.nonEnumArgs=0!=e,V.nonEnumShadows=!/valueOf/.test(r),V.unindexedChars="xx"!="x"[0]+Object("x")[0];
|
|
try{V.nodeClass=!($.call(document)==x&&!({toString:0}+""))}catch(n){V.nodeClass=!0}}(1);var K={a:"x,F,k",h:"var a=arguments,b=0,c=typeof k=='number'?2:a.length;while(++b<c){r=a[b];if(r&&z[typeof r]){",f:"if(typeof C[m]=='undefined')C[m]=r[m]",c:"}}"},T={a:"f,d,I",h:"d=d&&typeof I=='undefined'?d:u.createCallback(d,I)",b:"typeof s=='number'",f:"if(d(r[m],m,f)===false)return C"},B={h:"if(!z[typeof r])return C;"+T.h,b:!1};V.argsClass||(a=function(t){return t?q.call(t,"callee"):!1});var Q=G||function(t){return t?typeof t=="object"&&$.call(t)==j:!1
|
|
},U=u({a:"x",e:"[]",h:"if(!(z[typeof x]))return C",f:"C.push(m)"}),W=H?function(t){return i(t)?V.enumPrototypes&&typeof t=="function"||V.nonEnumArgs&&t.length&&a(t)?U(t):H(t):[]}:U,X=u(T),G=u(K,{h:K.h.replace(";",";if(c>3&&typeof a[c-2]=='function'){var d=u.createCallback(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){d=a[--c]}"),f:"C[m]=d?d(C[m],r[m]):r[m]"}),Y=u(T,B,{i:!1});f(/x/)&&(f=function(t){return typeof t=="function"&&"[object Function]"==$.call(t)}),o.assign=G,o.createCallback=function(t,r,e){if(null==t)return p;
|
|
var n=typeof t;if("function"!=n){if("object"!=n)return function(r){return r[t]};var o=W(t);return function(r){for(var e=o.length,n=!1;e--&&(n=c(r[o[e]],t[o[e]],h)););return n}}return typeof r=="undefined"||b&&!b.test(N.call(t))?t:1===e?function(e){return t.call(r,e)}:2===e?function(e,n){return t.call(r,e,n)}:4===e?function(e,n,o,u){return t.call(r,e,n,o,u)}:function(e,n,o){return t.call(r,e,n,o)}},o.forEach=s,o.forIn=Y,o.keys=W,o.each=s,o.extend=G,o.identity=p,o.isArguments=a,o.isArray=Q,o.isEqual=c,o.isFunction=f,o.isObject=i,o.isString=l,o.VERSION="1.3.1",typeof define=="function"&&typeof define.amd=="object"&&define.amd?(t._=o, define(function(){return o
|
|
})):P&&!P.nodeType?I?(I.exports=o)._=o:P._=o:t._=o}(this);
|
|
},{}],74:[function(require,module,exports){
|
|
var _ = require('lodash');
|
|
var serializer = new XMLSerializer();
|
|
var XML_NS = 'http://www.w3.org/XML/1998/namespace';
|
|
var TOP_LEVEL_LOOKUP = {};
|
|
var LOOKUP = {};
|
|
var LOOKUP_EXT = {};
|
|
|
|
|
|
var find = exports.find = function (xml, NS, selector) {
|
|
var children = xml.querySelectorAll(selector);
|
|
return _.filter(children, function (child) {
|
|
return child.namespaceURI === NS && child.parentNode == xml;
|
|
});
|
|
};
|
|
|
|
exports.findOrCreate = function (xml, NS, selector) {
|
|
var existing = find(xml, NS, selector);
|
|
if (existing.length) {
|
|
return existing[0];
|
|
} else {
|
|
var created = document.createElementNS(NS, selector);
|
|
xml.appendChild(created);
|
|
return created;
|
|
}
|
|
};
|
|
|
|
exports.init = function (self, xml, data, parentNS) {
|
|
self.xml = xml || document.createElementNS(self.NS, self.EL);
|
|
if (parentNS && parentNS !== self.NS || !self.xml.parentNode || self.xml.parentNode.namespaceURI !== self.NS) {
|
|
self.xml.setAttribute('xmlns', self.NS);
|
|
}
|
|
|
|
self._extensions = {};
|
|
_.each(self.xml.childNodes, function (child) {
|
|
var childName = child.namespaceURI + '|' + child.localName;
|
|
var ChildJXT = LOOKUP[childName];
|
|
if (ChildJXT !== undefined) {
|
|
var name = ChildJXT.prototype._name;
|
|
self._extensions[name] = new ChildJXT(null, child);
|
|
self._extensions[name].parent = self;
|
|
}
|
|
});
|
|
|
|
_.extend(self, data);
|
|
return self;
|
|
};
|
|
|
|
exports.getSubText = function (xml, NS, element) {
|
|
var subs = find(xml, NS, element);
|
|
if (!subs) {
|
|
return '';
|
|
}
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
return subs[i].textContent || '';
|
|
}
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
exports.getMultiSubText = function (xml, NS, element, extractor) {
|
|
var subs = find(xml, NS, element);
|
|
var results = [];
|
|
extractor = extractor || function (sub) {
|
|
return sub.textContent || '';
|
|
};
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
results.push(extractor(subs[i]));
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
exports.getSubLangText = function (xml, NS, element, defaultLang) {
|
|
var subs = find(xml, NS, element);
|
|
if (!subs) {
|
|
return {};
|
|
}
|
|
|
|
var lang, sub;
|
|
var results = {};
|
|
var langs = [];
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
sub = subs[i];
|
|
if (sub.namespaceURI === NS) {
|
|
lang = sub.getAttributeNS(XML_NS, 'lang') || defaultLang;
|
|
langs.push(lang);
|
|
results[lang] = sub.textContent || '';
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
|
|
exports.setSubText = function (xml, NS, element, value) {
|
|
var subs = find(xml, NS, element);
|
|
if (!subs.length) {
|
|
if (value) {
|
|
var sub = document.createElementNS(NS, element);
|
|
sub.textContent = value;
|
|
xml.appendChild(sub);
|
|
}
|
|
} else {
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
if (value) {
|
|
subs[i].textContent = value;
|
|
return;
|
|
} else {
|
|
xml.removeChild(subs[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.setMultiSubText = function (xml, NS, element, value, builder) {
|
|
var subs = find(xml, NS, element);
|
|
var values = [];
|
|
builder = builder || function (value) {
|
|
var sub = document.createElementNS(NS, element);
|
|
sub.textContent = value;
|
|
xml.appendChild(sub);
|
|
};
|
|
if (typeof value === 'string') {
|
|
values = (value || '').split('\n');
|
|
} else {
|
|
values = value;
|
|
}
|
|
_.forEach(subs, function (sub) {
|
|
xml.removeChild(sub);
|
|
});
|
|
_.forEach(values, function (val) {
|
|
if (val) {
|
|
builder(val);
|
|
}
|
|
});
|
|
};
|
|
|
|
exports.setSubLangText = function (xml, NS, element, value, defaultLang) {
|
|
var sub, lang;
|
|
var subs = find(xml, NS, element);
|
|
if (subs.length) {
|
|
for (var i = 0; i < subs.length; i++) {
|
|
sub = subs[i];
|
|
if (sub.namespaceURI === NS) {
|
|
xml.removeChild(sub);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof value === 'string') {
|
|
sub = document.createElementNS(NS, element);
|
|
sub.textContent = value;
|
|
xml.appendChild(sub);
|
|
} else if (typeof value === 'object') {
|
|
for (lang in value) {
|
|
if (value.hasOwnProperty(lang)) {
|
|
sub = document.createElementNS(NS, element);
|
|
if (lang !== defaultLang) {
|
|
sub.setAttributeNS(XML_NS, 'lang', lang);
|
|
}
|
|
sub.textContent = value[lang];
|
|
xml.appendChild(sub);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.getAttribute = function (xml, attr, defaultVal) {
|
|
return xml.getAttribute(attr) || defaultVal || '';
|
|
};
|
|
|
|
exports.setAttribute = function (xml, attr, value, force) {
|
|
if (value || force) {
|
|
xml.setAttribute(attr, value);
|
|
} else {
|
|
xml.removeAttribute(attr);
|
|
}
|
|
};
|
|
|
|
exports.getBoolAttribute = function (xml, attr, defaultVal) {
|
|
var val = xml.getAttribute(attr) || defaultVal || '';
|
|
return val === 'true' || val === '1';
|
|
};
|
|
|
|
exports.setBoolAttribute = function (xml, attr, value) {
|
|
if (value) {
|
|
xml.setAttribute(attr, '1');
|
|
} else {
|
|
xml.removeAttribute(attr);
|
|
}
|
|
};
|
|
|
|
exports.getSubAttribute = function (xml, NS, sub, attr, defaultVal) {
|
|
var subs = find(xml, NS, sub);
|
|
if (!subs) {
|
|
return '';
|
|
}
|
|
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
return subs[i].getAttribute(attr) || defaultVal || '';
|
|
}
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
exports.setSubAttribute = function (xml, NS, sub, attr, value) {
|
|
var subs = find(xml, NS, sub);
|
|
if (!subs.length) {
|
|
if (value) {
|
|
sub = document.createElementNS(NS, sub);
|
|
sub.setAttribute(attr, value);
|
|
xml.appendChild(sub);
|
|
}
|
|
} else {
|
|
for (var i = 0; i < subs.length; i++) {
|
|
if (subs[i].namespaceURI === NS) {
|
|
if (value) {
|
|
subs[i].setAttribute(attr, value);
|
|
return;
|
|
} else {
|
|
subs[i].removeAttribute(attr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.toString = function () {
|
|
return serializer.serializeToString(this.xml);
|
|
};
|
|
|
|
exports.toJSON = function () {
|
|
var prop;
|
|
var result = {};
|
|
var exclude = {
|
|
constructor: true,
|
|
NS: true,
|
|
EL: true,
|
|
toString: true,
|
|
toJSON: true,
|
|
_extensions: true,
|
|
prototype: true,
|
|
xml: true,
|
|
parent: true,
|
|
_name: true
|
|
};
|
|
for (prop in this._extensions) {
|
|
if (this._extensions[prop].toJSON) {
|
|
result[prop] = this._extensions[prop].toJSON();
|
|
}
|
|
}
|
|
for (prop in this) {
|
|
if (!exclude[prop] && !((LOOKUP_EXT[this.NS + '|' + this.EL] || {})[prop]) && !this._extensions[prop] && prop[0] !== '_') {
|
|
var val = this[prop];
|
|
if (typeof val == 'function') continue;
|
|
var type = Object.prototype.toString.call(val);
|
|
if (type.indexOf('Object') >= 0) {
|
|
if (Object.keys(val).length > 0) {
|
|
result[prop] = val;
|
|
}
|
|
} else if (type.indexOf('Array') >= 0) {
|
|
if (val.length > 0) {
|
|
result[prop] = val;
|
|
}
|
|
} else if (!!val) {
|
|
result[prop] = val;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
exports.extend = function (ParentJXT, ChildJXT) {
|
|
var parentName = ParentJXT.prototype.NS + '|' + ParentJXT.prototype.EL;
|
|
var name = ChildJXT.prototype._name;
|
|
var qName = ChildJXT.prototype.NS + '|' + ChildJXT.prototype.EL;
|
|
|
|
LOOKUP[qName] = ChildJXT;
|
|
if (!LOOKUP_EXT[qName]) {
|
|
LOOKUP_EXT[qName] = {};
|
|
}
|
|
if (!LOOKUP_EXT[parentName]) {
|
|
LOOKUP_EXT[parentName] = {};
|
|
}
|
|
LOOKUP_EXT[parentName][name] = ChildJXT;
|
|
|
|
ParentJXT.prototype.__defineGetter__(name, function () {
|
|
if (!this._extensions[name]) {
|
|
var existing = exports.find(this.xml, ChildJXT.prototype.NS, ChildJXT.prototype.EL);
|
|
if (!existing.length) {
|
|
this._extensions[name] = new ChildJXT();
|
|
this.xml.appendChild(this._extensions[name].xml);
|
|
} else {
|
|
this._extensions[name] = new ChildJXT(null, existing[0]);
|
|
}
|
|
this._extensions[name].parent = this;
|
|
}
|
|
return this._extensions[name];
|
|
});
|
|
ParentJXT.prototype.__defineSetter__(name, function (value) {
|
|
var child = this[name];
|
|
_.extend(child, value);
|
|
});
|
|
};
|
|
|
|
exports.topLevel = function (JXT) {
|
|
var name = JXT.prototype.NS + '|' + JXT.prototype.EL;
|
|
LOOKUP[name] = JXT;
|
|
TOP_LEVEL_LOOKUP[name] = JXT;
|
|
};
|
|
|
|
exports.build = function (xml) {
|
|
var JXT = TOP_LEVEL_LOOKUP[xml.namespaceURI + '|' + xml.localName];
|
|
if (JXT) {
|
|
return new JXT(null, xml);
|
|
}
|
|
};
|
|
|
|
exports.XML_NS = XML_NS;
|
|
exports.TOP_LEVEL_LOOKUP = TOP_LEVEL_LOOKUP;
|
|
exports.LOOKUP_EXT = LOOKUP_EXT;
|
|
exports.LOOKUP = LOOKUP;
|
|
|
|
},{"lodash":75}],75:[function(require,module,exports){
|
|
var global=self;/**
|
|
* @license
|
|
* Lo-Dash 1.0.1 (Custom Build) <http://lodash.com/>
|
|
* Build: `lodash modern -o ./dist/lodash.js`
|
|
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
|
|
* Based on Underscore.js 1.4.4 <http://underscorejs.org/>
|
|
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
|
* Available under MIT license <http://lodash.com/license>
|
|
*/
|
|
;(function(window, undefined) {
|
|
|
|
/** Detect free variable `exports` */
|
|
var freeExports = typeof exports == 'object' && exports;
|
|
|
|
/** Detect free variable `module` */
|
|
var freeModule = typeof module == 'object' && module && module.exports == freeExports && module;
|
|
|
|
/** Detect free variable `global` and use it as `window` */
|
|
var freeGlobal = typeof global == 'object' && global;
|
|
if (freeGlobal.global === freeGlobal) {
|
|
window = freeGlobal;
|
|
}
|
|
|
|
/** Used for array and object method references */
|
|
var arrayRef = [],
|
|
objectRef = {};
|
|
|
|
/** Used to generate unique IDs */
|
|
var idCounter = 0;
|
|
|
|
/** Used internally to indicate various things */
|
|
var indicatorObject = objectRef;
|
|
|
|
/** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */
|
|
var largeArraySize = 30;
|
|
|
|
/** Used to restore the original `_` reference in `noConflict` */
|
|
var oldDash = window._;
|
|
|
|
/** Used to match HTML entities */
|
|
var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g;
|
|
|
|
/** Used to match empty string literals in compiled template source */
|
|
var reEmptyStringLeading = /\b__p \+= '';/g,
|
|
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
|
|
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
|
|
|
|
/** Used to match regexp flags from their coerced string values */
|
|
var reFlags = /\w*$/;
|
|
|
|
/** Used to detect if a method is native */
|
|
var reNative = RegExp('^' +
|
|
(objectRef.valueOf + '')
|
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
.replace(/valueOf|for [^\]]+/g, '.+?') + '$'
|
|
);
|
|
|
|
/**
|
|
* Used to match ES6 template delimiters
|
|
* http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
|
|
*/
|
|
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
|
|
|
|
/** Used to match "interpolate" template delimiters */
|
|
var reInterpolate = /<%=([\s\S]+?)%>/g;
|
|
|
|
/** Used to ensure capturing order of template delimiters */
|
|
var reNoMatch = /($^)/;
|
|
|
|
/** Used to match HTML characters */
|
|
var reUnescapedHtml = /[&<>"']/g;
|
|
|
|
/** Used to match unescaped characters in compiled string literals */
|
|
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
|
|
|
|
/** Used to make template sourceURLs easier to identify */
|
|
var templateCounter = 0;
|
|
|
|
/** Native method shortcuts */
|
|
var ceil = Math.ceil,
|
|
concat = arrayRef.concat,
|
|
floor = Math.floor,
|
|
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
|
|
hasOwnProperty = objectRef.hasOwnProperty,
|
|
push = arrayRef.push,
|
|
toString = objectRef.toString;
|
|
|
|
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
|
var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind,
|
|
nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
|
|
nativeIsFinite = window.isFinite,
|
|
nativeIsNaN = window.isNaN,
|
|
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
|
|
nativeMax = Math.max,
|
|
nativeMin = Math.min,
|
|
nativeRandom = Math.random;
|
|
|
|
/** `Object#toString` result shortcuts */
|
|
var argsClass = '[object Arguments]',
|
|
arrayClass = '[object Array]',
|
|
boolClass = '[object Boolean]',
|
|
dateClass = '[object Date]',
|
|
funcClass = '[object Function]',
|
|
numberClass = '[object Number]',
|
|
objectClass = '[object Object]',
|
|
regexpClass = '[object RegExp]',
|
|
stringClass = '[object String]';
|
|
|
|
/** Detect various environments */
|
|
var isIeOpera = !!window.attachEvent,
|
|
isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera);
|
|
|
|
/* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */
|
|
var isBindFast = nativeBind && !isV8;
|
|
|
|
/* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */
|
|
var isKeysFast = nativeKeys && (isIeOpera || isV8);
|
|
|
|
/** Used to identify object classifications that `_.clone` supports */
|
|
var cloneableClasses = {};
|
|
cloneableClasses[funcClass] = false;
|
|
cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
|
|
cloneableClasses[boolClass] = cloneableClasses[dateClass] =
|
|
cloneableClasses[numberClass] = cloneableClasses[objectClass] =
|
|
cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
|
|
|
|
/** Used to lookup a built-in constructor by [[Class]] */
|
|
var ctorByClass = {};
|
|
ctorByClass[arrayClass] = Array;
|
|
ctorByClass[boolClass] = Boolean;
|
|
ctorByClass[dateClass] = Date;
|
|
ctorByClass[objectClass] = Object;
|
|
ctorByClass[numberClass] = Number;
|
|
ctorByClass[regexpClass] = RegExp;
|
|
ctorByClass[stringClass] = String;
|
|
|
|
/** Used to determine if values are of the language type Object */
|
|
var objectTypes = {
|
|
'boolean': false,
|
|
'function': true,
|
|
'object': true,
|
|
'number': false,
|
|
'string': false,
|
|
'undefined': false
|
|
};
|
|
|
|
/** Used to escape characters for inclusion in compiled string literals */
|
|
var stringEscapes = {
|
|
'\\': '\\',
|
|
"'": "'",
|
|
'\n': 'n',
|
|
'\r': 'r',
|
|
'\t': 't',
|
|
'\u2028': 'u2028',
|
|
'\u2029': 'u2029'
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a `lodash` object, that wraps the given `value`, to enable method
|
|
* chaining.
|
|
*
|
|
* In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
|
|
* `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
|
|
* and `unshift`
|
|
*
|
|
* The chainable wrapper functions are:
|
|
* `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`,
|
|
* `concat`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
|
|
* `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`,
|
|
* `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`,
|
|
* `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `partialRight`,
|
|
* `pick`, `pluck`, `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`,
|
|
* `slice`, `sort`, `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`,
|
|
* `union`, `uniq`, `unshift`, `values`, `where`, `without`, `wrap`, and `zip`
|
|
*
|
|
* The non-chainable wrapper functions are:
|
|
* `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, `identity`,
|
|
* `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`,
|
|
* `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`,
|
|
* `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`,
|
|
* `mixin`, `noConflict`, `pop`, `random`, `reduce`, `reduceRight`, `result`,
|
|
* `shift`, `size`, `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId`
|
|
*
|
|
* The wrapper functions `first` and `last` return wrapped values when `n` is
|
|
* passed, otherwise they return unwrapped values.
|
|
*
|
|
* @name _
|
|
* @constructor
|
|
* @category Chaining
|
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
|
* @returns {Object} Returns a `lodash` instance.
|
|
*/
|
|
function lodash(value) {
|
|
// exit early if already wrapped, even if wrapped by a different `lodash` constructor
|
|
if (value && typeof value == 'object' && value.__wrapped__) {
|
|
return value;
|
|
}
|
|
// allow invoking `lodash` without the `new` operator
|
|
if (!(this instanceof lodash)) {
|
|
return new lodash(value);
|
|
}
|
|
this.__wrapped__ = value;
|
|
}
|
|
|
|
/**
|
|
* By default, the template delimiters used by Lo-Dash are similar to those in
|
|
* embedded Ruby (ERB). Change the following template settings to use alternative
|
|
* delimiters.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Object
|
|
*/
|
|
lodash.templateSettings = {
|
|
|
|
/**
|
|
* Used to detect `data` property values to be HTML-escaped.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'escape': /<%-([\s\S]+?)%>/g,
|
|
|
|
/**
|
|
* Used to detect code to be evaluated.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'evaluate': /<%([\s\S]+?)%>/g,
|
|
|
|
/**
|
|
* Used to detect `data` property values to inject.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'interpolate': reInterpolate,
|
|
|
|
/**
|
|
* Used to reference the data object in the template text.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type String
|
|
*/
|
|
'variable': '',
|
|
|
|
/**
|
|
* Used to import variables into the compiled template.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type Object
|
|
*/
|
|
'imports': {
|
|
|
|
/**
|
|
* A reference to the `lodash` function.
|
|
*
|
|
* @memberOf _.templateSettings.imports
|
|
* @type Function
|
|
*/
|
|
'_': lodash
|
|
}
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* The template used to create iterator functions.
|
|
*
|
|
* @private
|
|
* @param {Obect} data The data object used to populate the text.
|
|
* @returns {String} Returns the interpolated text.
|
|
*/
|
|
var iteratorTemplate = function(obj) {
|
|
|
|
var __p = 'var index, iterable = ' +
|
|
(obj.firstArg ) +
|
|
', result = iterable;\nif (!iterable) return result;\n' +
|
|
(obj.top ) +
|
|
';\n';
|
|
if (obj.arrays) {
|
|
__p += 'var length = iterable.length; index = -1;\nif (' +
|
|
(obj.arrays ) +
|
|
') {\n while (++index < length) {\n ' +
|
|
(obj.loop ) +
|
|
'\n }\n}\nelse { ';
|
|
} ;
|
|
|
|
if (obj.isKeysFast && obj.useHas) {
|
|
__p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] ? nativeKeys(iterable) : [],\n length = ownProps.length;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n ' +
|
|
(obj.loop ) +
|
|
'\n } ';
|
|
} else {
|
|
__p += '\n for (index in iterable) {';
|
|
if (obj.useHas) {
|
|
__p += '\n if (';
|
|
if (obj.useHas) {
|
|
__p += 'hasOwnProperty.call(iterable, index)';
|
|
} ;
|
|
__p += ') { ';
|
|
} ;
|
|
__p +=
|
|
(obj.loop ) +
|
|
'; ';
|
|
if (obj.useHas) {
|
|
__p += '\n }';
|
|
} ;
|
|
__p += '\n } ';
|
|
} ;
|
|
|
|
if (obj.arrays) {
|
|
__p += '\n}';
|
|
} ;
|
|
__p +=
|
|
(obj.bottom ) +
|
|
';\nreturn result';
|
|
|
|
|
|
return __p
|
|
};
|
|
|
|
/** Reusable iterator options for `assign` and `defaults` */
|
|
var defaultsIteratorOptions = {
|
|
'args': 'object, source, guard',
|
|
'top':
|
|
'var args = arguments,\n' +
|
|
' argsIndex = 0,\n' +
|
|
" argsLength = typeof guard == 'number' ? 2 : args.length;\n" +
|
|
'while (++argsIndex < argsLength) {\n' +
|
|
' iterable = args[argsIndex];\n' +
|
|
' if (iterable && objectTypes[typeof iterable]) {',
|
|
'loop': "if (typeof result[index] == 'undefined') result[index] = iterable[index]",
|
|
'bottom': ' }\n}'
|
|
};
|
|
|
|
/** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */
|
|
var eachIteratorOptions = {
|
|
'args': 'collection, callback, thisArg',
|
|
'top': "callback = callback && typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg)",
|
|
'arrays': "typeof length == 'number'",
|
|
'loop': 'if (callback(iterable[index], index, collection) === false) return result'
|
|
};
|
|
|
|
/** Reusable iterator options for `forIn` and `forOwn` */
|
|
var forOwnIteratorOptions = {
|
|
'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top,
|
|
'arrays': false
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a function optimized to search large arrays for a given `value`,
|
|
* starting at `fromIndex`, using strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @private
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Number} [fromIndex=0] The index to search from.
|
|
* @param {Number} [largeSize=30] The length at which an array is considered large.
|
|
* @returns {Boolean} Returns `true`, if `value` is found, else `false`.
|
|
*/
|
|
function cachedContains(array, fromIndex, largeSize) {
|
|
fromIndex || (fromIndex = 0);
|
|
|
|
var length = array.length,
|
|
isLarge = (length - fromIndex) >= (largeSize || largeArraySize);
|
|
|
|
if (isLarge) {
|
|
var cache = {},
|
|
index = fromIndex - 1;
|
|
|
|
while (++index < length) {
|
|
// manually coerce `value` to a string because `hasOwnProperty`, in some
|
|
// older versions of Firefox, coerces objects incorrectly
|
|
var key = array[index] + '';
|
|
(hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]);
|
|
}
|
|
}
|
|
return function(value) {
|
|
if (isLarge) {
|
|
var key = value + '';
|
|
return hasOwnProperty.call(cache, key) && indexOf(cache[key], value) > -1;
|
|
}
|
|
return indexOf(array, value, fromIndex) > -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used by `_.max` and `_.min` as the default `callback` when a given
|
|
* `collection` is a string value.
|
|
*
|
|
* @private
|
|
* @param {String} value The character to inspect.
|
|
* @returns {Number} Returns the code unit of given character.
|
|
*/
|
|
function charAtCallback(value) {
|
|
return value.charCodeAt(0);
|
|
}
|
|
|
|
/**
|
|
* Used by `sortBy` to compare transformed `collection` values, stable sorting
|
|
* them in ascending order.
|
|
*
|
|
* @private
|
|
* @param {Object} a The object to compare to `b`.
|
|
* @param {Object} b The object to compare to `a`.
|
|
* @returns {Number} Returns the sort order indicator of `1` or `-1`.
|
|
*/
|
|
function compareAscending(a, b) {
|
|
var ai = a.index,
|
|
bi = b.index;
|
|
|
|
a = a.criteria;
|
|
b = b.criteria;
|
|
|
|
// ensure a stable sort in V8 and other engines
|
|
// http://code.google.com/p/v8/issues/detail?id=90
|
|
if (a !== b) {
|
|
if (a > b || typeof a == 'undefined') {
|
|
return 1;
|
|
}
|
|
if (a < b || typeof b == 'undefined') {
|
|
return -1;
|
|
}
|
|
}
|
|
return ai < bi ? -1 : 1;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with the `this` binding
|
|
* of `thisArg` and prepends any `partialArgs` to the arguments passed to the
|
|
* bound function.
|
|
*
|
|
* @private
|
|
* @param {Function|String} func The function to bind or the method name.
|
|
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
|
* @param {Array} partialArgs An array of arguments to be partially applied.
|
|
* @param {Object} [rightIndicator] Used to indicate partially applying arguments from the right.
|
|
* @returns {Function} Returns the new bound function.
|
|
*/
|
|
function createBound(func, thisArg, partialArgs, rightIndicator) {
|
|
var isFunc = isFunction(func),
|
|
isPartial = !partialArgs,
|
|
key = thisArg;
|
|
|
|
// juggle arguments
|
|
if (isPartial) {
|
|
partialArgs = thisArg;
|
|
}
|
|
if (!isFunc) {
|
|
thisArg = func;
|
|
}
|
|
|
|
function bound() {
|
|
// `Function#bind` spec
|
|
// http://es5.github.com/#x15.3.4.5
|
|
var args = arguments,
|
|
thisBinding = isPartial ? this : thisArg;
|
|
|
|
if (!isFunc) {
|
|
func = thisArg[key];
|
|
}
|
|
if (partialArgs.length) {
|
|
args = args.length
|
|
? (args = slice(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args))
|
|
: partialArgs;
|
|
}
|
|
if (this instanceof bound) {
|
|
// ensure `new bound` is an instance of `bound` and `func`
|
|
noop.prototype = func.prototype;
|
|
thisBinding = new noop;
|
|
noop.prototype = null;
|
|
|
|
// mimic the constructor's `return` behavior
|
|
// http://es5.github.com/#x13.2.2
|
|
var result = func.apply(thisBinding, args);
|
|
return isObject(result) ? result : thisBinding;
|
|
}
|
|
return func.apply(thisBinding, args);
|
|
}
|
|
return bound;
|
|
}
|
|
|
|
/**
|
|
* Produces a callback bound to an optional `thisArg`. If `func` is a property
|
|
* name, the created callback will return the property value for a given element.
|
|
* If `func` is an object, the created callback will return `true` for elements
|
|
* that contain the equivalent object properties, otherwise it will return `false`.
|
|
*
|
|
* @private
|
|
* @param {Mixed} [func=identity] The value to convert to a callback.
|
|
* @param {Mixed} [thisArg] The `this` binding of the created callback.
|
|
* @param {Number} [argCount=3] The number of arguments the callback accepts.
|
|
* @returns {Function} Returns a callback function.
|
|
*/
|
|
function createCallback(func, thisArg, argCount) {
|
|
if (func == null) {
|
|
return identity;
|
|
}
|
|
var type = typeof func;
|
|
if (type != 'function') {
|
|
if (type != 'object') {
|
|
return function(object) {
|
|
return object[func];
|
|
};
|
|
}
|
|
var props = keys(func);
|
|
return function(object) {
|
|
var length = props.length,
|
|
result = false;
|
|
while (length--) {
|
|
if (!(result = isEqual(object[props[length]], func[props[length]], indicatorObject))) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
if (typeof thisArg != 'undefined') {
|
|
if (argCount === 1) {
|
|
return function(value) {
|
|
return func.call(thisArg, value);
|
|
};
|
|
}
|
|
if (argCount === 2) {
|
|
return function(a, b) {
|
|
return func.call(thisArg, a, b);
|
|
};
|
|
}
|
|
if (argCount === 4) {
|
|
return function(accumulator, value, index, object) {
|
|
return func.call(thisArg, accumulator, value, index, object);
|
|
};
|
|
}
|
|
return function(value, index, object) {
|
|
return func.call(thisArg, value, index, object);
|
|
};
|
|
}
|
|
return func;
|
|
}
|
|
|
|
/**
|
|
* Creates compiled iteration functions.
|
|
*
|
|
* @private
|
|
* @param {Object} [options1, options2, ...] The compile options object(s).
|
|
* arrays - A string of code to determine if the iterable is an array or array-like.
|
|
* useHas - A boolean to specify using `hasOwnProperty` checks in the object loop.
|
|
* args - A string of comma separated arguments the iteration function will accept.
|
|
* top - A string of code to execute before the iteration branches.
|
|
* loop - A string of code to execute in the object loop.
|
|
* bottom - A string of code to execute after the iteration branches.
|
|
*
|
|
* @returns {Function} Returns the compiled function.
|
|
*/
|
|
function createIterator() {
|
|
var data = {
|
|
// support properties
|
|
'isKeysFast': isKeysFast,
|
|
|
|
// iterator options
|
|
'arrays': 'isArray(iterable)',
|
|
'bottom': '',
|
|
'loop': '',
|
|
'top': '',
|
|
'useHas': true
|
|
};
|
|
|
|
// merge options into a template data object
|
|
for (var object, index = 0; object = arguments[index]; index++) {
|
|
for (var key in object) {
|
|
data[key] = object[key];
|
|
}
|
|
}
|
|
var args = data.args;
|
|
data.firstArg = /^[^,]+/.exec(args)[0];
|
|
|
|
// create the function factory
|
|
var factory = Function(
|
|
'createCallback, hasOwnProperty, isArguments, isArray, isString, ' +
|
|
'objectTypes, nativeKeys',
|
|
'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
|
|
);
|
|
// return the compiled function
|
|
return factory(
|
|
createCallback, hasOwnProperty, isArguments, isArray, isString,
|
|
objectTypes, nativeKeys
|
|
);
|
|
}
|
|
|
|
/**
|
|
* A function compiled to iterate `arguments` objects, arrays, objects, and
|
|
* strings consistenly across environments, executing the `callback` for each
|
|
* element in the `collection`. The `callback` is bound to `thisArg` and invoked
|
|
* with three arguments; (value, index|key, collection). Callbacks may exit
|
|
* iteration early by explicitly returning `false`.
|
|
*
|
|
* @private
|
|
* @type Function
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array|Object|String} Returns `collection`.
|
|
*/
|
|
var each = createIterator(eachIteratorOptions);
|
|
|
|
/**
|
|
* Used by `template` to escape characters for inclusion in compiled
|
|
* string literals.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to escape.
|
|
* @returns {String} Returns the escaped character.
|
|
*/
|
|
function escapeStringChar(match) {
|
|
return '\\' + stringEscapes[match];
|
|
}
|
|
|
|
/**
|
|
* Used by `escape` to convert characters to HTML entities.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to escape.
|
|
* @returns {String} Returns the escaped character.
|
|
*/
|
|
function escapeHtmlChar(match) {
|
|
return htmlEscapes[match];
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a DOM node in IE < 9.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`.
|
|
*/
|
|
function isNode(value) {
|
|
// IE < 9 presents DOM nodes as `Object` objects except they have `toString`
|
|
// methods that are `typeof` "string" and still can coerce nodes to strings
|
|
return typeof value.toString != 'function' && typeof (value + '') == 'string';
|
|
}
|
|
|
|
/**
|
|
* A no-operation function.
|
|
*
|
|
* @private
|
|
*/
|
|
function noop() {
|
|
// no operation performed
|
|
}
|
|
|
|
/**
|
|
* Slices the `collection` from the `start` index up to, but not including,
|
|
* the `end` index.
|
|
*
|
|
* Note: This function is used, instead of `Array#slice`, to support node lists
|
|
* in IE < 9 and to ensure dense arrays are returned.
|
|
*
|
|
* @private
|
|
* @param {Array|Object|String} collection The collection to slice.
|
|
* @param {Number} start The start index.
|
|
* @param {Number} end The end index.
|
|
* @returns {Array} Returns the new array.
|
|
*/
|
|
function slice(array, start, end) {
|
|
start || (start = 0);
|
|
if (typeof end == 'undefined') {
|
|
end = array ? array.length : 0;
|
|
}
|
|
var index = -1,
|
|
length = end - start || 0,
|
|
result = Array(length < 0 ? 0 : length);
|
|
|
|
while (++index < length) {
|
|
result[index] = array[start + index];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Used by `unescape` to convert HTML entities to characters.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to unescape.
|
|
* @returns {String} Returns the unescaped character.
|
|
*/
|
|
function unescapeHtmlChar(match) {
|
|
return htmlUnescapes[match];
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Checks if `value` is an `arguments` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an `arguments` object, else `false`.
|
|
* @example
|
|
*
|
|
* (function() { return _.isArguments(arguments); })(1, 2, 3);
|
|
* // => true
|
|
*
|
|
* _.isArguments([1, 2, 3]);
|
|
* // => false
|
|
*/
|
|
function isArguments(value) {
|
|
return toString.call(value) == argsClass;
|
|
}
|
|
|
|
/**
|
|
* Iterates over `object`'s own and inherited enumerable properties, executing
|
|
* the `callback` for each property. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments; (value, key, object). Callbacks may exit iteration
|
|
* early by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The object to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* function Dog(name) {
|
|
* this.name = name;
|
|
* }
|
|
*
|
|
* Dog.prototype.bark = function() {
|
|
* alert('Woof, woof!');
|
|
* };
|
|
*
|
|
* _.forIn(new Dog('Dagny'), function(value, key) {
|
|
* alert(key);
|
|
* });
|
|
* // => alerts 'name' and 'bark' (order is not guaranteed)
|
|
*/
|
|
var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, {
|
|
'useHas': false
|
|
});
|
|
|
|
/**
|
|
* Iterates over an object's own enumerable properties, executing the `callback`
|
|
* for each property. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, key, object). Callbacks may exit iteration early by explicitly
|
|
* returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The object to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
|
|
* alert(key);
|
|
* });
|
|
* // => alerts '0', '1', and 'length' (order is not guaranteed)
|
|
*/
|
|
var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions);
|
|
|
|
/**
|
|
* Checks if `value` is an array.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an array, else `false`.
|
|
* @example
|
|
*
|
|
* (function() { return _.isArray(arguments); })();
|
|
* // => false
|
|
*
|
|
* _.isArray([1, 2, 3]);
|
|
* // => true
|
|
*/
|
|
var isArray = nativeIsArray || function(value) {
|
|
// `instanceof` may cause a memory leak in IE 7 if `value` is a host object
|
|
// http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak
|
|
return value instanceof Array || toString.call(value) == arrayClass;
|
|
};
|
|
|
|
/**
|
|
* Creates an array composed of the own enumerable property names of `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names.
|
|
* @example
|
|
*
|
|
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => ['one', 'two', 'three'] (order is not guaranteed)
|
|
*/
|
|
var keys = !nativeKeys ? shimKeys : function(object) {
|
|
if (!isObject(object)) {
|
|
return [];
|
|
}
|
|
return nativeKeys(object);
|
|
};
|
|
|
|
/**
|
|
* A fallback implementation of `isPlainObject` that checks if a given `value`
|
|
* is an object created by the `Object` constructor, assuming objects created
|
|
* by the `Object` constructor have no inherited enumerable properties and that
|
|
* there are no `Object.prototype` extensions.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
|
|
*/
|
|
function shimIsPlainObject(value) {
|
|
// avoid non-objects and false positives for `arguments` objects
|
|
var result = false;
|
|
if (!(value && typeof value == 'object') || isArguments(value)) {
|
|
return result;
|
|
}
|
|
// check that the constructor is `Object` (i.e. `Object instanceof Object`)
|
|
var ctor = value.constructor;
|
|
if ((!isFunction(ctor)) || ctor instanceof ctor) {
|
|
// In most environments an object's own properties are iterated before
|
|
// its inherited properties. If the last iterated property is an object's
|
|
// own property then there are no inherited enumerable properties.
|
|
forIn(value, function(value, key) {
|
|
result = key;
|
|
});
|
|
return result === false || hasOwnProperty.call(value, result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* A fallback implementation of `Object.keys` that produces an array of the
|
|
* given object's own enumerable property names.
|
|
*
|
|
* @private
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names.
|
|
*/
|
|
function shimKeys(object) {
|
|
var result = [];
|
|
forOwn(object, function(value, key) {
|
|
result.push(key);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Used to convert characters to HTML entities:
|
|
*
|
|
* Though the `>` character is escaped for symmetry, characters like `>` and `/`
|
|
* don't require escaping in HTML and have no special meaning unless they're part
|
|
* of a tag or an unquoted attribute value.
|
|
* http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
|
|
*/
|
|
var htmlEscapes = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
|
|
/** Used to convert HTML entities to characters */
|
|
var htmlUnescapes = invert(htmlEscapes);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Assigns own enumerable properties of source object(s) to the destination
|
|
* object. Subsequent sources will overwrite propery assignments of previous
|
|
* sources. If a `callback` function is passed, it will be executed to produce
|
|
* the assigned values. The `callback` is bound to `thisArg` and invoked with
|
|
* two arguments; (objectValue, sourceValue).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @alias extend
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param {Function} [callback] The function to customize assigning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* _.assign({ 'name': 'moe' }, { 'age': 40 });
|
|
* // => { 'name': 'moe', 'age': 40 }
|
|
*
|
|
* var defaults = _.partialRight(_.assign, function(a, b) {
|
|
* return typeof a == 'undefined' ? b : a;
|
|
* });
|
|
*
|
|
* var food = { 'name': 'apple' };
|
|
* defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
|
* // => { 'name': 'apple', 'type': 'fruit' }
|
|
*/
|
|
var assign = createIterator(defaultsIteratorOptions, {
|
|
'top':
|
|
defaultsIteratorOptions.top.replace(';',
|
|
';\n' +
|
|
"if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" +
|
|
' var callback = createCallback(args[--argsLength - 1], args[argsLength--], 2);\n' +
|
|
"} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" +
|
|
' callback = args[--argsLength];\n' +
|
|
'}'
|
|
),
|
|
'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]'
|
|
});
|
|
|
|
/**
|
|
* Creates a clone of `value`. If `deep` is `true`, nested objects will also
|
|
* be cloned, otherwise they will be assigned by reference. If a `callback`
|
|
* function is passed, it will be executed to produce the cloned values. If
|
|
* `callback` returns `undefined`, cloning will be handled by the method instead.
|
|
* The `callback` is bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to clone.
|
|
* @param {Boolean} [deep=false] A flag to indicate a deep clone.
|
|
* @param {Function} [callback] The function to customize cloning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Array} [stackA=[]] Internally used to track traversed source objects.
|
|
* @param- {Array} [stackB=[]] Internally used to associate clones with source counterparts.
|
|
* @returns {Mixed} Returns the cloned `value`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* var shallow = _.clone(stooges);
|
|
* shallow[0] === stooges[0];
|
|
* // => true
|
|
*
|
|
* var deep = _.clone(stooges, true);
|
|
* deep[0] === stooges[0];
|
|
* // => false
|
|
*
|
|
* _.mixin({
|
|
* 'clone': _.partialRight(_.clone, function(value) {
|
|
* return _.isElement(value) ? value.cloneNode(false) : undefined;
|
|
* })
|
|
* });
|
|
*
|
|
* var clone = _.clone(document.body);
|
|
* clone.childNodes.length;
|
|
* // => 0
|
|
*/
|
|
function clone(value, deep, callback, thisArg, stackA, stackB) {
|
|
var result = value;
|
|
|
|
// allows working with "Collections" methods without using their `callback`
|
|
// argument, `index|key`, for this method's `callback`
|
|
if (typeof deep == 'function') {
|
|
thisArg = callback;
|
|
callback = deep;
|
|
deep = false;
|
|
}
|
|
if (typeof callback == 'function') {
|
|
callback = typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg, 1);
|
|
result = callback(result);
|
|
|
|
var done = typeof result != 'undefined';
|
|
if (!done) {
|
|
result = value;
|
|
}
|
|
}
|
|
// inspect [[Class]]
|
|
var isObj = isObject(result);
|
|
if (isObj) {
|
|
var className = toString.call(result);
|
|
if (!cloneableClasses[className]) {
|
|
return result;
|
|
}
|
|
var isArr = isArray(result);
|
|
}
|
|
// shallow clone
|
|
if (!isObj || !deep) {
|
|
return isObj && !done
|
|
? (isArr ? slice(result) : assign({}, result))
|
|
: result;
|
|
}
|
|
var ctor = ctorByClass[className];
|
|
switch (className) {
|
|
case boolClass:
|
|
case dateClass:
|
|
return done ? result : new ctor(+result);
|
|
|
|
case numberClass:
|
|
case stringClass:
|
|
return done ? result : new ctor(result);
|
|
|
|
case regexpClass:
|
|
return done ? result : ctor(result.source, reFlags.exec(result));
|
|
}
|
|
// check for circular references and return corresponding clone
|
|
stackA || (stackA = []);
|
|
stackB || (stackB = []);
|
|
|
|
var length = stackA.length;
|
|
while (length--) {
|
|
if (stackA[length] == value) {
|
|
return stackB[length];
|
|
}
|
|
}
|
|
// init cloned object
|
|
if (!done) {
|
|
result = isArr ? ctor(result.length) : {};
|
|
|
|
// add array properties assigned by `RegExp#exec`
|
|
if (isArr) {
|
|
if (hasOwnProperty.call(value, 'index')) {
|
|
result.index = value.index;
|
|
}
|
|
if (hasOwnProperty.call(value, 'input')) {
|
|
result.input = value.input;
|
|
}
|
|
}
|
|
}
|
|
// add the source value to the stack of traversed objects
|
|
// and associate it with its clone
|
|
stackA.push(value);
|
|
stackB.push(result);
|
|
|
|
// recursively populate clone (susceptible to call stack limits)
|
|
(isArr ? forEach : forOwn)(done ? result : value, function(objValue, key) {
|
|
result[key] = clone(objValue, deep, callback, undefined, stackA, stackB);
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a deep clone of `value`. If a `callback` function is passed, it will
|
|
* be executed to produce the cloned values. If `callback` returns the value it
|
|
* was passed, cloning will be handled by the method instead. The `callback` is
|
|
* bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* Note: This function is loosely based on the structured clone algorithm. Functions
|
|
* and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
|
|
* objects created by constructors other than `Object` are cloned to plain `Object` objects.
|
|
* See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to deep clone.
|
|
* @param {Function} [callback] The function to customize cloning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the deep cloned `value`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* var deep = _.cloneDeep(stooges);
|
|
* deep[0] === stooges[0];
|
|
* // => false
|
|
*
|
|
* var view = {
|
|
* 'label': 'docs',
|
|
* 'node': element
|
|
* };
|
|
*
|
|
* var clone = _.cloneDeep(view, function(value) {
|
|
* return _.isElement(value) ? value.cloneNode(true) : value;
|
|
* });
|
|
*
|
|
* clone.node == view.node;
|
|
* // => false
|
|
*/
|
|
function cloneDeep(value, callback, thisArg) {
|
|
return clone(value, true, callback, thisArg);
|
|
}
|
|
|
|
/**
|
|
* Assigns own enumerable properties of source object(s) to the destination
|
|
* object for all destination properties that resolve to `undefined`. Once a
|
|
* property is set, additional defaults of the same property will be ignored.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param- {Object} [guard] Internally used to allow working with `_.reduce`
|
|
* without using its callback's `key` and `object` arguments as sources.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* var food = { 'name': 'apple' };
|
|
* _.defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
|
* // => { 'name': 'apple', 'type': 'fruit' }
|
|
*/
|
|
var defaults = createIterator(defaultsIteratorOptions);
|
|
|
|
/**
|
|
* Creates a sorted array of all enumerable properties, own and inherited,
|
|
* of `object` that have function values.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias methods
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names that have function values.
|
|
* @example
|
|
*
|
|
* _.functions(_);
|
|
* // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
|
|
*/
|
|
function functions(object) {
|
|
var result = [];
|
|
forIn(object, function(value, key) {
|
|
if (isFunction(value)) {
|
|
result.push(key);
|
|
}
|
|
});
|
|
return result.sort();
|
|
}
|
|
|
|
/**
|
|
* Checks if the specified object `property` exists and is a direct property,
|
|
* instead of an inherited property.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to check.
|
|
* @param {String} property The property to check for.
|
|
* @returns {Boolean} Returns `true` if key is a direct property, else `false`.
|
|
* @example
|
|
*
|
|
* _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
|
|
* // => true
|
|
*/
|
|
function has(object, property) {
|
|
return object ? hasOwnProperty.call(object, property) : false;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of the inverted keys and values of the given `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to invert.
|
|
* @returns {Object} Returns the created inverted object.
|
|
* @example
|
|
*
|
|
* _.invert({ 'first': 'moe', 'second': 'larry' });
|
|
* // => { 'moe': 'first', 'larry': 'second' } (order is not guaranteed)
|
|
*/
|
|
function invert(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = {};
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
result[object[key]] = key;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a boolean value.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a boolean value, else `false`.
|
|
* @example
|
|
*
|
|
* _.isBoolean(null);
|
|
* // => false
|
|
*/
|
|
function isBoolean(value) {
|
|
return value === true || value === false || toString.call(value) == boolClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a date.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a date, else `false`.
|
|
* @example
|
|
*
|
|
* _.isDate(new Date);
|
|
* // => true
|
|
*/
|
|
function isDate(value) {
|
|
return value instanceof Date || toString.call(value) == dateClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a DOM element.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a DOM element, else `false`.
|
|
* @example
|
|
*
|
|
* _.isElement(document.body);
|
|
* // => true
|
|
*/
|
|
function isElement(value) {
|
|
return value ? value.nodeType === 1 : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
|
|
* length of `0` and objects with no own enumerable properties are considered
|
|
* "empty".
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Array|Object|String} value The value to inspect.
|
|
* @returns {Boolean} Returns `true`, if the `value` is empty, else `false`.
|
|
* @example
|
|
*
|
|
* _.isEmpty([1, 2, 3]);
|
|
* // => false
|
|
*
|
|
* _.isEmpty({});
|
|
* // => true
|
|
*
|
|
* _.isEmpty('');
|
|
* // => true
|
|
*/
|
|
function isEmpty(value) {
|
|
var result = true;
|
|
if (!value) {
|
|
return result;
|
|
}
|
|
var className = toString.call(value),
|
|
length = value.length;
|
|
|
|
if ((className == arrayClass || className == stringClass ||
|
|
className == argsClass) ||
|
|
(className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
|
|
return !length;
|
|
}
|
|
forOwn(value, function() {
|
|
return (result = false);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Performs a deep comparison between two values to determine if they are
|
|
* equivalent to each other. If `callback` is passed, it will be executed to
|
|
* compare values. If `callback` returns `undefined`, comparisons will be handled
|
|
* by the method instead. The `callback` is bound to `thisArg` and invoked with
|
|
* two arguments; (a, b).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} a The value to compare.
|
|
* @param {Mixed} b The other value to compare.
|
|
* @param {Function} [callback] The function to customize comparing values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Object} [stackA=[]] Internally used track traversed `a` objects.
|
|
* @param- {Object} [stackB=[]] Internally used track traversed `b` objects.
|
|
* @returns {Boolean} Returns `true`, if the values are equvalent, else `false`.
|
|
* @example
|
|
*
|
|
* var moe = { 'name': 'moe', 'age': 40 };
|
|
* var copy = { 'name': 'moe', 'age': 40 };
|
|
*
|
|
* moe == copy;
|
|
* // => false
|
|
*
|
|
* _.isEqual(moe, copy);
|
|
* // => true
|
|
*
|
|
* var words = ['hello', 'goodbye'];
|
|
* var otherWords = ['hi', 'goodbye'];
|
|
*
|
|
* _.isEqual(words, otherWords, function(a, b) {
|
|
* var reGreet = /^(?:hello|hi)$/i,
|
|
* aGreet = _.isString(a) && reGreet.test(a),
|
|
* bGreet = _.isString(b) && reGreet.test(b);
|
|
*
|
|
* return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
|
|
* });
|
|
* // => true
|
|
*/
|
|
function isEqual(a, b, callback, thisArg, stackA, stackB) {
|
|
// used to indicate that when comparing objects, `a` has at least the properties of `b`
|
|
var whereIndicator = callback === indicatorObject;
|
|
if (callback && !whereIndicator) {
|
|
callback = typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg, 2);
|
|
var result = callback(a, b);
|
|
if (typeof result != 'undefined') {
|
|
return !!result;
|
|
}
|
|
}
|
|
// exit early for identical values
|
|
if (a === b) {
|
|
// treat `+0` vs. `-0` as not equal
|
|
return a !== 0 || (1 / a == 1 / b);
|
|
}
|
|
var type = typeof a,
|
|
otherType = typeof b;
|
|
|
|
// exit early for unlike primitive values
|
|
if (a === a &&
|
|
(!a || (type != 'function' && type != 'object')) &&
|
|
(!b || (otherType != 'function' && otherType != 'object'))) {
|
|
return false;
|
|
}
|
|
// exit early for `null` and `undefined`, avoiding ES3's Function#call behavior
|
|
// http://es5.github.com/#x15.3.4.4
|
|
if (a == null || b == null) {
|
|
return a === b;
|
|
}
|
|
// compare [[Class]] names
|
|
var className = toString.call(a),
|
|
otherClass = toString.call(b);
|
|
|
|
if (className == argsClass) {
|
|
className = objectClass;
|
|
}
|
|
if (otherClass == argsClass) {
|
|
otherClass = objectClass;
|
|
}
|
|
if (className != otherClass) {
|
|
return false;
|
|
}
|
|
switch (className) {
|
|
case boolClass:
|
|
case dateClass:
|
|
// coerce dates and booleans to numbers, dates to milliseconds and booleans
|
|
// to `1` or `0`, treating invalid dates coerced to `NaN` as not equal
|
|
return +a == +b;
|
|
|
|
case numberClass:
|
|
// treat `NaN` vs. `NaN` as equal
|
|
return a != +a
|
|
? b != +b
|
|
// but treat `+0` vs. `-0` as not equal
|
|
: (a == 0 ? (1 / a == 1 / b) : a == +b);
|
|
|
|
case regexpClass:
|
|
case stringClass:
|
|
// coerce regexes to strings (http://es5.github.com/#x15.10.6.4)
|
|
// treat string primitives and their corresponding object instances as equal
|
|
return a == b + '';
|
|
}
|
|
var isArr = className == arrayClass;
|
|
if (!isArr) {
|
|
// unwrap any `lodash` wrapped values
|
|
if (a.__wrapped__ || b.__wrapped__) {
|
|
return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, thisArg, stackA, stackB);
|
|
}
|
|
// exit for functions and DOM nodes
|
|
if (className != objectClass) {
|
|
return false;
|
|
}
|
|
// in older versions of Opera, `arguments` objects have `Array` constructors
|
|
var ctorA = a.constructor,
|
|
ctorB = b.constructor;
|
|
|
|
// non `Object` object instances with different constructors are not equal
|
|
if (ctorA != ctorB && !(
|
|
isFunction(ctorA) && ctorA instanceof ctorA &&
|
|
isFunction(ctorB) && ctorB instanceof ctorB
|
|
)) {
|
|
return false;
|
|
}
|
|
}
|
|
// assume cyclic structures are equal
|
|
// the algorithm for detecting cyclic structures is adapted from ES 5.1
|
|
// section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
|
|
stackA || (stackA = []);
|
|
stackB || (stackB = []);
|
|
|
|
var length = stackA.length;
|
|
while (length--) {
|
|
if (stackA[length] == a) {
|
|
return stackB[length] == b;
|
|
}
|
|
}
|
|
var size = 0;
|
|
result = true;
|
|
|
|
// add `a` and `b` to the stack of traversed objects
|
|
stackA.push(a);
|
|
stackB.push(b);
|
|
|
|
// recursively compare objects and arrays (susceptible to call stack limits)
|
|
if (isArr) {
|
|
length = a.length;
|
|
size = b.length;
|
|
|
|
// compare lengths to determine if a deep comparison is necessary
|
|
result = size == a.length;
|
|
if (!result && !whereIndicator) {
|
|
return result;
|
|
}
|
|
// deep compare the contents, ignoring non-numeric properties
|
|
while (size--) {
|
|
var index = length,
|
|
value = b[size];
|
|
|
|
if (whereIndicator) {
|
|
while (index--) {
|
|
if ((result = isEqual(a[index], value, callback, thisArg, stackA, stackB))) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (!(result = isEqual(a[size], value, callback, thisArg, stackA, stackB))) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
|
|
// which, in this case, is more costly
|
|
forIn(b, function(value, key, b) {
|
|
if (hasOwnProperty.call(b, key)) {
|
|
// count the number of properties.
|
|
size++;
|
|
// deep compare each property value.
|
|
return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, callback, thisArg, stackA, stackB));
|
|
}
|
|
});
|
|
|
|
if (result && !whereIndicator) {
|
|
// ensure both objects have the same number of properties
|
|
forIn(a, function(value, key, a) {
|
|
if (hasOwnProperty.call(a, key)) {
|
|
// `size` will be `-1` if `a` has more properties than `b`
|
|
return (result = --size > -1);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is, or can be coerced to, a finite number.
|
|
*
|
|
* Note: This is not the same as native `isFinite`, which will return true for
|
|
* booleans and empty strings. See http://es5.github.com/#x15.1.2.5.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is finite, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFinite(-101);
|
|
* // => true
|
|
*
|
|
* _.isFinite('10');
|
|
* // => true
|
|
*
|
|
* _.isFinite(true);
|
|
* // => false
|
|
*
|
|
* _.isFinite('');
|
|
* // => false
|
|
*
|
|
* _.isFinite(Infinity);
|
|
* // => false
|
|
*/
|
|
function isFinite(value) {
|
|
return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a function, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFunction(_);
|
|
* // => true
|
|
*/
|
|
function isFunction(value) {
|
|
return typeof value == 'function';
|
|
}
|
|
// fallback for older versions of Chrome and Safari
|
|
if (isFunction(/x/)) {
|
|
isFunction = function(value) {
|
|
return value instanceof Function || toString.call(value) == funcClass;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is the language type of Object.
|
|
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an object, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObject({});
|
|
* // => true
|
|
*
|
|
* _.isObject([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObject(1);
|
|
* // => false
|
|
*/
|
|
function isObject(value) {
|
|
// check if the value is the ECMAScript language type of Object
|
|
// http://es5.github.com/#x8
|
|
// and avoid a V8 bug
|
|
// http://code.google.com/p/v8/issues/detail?id=2291
|
|
return value ? objectTypes[typeof value] : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `NaN`.
|
|
*
|
|
* Note: This is not the same as native `isNaN`, which will return `true` for
|
|
* `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `NaN`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNaN(NaN);
|
|
* // => true
|
|
*
|
|
* _.isNaN(new Number(NaN));
|
|
* // => true
|
|
*
|
|
* isNaN(undefined);
|
|
* // => true
|
|
*
|
|
* _.isNaN(undefined);
|
|
* // => false
|
|
*/
|
|
function isNaN(value) {
|
|
// `NaN` as a primitive is the only value that is not equal to itself
|
|
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
|
|
return isNumber(value) && value != +value
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `null`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `null`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNull(null);
|
|
* // => true
|
|
*
|
|
* _.isNull(undefined);
|
|
* // => false
|
|
*/
|
|
function isNull(value) {
|
|
return value === null;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a number, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNumber(8.4 * 5);
|
|
* // => true
|
|
*/
|
|
function isNumber(value) {
|
|
return typeof value == 'number' || toString.call(value) == numberClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given `value` is an object created by the `Object` constructor.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
|
|
* @example
|
|
*
|
|
* function Stooge(name, age) {
|
|
* this.name = name;
|
|
* this.age = age;
|
|
* }
|
|
*
|
|
* _.isPlainObject(new Stooge('moe', 40));
|
|
* // => false
|
|
*
|
|
* _.isPlainObject([1, 2, 3]);
|
|
* // => false
|
|
*
|
|
* _.isPlainObject({ 'name': 'moe', 'age': 40 });
|
|
* // => true
|
|
*/
|
|
var isPlainObject = function(value) {
|
|
if (!(value && typeof value == 'object')) {
|
|
return false;
|
|
}
|
|
var valueOf = value.valueOf,
|
|
objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
|
|
|
|
return objProto
|
|
? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value))
|
|
: shimIsPlainObject(value);
|
|
};
|
|
|
|
/**
|
|
* Checks if `value` is a regular expression.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a regular expression, else `false`.
|
|
* @example
|
|
*
|
|
* _.isRegExp(/moe/);
|
|
* // => true
|
|
*/
|
|
function isRegExp(value) {
|
|
return value instanceof RegExp || toString.call(value) == regexpClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a string.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a string, else `false`.
|
|
* @example
|
|
*
|
|
* _.isString('moe');
|
|
* // => true
|
|
*/
|
|
function isString(value) {
|
|
return typeof value == 'string' || toString.call(value) == stringClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `undefined`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `undefined`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isUndefined(void 0);
|
|
* // => true
|
|
*/
|
|
function isUndefined(value) {
|
|
return typeof value == 'undefined';
|
|
}
|
|
|
|
/**
|
|
* Recursively merges own enumerable properties of the source object(s), that
|
|
* don't resolve to `undefined`, into the destination object. Subsequent sources
|
|
* will overwrite propery assignments of previous sources. If a `callback` function
|
|
* is passed, it will be executed to produce the merged values of the destination
|
|
* and source properties. If `callback` returns `undefined`, merging will be
|
|
* handled by the method instead. The `callback` is bound to `thisArg` and
|
|
* invoked with two arguments; (objectValue, sourceValue).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param {Function} [callback] The function to customize merging properties.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Object} [deepIndicator] Internally used to indicate that `stackA`
|
|
* and `stackB` are arrays of traversed objects instead of source objects.
|
|
* @param- {Array} [stackA=[]] Internally used to track traversed source objects.
|
|
* @param- {Array} [stackB=[]] Internally used to associate values with their
|
|
* source counterparts.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* var names = {
|
|
* 'stooges': [
|
|
* { 'name': 'moe' },
|
|
* { 'name': 'larry' }
|
|
* ]
|
|
* };
|
|
*
|
|
* var ages = {
|
|
* 'stooges': [
|
|
* { 'age': 40 },
|
|
* { 'age': 50 }
|
|
* ]
|
|
* };
|
|
*
|
|
* _.merge(names, ages);
|
|
* // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] }
|
|
*
|
|
* var food = {
|
|
* 'fruits': ['apple'],
|
|
* 'vegetables': ['beet']
|
|
* };
|
|
*
|
|
* var otherFood = {
|
|
* 'fruits': ['banana'],
|
|
* 'vegetables': ['carrot']
|
|
* };
|
|
*
|
|
* _.merge(food, otherFood, function(a, b) {
|
|
* return _.isArray(a) ? a.concat(b) : undefined;
|
|
* });
|
|
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
|
|
*/
|
|
function merge(object, source, deepIndicator) {
|
|
var args = arguments,
|
|
index = 0,
|
|
length = 2;
|
|
|
|
if (!isObject(object)) {
|
|
return object;
|
|
}
|
|
if (deepIndicator === indicatorObject) {
|
|
var callback = args[3],
|
|
stackA = args[4],
|
|
stackB = args[5];
|
|
} else {
|
|
stackA = [];
|
|
stackB = [];
|
|
|
|
// allows working with `_.reduce` and `_.reduceRight` without
|
|
// using their `callback` arguments, `index|key` and `collection`
|
|
if (typeof deepIndicator != 'number') {
|
|
length = args.length;
|
|
}
|
|
if (length > 3 && typeof args[length - 2] == 'function') {
|
|
callback = createCallback(args[--length - 1], args[length--], 2);
|
|
} else if (length > 2 && typeof args[length - 1] == 'function') {
|
|
callback = args[--length];
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
(isArray(args[index]) ? forEach : forOwn)(args[index], function(source, key) {
|
|
var found,
|
|
isArr,
|
|
result = source,
|
|
value = object[key];
|
|
|
|
if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
|
|
// avoid merging previously merged cyclic sources
|
|
var stackLength = stackA.length;
|
|
while (stackLength--) {
|
|
if ((found = stackA[stackLength] == source)) {
|
|
value = stackB[stackLength];
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
value = isArr
|
|
? (isArray(value) ? value : [])
|
|
: (isPlainObject(value) ? value : {});
|
|
|
|
if (callback) {
|
|
result = callback(value, source);
|
|
if (typeof result != 'undefined') {
|
|
value = result;
|
|
}
|
|
}
|
|
// add `source` and associated `value` to the stack of traversed objects
|
|
stackA.push(source);
|
|
stackB.push(value);
|
|
|
|
// recursively merge objects and arrays (susceptible to call stack limits)
|
|
if (!callback) {
|
|
value = merge(value, source, indicatorObject, callback, stackA, stackB);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (callback) {
|
|
result = callback(value, source);
|
|
if (typeof result == 'undefined') {
|
|
result = source;
|
|
}
|
|
}
|
|
if (typeof result != 'undefined') {
|
|
value = result;
|
|
}
|
|
}
|
|
object[key] = value;
|
|
});
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Creates a shallow clone of `object` excluding the specified properties.
|
|
* Property names may be specified as individual arguments or as arrays of
|
|
* property names. If a `callback` function is passed, it will be executed
|
|
* for each property in the `object`, omitting the properties `callback`
|
|
* returns truthy for. The `callback` is bound to `thisArg` and invoked
|
|
* with three arguments; (value, key, object).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The source object.
|
|
* @param {Function|String} callback|[prop1, prop2, ...] The properties to omit
|
|
* or the function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns an object without the omitted properties.
|
|
* @example
|
|
*
|
|
* _.omit({ 'name': 'moe', 'age': 40 }, 'age');
|
|
* // => { 'name': 'moe' }
|
|
*
|
|
* _.omit({ 'name': 'moe', 'age': 40 }, function(value) {
|
|
* return typeof value == 'number';
|
|
* });
|
|
* // => { 'name': 'moe' }
|
|
*/
|
|
function omit(object, callback, thisArg) {
|
|
var isFunc = typeof callback == 'function',
|
|
result = {};
|
|
|
|
if (isFunc) {
|
|
callback = createCallback(callback, thisArg);
|
|
} else {
|
|
var props = concat.apply(arrayRef, arguments);
|
|
}
|
|
forIn(object, function(value, key, object) {
|
|
if (isFunc
|
|
? !callback(value, key, object)
|
|
: indexOf(props, key, 1) < 0
|
|
) {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a two dimensional array of the given object's key-value pairs,
|
|
* i.e. `[[key1, value1], [key2, value2]]`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns new array of key-value pairs.
|
|
* @example
|
|
*
|
|
* _.pairs({ 'moe': 30, 'larry': 40 });
|
|
* // => [['moe', 30], ['larry', 40]] (order is not guaranteed)
|
|
*/
|
|
function pairs(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
result[index] = [key, object[key]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a shallow clone of `object` composed of the specified properties.
|
|
* Property names may be specified as individual arguments or as arrays of property
|
|
* names. If `callback` is passed, it will be executed for each property in the
|
|
* `object`, picking the properties `callback` returns truthy for. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, key, object).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The source object.
|
|
* @param {Array|Function|String} callback|[prop1, prop2, ...] The function called
|
|
* per iteration or properties to pick, either as individual arguments or arrays.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns an object composed of the picked properties.
|
|
* @example
|
|
*
|
|
* _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name');
|
|
* // => { 'name': 'moe' }
|
|
*
|
|
* _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) {
|
|
* return key.charAt(0) != '_';
|
|
* });
|
|
* // => { 'name': 'moe' }
|
|
*/
|
|
function pick(object, callback, thisArg) {
|
|
var result = {};
|
|
if (typeof callback != 'function') {
|
|
var index = 0,
|
|
props = concat.apply(arrayRef, arguments),
|
|
length = isObject(object) ? props.length : 0;
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
if (key in object) {
|
|
result[key] = object[key];
|
|
}
|
|
}
|
|
} else {
|
|
callback = createCallback(callback, thisArg);
|
|
forIn(object, function(value, key, object) {
|
|
if (callback(value, key, object)) {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array composed of the own enumerable property values of `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property values.
|
|
* @example
|
|
*
|
|
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function values(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = object[props[index]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates an array of elements from the specified indexes, or keys, of the
|
|
* `collection`. Indexes may be specified as individual arguments or as arrays
|
|
* of indexes.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Array|Number|String} [index1, index2, ...] The indexes of
|
|
* `collection` to retrieve, either as individual arguments or arrays.
|
|
* @returns {Array} Returns a new array of elements corresponding to the
|
|
* provided indexes.
|
|
* @example
|
|
*
|
|
* _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
|
|
* // => ['a', 'c', 'e']
|
|
*
|
|
* _.at(['moe', 'larry', 'curly'], 0, 2);
|
|
* // => ['moe', 'curly']
|
|
*/
|
|
function at(collection) {
|
|
var index = -1,
|
|
props = concat.apply(arrayRef, slice(arguments, 1)),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while(++index < length) {
|
|
result[index] = collection[props[index]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given `target` element is present in a `collection` using strict
|
|
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
|
* as the offset from the end of the collection.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias include
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Mixed} target The value to check for.
|
|
* @param {Number} [fromIndex=0] The index to search from.
|
|
* @returns {Boolean} Returns `true` if the `target` element is found, else `false`.
|
|
* @example
|
|
*
|
|
* _.contains([1, 2, 3], 1);
|
|
* // => true
|
|
*
|
|
* _.contains([1, 2, 3], 1, 2);
|
|
* // => false
|
|
*
|
|
* _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
|
|
* // => true
|
|
*
|
|
* _.contains('curly', 'ur');
|
|
* // => true
|
|
*/
|
|
function contains(collection, target, fromIndex) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = false;
|
|
|
|
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
|
|
if (typeof length == 'number') {
|
|
result = (isString(collection)
|
|
? collection.indexOf(target, fromIndex)
|
|
: indexOf(collection, target, fromIndex)
|
|
) > -1;
|
|
} else {
|
|
each(collection, function(value) {
|
|
if (++index >= fromIndex) {
|
|
return !(result = value === target);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of keys returned from running each element of the
|
|
* `collection` through the given `callback`. The corresponding value of each key
|
|
* is the number of times the key was returned by the `callback`. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the composed aggregate object.
|
|
* @example
|
|
*
|
|
* _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
|
|
* // => { '4': 1, '6': 2 }
|
|
*
|
|
* _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
|
* // => { '4': 1, '6': 2 }
|
|
*
|
|
* _.countBy(['one', 'two', 'three'], 'length');
|
|
* // => { '3': 2, '5': 1 }
|
|
*/
|
|
function countBy(collection, callback, thisArg) {
|
|
var result = {};
|
|
callback = createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, key, collection) {
|
|
key = callback(value, key, collection) + '';
|
|
(hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if the `callback` returns a truthy value for **all** elements of a
|
|
* `collection`. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias all
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Boolean} Returns `true` if all elements pass the callback check,
|
|
* else `false`.
|
|
* @example
|
|
*
|
|
* _.every([true, 1, null, 'yes'], Boolean);
|
|
* // => false
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.every(stooges, 'age');
|
|
* // => true
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.every(stooges, { 'age': 50 });
|
|
* // => false
|
|
*/
|
|
function every(collection, callback, thisArg) {
|
|
var result = true;
|
|
callback = createCallback(callback, thisArg);
|
|
|
|
if (isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
if (!(result = !!callback(collection[index], index, collection))) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
each(collection, function(value, index, collection) {
|
|
return (result = !!callback(value, index, collection));
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning an array of all elements
|
|
* the `callback` returns truthy for. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias select
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of elements that passed the callback check.
|
|
* @example
|
|
*
|
|
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => [2, 4, 6]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.filter(food, 'organic');
|
|
* // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.filter(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
|
|
*/
|
|
function filter(collection, callback, thisArg) {
|
|
var result = [];
|
|
callback = createCallback(callback, thisArg);
|
|
|
|
if (isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (callback(value, index, collection)) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
} else {
|
|
each(collection, function(value, index, collection) {
|
|
if (callback(value, index, collection)) {
|
|
result.push(value);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning the first that the `callback`
|
|
* returns truthy for. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias detect
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the element that passed the callback check,
|
|
* else `undefined`.
|
|
* @example
|
|
*
|
|
* var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => 2
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'banana', 'organic': true, 'type': 'fruit' },
|
|
* { 'name': 'beet', 'organic': false, 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* var veggie = _.find(food, { 'type': 'vegetable' });
|
|
* // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* var healthy = _.find(food, 'organic');
|
|
* // => { 'name': 'banana', 'organic': true, 'type': 'fruit' }
|
|
*/
|
|
function find(collection, callback, thisArg) {
|
|
var result;
|
|
callback = createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, index, collection) {
|
|
if (callback(value, index, collection)) {
|
|
result = value;
|
|
return false;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Iterates over a `collection`, executing the `callback` for each element in
|
|
* the `collection`. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection). Callbacks may exit iteration early
|
|
* by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias each
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array|Object|String} Returns `collection`.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).forEach(alert).join(',');
|
|
* // => alerts each number and returns '1,2,3'
|
|
*
|
|
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
|
|
* // => alerts each number value (order is not guaranteed)
|
|
*/
|
|
function forEach(collection, callback, thisArg) {
|
|
if (callback && typeof thisArg == 'undefined' && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
if (callback(collection[index], index, collection) === false) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
each(collection, callback, thisArg);
|
|
}
|
|
return collection;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of keys returned from running each element of the
|
|
* `collection` through the `callback`. The corresponding value of each key is
|
|
* an array of elements passed to `callback` that returned the key. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the composed aggregate object.
|
|
* @example
|
|
*
|
|
* _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
|
|
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
|
*
|
|
* _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
|
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.groupBy(['one', 'two', 'three'], 'length');
|
|
* // => { '3': ['one', 'two'], '5': ['three'] }
|
|
*/
|
|
function groupBy(collection, callback, thisArg) {
|
|
var result = {};
|
|
callback = createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, key, collection) {
|
|
key = callback(value, key, collection) + '';
|
|
(hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Invokes the method named by `methodName` on each element in the `collection`,
|
|
* returning an array of the results of each invoked method. Additional arguments
|
|
* will be passed to each invoked method. If `methodName` is a function, it will
|
|
* be invoked for, and `this` bound to, each element in the `collection`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|String} methodName The name of the method to invoke or
|
|
* the function invoked per iteration.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
|
|
* @returns {Array} Returns a new array of the results of each invoked method.
|
|
* @example
|
|
*
|
|
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
|
|
* // => [[1, 5, 7], [1, 2, 3]]
|
|
*
|
|
* _.invoke([123, 456], String.prototype.split, '');
|
|
* // => [['1', '2', '3'], ['4', '5', '6']]
|
|
*/
|
|
function invoke(collection, methodName) {
|
|
var args = slice(arguments, 2),
|
|
index = -1,
|
|
isFunc = typeof methodName == 'function',
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
forEach(collection, function(value) {
|
|
result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of values by running each element in the `collection`
|
|
* through the `callback`. The `callback` is bound to `thisArg` and invoked with
|
|
* three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias collect
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
|
* @example
|
|
*
|
|
* _.map([1, 2, 3], function(num) { return num * 3; });
|
|
* // => [3, 6, 9]
|
|
*
|
|
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
|
|
* // => [3, 6, 9] (order is not guaranteed)
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.map(stooges, 'name');
|
|
* // => ['moe', 'larry']
|
|
*/
|
|
function map(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
callback = createCallback(callback, thisArg);
|
|
if (isArray(collection)) {
|
|
while (++index < length) {
|
|
result[index] = callback(collection[index], index, collection);
|
|
}
|
|
} else {
|
|
each(collection, function(value, key, collection) {
|
|
result[++index] = callback(value, key, collection);
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the maximum value of an `array`. If `callback` is passed,
|
|
* it will be executed for each value in the `array` to generate the
|
|
* criterion by which the value is ranked. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the maximum value.
|
|
* @example
|
|
*
|
|
* _.max([4, 2, 8, 6]);
|
|
* // => 8
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.max(stooges, function(stooge) { return stooge.age; });
|
|
* // => { 'name': 'larry', 'age': 50 };
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.max(stooges, 'age');
|
|
* // => { 'name': 'larry', 'age': 50 };
|
|
*/
|
|
function max(collection, callback, thisArg) {
|
|
var computed = -Infinity,
|
|
result = computed;
|
|
|
|
if (!callback && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (value > result) {
|
|
result = value;
|
|
}
|
|
}
|
|
} else {
|
|
callback = !callback && isString(collection)
|
|
? charAtCallback
|
|
: createCallback(callback, thisArg);
|
|
|
|
each(collection, function(value, index, collection) {
|
|
var current = callback(value, index, collection);
|
|
if (current > computed) {
|
|
computed = current;
|
|
result = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the minimum value of an `array`. If `callback` is passed,
|
|
* it will be executed for each value in the `array` to generate the
|
|
* criterion by which the value is ranked. The `callback` is bound to `thisArg`
|
|
* and invoked with three arguments; (value, index, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the minimum value.
|
|
* @example
|
|
*
|
|
* _.min([4, 2, 8, 6]);
|
|
* // => 2
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.min(stooges, function(stooge) { return stooge.age; });
|
|
* // => { 'name': 'moe', 'age': 40 };
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.min(stooges, 'age');
|
|
* // => { 'name': 'moe', 'age': 40 };
|
|
*/
|
|
function min(collection, callback, thisArg) {
|
|
var computed = Infinity,
|
|
result = computed;
|
|
|
|
if (!callback && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (value < result) {
|
|
result = value;
|
|
}
|
|
}
|
|
} else {
|
|
callback = !callback && isString(collection)
|
|
? charAtCallback
|
|
: createCallback(callback, thisArg);
|
|
|
|
each(collection, function(value, index, collection) {
|
|
var current = callback(value, index, collection);
|
|
if (current < computed) {
|
|
computed = current;
|
|
result = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of a specified property from all elements in the `collection`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {String} property The property to pluck.
|
|
* @returns {Array} Returns a new array of property values.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.pluck(stooges, 'name');
|
|
* // => ['moe', 'larry']
|
|
*/
|
|
var pluck = map;
|
|
|
|
/**
|
|
* Reduces a `collection` to a value that is the accumulated result of running
|
|
* each element in the `collection` through the `callback`, where each successive
|
|
* `callback` execution consumes the return value of the previous execution.
|
|
* If `accumulator` is not passed, the first element of the `collection` will be
|
|
* used as the initial `accumulator` value. The `callback` is bound to `thisArg`
|
|
* and invoked with four arguments; (accumulator, value, index|key, collection).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias foldl, inject
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var sum = _.reduce([1, 2, 3], function(sum, num) {
|
|
* return sum + num;
|
|
* });
|
|
* // => 6
|
|
*
|
|
* var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
|
* result[key] = num * 3;
|
|
* return result;
|
|
* }, {});
|
|
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
|
*/
|
|
function reduce(collection, callback, accumulator, thisArg) {
|
|
var noaccum = arguments.length < 3;
|
|
callback = createCallback(callback, thisArg, 4);
|
|
|
|
if (isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
if (noaccum) {
|
|
accumulator = collection[++index];
|
|
}
|
|
while (++index < length) {
|
|
accumulator = callback(accumulator, collection[index], index, collection);
|
|
}
|
|
} else {
|
|
each(collection, function(value, index, collection) {
|
|
accumulator = noaccum
|
|
? (noaccum = false, value)
|
|
: callback(accumulator, value, index, collection)
|
|
});
|
|
}
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.reduce`, except that it iterates over a
|
|
* `collection` from right to left.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias foldr
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var list = [[0, 1], [2, 3], [4, 5]];
|
|
* var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
|
|
* // => [4, 5, 2, 3, 0, 1]
|
|
*/
|
|
function reduceRight(collection, callback, accumulator, thisArg) {
|
|
var iterable = collection,
|
|
length = collection ? collection.length : 0,
|
|
noaccum = arguments.length < 3;
|
|
|
|
if (typeof length != 'number') {
|
|
var props = keys(collection);
|
|
length = props.length;
|
|
}
|
|
callback = createCallback(callback, thisArg, 4);
|
|
forEach(collection, function(value, index, collection) {
|
|
index = props ? props[--length] : --length;
|
|
accumulator = noaccum
|
|
? (noaccum = false, iterable[index])
|
|
: callback(accumulator, iterable[index], index, collection);
|
|
});
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.filter`, this method returns the elements of a
|
|
* `collection` that `callback` does **not** return truthy for.
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of elements that did **not** pass the
|
|
* callback check.
|
|
* @example
|
|
*
|
|
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => [1, 3, 5]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.reject(food, 'organic');
|
|
* // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.reject(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
|
|
*/
|
|
function reject(collection, callback, thisArg) {
|
|
callback = createCallback(callback, thisArg);
|
|
return filter(collection, function(value, index, collection) {
|
|
return !callback(value, index, collection);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates an array of shuffled `array` values, using a version of the
|
|
* Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to shuffle.
|
|
* @returns {Array} Returns a new shuffled collection.
|
|
* @example
|
|
*
|
|
* _.shuffle([1, 2, 3, 4, 5, 6]);
|
|
* // => [4, 1, 6, 3, 5, 2]
|
|
*/
|
|
function shuffle(collection) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
forEach(collection, function(value) {
|
|
var rand = floor(nativeRandom() * (++index + 1));
|
|
result[index] = result[rand];
|
|
result[rand] = value;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the size of the `collection` by returning `collection.length` for arrays
|
|
* and array-like objects or the number of own enumerable properties for objects.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to inspect.
|
|
* @returns {Number} Returns `collection.length` or number of own enumerable properties.
|
|
* @example
|
|
*
|
|
* _.size([1, 2]);
|
|
* // => 2
|
|
*
|
|
* _.size({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => 3
|
|
*
|
|
* _.size('curly');
|
|
* // => 5
|
|
*/
|
|
function size(collection) {
|
|
var length = collection ? collection.length : 0;
|
|
return typeof length == 'number' ? length : keys(collection).length;
|
|
}
|
|
|
|
/**
|
|
* Checks if the `callback` returns a truthy value for **any** element of a
|
|
* `collection`. The function returns as soon as it finds passing value, and
|
|
* does not iterate over the entire `collection`. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias any
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Boolean} Returns `true` if any element passes the callback check,
|
|
* else `false`.
|
|
* @example
|
|
*
|
|
* _.some([null, 0, 'yes', false], Boolean);
|
|
* // => true
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.some(food, 'organic');
|
|
* // => true
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.some(food, { 'type': 'meat' });
|
|
* // => false
|
|
*/
|
|
function some(collection, callback, thisArg) {
|
|
var result;
|
|
callback = createCallback(callback, thisArg);
|
|
|
|
if (isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
if ((result = callback(collection[index], index, collection))) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
each(collection, function(value, index, collection) {
|
|
return !(result = callback(value, index, collection));
|
|
});
|
|
}
|
|
return !!result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of elements, sorted in ascending order by the results of
|
|
* running each element in the `collection` through the `callback`. This method
|
|
* performs a stable sort, that is, it will preserve the original sort order of
|
|
* equal elements. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of sorted elements.
|
|
* @example
|
|
*
|
|
* _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
|
|
* // => [3, 1, 2]
|
|
*
|
|
* _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
|
|
* // => [3, 1, 2]
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.sortBy(['banana', 'strawberry', 'apple'], 'length');
|
|
* // => ['apple', 'banana', 'strawberry']
|
|
*/
|
|
function sortBy(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
callback = createCallback(callback, thisArg);
|
|
forEach(collection, function(value, key, collection) {
|
|
result[++index] = {
|
|
'criteria': callback(value, key, collection),
|
|
'index': index,
|
|
'value': value
|
|
};
|
|
});
|
|
|
|
length = result.length;
|
|
result.sort(compareAscending);
|
|
while (length--) {
|
|
result[length] = result[length].value;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts the `collection` to an array.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to convert.
|
|
* @returns {Array} Returns the new converted array.
|
|
* @example
|
|
*
|
|
* (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
|
|
* // => [2, 3, 4]
|
|
*/
|
|
function toArray(collection) {
|
|
if (collection && typeof collection.length == 'number') {
|
|
return slice(collection);
|
|
}
|
|
return values(collection);
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning an array of all elements
|
|
* that have the given `properties`. When checking `properties`, this method
|
|
* performs a deep comparison between values to determine if they are equivalent
|
|
* to each other.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Object} properties The object of property values to filter by.
|
|
* @returns {Array} Returns a new array of elements that have the given `properties`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.where(stooges, { 'age': 40 });
|
|
* // => [{ 'name': 'moe', 'age': 40 }]
|
|
*/
|
|
var where = filter;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates an array with all falsey values of `array` removed. The values
|
|
* `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to compact.
|
|
* @returns {Array} Returns a new filtered array.
|
|
* @example
|
|
*
|
|
* _.compact([0, 1, false, 2, '', 3]);
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function compact(array) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (value) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of `array` elements not present in the other arrays
|
|
* using strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @param {Array} [array1, array2, ...] Arrays to check.
|
|
* @returns {Array} Returns a new array of `array` elements not present in the
|
|
* other arrays.
|
|
* @example
|
|
*
|
|
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
|
|
* // => [1, 3, 4]
|
|
*/
|
|
function difference(array) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
flattened = concat.apply(arrayRef, arguments),
|
|
contains = cachedContains(flattened, length),
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (!contains(value)) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the first element of the `array`. If a number `n` is passed, the first
|
|
* `n` elements of the `array` are returned. If a `callback` function is passed,
|
|
* the first elements the `callback` returns truthy for are returned. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias head, take
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n] The function called
|
|
* per element or the number of elements to return. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the first element(s) of `array`.
|
|
* @example
|
|
*
|
|
* _.first([1, 2, 3]);
|
|
* // => 1
|
|
*
|
|
* _.first([1, 2, 3], 2);
|
|
* // => [1, 2]
|
|
*
|
|
* _.first([1, 2, 3], function(num) {
|
|
* return num < 3;
|
|
* });
|
|
* // => [1, 2]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'organic': true },
|
|
* { 'name': 'beet', 'organic': false },
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.first(food, 'organic');
|
|
* // => [{ 'name': 'banana', 'organic': true }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'type': 'fruit' },
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.first(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }]
|
|
*/
|
|
function first(array, callback, thisArg) {
|
|
if (array) {
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = -1;
|
|
callback = createCallback(callback, thisArg);
|
|
while (++index < length && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = callback;
|
|
if (n == null || thisArg) {
|
|
return array[0];
|
|
}
|
|
}
|
|
return slice(array, 0, nativeMin(nativeMax(0, n), length));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flattens a nested array (the nesting can be to any depth). If `shallow` is
|
|
* truthy, `array` will only be flattened a single level.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to compact.
|
|
* @param {Boolean} shallow A flag to indicate only flattening a single level.
|
|
* @returns {Array} Returns a new flattened array.
|
|
* @example
|
|
*
|
|
* _.flatten([1, [2], [3, [[4]]]]);
|
|
* // => [1, 2, 3, 4];
|
|
*
|
|
* _.flatten([1, [2], [3, [[4]]]], true);
|
|
* // => [1, 2, 3, [[4]]];
|
|
*/
|
|
function flatten(array, shallow) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
|
|
// recursively flatten arrays (susceptible to call stack limits)
|
|
if (isArray(value)) {
|
|
push.apply(result, shallow ? value : flatten(value));
|
|
} else {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the index at which the first occurrence of `value` is found using
|
|
* strict equality for comparisons, i.e. `===`. If the `array` is already
|
|
* sorted, passing `true` for `fromIndex` will run a faster binary search.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to
|
|
* perform a binary search on a sorted `array`.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
* @example
|
|
*
|
|
* _.indexOf([1, 2, 3, 1, 2, 3], 2);
|
|
* // => 1
|
|
*
|
|
* _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
|
* // => 4
|
|
*
|
|
* _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
|
|
* // => 2
|
|
*/
|
|
function indexOf(array, value, fromIndex) {
|
|
var index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
if (typeof fromIndex == 'number') {
|
|
index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1;
|
|
} else if (fromIndex) {
|
|
index = sortedIndex(array, value);
|
|
return array[index] === value ? index : -1;
|
|
}
|
|
while (++index < length) {
|
|
if (array[index] === value) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Gets all but the last element of `array`. If a number `n` is passed, the
|
|
* last `n` elements are excluded from the result. If a `callback` function
|
|
* is passed, the last elements the `callback` returns truthy for are excluded
|
|
* from the result. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n=1] The function called
|
|
* per element or the number of elements to exclude. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a slice of `array`.
|
|
* @example
|
|
*
|
|
* _.initial([1, 2, 3]);
|
|
* // => [1, 2]
|
|
*
|
|
* _.initial([1, 2, 3], 2);
|
|
* // => [1]
|
|
*
|
|
* _.initial([1, 2, 3], function(num) {
|
|
* return num > 1;
|
|
* });
|
|
* // => [1]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'beet', 'organic': false },
|
|
* { 'name': 'carrot', 'organic': true }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.initial(food, 'organic');
|
|
* // => [{ 'name': 'beet', 'organic': false }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.initial(food, { 'type': 'vegetable' });
|
|
* // => [{ 'name': 'banana', 'type': 'fruit' }]
|
|
*/
|
|
function initial(array, callback, thisArg) {
|
|
if (!array) {
|
|
return [];
|
|
}
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = length;
|
|
callback = createCallback(callback, thisArg);
|
|
while (index-- && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = (callback == null || thisArg) ? 1 : callback || n;
|
|
}
|
|
return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
|
|
}
|
|
|
|
/**
|
|
* Computes the intersection of all the passed-in arrays using strict equality
|
|
* for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of unique elements that are present
|
|
* in **all** of the arrays.
|
|
* @example
|
|
*
|
|
* _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
|
* // => [1, 2]
|
|
*/
|
|
function intersection(array) {
|
|
var args = arguments,
|
|
argsLength = args.length,
|
|
cache = { '0': {} },
|
|
index = -1,
|
|
length = array ? array.length : 0,
|
|
isLarge = length >= 100,
|
|
result = [],
|
|
seen = result;
|
|
|
|
outer:
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (isLarge) {
|
|
var key = value + '';
|
|
var inited = hasOwnProperty.call(cache[0], key)
|
|
? !(seen = cache[0][key])
|
|
: (seen = cache[0][key] = []);
|
|
}
|
|
if (inited || indexOf(seen, value) < 0) {
|
|
if (isLarge) {
|
|
seen.push(value);
|
|
}
|
|
var argsIndex = argsLength;
|
|
while (--argsIndex) {
|
|
if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex], 0, 100)))(value)) {
|
|
continue outer;
|
|
}
|
|
}
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the last element of the `array`. If a number `n` is passed, the last
|
|
* `n` elements of the `array` are returned. If a `callback` function is passed,
|
|
* the last elements the `callback` returns truthy for are returned. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n] The function called
|
|
* per element or the number of elements to return. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the last element(s) of `array`.
|
|
* @example
|
|
*
|
|
* _.last([1, 2, 3]);
|
|
* // => 3
|
|
*
|
|
* _.last([1, 2, 3], 2);
|
|
* // => [2, 3]
|
|
*
|
|
* _.last([1, 2, 3], function(num) {
|
|
* return num > 1;
|
|
* });
|
|
* // => [2, 3]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'beet', 'organic': false },
|
|
* { 'name': 'carrot', 'organic': true }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.last(food, 'organic');
|
|
* // => [{ 'name': 'carrot', 'organic': true }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.last(food, { 'type': 'vegetable' });
|
|
* // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }]
|
|
*/
|
|
function last(array, callback, thisArg) {
|
|
if (array) {
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = length;
|
|
callback = createCallback(callback, thisArg);
|
|
while (index-- && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = callback;
|
|
if (n == null || thisArg) {
|
|
return array[length - 1];
|
|
}
|
|
}
|
|
return slice(array, nativeMax(0, length - n));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the index at which the last occurrence of `value` is found using strict
|
|
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
|
* as the offset from the end of the collection.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Number} [fromIndex=array.length-1] The index to search from.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
* @example
|
|
*
|
|
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
|
|
* // => 4
|
|
*
|
|
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
|
* // => 1
|
|
*/
|
|
function lastIndexOf(array, value, fromIndex) {
|
|
var index = array ? array.length : 0;
|
|
if (typeof fromIndex == 'number') {
|
|
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
|
|
}
|
|
while (index--) {
|
|
if (array[index] === value) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed from arrays of `keys` and `values`. Pass either
|
|
* a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
|
|
* two arrays, one of `keys` and one of corresponding `values`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} keys The array of keys.
|
|
* @param {Array} [values=[]] The array of values.
|
|
* @returns {Object} Returns an object composed of the given keys and
|
|
* corresponding values.
|
|
* @example
|
|
*
|
|
* _.object(['moe', 'larry'], [30, 40]);
|
|
* // => { 'moe': 30, 'larry': 40 }
|
|
*/
|
|
function object(keys, values) {
|
|
var index = -1,
|
|
length = keys ? keys.length : 0,
|
|
result = {};
|
|
|
|
while (++index < length) {
|
|
var key = keys[index];
|
|
if (values) {
|
|
result[key] = values[index];
|
|
} else {
|
|
result[key[0]] = key[1];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of numbers (positive and/or negative) progressing from
|
|
* `start` up to but not including `end`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Number} [start=0] The start of the range.
|
|
* @param {Number} end The end of the range.
|
|
* @param {Number} [step=1] The value to increment or descrement by.
|
|
* @returns {Array} Returns a new range array.
|
|
* @example
|
|
*
|
|
* _.range(10);
|
|
* // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
*
|
|
* _.range(1, 11);
|
|
* // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
*
|
|
* _.range(0, 30, 5);
|
|
* // => [0, 5, 10, 15, 20, 25]
|
|
*
|
|
* _.range(0, -10, -1);
|
|
* // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
|
|
*
|
|
* _.range(0);
|
|
* // => []
|
|
*/
|
|
function range(start, end, step) {
|
|
start = +start || 0;
|
|
step = +step || 1;
|
|
|
|
if (end == null) {
|
|
end = start;
|
|
start = 0;
|
|
}
|
|
// use `Array(length)` so V8 will avoid the slower "dictionary" mode
|
|
// http://youtu.be/XAqIpGU8ZZk#t=17m25s
|
|
var index = -1,
|
|
length = nativeMax(0, ceil((end - start) / step)),
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = start;
|
|
start += step;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.initial`, this method gets all but the first value of `array`.
|
|
* If a number `n` is passed, the first `n` values are excluded from the result.
|
|
* If a `callback` function is passed, the first elements the `callback` returns
|
|
* truthy for are excluded from the result. The `callback` is bound to `thisArg`
|
|
* and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias drop, tail
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n=1] The function called
|
|
* per element or the number of elements to exclude. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a slice of `array`.
|
|
* @example
|
|
*
|
|
* _.rest([1, 2, 3]);
|
|
* // => [2, 3]
|
|
*
|
|
* _.rest([1, 2, 3], 2);
|
|
* // => [3]
|
|
*
|
|
* _.rest([1, 2, 3], function(num) {
|
|
* return num < 3;
|
|
* });
|
|
* // => [3]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'organic': true },
|
|
* { 'name': 'beet', 'organic': false },
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.rest(food, 'organic');
|
|
* // => [{ 'name': 'beet', 'organic': false }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'type': 'fruit' },
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.rest(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'beet', 'type': 'vegetable' }]
|
|
*/
|
|
function rest(array, callback, thisArg) {
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var n = 0,
|
|
index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
callback = createCallback(callback, thisArg);
|
|
while (++index < length && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
|
|
}
|
|
return slice(array, n);
|
|
}
|
|
|
|
/**
|
|
* Uses a binary search to determine the smallest index at which the `value`
|
|
* should be inserted into `array` in order to maintain the sort order of the
|
|
* sorted `array`. If `callback` is passed, it will be executed for `value` and
|
|
* each element in `array` to compute their sort ranking. The `callback` is
|
|
* bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to iterate over.
|
|
* @param {Mixed} value The value to evaluate.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Number} Returns the index at which the value should be inserted
|
|
* into `array`.
|
|
* @example
|
|
*
|
|
* _.sortedIndex([20, 30, 50], 40);
|
|
* // => 2
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
|
|
* // => 2
|
|
*
|
|
* var dict = {
|
|
* 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
|
|
* };
|
|
*
|
|
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
|
* return dict.wordToNumber[word];
|
|
* });
|
|
* // => 2
|
|
*
|
|
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
|
* return this.wordToNumber[word];
|
|
* }, dict);
|
|
* // => 2
|
|
*/
|
|
function sortedIndex(array, value, callback, thisArg) {
|
|
var low = 0,
|
|
high = array ? array.length : low;
|
|
|
|
// explicitly reference `identity` for better inlining in Firefox
|
|
callback = callback ? createCallback(callback, thisArg, 1) : identity;
|
|
value = callback(value);
|
|
|
|
while (low < high) {
|
|
var mid = (low + high) >>> 1;
|
|
callback(array[mid]) < value
|
|
? low = mid + 1
|
|
: high = mid;
|
|
}
|
|
return low;
|
|
}
|
|
|
|
/**
|
|
* Computes the union of the passed-in arrays using strict equality for
|
|
* comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of unique values, in order, that are
|
|
* present in one or more of the arrays.
|
|
* @example
|
|
*
|
|
* _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
|
* // => [1, 2, 3, 101, 10]
|
|
*/
|
|
function union() {
|
|
return uniq(concat.apply(arrayRef, arguments));
|
|
}
|
|
|
|
/**
|
|
* Creates a duplicate-value-free version of the `array` using strict equality
|
|
* for comparisons, i.e. `===`. If the `array` is already sorted, passing `true`
|
|
* for `isSorted` will run a faster algorithm. If `callback` is passed, each
|
|
* element of `array` is passed through a callback` before uniqueness is computed.
|
|
* The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the propeties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias unique
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a duplicate-value-free array.
|
|
* @example
|
|
*
|
|
* _.uniq([1, 2, 1, 3, 1]);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq([1, 1, 2, 2, 3], true);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); });
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
|
* // => [{ 'x': 1 }, { 'x': 2 }]
|
|
*/
|
|
function uniq(array, isSorted, callback, thisArg) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [],
|
|
seen = result;
|
|
|
|
// juggle arguments
|
|
if (typeof isSorted == 'function') {
|
|
thisArg = callback;
|
|
callback = isSorted;
|
|
isSorted = false;
|
|
}
|
|
// init value cache for large arrays
|
|
var isLarge = !isSorted && length >= 75;
|
|
if (isLarge) {
|
|
var cache = {};
|
|
}
|
|
if (callback) {
|
|
seen = [];
|
|
callback = createCallback(callback, thisArg);
|
|
}
|
|
while (++index < length) {
|
|
var value = array[index],
|
|
computed = callback ? callback(value, index, array) : value;
|
|
|
|
if (isLarge) {
|
|
var key = computed + '';
|
|
var inited = hasOwnProperty.call(cache, key)
|
|
? !(seen = cache[key])
|
|
: (seen = cache[key] = []);
|
|
}
|
|
if (isSorted
|
|
? !index || seen[seen.length - 1] !== computed
|
|
: inited || indexOf(seen, computed) < 0
|
|
) {
|
|
if (callback || isLarge) {
|
|
seen.push(computed);
|
|
}
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array with all occurrences of the passed values removed using
|
|
* strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to filter.
|
|
* @param {Mixed} [value1, value2, ...] Values to remove.
|
|
* @returns {Array} Returns a new filtered array.
|
|
* @example
|
|
*
|
|
* _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
|
|
* // => [2, 3, 4]
|
|
*/
|
|
function without(array) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
contains = cachedContains(arguments, 1),
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (!contains(value)) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Groups the elements of each array at their corresponding indexes. Useful for
|
|
* separate data sources that are coordinated through matching array indexes.
|
|
* For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix
|
|
* in a similar fashion.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of grouped elements.
|
|
* @example
|
|
*
|
|
* _.zip(['moe', 'larry'], [30, 40], [true, false]);
|
|
* // => [['moe', 30, true], ['larry', 40, false]]
|
|
*/
|
|
function zip(array) {
|
|
var index = -1,
|
|
length = array ? max(pluck(arguments, 'length')) : 0,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = pluck(arguments, index);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a function that is restricted to executing `func` only after it is
|
|
* called `n` times. The `func` is executed with the `this` binding of the
|
|
* created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Number} n The number of times the function must be called before
|
|
* it is executed.
|
|
* @param {Function} func The function to restrict.
|
|
* @returns {Function} Returns the new restricted function.
|
|
* @example
|
|
*
|
|
* var renderNotes = _.after(notes.length, render);
|
|
* _.forEach(notes, function(note) {
|
|
* note.asyncSave({ 'success': renderNotes });
|
|
* });
|
|
* // `renderNotes` is run once, after all notes have saved
|
|
*/
|
|
function after(n, func) {
|
|
if (n < 1) {
|
|
return func();
|
|
}
|
|
return function() {
|
|
if (--n < 1) {
|
|
return func.apply(this, arguments);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with the `this`
|
|
* binding of `thisArg` and prepends any additional `bind` arguments to those
|
|
* passed to the bound function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to bind.
|
|
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new bound function.
|
|
* @example
|
|
*
|
|
* var func = function(greeting) {
|
|
* return greeting + ' ' + this.name;
|
|
* };
|
|
*
|
|
* func = _.bind(func, { 'name': 'moe' }, 'hi');
|
|
* func();
|
|
* // => 'hi moe'
|
|
*/
|
|
function bind(func, thisArg) {
|
|
// use `Function#bind` if it exists and is fast
|
|
// (in V8 `Function#bind` is slower except when partially applied)
|
|
return isBindFast || (nativeBind && arguments.length > 2)
|
|
? nativeBind.call.apply(nativeBind, arguments)
|
|
: createBound(func, thisArg, slice(arguments, 2));
|
|
}
|
|
|
|
/**
|
|
* Binds methods on `object` to `object`, overwriting the existing method.
|
|
* Method names may be specified as individual arguments or as arrays of method
|
|
* names. If no method names are provided, all the function properties of `object`
|
|
* will be bound.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Object} object The object to bind and assign the bound methods to.
|
|
* @param {String} [methodName1, methodName2, ...] Method names on the object to bind.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* var view = {
|
|
* 'label': 'docs',
|
|
* 'onClick': function() { alert('clicked ' + this.label); }
|
|
* };
|
|
*
|
|
* _.bindAll(view);
|
|
* jQuery('#docs').on('click', view.onClick);
|
|
* // => alerts 'clicked docs', when the button is clicked
|
|
*/
|
|
function bindAll(object) {
|
|
var funcs = concat.apply(arrayRef, arguments),
|
|
index = funcs.length > 1 ? 0 : (funcs = functions(object), -1),
|
|
length = funcs.length;
|
|
|
|
while (++index < length) {
|
|
var key = funcs[index];
|
|
object[key] = bind(object[key], object);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes the method at `object[key]`
|
|
* and prepends any additional `bindKey` arguments to those passed to the bound
|
|
* function. This method differs from `_.bind` by allowing bound functions to
|
|
* reference methods that will be redefined or don't yet exist.
|
|
* See http://michaux.ca/articles/lazy-function-definition-pattern.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Object} object The object the method belongs to.
|
|
* @param {String} key The key of the method.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new bound function.
|
|
* @example
|
|
*
|
|
* var object = {
|
|
* 'name': 'moe',
|
|
* 'greet': function(greeting) {
|
|
* return greeting + ' ' + this.name;
|
|
* }
|
|
* };
|
|
*
|
|
* var func = _.bindKey(object, 'greet', 'hi');
|
|
* func();
|
|
* // => 'hi moe'
|
|
*
|
|
* object.greet = function(greeting) {
|
|
* return greeting + ', ' + this.name + '!';
|
|
* };
|
|
*
|
|
* func();
|
|
* // => 'hi, moe!'
|
|
*/
|
|
function bindKey(object, key) {
|
|
return createBound(object, key, slice(arguments, 2));
|
|
}
|
|
|
|
/**
|
|
* Creates a function that is the composition of the passed functions,
|
|
* where each function consumes the return value of the function that follows.
|
|
* For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
|
|
* Each function is executed with the `this` binding of the composed function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} [func1, func2, ...] Functions to compose.
|
|
* @returns {Function} Returns the new composed function.
|
|
* @example
|
|
*
|
|
* var greet = function(name) { return 'hi ' + name; };
|
|
* var exclaim = function(statement) { return statement + '!'; };
|
|
* var welcome = _.compose(exclaim, greet);
|
|
* welcome('moe');
|
|
* // => 'hi moe!'
|
|
*/
|
|
function compose() {
|
|
var funcs = arguments;
|
|
return function() {
|
|
var args = arguments,
|
|
length = funcs.length;
|
|
|
|
while (length--) {
|
|
args = [funcs[length].apply(this, args)];
|
|
}
|
|
return args[0];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that will delay the execution of `func` until after
|
|
* `wait` milliseconds have elapsed since the last time it was invoked. Pass
|
|
* `true` for `immediate` to cause debounce to invoke `func` on the leading,
|
|
* instead of the trailing, edge of the `wait` timeout. Subsequent calls to
|
|
* the debounced function will return the result of the last `func` call.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to debounce.
|
|
* @param {Number} wait The number of milliseconds to delay.
|
|
* @param {Boolean} immediate A flag to indicate execution is on the leading
|
|
* edge of the timeout.
|
|
* @returns {Function} Returns the new debounced function.
|
|
* @example
|
|
*
|
|
* var lazyLayout = _.debounce(calculateLayout, 300);
|
|
* jQuery(window).on('resize', lazyLayout);
|
|
*/
|
|
function debounce(func, wait, immediate) {
|
|
var args,
|
|
result,
|
|
thisArg,
|
|
timeoutId;
|
|
|
|
function delayed() {
|
|
timeoutId = null;
|
|
if (!immediate) {
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
}
|
|
return function() {
|
|
var isImmediate = immediate && !timeoutId;
|
|
args = arguments;
|
|
thisArg = this;
|
|
|
|
clearTimeout(timeoutId);
|
|
timeoutId = setTimeout(delayed, wait);
|
|
|
|
if (isImmediate) {
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Executes the `func` function after `wait` milliseconds. Additional arguments
|
|
* will be passed to `func` when it is invoked.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to delay.
|
|
* @param {Number} wait The number of milliseconds to delay execution.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
|
* @returns {Number} Returns the `setTimeout` timeout id.
|
|
* @example
|
|
*
|
|
* var log = _.bind(console.log, console);
|
|
* _.delay(log, 1000, 'logged later');
|
|
* // => 'logged later' (Appears after one second.)
|
|
*/
|
|
function delay(func, wait) {
|
|
var args = slice(arguments, 2);
|
|
return setTimeout(function() { func.apply(undefined, args); }, wait);
|
|
}
|
|
|
|
/**
|
|
* Defers executing the `func` function until the current call stack has cleared.
|
|
* Additional arguments will be passed to `func` when it is invoked.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to defer.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
|
* @returns {Number} Returns the `setTimeout` timeout id.
|
|
* @example
|
|
*
|
|
* _.defer(function() { alert('deferred'); });
|
|
* // returns from the function before `alert` is called
|
|
*/
|
|
function defer(func) {
|
|
var args = slice(arguments, 1);
|
|
return setTimeout(function() { func.apply(undefined, args); }, 1);
|
|
}
|
|
// use `setImmediate` if it's available in Node.js
|
|
if (isV8 && freeModule && typeof setImmediate == 'function') {
|
|
defer = bind(setImmediate, window);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that memoizes the result of `func`. If `resolver` is
|
|
* passed, it will be used to determine the cache key for storing the result
|
|
* based on the arguments passed to the memoized function. By default, the first
|
|
* argument passed to the memoized function is used as the cache key. The `func`
|
|
* is executed with the `this` binding of the memoized function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to have its output memoized.
|
|
* @param {Function} [resolver] A function used to resolve the cache key.
|
|
* @returns {Function} Returns the new memoizing function.
|
|
* @example
|
|
*
|
|
* var fibonacci = _.memoize(function(n) {
|
|
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
|
|
* });
|
|
*/
|
|
function memoize(func, resolver) {
|
|
var cache = {};
|
|
return function() {
|
|
var key = (resolver ? resolver.apply(this, arguments) : arguments[0]) + '';
|
|
return hasOwnProperty.call(cache, key)
|
|
? cache[key]
|
|
: (cache[key] = func.apply(this, arguments));
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that is restricted to execute `func` once. Repeat calls to
|
|
* the function will return the value of the first call. The `func` is executed
|
|
* with the `this` binding of the created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to restrict.
|
|
* @returns {Function} Returns the new restricted function.
|
|
* @example
|
|
*
|
|
* var initialize = _.once(createApplication);
|
|
* initialize();
|
|
* initialize();
|
|
* // `initialize` executes `createApplication` once
|
|
*/
|
|
function once(func) {
|
|
var ran,
|
|
result;
|
|
|
|
return function() {
|
|
if (ran) {
|
|
return result;
|
|
}
|
|
ran = true;
|
|
result = func.apply(this, arguments);
|
|
|
|
// clear the `func` variable so the function may be garbage collected
|
|
func = null;
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with any additional
|
|
* `partial` arguments prepended to those passed to the new function. This
|
|
* method is similar to `_.bind`, except it does **not** alter the `this` binding.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to partially apply arguments to.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new partially applied function.
|
|
* @example
|
|
*
|
|
* var greet = function(greeting, name) { return greeting + ' ' + name; };
|
|
* var hi = _.partial(greet, 'hi');
|
|
* hi('moe');
|
|
* // => 'hi moe'
|
|
*/
|
|
function partial(func) {
|
|
return createBound(func, slice(arguments, 1));
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.partial`, except that `partial` arguments are
|
|
* appended to those passed to the new function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to partially apply arguments to.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new partially applied function.
|
|
* @example
|
|
*
|
|
* var defaultsDeep = _.partialRight(_.merge, _.defaults);
|
|
*
|
|
* var options = {
|
|
* 'variable': 'data',
|
|
* 'imports': { 'jq': $ }
|
|
* };
|
|
*
|
|
* defaultsDeep(options, _.templateSettings);
|
|
*
|
|
* options.variable
|
|
* // => 'data'
|
|
*
|
|
* options.imports
|
|
* // => { '_': _, 'jq': $ }
|
|
*/
|
|
function partialRight(func) {
|
|
return createBound(func, slice(arguments, 1), null, indicatorObject);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when executed, will only call the `func`
|
|
* function at most once per every `wait` milliseconds. If the throttled
|
|
* function is invoked more than once during the `wait` timeout, `func` will
|
|
* also be called on the trailing edge of the timeout. Subsequent calls to the
|
|
* throttled function will return the result of the last `func` call.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to throttle.
|
|
* @param {Number} wait The number of milliseconds to throttle executions to.
|
|
* @returns {Function} Returns the new throttled function.
|
|
* @example
|
|
*
|
|
* var throttled = _.throttle(updatePosition, 100);
|
|
* jQuery(window).on('scroll', throttled);
|
|
*/
|
|
function throttle(func, wait) {
|
|
var args,
|
|
result,
|
|
thisArg,
|
|
timeoutId,
|
|
lastCalled = 0;
|
|
|
|
function trailingCall() {
|
|
lastCalled = new Date;
|
|
timeoutId = null;
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
return function() {
|
|
var now = new Date,
|
|
remaining = wait - (now - lastCalled);
|
|
|
|
args = arguments;
|
|
thisArg = this;
|
|
|
|
if (remaining <= 0) {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = null;
|
|
lastCalled = now;
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
else if (!timeoutId) {
|
|
timeoutId = setTimeout(trailingCall, remaining);
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that passes `value` to the `wrapper` function as its
|
|
* first argument. Additional arguments passed to the function are appended
|
|
* to those passed to the `wrapper` function. The `wrapper` is executed with
|
|
* the `this` binding of the created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Mixed} value The value to wrap.
|
|
* @param {Function} wrapper The wrapper function.
|
|
* @returns {Function} Returns the new function.
|
|
* @example
|
|
*
|
|
* var hello = function(name) { return 'hello ' + name; };
|
|
* hello = _.wrap(hello, function(func) {
|
|
* return 'before, ' + func('moe') + ', after';
|
|
* });
|
|
* hello();
|
|
* // => 'before, hello moe, after'
|
|
*/
|
|
function wrap(value, wrapper) {
|
|
return function() {
|
|
var args = [value];
|
|
push.apply(args, arguments);
|
|
return wrapper.apply(this, args);
|
|
};
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
|
|
* corresponding HTML entities.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} string The string to escape.
|
|
* @returns {String} Returns the escaped string.
|
|
* @example
|
|
*
|
|
* _.escape('Moe, Larry & Curly');
|
|
* // => 'Moe, Larry & Curly'
|
|
*/
|
|
function escape(string) {
|
|
return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar);
|
|
}
|
|
|
|
/**
|
|
* This function returns the first argument passed to it.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Mixed} value Any value.
|
|
* @returns {Mixed} Returns `value`.
|
|
* @example
|
|
*
|
|
* var moe = { 'name': 'moe' };
|
|
* moe === _.identity(moe);
|
|
* // => true
|
|
*/
|
|
function identity(value) {
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Adds functions properties of `object` to the `lodash` function and chainable
|
|
* wrapper.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} object The object of function properties to add to `lodash`.
|
|
* @example
|
|
*
|
|
* _.mixin({
|
|
* 'capitalize': function(string) {
|
|
* return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
|
* }
|
|
* });
|
|
*
|
|
* _.capitalize('moe');
|
|
* // => 'Moe'
|
|
*
|
|
* _('moe').capitalize();
|
|
* // => 'Moe'
|
|
*/
|
|
function mixin(object) {
|
|
forEach(functions(object), function(methodName) {
|
|
var func = lodash[methodName] = object[methodName];
|
|
|
|
lodash.prototype[methodName] = function() {
|
|
var args = [this.__wrapped__];
|
|
push.apply(args, arguments);
|
|
return new lodash(func.apply(lodash, args));
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reverts the '_' variable to its previous value and returns a reference to
|
|
* the `lodash` function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @returns {Function} Returns the `lodash` function.
|
|
* @example
|
|
*
|
|
* var lodash = _.noConflict();
|
|
*/
|
|
function noConflict() {
|
|
window._ = oldDash;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Produces a random number between `min` and `max` (inclusive). If only one
|
|
* argument is passed, a number between `0` and the given number will be returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Number} [min=0] The minimum possible value.
|
|
* @param {Number} [max=1] The maximum possible value.
|
|
* @returns {Number} Returns a random number.
|
|
* @example
|
|
*
|
|
* _.random(0, 5);
|
|
* // => a number between 0 and 5
|
|
*
|
|
* _.random(5);
|
|
* // => also a number between 0 and 5
|
|
*/
|
|
function random(min, max) {
|
|
if (min == null && max == null) {
|
|
max = 1;
|
|
}
|
|
min = +min || 0;
|
|
if (max == null) {
|
|
max = min;
|
|
min = 0;
|
|
}
|
|
return min + floor(nativeRandom() * ((+max || 0) - min + 1));
|
|
}
|
|
|
|
/**
|
|
* Resolves the value of `property` on `object`. If `property` is a function,
|
|
* it will be invoked and its result returned, else the property value is
|
|
* returned. If `object` is falsey, then `null` is returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} object The object to inspect.
|
|
* @param {String} property The property to get the value of.
|
|
* @returns {Mixed} Returns the resolved value.
|
|
* @example
|
|
*
|
|
* var object = {
|
|
* 'cheese': 'crumpets',
|
|
* 'stuff': function() {
|
|
* return 'nonsense';
|
|
* }
|
|
* };
|
|
*
|
|
* _.result(object, 'cheese');
|
|
* // => 'crumpets'
|
|
*
|
|
* _.result(object, 'stuff');
|
|
* // => 'nonsense'
|
|
*/
|
|
function result(object, property) {
|
|
var value = object ? object[property] : undefined;
|
|
return isFunction(value) ? object[property]() : value;
|
|
}
|
|
|
|
/**
|
|
* A micro-templating method that handles arbitrary delimiters, preserves
|
|
* whitespace, and correctly escapes quotes within interpolated code.
|
|
*
|
|
* Note: In the development build, `_.template` utilizes sourceURLs for easier
|
|
* debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
|
*
|
|
* Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp`
|
|
* build and using precompiled templates, or loading Lo-Dash in a sandbox.
|
|
*
|
|
* For more information on precompiling templates see:
|
|
* http://lodash.com/#custom-builds
|
|
*
|
|
* For more information on Chrome extension sandboxes see:
|
|
* http://developer.chrome.com/stable/extensions/sandboxingEval.html
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} text The template text.
|
|
* @param {Obect} data The data object used to populate the text.
|
|
* @param {Object} options The options object.
|
|
* escape - The "escape" delimiter regexp.
|
|
* evaluate - The "evaluate" delimiter regexp.
|
|
* interpolate - The "interpolate" delimiter regexp.
|
|
* sourceURL - The sourceURL of the template's compiled source.
|
|
* variable - The data object variable name.
|
|
*
|
|
* @returns {Function|String} Returns a compiled function when no `data` object
|
|
* is given, else it returns the interpolated text.
|
|
* @example
|
|
*
|
|
* // using a compiled template
|
|
* var compiled = _.template('hello <%= name %>');
|
|
* compiled({ 'name': 'moe' });
|
|
* // => 'hello moe'
|
|
*
|
|
* var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>';
|
|
* _.template(list, { 'people': ['moe', 'larry'] });
|
|
* // => '<li>moe</li><li>larry</li>'
|
|
*
|
|
* // using the "escape" delimiter to escape HTML in data property values
|
|
* _.template('<b><%- value %></b>', { 'value': '<script>' });
|
|
* // => '<b><script></b>'
|
|
*
|
|
* // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
|
|
* _.template('hello ${ name }', { 'name': 'curly' });
|
|
* // => 'hello curly'
|
|
*
|
|
* // using the internal `print` function in "evaluate" delimiters
|
|
* _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' });
|
|
* // => 'hello stooge!'
|
|
*
|
|
* // using custom template delimiters
|
|
* _.templateSettings = {
|
|
* 'interpolate': /{{([\s\S]+?)}}/g
|
|
* };
|
|
*
|
|
* _.template('hello {{ name }}!', { 'name': 'mustache' });
|
|
* // => 'hello mustache!'
|
|
*
|
|
* // using the `sourceURL` option to specify a custom sourceURL for the template
|
|
* var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
|
|
* compiled(data);
|
|
* // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
|
|
*
|
|
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
|
|
* var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
|
|
* compiled.source;
|
|
* // => function(data) {
|
|
* var __t, __p = '', __e = _.escape;
|
|
* __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
|
|
* return __p;
|
|
* }
|
|
*
|
|
* // using the `source` property to inline compiled templates for meaningful
|
|
* // line numbers in error messages and a stack trace
|
|
* fs.writeFileSync(path.join(cwd, 'jst.js'), '\
|
|
* var JST = {\
|
|
* "main": ' + _.template(mainText).source + '\
|
|
* };\
|
|
* ');
|
|
*/
|
|
function template(text, data, options) {
|
|
// based on John Resig's `tmpl` implementation
|
|
// http://ejohn.org/blog/javascript-micro-templating/
|
|
// and Laura Doktorova's doT.js
|
|
// https://github.com/olado/doT
|
|
var settings = lodash.templateSettings;
|
|
text || (text = '');
|
|
|
|
// avoid missing dependencies when `iteratorTemplate` is not defined
|
|
options = defaults({}, options, settings);
|
|
|
|
var imports = defaults({}, options.imports, settings.imports),
|
|
importsKeys = keys(imports),
|
|
importsValues = values(imports);
|
|
|
|
var isEvaluating,
|
|
index = 0,
|
|
interpolate = options.interpolate || reNoMatch,
|
|
source = "__p += '";
|
|
|
|
// compile regexp to match each delimiter
|
|
var reDelimiters = RegExp(
|
|
(options.escape || reNoMatch).source + '|' +
|
|
interpolate.source + '|' +
|
|
(interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
|
|
(options.evaluate || reNoMatch).source + '|$'
|
|
, 'g');
|
|
|
|
text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
|
|
interpolateValue || (interpolateValue = esTemplateValue);
|
|
|
|
// escape characters that cannot be included in string literals
|
|
source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
|
|
|
|
// replace delimiters with snippets
|
|
if (escapeValue) {
|
|
source += "' +\n__e(" + escapeValue + ") +\n'";
|
|
}
|
|
if (evaluateValue) {
|
|
isEvaluating = true;
|
|
source += "';\n" + evaluateValue + ";\n__p += '";
|
|
}
|
|
if (interpolateValue) {
|
|
source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
|
|
}
|
|
index = offset + match.length;
|
|
|
|
// the JS engine embedded in Adobe products requires returning the `match`
|
|
// string in order to produce the correct `offset` value
|
|
return match;
|
|
});
|
|
|
|
source += "';\n";
|
|
|
|
// if `variable` is not specified and the template contains "evaluate"
|
|
// delimiters, wrap a with-statement around the generated code to add the
|
|
// data object to the top of the scope chain
|
|
var variable = options.variable,
|
|
hasVariable = variable;
|
|
|
|
if (!hasVariable) {
|
|
variable = 'obj';
|
|
source = 'with (' + variable + ') {\n' + source + '\n}\n';
|
|
}
|
|
// cleanup code by stripping empty strings
|
|
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
|
|
.replace(reEmptyStringMiddle, '$1')
|
|
.replace(reEmptyStringTrailing, '$1;');
|
|
|
|
// frame code as the function body
|
|
source = 'function(' + variable + ') {\n' +
|
|
(hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
|
|
"var __t, __p = '', __e = _.escape" +
|
|
(isEvaluating
|
|
? ', __j = Array.prototype.join;\n' +
|
|
"function print() { __p += __j.call(arguments, '') }\n"
|
|
: ';\n'
|
|
) +
|
|
source +
|
|
'return __p\n}';
|
|
|
|
// Use a sourceURL for easier debugging and wrap in a multi-line comment to
|
|
// avoid issues with Narwhal, IE conditional compilation, and the JS engine
|
|
// embedded in Adobe products.
|
|
// http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
|
var sourceURL = '\n/*\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
|
|
|
|
try {
|
|
var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
|
|
} catch(e) {
|
|
e.source = source;
|
|
throw e;
|
|
}
|
|
if (data) {
|
|
return result(data);
|
|
}
|
|
// provide the compiled function's source via its `toString` method, in
|
|
// supported environments, or the `source` property as a convenience for
|
|
// inlining compiled templates during the build process
|
|
result.source = source;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Executes the `callback` function `n` times, returning an array of the results
|
|
* of each `callback` execution. The `callback` is bound to `thisArg` and invoked
|
|
* with one argument; (index).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Number} n The number of times to execute the callback.
|
|
* @param {Function} callback The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
|
* @example
|
|
*
|
|
* var diceRolls = _.times(3, _.partial(_.random, 1, 6));
|
|
* // => [3, 6, 4]
|
|
*
|
|
* _.times(3, function(n) { mage.castSpell(n); });
|
|
* // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
|
|
*
|
|
* _.times(3, function(n) { this.cast(n); }, mage);
|
|
* // => also calls `mage.castSpell(n)` three times
|
|
*/
|
|
function times(n, callback, thisArg) {
|
|
n = +n || 0;
|
|
var index = -1,
|
|
result = Array(n);
|
|
|
|
while (++index < n) {
|
|
result[index] = callback.call(thisArg, index);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.escape`, this method converts the HTML entities
|
|
* `&`, `<`, `>`, `"`, and `'` in `string` to their
|
|
* corresponding characters.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} string The string to unescape.
|
|
* @returns {String} Returns the unescaped string.
|
|
* @example
|
|
*
|
|
* _.unescape('Moe, Larry & Curly');
|
|
* // => 'Moe, Larry & Curly'
|
|
*/
|
|
function unescape(string) {
|
|
return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar);
|
|
}
|
|
|
|
/**
|
|
* Generates a unique ID. If `prefix` is passed, the ID will be appended to it.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} [prefix] The value to prefix the ID with.
|
|
* @returns {String} Returns the unique ID.
|
|
* @example
|
|
*
|
|
* _.uniqueId('contact_');
|
|
* // => 'contact_104'
|
|
*
|
|
* _.uniqueId();
|
|
* // => '105'
|
|
*/
|
|
function uniqueId(prefix) {
|
|
var id = ++idCounter;
|
|
return (prefix == null ? '' : prefix + '') + id;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Invokes `interceptor` with the `value` as the first argument, and then
|
|
* returns `value`. The purpose of this method is to "tap into" a method chain,
|
|
* in order to perform operations on intermediate results within the chain.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Chaining
|
|
* @param {Mixed} value The value to pass to `interceptor`.
|
|
* @param {Function} interceptor The function to invoke.
|
|
* @returns {Mixed} Returns `value`.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3, 4])
|
|
* .filter(function(num) { return num % 2 == 0; })
|
|
* .tap(alert)
|
|
* .map(function(num) { return num * num; })
|
|
* .value();
|
|
* // => // [2, 4] (alerted)
|
|
* // => [4, 16]
|
|
*/
|
|
function tap(value, interceptor) {
|
|
interceptor(value);
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Produces the `toString` result of the wrapped value.
|
|
*
|
|
* @name toString
|
|
* @memberOf _
|
|
* @category Chaining
|
|
* @returns {String} Returns the string result.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).toString();
|
|
* // => '1,2,3'
|
|
*/
|
|
function wrapperToString() {
|
|
return this.__wrapped__ + '';
|
|
}
|
|
|
|
/**
|
|
* Extracts the wrapped value.
|
|
*
|
|
* @name valueOf
|
|
* @memberOf _
|
|
* @alias value
|
|
* @category Chaining
|
|
* @returns {Mixed} Returns the wrapped value.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).valueOf();
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function wrapperValueOf() {
|
|
return this.__wrapped__;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions that return wrapped values when chaining
|
|
lodash.after = after;
|
|
lodash.assign = assign;
|
|
lodash.at = at;
|
|
lodash.bind = bind;
|
|
lodash.bindAll = bindAll;
|
|
lodash.bindKey = bindKey;
|
|
lodash.compact = compact;
|
|
lodash.compose = compose;
|
|
lodash.countBy = countBy;
|
|
lodash.debounce = debounce;
|
|
lodash.defaults = defaults;
|
|
lodash.defer = defer;
|
|
lodash.delay = delay;
|
|
lodash.difference = difference;
|
|
lodash.filter = filter;
|
|
lodash.flatten = flatten;
|
|
lodash.forEach = forEach;
|
|
lodash.forIn = forIn;
|
|
lodash.forOwn = forOwn;
|
|
lodash.functions = functions;
|
|
lodash.groupBy = groupBy;
|
|
lodash.initial = initial;
|
|
lodash.intersection = intersection;
|
|
lodash.invert = invert;
|
|
lodash.invoke = invoke;
|
|
lodash.keys = keys;
|
|
lodash.map = map;
|
|
lodash.max = max;
|
|
lodash.memoize = memoize;
|
|
lodash.merge = merge;
|
|
lodash.min = min;
|
|
lodash.object = object;
|
|
lodash.omit = omit;
|
|
lodash.once = once;
|
|
lodash.pairs = pairs;
|
|
lodash.partial = partial;
|
|
lodash.partialRight = partialRight;
|
|
lodash.pick = pick;
|
|
lodash.pluck = pluck;
|
|
lodash.range = range;
|
|
lodash.reject = reject;
|
|
lodash.rest = rest;
|
|
lodash.shuffle = shuffle;
|
|
lodash.sortBy = sortBy;
|
|
lodash.tap = tap;
|
|
lodash.throttle = throttle;
|
|
lodash.times = times;
|
|
lodash.toArray = toArray;
|
|
lodash.union = union;
|
|
lodash.uniq = uniq;
|
|
lodash.values = values;
|
|
lodash.where = where;
|
|
lodash.without = without;
|
|
lodash.wrap = wrap;
|
|
lodash.zip = zip;
|
|
|
|
// add aliases
|
|
lodash.collect = map;
|
|
lodash.drop = rest;
|
|
lodash.each = forEach;
|
|
lodash.extend = assign;
|
|
lodash.methods = functions;
|
|
lodash.select = filter;
|
|
lodash.tail = rest;
|
|
lodash.unique = uniq;
|
|
|
|
// add functions to `lodash.prototype`
|
|
mixin(lodash);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions that return unwrapped values when chaining
|
|
lodash.clone = clone;
|
|
lodash.cloneDeep = cloneDeep;
|
|
lodash.contains = contains;
|
|
lodash.escape = escape;
|
|
lodash.every = every;
|
|
lodash.find = find;
|
|
lodash.has = has;
|
|
lodash.identity = identity;
|
|
lodash.indexOf = indexOf;
|
|
lodash.isArguments = isArguments;
|
|
lodash.isArray = isArray;
|
|
lodash.isBoolean = isBoolean;
|
|
lodash.isDate = isDate;
|
|
lodash.isElement = isElement;
|
|
lodash.isEmpty = isEmpty;
|
|
lodash.isEqual = isEqual;
|
|
lodash.isFinite = isFinite;
|
|
lodash.isFunction = isFunction;
|
|
lodash.isNaN = isNaN;
|
|
lodash.isNull = isNull;
|
|
lodash.isNumber = isNumber;
|
|
lodash.isObject = isObject;
|
|
lodash.isPlainObject = isPlainObject;
|
|
lodash.isRegExp = isRegExp;
|
|
lodash.isString = isString;
|
|
lodash.isUndefined = isUndefined;
|
|
lodash.lastIndexOf = lastIndexOf;
|
|
lodash.mixin = mixin;
|
|
lodash.noConflict = noConflict;
|
|
lodash.random = random;
|
|
lodash.reduce = reduce;
|
|
lodash.reduceRight = reduceRight;
|
|
lodash.result = result;
|
|
lodash.size = size;
|
|
lodash.some = some;
|
|
lodash.sortedIndex = sortedIndex;
|
|
lodash.template = template;
|
|
lodash.unescape = unescape;
|
|
lodash.uniqueId = uniqueId;
|
|
|
|
// add aliases
|
|
lodash.all = every;
|
|
lodash.any = some;
|
|
lodash.detect = find;
|
|
lodash.foldl = reduce;
|
|
lodash.foldr = reduceRight;
|
|
lodash.include = contains;
|
|
lodash.inject = reduce;
|
|
|
|
forOwn(lodash, function(func, methodName) {
|
|
if (!lodash.prototype[methodName]) {
|
|
lodash.prototype[methodName] = function() {
|
|
var args = [this.__wrapped__];
|
|
push.apply(args, arguments);
|
|
return func.apply(lodash, args);
|
|
};
|
|
}
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions capable of returning wrapped and unwrapped values when chaining
|
|
lodash.first = first;
|
|
lodash.last = last;
|
|
|
|
// add aliases
|
|
lodash.take = first;
|
|
lodash.head = first;
|
|
|
|
forOwn(lodash, function(func, methodName) {
|
|
if (!lodash.prototype[methodName]) {
|
|
lodash.prototype[methodName]= function(callback, thisArg) {
|
|
var result = func(this.__wrapped__, callback, thisArg);
|
|
return callback == null || (thisArg && typeof callback != 'function')
|
|
? result
|
|
: new lodash(result);
|
|
};
|
|
}
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* The semantic version number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type String
|
|
*/
|
|
lodash.VERSION = '1.0.1';
|
|
|
|
// add "Chaining" functions to the wrapper
|
|
lodash.prototype.toString = wrapperToString;
|
|
lodash.prototype.value = wrapperValueOf;
|
|
lodash.prototype.valueOf = wrapperValueOf;
|
|
|
|
// add `Array` functions that return unwrapped values
|
|
each(['join', 'pop', 'shift'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
return func.apply(this.__wrapped__, arguments);
|
|
};
|
|
});
|
|
|
|
// add `Array` functions that return the wrapped value
|
|
each(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
func.apply(this.__wrapped__, arguments);
|
|
return this;
|
|
};
|
|
});
|
|
|
|
// add `Array` functions that return new wrapped values
|
|
each(['concat', 'slice', 'splice'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
return new lodash(func.apply(this.__wrapped__, arguments));
|
|
};
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// expose Lo-Dash
|
|
// some AMD build optimizers, like r.js, check for specific condition patterns like the following:
|
|
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
|
// Expose Lo-Dash to the global object even when an AMD loader is present in
|
|
// case Lo-Dash was injected by a third-party script and not intended to be
|
|
// loaded as a module. The global assignment can be reverted in the Lo-Dash
|
|
// module via its `noConflict()` method.
|
|
window._ = lodash;
|
|
|
|
// define as an anonymous module so, through path mapping, it can be
|
|
// referenced as the "underscore" module
|
|
define(function() {
|
|
return lodash;
|
|
});
|
|
}
|
|
// check for `exports` after `define` in case a build optimizer adds an `exports` object
|
|
else if (freeExports) {
|
|
// in Node.js or RingoJS v0.8.0+
|
|
if (freeModule) {
|
|
(freeModule.exports = lodash)._ = lodash;
|
|
}
|
|
// in Narwhal or RingoJS v0.7.0-
|
|
else {
|
|
freeExports._ = lodash;
|
|
}
|
|
}
|
|
else {
|
|
// in a browser or Rhino
|
|
window._ = lodash;
|
|
}
|
|
}(this));
|
|
|
|
},{}],76:[function(require,module,exports){
|
|
var Buffer=require("__browserify_Buffer").Buffer;// uuid.js
|
|
//
|
|
// (c) 2010-2012 Robert Kieffer
|
|
// MIT License
|
|
// https://github.com/broofa/node-uuid
|
|
(function() {
|
|
var _global = this;
|
|
|
|
// Unique ID creation requires a high quality random # generator. We feature
|
|
// detect to determine the best RNG source, normalizing to a function that
|
|
// returns 128-bits of randomness, since that's what's usually required
|
|
var _rng;
|
|
|
|
// Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
|
|
//
|
|
// Moderately fast, high quality
|
|
if (typeof(require) == 'function') {
|
|
try {
|
|
var _rb = require('crypto').randomBytes;
|
|
_rng = _rb && function() {return _rb(16);};
|
|
} catch(e) {}
|
|
}
|
|
|
|
if (!_rng && _global.crypto && crypto.getRandomValues) {
|
|
// WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
|
|
//
|
|
// Moderately fast, high quality
|
|
var _rnds8 = new Uint8Array(16);
|
|
_rng = function whatwgRNG() {
|
|
crypto.getRandomValues(_rnds8);
|
|
return _rnds8;
|
|
};
|
|
}
|
|
|
|
if (!_rng) {
|
|
// Math.random()-based (RNG)
|
|
//
|
|
// If all else fails, use Math.random(). It's fast, but is of unspecified
|
|
// quality.
|
|
var _rnds = new Array(16);
|
|
_rng = function() {
|
|
for (var i = 0, r; i < 16; i++) {
|
|
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
|
|
_rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
|
}
|
|
|
|
return _rnds;
|
|
};
|
|
}
|
|
|
|
// Buffer class to use
|
|
var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
|
|
|
|
// Maps for number <-> hex string conversion
|
|
var _byteToHex = [];
|
|
var _hexToByte = {};
|
|
for (var i = 0; i < 256; i++) {
|
|
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
|
_hexToByte[_byteToHex[i]] = i;
|
|
}
|
|
|
|
// **`parse()` - Parse a UUID into it's component bytes**
|
|
function parse(s, buf, offset) {
|
|
var i = (buf && offset) || 0, ii = 0;
|
|
|
|
buf = buf || [];
|
|
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
|
|
if (ii < 16) { // Don't overflow!
|
|
buf[i + ii++] = _hexToByte[oct];
|
|
}
|
|
});
|
|
|
|
// Zero out remaining bytes if string was short
|
|
while (ii < 16) {
|
|
buf[i + ii++] = 0;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
|
|
function unparse(buf, offset) {
|
|
var i = offset || 0, bth = _byteToHex;
|
|
return bth[buf[i++]] + bth[buf[i++]] +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] +
|
|
bth[buf[i++]] + bth[buf[i++]] +
|
|
bth[buf[i++]] + bth[buf[i++]];
|
|
}
|
|
|
|
// **`v1()` - Generate time-based UUID**
|
|
//
|
|
// Inspired by https://github.com/LiosK/UUID.js
|
|
// and http://docs.python.org/library/uuid.html
|
|
|
|
// random #'s we need to init node and clockseq
|
|
var _seedBytes = _rng();
|
|
|
|
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
|
var _nodeId = [
|
|
_seedBytes[0] | 0x01,
|
|
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
|
|
];
|
|
|
|
// Per 4.2.2, randomize (14 bit) clockseq
|
|
var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
|
|
|
|
// Previous uuid creation time
|
|
var _lastMSecs = 0, _lastNSecs = 0;
|
|
|
|
// See https://github.com/broofa/node-uuid for API details
|
|
function v1(options, buf, offset) {
|
|
var i = buf && offset || 0;
|
|
var b = buf || [];
|
|
|
|
options = options || {};
|
|
|
|
var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
|
|
|
|
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
|
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
|
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
|
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
|
var msecs = options.msecs != null ? options.msecs : new Date().getTime();
|
|
|
|
// Per 4.2.1.2, use count of uuid's generated during the current clock
|
|
// cycle to simulate higher resolution clock
|
|
var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
|
|
|
|
// Time since last uuid creation (in msecs)
|
|
var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
|
|
|
|
// Per 4.2.1.2, Bump clockseq on clock regression
|
|
if (dt < 0 && options.clockseq == null) {
|
|
clockseq = clockseq + 1 & 0x3fff;
|
|
}
|
|
|
|
// Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
|
|
// time interval
|
|
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
|
|
nsecs = 0;
|
|
}
|
|
|
|
// Per 4.2.1.2 Throw error if too many uuids are requested
|
|
if (nsecs >= 10000) {
|
|
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
|
|
}
|
|
|
|
_lastMSecs = msecs;
|
|
_lastNSecs = nsecs;
|
|
_clockseq = clockseq;
|
|
|
|
// Per 4.1.4 - Convert from unix epoch to Gregorian epoch
|
|
msecs += 12219292800000;
|
|
|
|
// `time_low`
|
|
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
|
|
b[i++] = tl >>> 24 & 0xff;
|
|
b[i++] = tl >>> 16 & 0xff;
|
|
b[i++] = tl >>> 8 & 0xff;
|
|
b[i++] = tl & 0xff;
|
|
|
|
// `time_mid`
|
|
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
|
|
b[i++] = tmh >>> 8 & 0xff;
|
|
b[i++] = tmh & 0xff;
|
|
|
|
// `time_high_and_version`
|
|
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
|
|
b[i++] = tmh >>> 16 & 0xff;
|
|
|
|
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
|
|
b[i++] = clockseq >>> 8 | 0x80;
|
|
|
|
// `clock_seq_low`
|
|
b[i++] = clockseq & 0xff;
|
|
|
|
// `node`
|
|
var node = options.node || _nodeId;
|
|
for (var n = 0; n < 6; n++) {
|
|
b[i + n] = node[n];
|
|
}
|
|
|
|
return buf ? buf : unparse(b);
|
|
}
|
|
|
|
// **`v4()` - Generate random UUID**
|
|
|
|
// See https://github.com/broofa/node-uuid for API details
|
|
function v4(options, buf, offset) {
|
|
// Deprecated - 'format' argument, as supported in v1.2
|
|
var i = buf && offset || 0;
|
|
|
|
if (typeof(options) == 'string') {
|
|
buf = options == 'binary' ? new BufferClass(16) : null;
|
|
options = null;
|
|
}
|
|
options = options || {};
|
|
|
|
var rnds = options.random || (options.rng || _rng)();
|
|
|
|
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
rnds[6] = (rnds[6] & 0x0f) | 0x40;
|
|
rnds[8] = (rnds[8] & 0x3f) | 0x80;
|
|
|
|
// Copy bytes to buffer, if provided
|
|
if (buf) {
|
|
for (var ii = 0; ii < 16; ii++) {
|
|
buf[i + ii] = rnds[ii];
|
|
}
|
|
}
|
|
|
|
return buf || unparse(rnds);
|
|
}
|
|
|
|
// Export public API
|
|
var uuid = v4;
|
|
uuid.v1 = v1;
|
|
uuid.v4 = v4;
|
|
uuid.parse = parse;
|
|
uuid.unparse = unparse;
|
|
uuid.BufferClass = BufferClass;
|
|
|
|
if (_global.define && define.amd) {
|
|
// Publish as AMD module
|
|
define(function() {return uuid;});
|
|
} else if (typeof(module) != 'undefined' && module.exports) {
|
|
// Publish as node.js module
|
|
module.exports = uuid;
|
|
} else {
|
|
// Publish as global (in browsers)
|
|
var _previousRoot = _global.uuid;
|
|
|
|
// **`noConflict()` - (browser only) to reset global 'uuid' var**
|
|
uuid.noConflict = function() {
|
|
_global.uuid = _previousRoot;
|
|
return uuid;
|
|
};
|
|
|
|
_global.uuid = uuid;
|
|
}
|
|
}());
|
|
|
|
},{"__browserify_Buffer":65,"crypto":60}],77:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports, module);
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports', 'module'], factory);
|
|
}
|
|
}(this, function(exports, module) {
|
|
|
|
/**
|
|
* ANONYMOUS `Mechanism` constructor.
|
|
*
|
|
* This class implements the ANONYMOUS SASL mechanism.
|
|
*
|
|
* The ANONYMOUS SASL mechanism provides support for permitting anonymous
|
|
* access to various services
|
|
*
|
|
* References:
|
|
* - [RFC 4505](http://tools.ietf.org/html/rfc4505)
|
|
*
|
|
* @api public
|
|
*/
|
|
function Mechanism() {
|
|
}
|
|
|
|
Mechanism.prototype.name = 'ANONYMOUS';
|
|
Mechanism.prototype.clientFirst = true;
|
|
|
|
/**
|
|
* Encode a response using optional trace information.
|
|
*
|
|
* Options:
|
|
* - `trace` trace information (optional)
|
|
*
|
|
* @param {Object} cred
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.response = function(cred) {
|
|
return cred.trace || '';
|
|
};
|
|
|
|
/**
|
|
* Decode a challenge issued by the server.
|
|
*
|
|
* @param {String} chal
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.challenge = function(chal) {
|
|
};
|
|
|
|
exports = module.exports = Mechanism;
|
|
|
|
}));
|
|
|
|
},{}],78:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports,
|
|
module,
|
|
require('./lib/mechanism'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports',
|
|
'module',
|
|
'./lib/mechanism'], factory);
|
|
}
|
|
}(this, function(exports, module, Mechanism) {
|
|
|
|
exports = module.exports = Mechanism;
|
|
exports.Mechanism = Mechanism;
|
|
|
|
}));
|
|
|
|
},{"./lib/mechanism":77}],79:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports, module, require('crypto'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports', 'module', 'crypto'], factory);
|
|
}
|
|
}(this, function(exports, module, crypto) {
|
|
|
|
/**
|
|
* DIGEST-MD5 `Mechanism` constructor.
|
|
*
|
|
* This class implements the DIGEST-MD5 SASL mechanism.
|
|
*
|
|
* References:
|
|
* - [RFC 2831](http://tools.ietf.org/html/rfc2831)
|
|
*
|
|
* @api public
|
|
*/
|
|
function Mechanism(options) {
|
|
options = options || {};
|
|
this._genNonce = options.genNonce || genNonce(32);
|
|
}
|
|
|
|
Mechanism.prototype.name = 'DIGEST-MD5';
|
|
Mechanism.prototype.clientFirst = false;
|
|
|
|
/**
|
|
* Encode a response using given credential.
|
|
*
|
|
* Options:
|
|
* - `username`
|
|
* - `password`
|
|
* - `host`
|
|
* - `serviceType`
|
|
* - `authzid` authorization identity (optional)
|
|
*
|
|
* @param {Object} cred
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.response = function(cred) {
|
|
// TODO: Implement support for subsequent authentication. This requires
|
|
// that the client be able to store username, realm, nonce,
|
|
// nonce-count, cnonce, and qop values from prior authentication.
|
|
// The impact of this requirement needs to be investigated.
|
|
//
|
|
// See RFC 2831 (Section 2.2) for further details.
|
|
|
|
// TODO: Implement support for auth-int and auth-conf, as defined in RFC
|
|
// 2831 sections 2.3 Integrity Protection and 2.4 Confidentiality
|
|
// Protection, respectively.
|
|
//
|
|
// Note that supporting this functionality has implications
|
|
// regarding the negotiation of security layers via SASL. Due to
|
|
// the fact that TLS has largely superseded this functionality,
|
|
// implementing it is a low priority.
|
|
|
|
var uri = cred.serviceType + '/' + cred.host;
|
|
if (cred.serviceName && cred.host !== cred.serviceName) {
|
|
uri += '/' + serviceName;
|
|
}
|
|
var realm = cred.realm || this._realm || ''
|
|
, cnonce = this._genNonce()
|
|
, nc = '00000001'
|
|
, qop = 'auth'
|
|
, ha1
|
|
, ha2
|
|
, digest;
|
|
|
|
var str = '';
|
|
str += 'username="' + cred.username + '"';
|
|
if (realm) { str += ',realm="' + realm + '"'; };
|
|
str += ',nonce="' + this._nonce + '"';
|
|
str += ',cnonce="' + cnonce + '"';
|
|
str += ',nc=' + nc;
|
|
str += ',qop=' + qop;
|
|
str += ',digest-uri="' + uri + '"';
|
|
|
|
if (cred.authzid) {
|
|
ha1 = md5(md5(cred.username + ":" + realm + ":" + cred.password, 'binary') + ":" + this._nonce + ":" + cnonce + ":" + cred.authzid);
|
|
} else {
|
|
ha1 = md5(md5(cred.username + ":" + realm + ":" + cred.password, 'binary') + ":" + this._nonce + ":" + cnonce);
|
|
}
|
|
|
|
if (qop == 'auth') {
|
|
ha2 = md5('AUTHENTICATE:' + uri);
|
|
} else if (qop == 'auth-int' || qop == 'auth-conf') {
|
|
ha2 = md5('AUTHENTICATE:' + uri + ':00000000000000000000000000000000');
|
|
}
|
|
|
|
digest = md5(ha1 + ":" + this._nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2);
|
|
str += ',response=' + digest;
|
|
|
|
if (this._charset == 'utf-8') { str += ',charset=utf-8'; }
|
|
if (cred.authzid) { str += 'authzid="' + cred.authzid + '"'; }
|
|
|
|
return str;
|
|
};
|
|
|
|
/**
|
|
* Decode a challenge issued by the server.
|
|
*
|
|
* @param {String} chal
|
|
* @return {Mechanism} for chaining
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.challenge = function(chal) {
|
|
var dtives = parse(chal);
|
|
|
|
// TODO: Implement support for multiple realm directives, as allowed by the
|
|
// DIGEST-MD5 specification.
|
|
this._realm = dtives['realm'];
|
|
this._nonce = dtives['nonce'];
|
|
this._qop = (dtives['qop'] || 'auth').split(',');
|
|
this._stale = dtives['stale'];
|
|
this._maxbuf = parseInt(dtives['maxbuf']) || 65536;
|
|
this._charset = dtives['charset'];
|
|
this._algo = dtives['algorithm'];
|
|
this._cipher = dtives['cipher'];
|
|
if (this._cipher) { this._cipher.split(','); }
|
|
return this;
|
|
};
|
|
|
|
|
|
/**
|
|
* Parse challenge.
|
|
*
|
|
* @api private
|
|
*/
|
|
function parse(chal) {
|
|
var dtives = {};
|
|
var tokens = chal.split(/,(?=(?:[^"]|"[^"]*")*$)/);
|
|
for (var i = 0, len = tokens.length; i < len; i++) {
|
|
var dtiv = /(\w+)=["]?([^"]+)["]?$/.exec(tokens[i]);
|
|
if (dtiv) {
|
|
dtives[dtiv[1]] = dtiv[2];
|
|
}
|
|
}
|
|
return dtives;
|
|
}
|
|
|
|
/**
|
|
* Return a unique nonce with the given `len`.
|
|
*
|
|
* genNonce(10)();
|
|
* // => "FDaS435D2z"
|
|
*
|
|
* @param {Number} len
|
|
* @return {Function}
|
|
* @api private
|
|
*/
|
|
function genNonce(len) {
|
|
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
, charlen = chars.length;
|
|
|
|
return function() {
|
|
var buf = [];
|
|
for (var i = 0; i < len; ++i) {
|
|
buf.push(chars[Math.random() * charlen | 0]);
|
|
}
|
|
return buf.join('');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return md5 hash of the given string and optional encoding,
|
|
* defaulting to hex.
|
|
*
|
|
* md5('wahoo');
|
|
* // => "e493298061761236c96b02ea6aa8a2ad"
|
|
*
|
|
* @param {String} str
|
|
* @param {String} encoding
|
|
* @return {String}
|
|
* @api private
|
|
*/
|
|
function md5(str, encoding){
|
|
return crypto
|
|
.createHash('md5')
|
|
.update(str)
|
|
.digest(encoding || 'hex');
|
|
}
|
|
|
|
|
|
exports = module.exports = Mechanism;
|
|
|
|
}));
|
|
|
|
},{"crypto":60}],80:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports,
|
|
module,
|
|
require('./lib/mechanism'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports',
|
|
'module',
|
|
'./lib/mechanism'], factory);
|
|
}
|
|
}(this, function(exports, module, Mechanism) {
|
|
|
|
exports = module.exports = Mechanism;
|
|
exports.Mechanism = Mechanism;
|
|
|
|
}));
|
|
|
|
},{"./lib/mechanism":79}],81:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports, module);
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports', 'module'], factory);
|
|
}
|
|
}(this, function(exports, module) {
|
|
|
|
/**
|
|
* EXTERNAL `Mechanism` constructor.
|
|
*
|
|
* This class implements the EXTERNAL SASL mechanism.
|
|
*
|
|
* The EXTERNAL SASL mechanism provides support for authentication using
|
|
* credentials established by external means.
|
|
*
|
|
* References:
|
|
* - [RFC 4422](http://tools.ietf.org/html/rfc4422)
|
|
*
|
|
* @api public
|
|
*/
|
|
function Mechanism() {
|
|
}
|
|
|
|
Mechanism.prototype.name = 'EXTERNAL';
|
|
Mechanism.prototype.clientFirst = true;
|
|
|
|
/**
|
|
* Encode a response using given credential.
|
|
*
|
|
* Options:
|
|
* - `authzid` authorization identity (optional)
|
|
*
|
|
* @param {Object} cred
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.response = function(cred) {
|
|
return cred.authzid || '';
|
|
};
|
|
|
|
/**
|
|
* Decode a challenge issued by the server.
|
|
*
|
|
* @param {String} chal
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.challenge = function(chal) {
|
|
};
|
|
|
|
exports = module.exports = Mechanism;
|
|
|
|
}));
|
|
|
|
},{}],82:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports,
|
|
module,
|
|
require('./lib/mechanism'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports',
|
|
'module',
|
|
'./lib/mechanism'], factory);
|
|
}
|
|
}(this, function(exports, module, Mechanism) {
|
|
|
|
exports = module.exports = Mechanism;
|
|
exports.Mechanism = Mechanism;
|
|
|
|
}));
|
|
|
|
},{"./lib/mechanism":81}],83:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports, module);
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports', 'module'], factory);
|
|
}
|
|
}(this, function(exports, module) {
|
|
|
|
/**
|
|
* PLAIN `Mechanism` constructor.
|
|
*
|
|
* This class implements the PLAIN SASL mechanism.
|
|
*
|
|
* The PLAIN SASL mechanism provides support for exchanging a clear-text
|
|
* username and password. This mechanism should not be used without adequate
|
|
* security provided by an underlying transport layer.
|
|
*
|
|
* References:
|
|
* - [RFC 4616](http://tools.ietf.org/html/rfc4616)
|
|
*
|
|
* @api public
|
|
*/
|
|
function Mechanism() {
|
|
}
|
|
|
|
Mechanism.prototype.name = 'PLAIN';
|
|
Mechanism.prototype.clientFirst = true;
|
|
|
|
/**
|
|
* Encode a response using given credential.
|
|
*
|
|
* Options:
|
|
* - `username`
|
|
* - `password`
|
|
* - `authzid` authorization identity (optional)
|
|
*
|
|
* @param {Object} cred
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.response = function(cred) {
|
|
var str = '';
|
|
str += cred.authzid || '';
|
|
str += '\0';
|
|
str += cred.username;
|
|
str += '\0';
|
|
str += cred.password;
|
|
return str;
|
|
};
|
|
|
|
/**
|
|
* Decode a challenge issued by the server.
|
|
*
|
|
* @param {String} chal
|
|
* @return {Mechanism} for chaining
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.challenge = function(chal) {
|
|
return this;
|
|
};
|
|
|
|
exports = module.exports = Mechanism;
|
|
|
|
}));
|
|
|
|
},{}],84:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports,
|
|
module,
|
|
require('./lib/mechanism'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports',
|
|
'module',
|
|
'./lib/mechanism'], factory);
|
|
}
|
|
}(this, function(exports, module, Mechanism) {
|
|
|
|
exports = module.exports = Mechanism;
|
|
exports.Mechanism = Mechanism;
|
|
|
|
}));
|
|
|
|
},{"./lib/mechanism":83}],85:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports, module, require('crypto'), require('buffer'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports', 'module', 'crypto', 'buffer'], factory);
|
|
}
|
|
}(this, function(exports, module, crypto, buffer) {
|
|
|
|
var Buffer = buffer.Buffer;
|
|
|
|
/**
|
|
* SCRAM-SHA-1 `Mechanism` constructor.
|
|
*
|
|
* This class implements the SCRAM-SHA-1 SASL mechanism.
|
|
*
|
|
* References:
|
|
* - [RFC 5802](http://tools.ietf.org/html/rfc5802)
|
|
*
|
|
* @api public
|
|
*/
|
|
function Mechanism(options) {
|
|
options = options || {};
|
|
this._genNonce = options.genNonce || genNonce(32);
|
|
this._stage = 0;
|
|
}
|
|
|
|
Mechanism.prototype.name = 'SCRAM-SHA-1';
|
|
Mechanism.prototype.clientFirst = true;
|
|
|
|
/**
|
|
* Encode a response using given credentials.
|
|
*
|
|
* Options:
|
|
* - `username`
|
|
* - `password`
|
|
* - `authzid`
|
|
*
|
|
* @param {object} cred
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.response = function (cred) {
|
|
return responses[this._stage](this, cred);
|
|
};
|
|
|
|
/**
|
|
* Decode a challenge issued by the server.
|
|
*
|
|
* @param {String} chal
|
|
* @return {Mechanism} for chaining
|
|
* @api public
|
|
*/
|
|
Mechanism.prototype.challenge = function (chal) {
|
|
var values = parse(chal);
|
|
|
|
this._salt = new Buffer(values.s || '', 'base64').toString('binary');
|
|
this._iterationCount = parseInt(values.i, 10);
|
|
this._nonce = values.r;
|
|
this._verifier = values.v;
|
|
this._error = values.e;
|
|
this._challenge = chal;
|
|
|
|
return this;
|
|
};
|
|
|
|
|
|
var responses = {};
|
|
responses[0] = function (mech, cred) {
|
|
mech._cnonce = mech._genNonce();
|
|
|
|
var authzid = '';
|
|
if (cred.authzid) {
|
|
authzid = 'a=' + saslname(cred.authzid);
|
|
}
|
|
|
|
mech._gs2Header = 'n,' + authzid + ',';
|
|
|
|
var nonce = 'r=' + mech._cnonce;
|
|
var username = 'n=' + saslname(cred.username);
|
|
|
|
mech._clientFirstMessageBare = username + ',' + nonce;
|
|
var result = mech._gs2Header + mech._clientFirstMessageBare
|
|
|
|
mech._stage = 1;
|
|
|
|
return result;
|
|
};
|
|
responses[1] = function (mech, cred) {
|
|
var gs2Header = new Buffer(mech._gs2Header).toString('base64');
|
|
|
|
mech._clientFinalMessageWithoutProof = 'c=' + gs2Header + ',r=' + mech._nonce;
|
|
|
|
var saltedPassword = Hi(cred.password, mech._salt, mech._iterationCount);
|
|
var clientKey = HMAC(saltedPassword, 'Client Key');
|
|
var storedKey = H(clientKey);
|
|
var authMessage = mech._clientFirstMessageBare + ',' +
|
|
mech._challenge + ',' +
|
|
mech._clientFinalMessageWithoutProof;
|
|
var clientSignature = HMAC(storedKey, authMessage);
|
|
|
|
var xorstuff = XOR(clientKey, clientSignature);
|
|
|
|
var clientProof = new Buffer(xorstuff, 'binary').toString('base64');
|
|
var serverKey = HMAC(saltedPassword, 'Server Key');
|
|
|
|
mech._serverSignature = HMAC(serverKey, authMessage);
|
|
|
|
var result = mech._clientFinalMessageWithoutProof + ',p=' + clientProof;
|
|
|
|
mech._stage = 2;
|
|
|
|
return result;
|
|
};
|
|
responses[2] = function (mech, cred) {
|
|
// TODO: Signal errors
|
|
return '';
|
|
};
|
|
|
|
/**
|
|
* Create a SHA-1 HMAC.
|
|
*
|
|
* @param {String} key
|
|
* @param {String} msg
|
|
* @api private
|
|
*/
|
|
function HMAC(key, msg) {
|
|
return crypto.createHmac('sha1', key).update(msg).digest('binary');
|
|
}
|
|
|
|
/**
|
|
* Iteratively create an HMAC, with a salt.
|
|
*
|
|
* @param {String} text
|
|
* @param {String} salt
|
|
* @param {Number} iterations
|
|
* @api private
|
|
*/
|
|
function Hi(text, salt, iterations) {
|
|
var ui1 = HMAC(text, salt + '\0\0\0\1');
|
|
ui = ui1;
|
|
for (var i = 0; i < iterations - 1; i++) {
|
|
ui1 = HMAC(text, ui1);
|
|
ui = XOR(ui, ui1);
|
|
}
|
|
return ui;
|
|
}
|
|
|
|
/**
|
|
* Create a SHA-1 hash.
|
|
*
|
|
* @param {String} text
|
|
* @api private
|
|
*/
|
|
function H(text) {
|
|
return crypto.createHash('sha1').update(text).digest('binary');
|
|
}
|
|
|
|
/**
|
|
* String XOR
|
|
*
|
|
* @param {String} a
|
|
* @param {String} b
|
|
* @api private
|
|
*/
|
|
function XOR(a, b) {
|
|
a = new Buffer(a, 'binary');
|
|
b = new Buffer(b, 'binary');
|
|
|
|
var len = Math.min(a.length, b.length);
|
|
result = [];
|
|
for (var i = 0; i < len; i++) {
|
|
result.push(a[i] ^ b[i]);
|
|
}
|
|
result = new Buffer(result, 'binary');
|
|
return result.toString('binary');
|
|
}
|
|
|
|
/**
|
|
* Escape special characters in username values.
|
|
*
|
|
* @param {String} name
|
|
* @api private
|
|
*/
|
|
function saslname(name) {
|
|
var escaped = [];
|
|
var curr = '';
|
|
for (var i = 0; i < name.length; i++) {
|
|
curr = name[i];
|
|
if (curr === ',') {
|
|
escaped.push('=2C');
|
|
} else if (curr === '=') {
|
|
escaped.push('=3D');
|
|
} else {
|
|
escaped.push(curr);
|
|
}
|
|
}
|
|
return escaped.join('');
|
|
}
|
|
|
|
/**
|
|
* Parse challenge.
|
|
*
|
|
* @api private
|
|
*/
|
|
function parse(chal) {
|
|
var dtives = {};
|
|
var tokens = chal.split(/,(?=(?:[^"]|"[^"]*")*$)/);
|
|
for (var i = 0, len = tokens.length; i < len; i++) {
|
|
var dtiv = /(\w+)=["]?([^"]+)["]?$/.exec(tokens[i]);
|
|
if (dtiv) {
|
|
dtives[dtiv[1]] = dtiv[2];
|
|
}
|
|
}
|
|
return dtives;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return a unique nonce with the given `len`.
|
|
*
|
|
* genNonce(10)();
|
|
* // => "FDaS435D2z"
|
|
*
|
|
* @param {Number} len
|
|
* @return {Function}
|
|
* @api private
|
|
*/
|
|
function genNonce(len) {
|
|
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
var charlen = chars.length;
|
|
|
|
return function() {
|
|
var buf = [];
|
|
for (var i = 0; i < len; ++i) {
|
|
buf.push(chars[Math.random() * charlen | 0]);
|
|
}
|
|
return buf.join('');
|
|
}
|
|
}
|
|
|
|
exports = module.exports = Mechanism;
|
|
}));
|
|
|
|
},{"buffer":58,"crypto":60}],86:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports,
|
|
module,
|
|
require('./lib/mechanism'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports',
|
|
'module',
|
|
'./lib/mechanism'], factory);
|
|
}
|
|
}(this, function(exports, module, Mechanism) {
|
|
|
|
exports = module.exports = Mechanism;
|
|
exports.Mechanism = Mechanism;
|
|
|
|
}));
|
|
|
|
},{"./lib/mechanism":85}],87:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports, module);
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports', 'module'], factory);
|
|
}
|
|
}(this, function(exports, module) {
|
|
|
|
/**
|
|
* `Factory` constructor.
|
|
*
|
|
* @api public
|
|
*/
|
|
function Factory() {
|
|
this._mechs = [];
|
|
}
|
|
|
|
/**
|
|
* Utilize the given `mech` with optional `name`, overridding the mechanism's
|
|
* default name.
|
|
*
|
|
* Examples:
|
|
*
|
|
* factory.use(FooMechanism);
|
|
*
|
|
* factory.use('XFOO', FooMechanism);
|
|
*
|
|
* @param {String|Mechanism} name
|
|
* @param {Mechanism} mech
|
|
* @return {Factory} for chaining
|
|
* @api public
|
|
*/
|
|
Factory.prototype.use = function(name, mech) {
|
|
if (!mech) {
|
|
mech = name;
|
|
name = mech.prototype.name;
|
|
}
|
|
this._mechs.push({ name: name, mech: mech });
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Create a new mechanism from supported list of `mechs`.
|
|
*
|
|
* If no mechanisms are supported, returns `null`.
|
|
*
|
|
* Examples:
|
|
*
|
|
* var mech = factory.create(['FOO', 'BAR']);
|
|
*
|
|
* @param {Array} mechs
|
|
* @return {Mechanism}
|
|
* @api public
|
|
*/
|
|
Factory.prototype.create = function(mechs) {
|
|
for (var i = 0, len = this._mechs.length; i < len; i++) {
|
|
for (var j = 0, jlen = mechs.length; j < jlen; j++) {
|
|
var entry = this._mechs[i];
|
|
if (entry.name == mechs[j]) {
|
|
return new entry.mech();
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
exports = module.exports = Factory;
|
|
|
|
}));
|
|
|
|
},{}],88:[function(require,module,exports){
|
|
(function(root, factory) {
|
|
if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(exports,
|
|
module,
|
|
require('./lib/factory'));
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['exports',
|
|
'module',
|
|
'./lib/factory'], factory);
|
|
}
|
|
}(this, function(exports, module, Factory) {
|
|
|
|
exports = module.exports = Factory;
|
|
exports.Factory = Factory;
|
|
|
|
}));
|
|
|
|
},{"./lib/factory":87}],89:[function(require,module,exports){
|
|
/*
|
|
WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based
|
|
on @visionmedia's Emitter from UI Kit.
|
|
|
|
Why? I wanted it standalone.
|
|
|
|
I also wanted support for wildcard emitters like this:
|
|
|
|
emitter.on('*', function (eventName, other, event, payloads) {
|
|
|
|
});
|
|
|
|
emitter.on('somenamespace*', function (eventName, payloads) {
|
|
|
|
});
|
|
|
|
Please note that callbacks triggered by wildcard registered events also get
|
|
the event name as the first argument.
|
|
*/
|
|
module.exports = WildEmitter;
|
|
|
|
function WildEmitter() {
|
|
this.callbacks = {};
|
|
}
|
|
|
|
// Listen on the given `event` with `fn`. Store a group name if present.
|
|
WildEmitter.prototype.on = function (event, groupName, fn) {
|
|
var hasGroup = (arguments.length === 3),
|
|
group = hasGroup ? arguments[1] : undefined,
|
|
func = hasGroup ? arguments[2] : arguments[1];
|
|
func._groupName = group;
|
|
(this.callbacks[event] = this.callbacks[event] || []).push(func);
|
|
return this;
|
|
};
|
|
|
|
// Adds an `event` listener that will be invoked a single
|
|
// time then automatically removed.
|
|
WildEmitter.prototype.once = function (event, groupName, fn) {
|
|
var self = this,
|
|
hasGroup = (arguments.length === 3),
|
|
group = hasGroup ? arguments[1] : undefined,
|
|
func = hasGroup ? arguments[2] : arguments[1];
|
|
function on() {
|
|
self.off(event, on);
|
|
func.apply(this, arguments);
|
|
}
|
|
this.on(event, group, on);
|
|
return this;
|
|
};
|
|
|
|
// Unbinds an entire group
|
|
WildEmitter.prototype.releaseGroup = function (groupName) {
|
|
var item, i, len, handlers;
|
|
for (item in this.callbacks) {
|
|
handlers = this.callbacks[item];
|
|
for (i = 0, len = handlers.length; i < len; i++) {
|
|
if (handlers[i]._groupName === groupName) {
|
|
//console.log('removing');
|
|
// remove it and shorten the array we're looping through
|
|
handlers.splice(i, 1);
|
|
i--;
|
|
len--;
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
// Remove the given callback for `event` or all
|
|
// registered callbacks.
|
|
WildEmitter.prototype.off = function (event, fn) {
|
|
var callbacks = this.callbacks[event],
|
|
i;
|
|
|
|
if (!callbacks) return this;
|
|
|
|
// remove all handlers
|
|
if (arguments.length === 1) {
|
|
delete this.callbacks[event];
|
|
return this;
|
|
}
|
|
|
|
// remove specific handler
|
|
i = callbacks.indexOf(fn);
|
|
callbacks.splice(i, 1);
|
|
return this;
|
|
};
|
|
|
|
// Emit `event` with the given args.
|
|
// also calls any `*` handlers
|
|
WildEmitter.prototype.emit = function (event) {
|
|
var args = [].slice.call(arguments, 1),
|
|
callbacks = this.callbacks[event],
|
|
specialCallbacks = this.getWildcardCallbacks(event),
|
|
i,
|
|
len,
|
|
item;
|
|
|
|
if (callbacks) {
|
|
for (i = 0, len = callbacks.length; i < len; ++i) {
|
|
if (callbacks[i]) {
|
|
callbacks[i].apply(this, args);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (specialCallbacks) {
|
|
for (i = 0, len = specialCallbacks.length; i < len; ++i) {
|
|
if (specialCallbacks[i]) {
|
|
specialCallbacks[i].apply(this, [event].concat(args));
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
// Helper for for finding special wildcard event handlers that match the event
|
|
WildEmitter.prototype.getWildcardCallbacks = function (eventName) {
|
|
var item,
|
|
split,
|
|
result = [];
|
|
|
|
for (item in this.callbacks) {
|
|
split = item.split('*');
|
|
if (item === '*' || (split.length === 2 && eventName.slice(0, split[1].length) === split[1])) {
|
|
result = result.concat(this.callbacks[item]);
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
},{}],90:[function(require,module,exports){
|
|
var global=self;/**
|
|
* @license
|
|
* Lo-Dash 1.3.1 (Custom Build) lodash.com/license
|
|
* Build: `lodash include="each,unique,extend"`
|
|
* Underscore.js 1.4.4 underscorejs.org/LICENSE
|
|
*/
|
|
;(function(G){function H(a,d,b){b=(b||0)-1;for(var c=a.length;++b<c;)if(a[b]===d)return b;return-1}function pa(a,d){var b=typeof d;a=a.k;if("boolean"==b||null==d)return a[d];"number"!=b&&"string"!=b&&(b="object");var c="number"==b?d:Z+d;a=a[b]||(a[b]={});return"object"==b?a[c]&&-1<H(a[c],d)?0:-1:a[c]?0:-1}function qa(a){var d=this.k,b=typeof a;if("boolean"==b||null==a)d[a]=!0;else{"number"!=b&&"string"!=b&&(b="object");var c="number"==b?a:Z+a,e=d[b]||(d[b]={});if("object"==b){if((e[c]||(e[c]=[])).push(a)==
|
|
this.b.length)d[b]=!1}else e[c]=!0}}function P(){return Q.pop()||{a:"",b:null,c:"",k:null,"false":!1,d:"",e:"",f:"","null":!1,number:null,object:null,push:null,g:null,string:null,h:"","true":!1,undefined:!1,i:!1,j:!1}}function $(a){return typeof a.toString!="function"&&typeof(a+"")=="string"}function y(a){a.length=0;z.length<aa&&z.push(a)}function I(a){var d=a.k;d&&I(d);a.b=a.k=a.object=a.number=a.string=null;Q.length<aa&&Q.push(a)}function f(){}function J(){var a=P();a.g=R;a.b=a.c=a.f=a.h="";a.e=
|
|
"r";a.i=!0;a.j=!!K;for(var d,b=0;d=arguments[b];b++)for(var c in d)a[c]=d[c];b=a.a;a.d=/^[^,]+/.exec(b)[0];d=Function;b="return function("+b+"){";c="var m,r="+a.d+",C="+a.e+";if(!r)return C;"+a.h+";";a.b?(c+="var s=r.length;m=-1;if("+a.b+"){",h.unindexedChars&&(c+="if(q(r)){r=r.split('')}"),c+="while(++m<s){"+a.f+";}}else{"):h.nonEnumArgs&&(c+="var s=r.length;m=-1;if(s&&n(r)){while(++m<s){m+='';"+a.f+";}}else{");h.enumPrototypes&&(c+="var E=typeof r=='function';");h.enumErrorProps&&(c+="var D=r===j||r instanceof Error;");
|
|
var e=[];h.enumPrototypes&&e.push('!(E&&m=="prototype")');h.enumErrorProps&&e.push('!(D&&(m=="message"||m=="name"))');if(a.i&&a.j)c+="var A=-1,B=z[typeof r]&&t(r),s=B?B.length:0;while(++A<s){m=B[A];",e.length&&(c+="if("+e.join("&&")+"){"),c+=a.f+";",e.length&&(c+="}"),c+="}";else if(c+="for(m in r){",a.i&&e.push("l.call(r, m)"),e.length&&(c+="if("+e.join("&&")+"){"),c+=a.f+";",e.length&&(c+="}"),c+="}",h.nonEnumShadows){c+="if(r!==y){var h=r.constructor,p=r===(h&&h.prototype),e=r===H?G:r===j?i:J.call(r),v=w[e];";
|
|
for(k=0;7>k;k++)c+="m='"+a.g[k]+"';if((!(p&&v[m])&&l.call(r,m))",a.i||(c+="||(!v[m]&&r[m]!==y[m])"),c+="){"+a.f+"}";c+="}"}if(a.b||h.nonEnumArgs)c+="}";c+=a.c+";return C";d=d("i,j,l,n,o,q,t,u,y,z,w,G,H,J",b+c+"}");I(a);return d(ba,S,q,v,T,ca,K,f,A,B,l,L,ra,t)}function v(a){return t.call(a)==U}function w(a,d,b,c,e,r){var M=b===da;if(typeof b=="function"&&!M){b=f.createCallback(b,c,2);var n=b(a,d);if(typeof n!="undefined")return!!n}if(a===d)return 0!==a||1/a==1/d;var m=typeof a,g=typeof d;if(a===a&&
|
|
(!a||"function"!=m&&"object"!=m)&&(!d||"function"!=g&&"object"!=g))return!1;if(null==a||null==d)return a===d;g=t.call(a);m=t.call(d);g==U&&(g=C);m==U&&(m=C);if(g!=m)return!1;switch(g){case ea:case fa:return+a==+d;case ga:return a!=+a?d!=+d:0==a?1/a==1/d:a==+d;case ha:case L:return a==String(d)}m=g==V;if(!m){if(q.call(a,"__wrapped__")||q.call(d,"__wrapped__"))return w(a.__wrapped__||a,d.__wrapped__||d,b,c,e,r);if(g!=C||!h.nodeClass&&($(a)||$(d)))return!1;var g=!h.argsObject&&v(a)?Object:a.constructor,
|
|
u=!h.argsObject&&v(d)?Object:d.constructor;if(g!=u&&(!D(g)||!(g instanceof g&&D(u)&&u instanceof u)))return!1}u=!e;e||(e=z.pop()||[]);r||(r=z.pop()||[]);for(g=e.length;g--;)if(e[g]==a)return r[g]==d;var l=0,n=!0;e.push(a);r.push(d);if(m){g=a.length;l=d.length;n=l==a.length;if(!n&&!M)return n;for(;l--;)if(m=g,u=d[l],M)for(;m--&&!(n=w(a[m],u,b,c,e,r)););else if(!(n=w(a[l],u,b,c,e,r)))break;return n}W(d,function(d,f,g){if(q.call(g,f))return l++,n=q.call(a,f)&&w(a[f],d,b,c,e,r)});n&&!M&&W(a,function(a,
|
|
b,c){if(q.call(c,b))return n=-1<--l});u&&(y(e),y(r));return n}function D(a){return typeof a=="function"}function ia(a){return!(!a||!B[typeof a])}function ca(a){return typeof a=="string"||t.call(a)==L}function ja(a,d,b){if(d&&typeof b=="undefined"&&T(a)){b=-1;for(var c=a.length;++b<c&&false!==d(a[b],b,a););}else sa(a,d,b);return a}function ka(a,d,b){if(typeof b=="number"){var c=a?a.length:0;b=0>b?ta(0,c+b):b||0}else if(b)return b=la(a,d),a[b]===d?b:-1;return a?H(a,d,b):-1}function la(a,d,b,c){var e=0,r=
|
|
a?a.length:e;b=b?f.createCallback(b,c,1):X;for(d=b(d);e<r;)c=e+r>>>1,b(a[c])<d?e=c+1:r=c;return e}function X(a){return a}var z=[],Q=[],da={},Z=+new Date+"",aa=40,E=(E=/\bthis\b/)&&E.test(function(){return this})&&E,R="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),U="[object Arguments]",V="[object Array]",ea="[object Boolean]",fa="[object Date]",ba="[object Error]",ga="[object Number]",C="[object Object]",ha="[object RegExp]",L="[object String]",
|
|
B={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},N=B[typeof exports]&&exports,ma=B[typeof module]&&module&&module.exports==N&&module,s=B[typeof global]&&global;if(s&&(s.global===s||s.window===s))G=s;var S=Error.prototype,A=Object.prototype,ra=String.prototype,s=RegExp("^"+String(A.valueOf).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),ua=Function.prototype.toString,q=A.hasOwnProperty,Y=A.propertyIsEnumerable,t=A.toString,F=s.test(F=t.bind)&&
|
|
F,p=s.test(p=Object.create)&&p,x=s.test(x=Array.isArray)&&x,O=s.test(O=Object.keys)&&O,ta=Math.max,p=s.test(G.attachEvent),va=F&&!/\n|true/.test(F+p),l={};l[V]=l[fa]=l[ga]={constructor:!0,toLocaleString:!0,toString:!0,valueOf:!0};l[ea]=l[L]={constructor:!0,toString:!0,valueOf:!0};l[ba]=l["[object Function]"]=l[ha]={constructor:!0,toString:!0};l[C]={constructor:!0};(function(){for(var a=R.length;a--;){var d=R[a],b;for(b in l)q.call(l,b)&&!q.call(l[b],d)&&(l[b][d]=!1)}})();var h=f.support={};(function(){var a=
|
|
function(){this.x=1},d=[];a.prototype={valueOf:1,y:1};for(var b in new a)d.push(b);for(b in arguments);h.argsObject=arguments.constructor==Object&&!(arguments instanceof Array);h.argsClass=v(arguments);h.enumErrorProps=Y.call(S,"message")||Y.call(S,"name");h.enumPrototypes=Y.call(a,"prototype");h.fastBind=F&&!va;h.nonEnumArgs=0!=b;h.nonEnumShadows=!/valueOf/.test(d);h.unindexedChars="xx"!="x"[0]+Object("x")[0];try{h.nodeClass=!(t.call(document)==C&&!({toString:0}+""))}catch(c){h.nodeClass=!0}})(1);var na={a:"x,F,k",
|
|
h:"var a=arguments,b=0,c=typeof k=='number'?2:a.length;while(++b<c){r=a[b];if(r&&z[typeof r]){",f:"if(typeof C[m]=='undefined')C[m]=r[m]",c:"}}"},p={a:"f,d,I",h:"d=d&&typeof I=='undefined'?d:u.createCallback(d,I)",b:"typeof s=='number'",f:"if(d(r[m],m,f)===false)return C"},s={h:"if(!z[typeof r])return C;"+p.h,b:!1};h.argsClass||(v=function(a){return a?q.call(a,"callee"):!1});var T=x||function(a){return a?typeof a=="object"&&t.call(a)==V:!1},oa=J({a:"x",e:"[]",h:"if(!(z[typeof x]))return C",f:"C.push(m)"}),
|
|
K=!O?oa:function(a){return!ia(a)?[]:h.enumPrototypes&&typeof a=="function"||h.nonEnumArgs&&a.length&&v(a)?oa(a):O(a)},sa=J(p),x=J(na,{h:na.h.replace(";",";if(c>3&&typeof a[c-2]=='function'){var d=u.createCallback(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){d=a[--c]}"),f:"C[m]=d?d(C[m],r[m]):r[m]"}),W=J(p,s,{i:!1});D(/x/)&&(D=function(a){return typeof a=="function"&&"[object Function]"==t.call(a)});p=function(a){return function(d,b,c,e){typeof b!="boolean"&&null!=b&&(e=c,c=!(e&&e[b]===
|
|
d)?b:void 0,b=!1);null!=c&&(c=f.createCallback(c,e));return a(d,b,c,e)}}(function(a,d,b){var c=-1,e;e=(e=f.indexOf)===ka?H:e;var r=a?a.length:0,h=[],n=!d&&75<=r&&e===H,m=b||n?z.pop()||[]:h;if(n){var g;g=m;var l=-1,s=g.length,p=P();p["false"]=p["null"]=p["true"]=p.undefined=!1;var q=P();q.b=g;q.k=p;for(q.push=qa;++l<s;)q.push(g[l]);(g=false===p.object?(I(q),null):q)?(e=pa,m=g):(n=!1,m=b?m:(y(m),h))}for(;++c<r;)if(g=a[c],l=b?b(g,c,a):g,d?!c||m[m.length-1]!==l:0>e(m,l))(b||n)&&m.push(l),h.push(g);n?(y(m.b),
|
|
I(m)):b&&y(m);return h});f.assign=x;f.createCallback=function(a,d,b){if(null==a)return X;var c=typeof a;if("function"!=c){if("object"!=c)return function(b){return b[a]};var e=K(a);return function(b){for(var c=e.length,d=!1;c--&&(d=w(b[e[c]],a[e[c]],da)););return d}}return typeof d=="undefined"||E&&!E.test(ua.call(a))?a:1===b?function(b){return a.call(d,b)}:2===b?function(b,c){return a.call(d,b,c)}:4===b?function(b,c,e,f){return a.call(d,b,c,e,f)}:function(b,c,e){return a.call(d,b,c,e)}};f.forEach=
|
|
ja;f.forIn=W;f.keys=K;f.uniq=p;f.each=ja;f.extend=x;f.unique=p;f.identity=X;f.indexOf=ka;f.isArguments=v;f.isArray=T;f.isEqual=w;f.isFunction=D;f.isObject=ia;f.isString=ca;f.sortedIndex=la;f.VERSION="1.3.1";typeof define=="function"&&typeof define.amd=="object"&&define.amd?(G._=f, define(function(){return f})):N&&!N.nodeType?ma?(ma.exports=f)._=f:N._=f:G._=f})(this);
|
|
},{}]},{},[1])(1)
|
|
});
|
|
;
|
|
/*
|
|
* Sugar Library v1.2.1
|
|
*
|
|
* Freely distributable and licensed under the MIT-style license.
|
|
* Copyright (c) 2012 Andrew Plummer
|
|
* http://sugarjs.com/
|
|
*
|
|
* ---------------------------- */
|
|
(function(context){var i=true,j=false;function k(a){return function(){return a}}var l=Object,o=Array,r=RegExp,s=Date,t=String,u=Number,aa=l.defineProperty&&l.defineProperties;function v(a,b,c,d){var f=b?a.prototype:a;w(d,function(g,h){if(typeof c==="function")y(f,g,ba(f[g],h,c));else if(c===i||!f[g])y(f,g,h)})}function ba(a,b,c){return function(){return a&&(c===i||c.apply(this,arguments))?a.apply(this,arguments):b.apply(this,arguments)}}
|
|
function y(a,b,c){if(aa)l.defineProperty(a,b,{value:c,configurable:i,enumerable:j,writable:i});else a[b]=c}function w(a,b){var c=0,d;for(d in a)if(a.hasOwnProperty(d)){b.call(a,d,a[d],c);c++}}function z(a,b,c,d){return a===b?i:l.isRegExp(b)?r(b).test(a):l.isFunction(b)?b.apply(c,[a].concat(d)):l.equal(b,a)}function A(a,b,c,d){return B(b)?a:l.isFunction(b)?b.apply(c,d||[]):l.isFunction(a[b])?a[b].call(a):a[b]}function da(a,b,c,d){a=Array.prototype.slice.call(a,void 0);if(c!==j)a=C(a);D(a,b,d)}
|
|
function B(a){return a===void 0}function E(a){return a!==void 0}function F(a,b,c,d){typeof b=="object"&&w(b,function(f,g){var h=a[f],e=E(h),m=l.isArray(g);if(c===i&&(m||l.isObject(g))){h||(h=m?[]:{});F(h,g,c)}else if(e&&l.isFunction(d))h=d.call(b,f,a[f],b[f]);else if(!e||e&&d!==j)h=b[f];if(E(h))a[f]=h});return a}
|
|
v(l,j,j,{isObject:function(a){return a===null||B(a)?j:l.prototype.toString.call(a)==="[object Object]"&&a.constructor===l},each:function(a,b){b&&w(a,function(c,d){b.call(a,c,d,a)});return a},merge:function(a,b,c){return F(a,b,i,c)}});function D(a,b,c,d){var f;G(b);if(c<0)c=a.length+c;c=isNaN(c)?0:parseInt(c>>0);for(d=d===i?a.length+c:a.length;c<d;){f=c%a.length;if(b.call(a,a[f],f,a)===j)break;c++}}
|
|
function H(a,b,c,d,f){var g,h;D(a,function(e,m,q){if(z(e,b,q,[m,q])){g=e;h=m;return j}},c,d);return f?h:g}function C(a,b,c){b=b||Infinity;c=c||0;var d=[];D(a,function(f){if(l.isArray(f)&&c<b)d=d.concat(C(f,b,c+1));else d.push(f)});return d}function I(a,b,c,d){var f=a.length,g=d==-1,h=g?f-1:0;c=isNaN(c)?h:parseInt(c>>0);if(c<0)c=f+c;if(!g&&c<0||g&&c>=f)c=h;for(;g&&c>=0||!g&&c<f;){if(a[c]===b)return c;c+=d}return-1}function G(a){if(!a||!a.call)throw new TypeError("Callback is not callable");}
|
|
function J(a){if(a.length===0)throw new TypeError("First argument must be defined");}
|
|
v(o,i,function(){var a=arguments;return a.length===0||l.isFunction(a[0])},{every:function(a,b){var c=this.length,d=0;for(J(arguments);d<c;){if(d in this&&!z(this[d],a,b,[d,this]))return j;d++}return i},some:function(a,b){var c=this.length,d=0;for(J(arguments);d<c;){if(d in this&&z(this[d],a,b,[d,this]))return i;d++}return j},map:function(a,b){var c=this.length,d=0,f,g=Array(c);for(J(arguments);d<c;){if(d in this){f=this[d];g[d]=A(f,a,b,[f,d,this])}d++}return g},filter:function(a,b){var c=this.length,
|
|
d=0,f=[];for(J(arguments);d<c;){d in this&&z(this[d],a,b,[d,this])&&f.push(this[d]);d++}return f}});
|
|
v(o,i,j,{indexOf:function(a,b){if(l.isString(this))return this.indexOf(a,b);return I(this,a,b,1)},lastIndexOf:function(a,b){if(l.isString(this))return this.lastIndexOf(a,b);return I(this,a,b,-1)},forEach:function(a,b){var c=this.length,d=0;for(G(a);d<c;){d in this&&a.call(b,this[d],d,this);d++}},reduce:function(a,b){return arrayReduce(this,a,b)},reduceRight:function(a,b){return arrayReduce(this,a,b,i)},groupBy:function(a,b){var c=this,d={},f;D(c,function(g,h){f=A(g,a,c,[g,h,c]);d[f]||(d[f]=[]);d[f].push(g)});
|
|
return l.each(d,b)},compact:function(a){var b=[];D(this,function(c){if(l.isArray(c))b.push(c.compact());else if(a&&c)b.push(c);else if(!a&&E(c)&&c!==null&&(!l.isNumber(c)||!isNaN(c)))b.push(c)});return b}});function K(a,b,c){c=Math[c||"round"];var d=Math.abs(Math.pow(10,b||0));if(b<0)d=1/d;return c(a*d)/d}function ea(a,b,c,d){var f=[];a=parseInt(a);for(var g=d>0;g&&a<=b||!g&&a>=b;){f.push(a);c&&c.call(this,a);a+=d}return f}
|
|
v(u,i,j,{toNumber:function(){return parseFloat(this,10)},ordinalize:function(){var a;if(this>=11&&this<=13)a="th";else switch(this%10){case 1:a="st";break;case 2:a="nd";break;case 3:a="rd";break;default:a="th"}return this.toString()+a},pad:function(a,b,c){c=c||10;var d=this.toNumber()===0?"":this.toString(c).replace(/^-/,"");c=d;a=a-d.replace(/\.\d+$/,"").length;d=0;var f=String("0");if(f!="0")f="";l.isNumber(a)||(a=1);l.isNumber(d)||(d=1);d=f.repeat(a)+c+f.repeat(d);if(b||this<0)d=(this<0?"-":"+")+
|
|
d;return d}});function fa(a,b){function c(){return K(this*b)}function d(){return L(arguments)[g](this)}function f(){return L(arguments)[g](-this)}var g="add"+a.capitalize()+"s";y(u.prototype,a,c);y(u.prototype,a+"s",c);y(u.prototype,a+"Before",f);y(u.prototype,a+"sBefore",f);y(u.prototype,a+"Ago",f);y(u.prototype,a+"sAgo",f);y(u.prototype,a+"After",d);y(u.prototype,a+"sAfter",d);y(u.prototype,a+"FromNow",d);y(u.prototype,a+"sFromNow",d)}
|
|
function M(){return"\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u2028\u2029\u3000\ufeff"}
|
|
v(t,i,j,{capitalize:function(a){return this.toLowerCase().replace(a?/\b[a-z]/g:/^[a-z]/,function(b){return b.toUpperCase()})},repeat:function(a){var b="",c=0;if(l.isNumber(a)&&a>0)for(;c<a;){b+=this;c++}return b},toNumber:function(a){var b=this.replace(/,/g,"");return b.match(/\./)?parseFloat(b):parseInt(b,a||10)},first:function(a){a=B(a)?1:a;return this.substr(0,a)},last:function(a){a=B(a)?1:a;return this.substr(this.length-a<0?0:this.length-a)},to:function(a){if(B(a))a=this.length;return this.slice(0,
|
|
a)},toDate:function(a){return L([this.toString(),a])},assign:function(){var a={};da(arguments,function(b,c){if(l.isObject(b))l.merge(a,b);else a[c+1]=b});return this.replace(/\{(.+?)\}/g,function(b,c){return a.hasOwnProperty(c)?a[c]:b})}});
|
|
var N=["hour","minute","second","millisecond","meridian","utc","offset_sign","offset_hours","offset_minutes"],O="(\\d{1,2}):?(\\d{2})?:?(\\d{2})?(?:\\.(\\d{1,6}))?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?",P="\\s*(?:(?:t|at |\\s+)"+O+")?",Q="\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d",R="\u5341\u767e\u5343\u4e07",ga=r("["+Q+R+"]","g"),S=[],T,U,ha=[{src:"(\\d{4})",to:["year"]},{src:"([+-])?(\\d{4})[-.]?({month})[-.]?(\\d{1,2})?",to:["year_sign","year","month","date"]},{src:"(\\d{1,2})[-.\\/]({month})[-.\\/]?(\\d{2,4})?",
|
|
to:["month","date","year"],h:i},{src:"\\/Date\\((\\d+(?:\\+\\d{4})?)\\)\\/",to:["timestamp"],r:j}],ia=[{b:"f{1,4}|ms|milliseconds",format:function(a){return a.getMilliseconds()}},{b:"ss?|seconds",format:function(a){return a.getSeconds()}},{b:"mm?|minutes",format:function(a){return a.getMinutes()}},{b:"hh?|hours|12hr",format:function(a){a=a.getHours(void 0);return a===0?12:a-(a/13|0)*12}},{b:"HH?|24hr",format:function(a){return a.getHours()}},{b:"dd?|date|day",format:function(a){return a.getDate()}},
|
|
{b:"dow|weekday",i:i,format:function(a,b,c){return b.weekdays[a.getDay()+(c-1)*7]}},{b:"MM?",format:function(a){return a.getMonth()+1}},{b:"mon|month",i:i,format:function(a,b,c){return b.months[a.getMonth()+(c-1)*12]}},{b:"y{2,4}|year",format:function(a){return a.getFullYear()}},{b:"[Tt]{1,2}",format:function(a,b,c,d){a=a.getHours(void 0)<12?"am":"pm";if(d.length===1)a=a.first();if(d.first()==="T")a=a.toUpperCase();return a}},{b:"z{1,4}|tz|timezone",text:i,format:function(a,b,c,d){a=a.getUTCOffset();
|
|
if(d=="z"||d=="zz")a=a.replace(/(\d{2})(\d{2})/,function(f,g){return g.toNumber().pad(d.length)});return a}},{b:"iso(tz|timezone)",format:function(a){return a.getUTCOffset(i)}},{b:"ord",format:function(a){return a.getDate().ordinalize()}}],V=[{a:"year",method:"FullYear",c:function(a){return(365+(a?a.isLeapYear()?1:0:0.25))*24*60*60*1E3}},{a:"month",method:"Month",c:function(a,b){var c=30.4375,d;if(a){d=a.daysInMonth();if(b<=d.days())c=d}return c*24*60*60*1E3}},{a:"week",method:"Week",c:k(6048E5)},
|
|
{a:"day",method:"Date",c:k(864E5)},{a:"hour",method:"Hours",c:k(36E5)},{a:"minute",method:"Minutes",c:k(6E4)},{a:"second",method:"Seconds",c:k(1E3)},{a:"millisecond",method:"Milliseconds",c:k(1)}],W={},ja={en:"2;;January,February,March,April,May,June,July,August,September,October,November,December;Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday;millisecond:|s,second:|s,minute:|s,hour:|s,day:|s,week:|s,month:|s,year:|s;one,two,three,four,five,six,seven,eight,nine,ten;a,an,the;the,st|nd|rd|th,of;{num} {unit} {sign},{num} {unit=4-5} {sign} {day},{weekday?} {month} {date}{2} {year?} {time?},{date} {month} {year},{month} {year},{shift?} {weekday} {time?},{shift} week {weekday} {time?},{shift} {unit=5-7},{1} {edge} of {shift?} {unit=4-7?}{month?}{year?},{weekday} {3} {shift} week,{1} {date}{2} of {month},{1}{month?} {date?}{2} of {shift} {unit=6-7},{day} at {time?},{time} {day};{Month} {d}, {yyyy};,yesterday,today,tomorrow;,ago|before,,from now|after|from;,last,the|this,next;last day,end,,first day|beginning",
|
|
ja:"1;\u6708;;\u65e5\u66dc\u65e5,\u6708\u66dc\u65e5,\u706b\u66dc\u65e5,\u6c34\u66dc\u65e5,\u6728\u66dc\u65e5,\u91d1\u66dc\u65e5,\u571f\u66dc\u65e5;\u30df\u30ea\u79d2,\u79d2,\u5206,\u6642\u9593,\u65e5,\u9031\u9593|\u9031,\u30f6\u6708|\u30f5\u6708|\u6708,\u5e74;;;;{num}{unit}{sign},{shift}{unit=5-7}{weekday?},{year}\u5e74{month?}\u6708?{date?}\u65e5?,{month}\u6708{date?}\u65e5?,{date}\u65e5;{yyyy}\u5e74{M}\u6708{d}\u65e5;\u4e00\u6628\u65e5,\u6628\u65e5,\u4eca\u65e5,\u660e\u65e5,\u660e\u5f8c\u65e5;,\u524d,,\u5f8c;,\u53bb|\u5148,,\u6765",
|
|
ko:"1;\uc6d4;;\uc77c\uc694\uc77c,\uc6d4\uc694\uc77c,\ud654\uc694\uc77c,\uc218\uc694\uc77c,\ubaa9\uc694\uc77c,\uae08\uc694\uc77c,\ud1a0\uc694\uc77c;\ubc00\ub9ac\ucd08,\ucd08,\ubd84,\uc2dc\uac04,\uc77c,\uc8fc,\uac1c\uc6d4|\ub2ec,\ub144;\uc77c|\ud55c,\uc774,\uc0bc,\uc0ac,\uc624,\uc721,\uce60,\ud314,\uad6c,\uc2ed;;;{num}{unit} {sign},{shift} {unit=5-7},{shift} {unit=5?} {weekday},{year}\ub144{month?}\uc6d4?{date?}\uc77c?,{month}\uc6d4{date?}\uc77c?,{date}\uc77c;{yyyy}\ub144{M}\uc6d4{d}\uc77c;\uadf8\uc800\uaed8,\uc5b4\uc81c,\uc624\ub298,\ub0b4\uc77c,\ubaa8\ub808;,\uc804,,\ud6c4;,\uc9c0\ub09c|\uc791,\uc774\ubc88,\ub2e4\uc74c|\ub0b4",
|
|
ru:"4;;\u042f\u043d\u0432\u0430\u0440:\u044f|\u044c,\u0424\u0435\u0432\u0440\u0430\u043b:\u044f|\u044c,\u041c\u0430\u0440\u0442:\u0430|,\u0410\u043f\u0440\u0435\u043b:\u044f|\u044c,\u041c\u0430:\u044f|\u0439,\u0418\u044e\u043d:\u044f|\u044c,\u0418\u044e\u043b:\u044f|\u044c,\u0410\u0432\u0433\u0443\u0441\u0442:\u0430|,\u0421\u0435\u043d\u0442\u044f\u0431\u0440:\u044f|\u044c,\u041e\u043a\u0442\u044f\u0431\u0440:\u044f|\u044c,\u041d\u043e\u044f\u0431\u0440:\u044f|\u044c,\u0414\u0435\u043a\u0430\u0431\u0440:\u044f|\u044c;\u0412\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435,\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a,\u0412\u0442\u043e\u0440\u043d\u0438\u043a,\u0421\u0440\u0435\u0434\u0430,\u0427\u0435\u0442\u0432\u0435\u0440\u0433,\u041f\u044f\u0442\u043d\u0438\u0446\u0430,\u0421\u0443\u0431\u0431\u043e\u0442\u0430;\u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434:\u0430|\u0443|\u044b|,\u0441\u0435\u043a\u0443\u043d\u0434:\u0430|\u0443|\u044b|,\u043c\u0438\u043d\u0443\u0442:\u0430|\u0443|\u044b|,\u0447\u0430\u0441:||\u0430|\u043e\u0432,\u0434\u0435\u043d\u044c|\u0434\u0435\u043d\u044c|\u0434\u043d\u044f|\u0434\u043d\u0435\u0439,\u043d\u0435\u0434\u0435\u043b:\u044f|\u044e|\u0438|\u044c|\u0435,\u043c\u0435\u0441\u044f\u0446:||\u0430|\u0435\u0432|\u0435,\u0433\u043e\u0434|\u0433\u043e\u0434|\u0433\u043e\u0434\u0430|\u043b\u0435\u0442|\u0433\u043e\u0434\u0443;\u043e\u0434:\u0438\u043d|\u043d\u0443,\u0434\u0432:\u0430|\u0435,\u0442\u0440\u0438,\u0447\u0435\u0442\u044b\u0440\u0435,\u043f\u044f\u0442\u044c,\u0448\u0435\u0441\u0442\u044c,\u0441\u0435\u043c\u044c,\u0432\u043e\u0441\u0435\u043c\u044c,\u0434\u0435\u0432\u044f\u0442\u044c,\u0434\u0435\u0441\u044f\u0442\u044c;;\u0432|\u043d\u0430,\u0433\u043e\u0434\u0430;{num} {unit} {sign},{sign} {num} {unit},{date} {month} {year?} {2},{month} {year},{1} {shift} {unit=5-7};{d} {month} {yyyy} \u0433\u043e\u0434\u0430;\u043f\u043e\u0437\u0430\u0432\u0447\u0435\u0440\u0430,\u0432\u0447\u0435\u0440\u0430,\u0441\u0435\u0433\u043e\u0434\u043d\u044f,\u0437\u0430\u0432\u0442\u0440\u0430,\u043f\u043e\u0441\u043b\u0435\u0437\u0430\u0432\u0442\u0440\u0430;,\u043d\u0430\u0437\u0430\u0434,,\u0447\u0435\u0440\u0435\u0437;,\u043f\u0440\u043e\u0448\u043b\u043e:\u0439|\u043c,,\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435:\u0439|\u043c",
|
|
es:"6;;enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre;domingo,lunes,martes,mi\u00e9rcoles|miercoles,jueves,viernes,s\u00e1bado|sabado;milisegundo:|s,segundo:|s,minuto:|s,hora:|s,d\u00eda|d\u00edas|dia|dias,semana:|s,mes:|es,a\u00f1o|a\u00f1os|ano|anos;uno,dos,tres,cuatro,cinco,seis,siete,ocho,nueve,diez;;el,de;{sign} {num} {unit},{num} {unit} {sign},{date?} {2} {month} {2} {year?},{1} {unit=5-7} {shift},{1} {shift} {unit=5-7};{d} de {month} de {yyyy};anteayer,ayer,hoy,ma\u00f1ana|manana;,hace,,de ahora;,pasad:o|a,,pr\u00f3ximo|pr\u00f3xima|proximo|proxima",
|
|
pt:"6;;janeiro,fevereiro,mar\u00e7o,abril,maio,junho,julho,agosto,setembro,outubro,novembro,dezembro;domingo,segunda-feira,ter\u00e7a-feira,quarta-feira,quinta-feira,sexta-feira,s\u00e1bado|sabado;milisegundo:|s,segundo:|s,minuto:|s,hora:|s,dia:|s,semana:|s,m\u00eas|m\u00eases|mes|meses,ano:|s;um,dois,tr\u00eas|tres,quatro,cinco,seis,sete,oito,nove,dez,uma,duas;;a,de;{num} {unit} {sign},{sign} {num} {unit},{date?} {2} {month} {2} {year?},{1} {unit=5-7} {shift},{1} {shift} {unit=5-7};{d} de {month} de {yyyy};anteontem,ontem,hoje,amanh:\u00e3|a;,atr\u00e1s|atras|h\u00e1|ha,,daqui a;,passad:o|a,,pr\u00f3ximo|pr\u00f3xima|proximo|proxima",
|
|
fr:"2;;janvier,f\u00e9vrier|fevrier,mars,avril,mai,juin,juillet,ao\u00fbt,septembre,octobre,novembre,d\u00e9cembre|decembre;dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi;milliseconde:|s,seconde:|s,minute:|s,heure:|s,jour:|s,semaine:|s,mois,an:|s|n\u00e9e|nee;un:|e,deux,trois,quatre,cinq,six,sept,huit,neuf,dix;;l'|la|le;{sign} {num} {unit},{sign} {num} {unit},{1} {date?} {month} {year?},{1} {unit=5-7} {shift};{d} {month} {yyyy};,hier,aujourd'hui,demain;,il y a,,dans|d'ici;,derni:er|\u00e8re|ere,,prochain:|e",
|
|
it:"2;;Gennaio,Febbraio,Marzo,Aprile,Maggio,Giugno,Luglio,Agosto,Settembre,Ottobre,Novembre,Dicembre;Domenica,Luned:\u00ec|i,Marted:\u00ec|i,Mercoled:\u00ec|i,Gioved:\u00ec|i,Venerd:\u00ec|i,Sabato;millisecond:o|i,second:o|i,minut:o|i,or:a|e,giorn:o|i,settiman:a|e,mes:e|i,ann:o|i;un:|'|a|o,due,tre,quattro,cinque,sei,sette,otto,nove,dieci;;l'|la|il;{num} {unit} {sign},{weekday?} {date?} {month} {year?},{1} {unit=5-7} {shift},{1} {shift} {unit=5-7};{d} {month} {yyyy};,ieri,oggi,domani,dopodomani;,fa,,da adesso;,scors:o|a,,prossim:o|a",
|
|
de:"2;;Januar,Februar,M\u00e4rz|Marz,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember;Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag;Millisekunde:|n,Sekunde:|n,Minute:|n,Stunde:|n,Tag:|en,Woche:|n,Monat:|en,Jahr:|en;ein:|e|er|em|en,zwei,drei,vier,fuenf,sechs,sieben,acht,neun,zehn;;der;{sign} {num} {unit},{num} {unit} {sign},{num} {unit} {sign},{sign} {num} {unit},{weekday?} {date?} {month} {year?},{shift} {unit=5-7};{d}. {Month} {yyyy};vorgestern,gestern,heute,morgen,\u00fcbermorgen|ubermorgen|uebermorgen;,vor:|her,,in;,letzte:|r|n|s,,n\u00e4chste:|r|n|s+naechste:|r|n|s",
|
|
"zh-TW":"1;\u6708;;\u65e5,\u4e00,\u4e8c,\u4e09,\u56db,\u4e94,\u516d;\u6beb\u79d2,\u79d2\u9418,\u5206\u9418,\u5c0f\u6642,\u5929,\u500b\u661f\u671f|\u9031,\u500b\u6708,\u5e74;;;\u65e5|\u865f;{num}{unit}{sign},\u661f\u671f{weekday},{shift}{unit=5-7},{shift}{unit=5}{weekday},{year}\u5e74{month?}\u6708?{date?}{1},{month}\u6708{date?}{1},{date}{1};{yyyy}\u5e74{M}\u6708{d}\u65e5;\u524d\u5929,\u6628\u5929,\u4eca\u5929,\u660e\u5929,\u5f8c\u5929;,\u524d,,\u5f8c;,\u4e0a|\u53bb,\u9019,\u4e0b|\u660e","zh-CN":"1;\u6708;;\u65e5,\u4e00,\u4e8c,\u4e09,\u56db,\u4e94,\u516d;\u6beb\u79d2,\u79d2\u949f,\u5206\u949f,\u5c0f\u65f6,\u5929,\u4e2a\u661f\u671f|\u5468,\u4e2a\u6708,\u5e74;;;\u65e5|\u53f7;{num}{unit}{sign},\u661f\u671f{weekday},{shift}{unit=5-7},{shift}{unit=5}{weekday},{year}\u5e74{month?}\u6708?{date?}{1},{month}\u6708{date?}{1},{date}{1};{yyyy}\u5e74{M}\u6708{d}\u65e5;\u524d\u5929,\u6628\u5929,\u4eca\u5929,\u660e\u5929,\u540e\u5929;,\u524d,,\u540e;,\u4e0a|\u53bb,\u8fd9,\u4e0b|\u660e"};
|
|
function ka(a){var b=s.addFormat,c=a.code;if(!a.l){b("("+a.months.compact().join("|")+")",["month"],c);b("("+a.weekdays.compact().join("|")+")",["weekday"],c);b("("+a.modifiers.filter(function(d){return d.name==="day"}).map("text").join("|")+")",["day"],c);D(a.formats,function(d){var f=[];d=d.replace(/\s+/g,"[-,. ]*");d=d.replace(/\{(.+?)\}/g,function(g,h){var e=h.match(/\?$/),m=h.match(/(\d)(?:-(\d))?/),q=h.match(/^\d+$/),n=h.replace(/[^a-z]+$/,""),p,x;if(n==="time"){f=f.concat(N);return e?P:O}if(q)p=
|
|
a.optionals[q[0]-1];else if(a[n])p=a[n];else if(a[n+"s"]){p=a[n+"s"];if(m){x=[];D(p,function(pa,qa){var ca=qa%(a.units?8:p.length);if(ca>=m[1]&&ca<=(m[2]||m[1]))x.push(pa)});p=x}p=p.compact().join("|")}if(q)return"(?:"+p+")?";else{f.push(n);return"("+p+")"+(e?"?":"")}});b(d,f,c)});a.l=i}}function X(a,b,c){if(b&&(!l.isString(a)||!a))a=Date.currentLocale;a&&!W[a]&&la(a,c);return W[a]}
|
|
function la(a,b){function c(g,h){g=g.split("+").map(function(e){return e.replace(/(.+):(.+)$/,function(m,q,n){return n.split("|").map(function(p){return q+p}).join("|")})}).join("|");return D(g.split("|"),h)}function d(g,h,e){var m=[];if(b[g]){D(b[g],function(q,n){c(q,function(p,x){m[x*e+n]=p.toLowerCase()})});if(h)m=m.concat(b[g].map(function(q){return q.slice(0,3).toLowerCase()}));return b[g]=m}}function f(g,h){var e="[0-9\uff10-\uff19]"+(g?"{"+g+","+h+"}":"+");if(b.digits)e+="|["+b.digits+"]+";
|
|
return e}b=b||ma(a);if(!b)throw Error("Invalid locale.");d("months",i,12);d("weekdays",i,7);d("units",j,8);d("numbers",j,10);b.code=a;b.date=f(1,2);b.year=f(4,4);b.num=function(){var g=[f()].concat(b.articles);b.digits||(g=g.concat(b.numbers));return g.compact().join("|")}();(function(){var g=[];b.f={};D(b.modifiers,function(h){c(h.text,function(e){b.f[e]=h;g.push({name:h.name,text:e,value:h.value})})});g.groupBy("name",function(h,e){e=e.map("text");if(h==="day")e=e.concat(b.weekdays);b[h]=e.join("|")});
|
|
b.modifiers=g})();if(b.monthSuffix){b.month=f(1,2);b.months=ea(1,12,null,1).map(function(g){return g+b.monthSuffix})}W[a]=new na(b)}
|
|
function ma(a){function b(f){return!!(d[0]&Math.pow(2,f-1))}if(a.slice(0,3)=="en-")a="en";if(!ja[a])return null;var c={modifiers:[]},d=ja[a].split(";");D(["months","weekdays","units","numbers","articles","optionals","formats"],function(f,g){c[f]=d[g+2]?d[g+2].split(","):[]});c.outputFormat=d[9];D(["day","sign","shift","edge"],function(f,g){d[g+10]&&D(d[g+10].split(","),function(h,e){h&&c.modifiers.push({name:f,text:h,value:e-2})})});if(b(1)){c.digits=Q+R;if(c.numbers.length>0)c.digits+=c.numbers.join("");
|
|
else c.numbers=Q.split("");c.monthSuffix=d[1]}c.capitalizeUnit=a=="de";c.hasPlural=b(2);c.pastRelativeFormat=c.formats[0];c.futureRelativeFormat=c.formats[b(3)?1:0];return c}function oa(a){a||(a=Date.currentLocale);return a!="en"&&a!="en-US"}function na(a){l.merge(this,a)}
|
|
v(na,i,j,{getMonth:function(a){return l.isNumber(a)?a-1:H(this.months,r(a,"i"),0,j,i)%12},k:function(a){return H(this.weekdays,r(a,"i"),0,j,i)%7},j:function(a){var b;return l.isNumber(a)?a:a&&(b=this.numbers.indexOf(a))!==-1?(b+1)%10:1},n:function(a){var b=this;return a.replace(this.numbers[9],"").replace(/./g,function(c){return b.j(c)})},m:function(a){return English.units[this.units.indexOf(a)%8]},q:function(a,b,c){var d,f;d=c>0?this.futureRelativeFormat:this.pastRelativeFormat;if(this.code=="ru"){f=
|
|
a.toString().slice(-1);switch(i){case f==1:f=1;break;case f>=2&&f<=4:f=2;break;default:f=3}}else f=this.hasPlural&&a>1?1:0;f=this.units[f*8+b]||this.units[b];if(this.capitalizeUnit)f=f.capitalize();b=H(this.modifiers,function(g){return g.name=="sign"&&g.value==(c>0?1:-1)});return d.assign({num:a,unit:f,sign:b.text})}});function Y(a){var b;if(typeof a[0]=="object")return a;else if(a.length==1&&l.isNumber(a[0]))return[a[0]];b={};D(T,function(c,d){b[c.a]=a[d]});return[b]}
|
|
function ra(a,b){a=a.replace(/[\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19\uff10]/g,function(c){return String.fromCharCode(c.charCodeAt(0)-65248)});if(b!="date"&&b!="month"&&b!="year")return a;return a.replace(ga,function(c){return Q.indexOf(c)+1||""})}function sa(a,b){var c={},d,f;D(b,function(g,h){d=a[h+1];if(!(B(d)||d==="")){d=ra(d,g);if(g==="year")c.s=d;if(g==="millisecond")d*=Math.pow(10,3-d.length);f=parseFloat(d);c[g]=!isNaN(f)?f:d.toLowerCase()}});return c}
|
|
function ta(a,b){var c=new s,d=j,f,g,h,e,m,q,n;if(l.isDate(a))c=a;else if(l.isNumber(a))c=new s(a);else if(l.isObject(a)){c=(new s).set(a,i);e=a}else if(l.isString(a)){ka(X(b,i));g=oa(b);a=a.trim().replace(/\.+$/,"").replace(/^now$/,"");D(S,function(p){var x=a.match(p.p);if(x){h=p;e=sa(x,h.to);f=X(h.o,i);if(e.timestamp){c.setTime(0);e={milliseconds:e.timestamp};return j}if(h.h&&!l.isString(e.month)&&(l.isString(e.date)||g)){n=e.month;e.month=e.date;e.date=n}if(e.year&&e.s.length===2)e.year=K((new s).getFullYear()/
|
|
100)*100-K(e.year/100)*100+e.year;if(e.month){e.month=f.getMonth(e.month);if(e.shift&&!e.unit)e.unit="year"}if(e.weekday&&e.date)delete e.weekday;else if(e.weekday){e.weekday=f.k(e.weekday);if(e.shift&&!e.unit)e.unit="week"}if(e.day&&(n=f.f[e.day])){e.day=n.value;c.resetTime();d=i}else if(e.day&&(n=f.k(e.day))>-1){delete e.day;e.weekday=n}if(e.date&&!l.isNumber(e.date))e.date=f.n(e.date);if(e.meridian)if(e.meridian==="pm"&&e.hour<12)e.hour+=12;if(e.offset_hours||e.offset_minutes){e.utc=i;e.offset_minutes=
|
|
e.offset_minutes||0;e.offset_minutes+=e.offset_hours*60;if(e.offset_sign==="-")e.offset_minutes*=-1;e.minute-=e.offset_minutes}if(e.unit){d=i;q=f.j(e.num);m=f.m(e.unit);if(e.shift||e.edge){q*=(n=f.f[e.shift])?n.value:0;if(m==="month"&&E(e.date)){c.set({day:e.date},i);delete e.date}if(m==="year"&&E(e.month)){c.set({month:e.month,day:e.date},i);delete e.month;delete e.date}}if(e.sign&&(n=f.f[e.sign]))q*=n.value;if(E(e.weekday)){c.set({weekday:e.weekday},i);delete e.weekday}e[m]=(e[m]||0)+q}if(e.year_sign===
|
|
"-")e.year*=-1;return j}});if(h)if(d)c.advance(e);else e.utc?c.setUTC(e,i):c.set(e,i);else c=a?new s(a):new s;if(e&&e.edge){n=f.f[e.edge];D(U.slice(4),function(p){if(E(e[p.a])){m=p.a;return j}});if(m==="year")e.d="month";else if(m==="month"||m==="week")e.d="day";c[(n.value<0?"endOf":"beginningOf")+m.capitalize()]();n.value===-2&&c.resetTime()}}return{e:c,set:e}}
|
|
function Z(a,b,c,d){var f,g=X(d,i),h=r(/^[A-Z]/);if(a.isValid())if(Date[b])b=Date[b];else{if(l.isFunction(b)){f=ua(a);b=b.apply(a,f.concat(g))}}else return"Invalid Date";if(!b&&!c)b=g.outputFormat;else if(!b&&c){f=f||ua(a);if(f[1]===0){f[1]=1;f[0]=1}return g.q(f[0],f[1],f[2])}D(ia,function(e){b=b.replace(r("\\{("+e.b+")(\\d)?\\}",e.i?"i":""),function(m,q,n){m=e.format(a,g,n||1,q);n=q.length;var p=q.match(/^(.)\1+$/);if(e.i){if(n===3)m=m.slice(0,3);if(p||q.match(h))m=m.capitalize()}else if(p&&!e.text)m=
|
|
(l.isNumber(m)?m.pad(n):m.toString()).last(n);return m})});return b}function va(a,b,c){var d=ta(b),f=0,g=b=0,h;if(c>0){b=g=c;h=i}if(!d.e.isValid())return j;if(d.set&&d.set.d){D(V,function(m){if(m.a===d.set.d)f=m.c(d.e,a-d.e)-1});if(d.set.edge||d.set.shift)d.e["beginningOf"+d.set.d.capitalize()]();if(!h&&d.set.sign&&d.set.d!="millisecond"){b=50;g=-50}}c=a.getTime();h=d.e.getTime();var e=h+f;if(d.set&&d.set.d=="week"&&(new Date(e+1)).getHours()!=0)e-=s.DSTOffset;return c>=h-b&&c<=e+g}
|
|
function $(a,b,c,d,f){if(l.isNumber(b)&&f)b={milliseconds:b};else if(l.isNumber(b)){a.setTime(b);return a}if(b.date)b.day=b.date;if(!f&&B(b.day)&&E(b.weekday)){a["set"+(d?"UTC":"")+"Weekday"](b.weekday);b.day=a["get"+(d?"UTC":"")+"Date"](void 0);delete b.weekday}D(U,function(g){if(E(b[g.a])||E(b[g.a+"s"])){b.d=g.a;return j}else if(c&&g.a!=="week"&&g.a!=="year")a["set"+(d?"UTC":"")+g.method](g.a==="day"?1:0)});D(V,function(g){var h=g.a;g=g.method;var e=E(b[h])?b[h]:b[h+"s"];if(!B(e)){if(f){if(h===
|
|
"week"){e=(b.day||0)+e*7;g="Date"}e=e*f+a["get"+g](void 0)}a["set"+(d?"UTC":"")+g](e);if(h==="month"){h=e;if(h<0)h+=12;h%12!=a.getMonth()&&a.setDate(0)}}});return a}function wa(a){a.addDays(4-(a.getDay()||7)).resetTime();return 1+(a.daysSince(a.clone().beginningOfYear())/7|0)}function ua(a){var b;a=a.millisecondsFromNow();var c=Math.abs(a),d=c,f=0;D(U.slice(1),function(g,h){b=K(c/g.c(),1)|0;if(b>=1){d=b;f=h+1}});return[d,f,a]}
|
|
function L(a){var b;b=l.isNumber(a[1])?Y(a)[0]:a[0];return ta(b,a[1]).e}v(s,j,j,{create:function(){return L(arguments)},now:function(){return(new s).getTime()},setLocale:function(a,b){var c=X(a,j,b);if(c){Date.currentLocale=a;ka(c);return c}},getLocale:function(a){return X(a,i)},addFormat:function(a,b,c,d){S.push({h:d,o:c,p:r("^"+a+"$","i"),to:b})}});
|
|
v(s,i,j,{set:function(){var a=Y(arguments);return $(this,a[0],a[1])},setUTC:function(){var a=Y(arguments);return $(this,a[0],a[1],i)},setWeekday:function(a){B(a)||this.setDate(this.getDate()+a-this.getDay())},setUTCWeekday:function(a){B(a)||this.setDate(this.getUTCDate()+a-this.getDay())},setWeek:function(a){if(!B(a)){this.setMonth(0);this.setDate(a*7+1)}},setUTCWeek:function(a){if(!B(a)){this.setMonth(0);this.setUTCDate(a*7+1)}},getWeek:function(){return wa(this)},getUTCWeek:function(){return wa(this.toUTC())},
|
|
getUTCOffset:function(a){var b=this.g?0:this.getTimezoneOffset(),c=a===i?":":"";if(!b&&a)return"Z";return K(-b/60).pad(2,i)+c+(b%60).pad(2)},toUTC:function(){if(this.g)return this;var a=this.clone().addMinutes(this.getTimezoneOffset());a.g=i;return a},isUTC:function(){return this.g||this.getTimezoneOffset()===0},advance:function(){var a=Y(arguments);return $(this,a[0],j,j,1,i)},rewind:function(){var a=Y(arguments);return $(this,a[0],j,j,-1)},isValid:function(){return!isNaN(this.getTime())},isAfter:function(a,
|
|
b){return this.getTime()>s.create(a).getTime()-(b||0)},isBefore:function(a,b){return this.getTime()<s.create(a).getTime()+(b||0)},isBetween:function(a,b,c){var d=this.getTime();a=s.create(a).getTime();var f=s.create(b).getTime();b=Math.min(a,f);a=Math.max(a,f);c=c||0;return b-c<d&&a+c>d},isLeapYear:function(){var a=this.getFullYear();return a%4===0&&a%100!==0||a%400===0},daysInMonth:function(){return 32-(new s(this.getFullYear(),this.getMonth(),32)).getDate()},format:function(a,b){return Z(this,a,
|
|
j,b)},relative:function(a,b){if(l.isString(a)){b=a;a=null}return Z(this,a,i,b)},is:function(a,b){var c;if(l.isString(a)){a=a.trim().toLowerCase();switch(i){case a==="future":return this.getTime()>(new s).getTime();case a==="past":return this.getTime()<(new s).getTime();case a==="weekday":return this.getDay()>0&&this.getDay()<6;case a==="weekend":return this.getDay()===0||this.getDay()===6;case (c=English.weekdays.indexOf(a)%7)>-1:return this.getDay()===c;case (c=English.months.indexOf(a)%12)>-1:return this.getMonth()===
|
|
c}}return va(this,a,b)},resetTime:function(){return this.set({hour:0,minute:0,second:0,millisecond:0})},clone:function(){return new s(this.getTime())},compare:function(){return this-L(arguments)}});v(s,i,j,{getWeekday:s.prototype.getDay,getUTCWeekday:s.prototype.getUTCDay});(function(){var a={};D(["Array","Boolean","Date","Function","Number","String","RegExp"],function(b){a["is"+b]=function(c){return l.prototype.toString.call(c)==="[object "+b+"]"}});v(Object,j,j,a)})();
|
|
(function(){var a=M().match(/^\s+$/);try{t.prototype.trim.call([1])}catch(b){a=j}var c=r("^["+M()+"]+"),d=r("["+M()+"]+$");v(t,i,!a,{trim:function(){return this.toString().trimLeft().trimRight()},trimLeft:function(){return this.replace(c,"")},trimRight:function(){return this.replace(d,"")}})})();English=s.setLocale("en");
|
|
D(V,function(a,b){var c=a.a,d=c.capitalize(),f=a.c();y(s.prototype,c+"sSince",function(g,h){return K((this.getTime()-s.create(g,h).getTime())/f)});y(s.prototype,c+"sUntil",function(g,h){return K((s.create(g,h).getTime()-this.getTime())/f)});y(s.prototype,c+"sAgo",s.prototype[c+"sUntil"]);y(s.prototype,c+"sFromNow",s.prototype[c+"sSince"]);y(s.prototype,"add"+d+"s",function(g){var h={};h[c]=g;return this.advance(h)});fa(c,f);b<3&&D(["Last","This","Next"],function(g){y(s.prototype,"is"+g+d,function(){return this.is(g+
|
|
" "+c)})});if(b<4){y(s.prototype,"beginningOf"+d,function(){var g={};switch(c){case "year":g.year=this.getFullYear();break;case "month":g.month=this.getMonth();break;case "day":g.day=this.getDate();break;case "week":g.weekday=0}return this.set(g,i)});y(s.prototype,"endOf"+d,function(){var g={hours:23,minutes:59,seconds:59,milliseconds:999};switch(c){case "year":g.month=11;g.day=31;break;case "month":g.day=this.daysInMonth();break;case "week":g.weekday=6}return this.set(g,i)})}});
|
|
(function(){T=V.concat();T.splice(2,1);U=V.concat().reverse();var a="\\d{1,2}|"+English.months.join("|");D(ha,function(b){s.addFormat(b.src.replace(/\{month\}/,a)+(b.r===j?"":P),b.to.concat(N),"en",b.h)});s.addFormat(O,N)})();(function(){var a=English.weekdays.slice(0,7),b=English.months.slice(0,12);D(["today","yesterday","tomorrow","weekday","weekend","future","past"].concat(a).concat(b),function(c){y(s.prototype,"is"+c.capitalize(),function(){return this.is(c)})})})();
|
|
v(s,j,i,{DSTOffset:((new s(2E3,6,1)).getTimezoneOffset()-(new s(2E3,0,1)).getTimezoneOffset())*60*1E3,INTERNATIONAL_TIME:"{h}:{mm}:{ss}",RFC1123:"{Dow}, {dd} {Mon} {yyyy} {HH}:{mm}:{ss} {tz}",RFC1036:"{Weekday}, {dd}-{Mon}-{yy} {HH}:{mm}:{ss} {tz}",ISO8601_DATE:"{yyyy}-{MM}-{dd}",ISO8601_DATETIME:"{yyyy}-{MM}-{dd}T{HH}:{mm}:{ss}.{fff}{isotz}"});
|
|
(function(){var a=new s(s.UTC(1999,11,31));if(!a.toISOString||a.toISOString()!=="1999-12-31T00:00:00.000Z")v(s,i,i,{toISOString:function(){return Z(this.toUTC(),s.ISO8601_DATETIME)}});if(!a.toJSON||a.toJSON()!=="1999-12-31T00:00:00.000Z")v(s,i,i,{toJSON:s.prototype.toISOString});v(s,i,j,{iso:s.prototype.toISOString})})();})(this);
|
|
|
|
$('head').prepend([
|
|
'<link rel="stylesheet" href="/style.css">',
|
|
// '<link rel="stylesheet" href="/fonts.css">',
|
|
// '<link rel="stylesheet" href="/ui.css">',
|
|
].join(''))
|
|
|
|
$(function () {
|
|
require('app').launch();
|
|
});
|
|
|
|
(function(/*! Stitch !*/) {
|
|
if (!this.require) {
|
|
var modules = {}, cache = {}, require = function(name, root) {
|
|
var path = expand(root, name), module = cache[path], fn;
|
|
if (module) {
|
|
return module.exports;
|
|
} else if (fn = modules[path] || modules[path = expand(path, './index')]) {
|
|
module = {id: path, exports: {}};
|
|
try {
|
|
cache[path] = module;
|
|
fn(module.exports, function(name) {
|
|
return require(name, dirname(path));
|
|
}, module);
|
|
return module.exports;
|
|
} catch (err) {
|
|
delete cache[path];
|
|
throw err;
|
|
}
|
|
} else {
|
|
throw 'module \'' + name + '\' not found';
|
|
}
|
|
}, expand = function(root, name) {
|
|
var results = [], parts, part;
|
|
if (/^\.\.?(\/|$)/.test(name)) {
|
|
parts = [root, name].join('/').split('/');
|
|
} else {
|
|
parts = name.split('/');
|
|
}
|
|
for (var i = 0, length = parts.length; i < length; i++) {
|
|
part = parts[i];
|
|
if (part == '..') {
|
|
results.pop();
|
|
} else if (part != '.' && part != '') {
|
|
results.push(part);
|
|
}
|
|
}
|
|
return results.join('/');
|
|
}, dirname = function(path) {
|
|
return path.split('/').slice(0, -1).join('/');
|
|
};
|
|
this.require = function(name) {
|
|
return require(name, '');
|
|
}
|
|
this.require.define = function(bundle) {
|
|
for (var key in bundle)
|
|
modules[key] = bundle[key];
|
|
};
|
|
}
|
|
return this.require.define;
|
|
}).call(this)({"andlog": function(exports, require, module) {// follow @HenrikJoreteg and @andyet if you like this ;)
|
|
(function (window) {
|
|
var ls = window.localStorage,
|
|
out = {},
|
|
inNode = typeof process !== 'undefined';
|
|
|
|
if (inNode) {
|
|
module.exports = console;
|
|
return;
|
|
}
|
|
|
|
if (ls && ls.debug && window.console) {
|
|
out = window.console;
|
|
} else {
|
|
var methods = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","),
|
|
l = methods.length,
|
|
fn = function () {};
|
|
|
|
while (l--) {
|
|
out[methods[l]] = fn;
|
|
}
|
|
}
|
|
if (typeof exports !== 'undefined') {
|
|
module.exports = out;
|
|
} else {
|
|
window.console = out;
|
|
}
|
|
})(this);}, "backbone": function(exports, require, module) {// Backbone.js 1.0.0
|
|
|
|
// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
|
// Backbone may be freely distributed under the MIT license.
|
|
// For all details and documentation:
|
|
// http://backbonejs.org
|
|
|
|
(function(){
|
|
|
|
// Initial Setup
|
|
// -------------
|
|
|
|
// Save a reference to the global object (`window` in the browser, `exports`
|
|
// on the server).
|
|
var root = this;
|
|
|
|
// Save the previous value of the `Backbone` variable, so that it can be
|
|
// restored later on, if `noConflict` is used.
|
|
var previousBackbone = root.Backbone;
|
|
|
|
// Create local references to array methods we'll want to use later.
|
|
var array = [];
|
|
var push = array.push;
|
|
var slice = array.slice;
|
|
var splice = array.splice;
|
|
|
|
// The top-level namespace. All public Backbone classes and modules will
|
|
// be attached to this. Exported for both the browser and the server.
|
|
var Backbone;
|
|
if (typeof exports !== 'undefined') {
|
|
Backbone = exports;
|
|
} else {
|
|
Backbone = root.Backbone = {};
|
|
}
|
|
|
|
// Current version of the library. Keep in sync with `package.json`.
|
|
Backbone.VERSION = '1.0.0';
|
|
|
|
// Require Underscore, if we're on the server, and it's not already present.
|
|
var _ = root._;
|
|
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
|
|
|
|
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
|
|
// the `$` variable.
|
|
Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
|
|
|
|
// Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
|
|
// to its previous owner. Returns a reference to this Backbone object.
|
|
Backbone.noConflict = function() {
|
|
root.Backbone = previousBackbone;
|
|
return this;
|
|
};
|
|
|
|
// Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
|
|
// will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
|
|
// set a `X-Http-Method-Override` header.
|
|
Backbone.emulateHTTP = false;
|
|
|
|
// Turn on `emulateJSON` to support legacy servers that can't deal with direct
|
|
// `application/json` requests ... will encode the body as
|
|
// `application/x-www-form-urlencoded` instead and will send the model in a
|
|
// form param named `model`.
|
|
Backbone.emulateJSON = false;
|
|
|
|
// Backbone.Events
|
|
// ---------------
|
|
|
|
// A module that can be mixed in to *any object* in order to provide it with
|
|
// custom events. You may bind with `on` or remove with `off` callback
|
|
// functions to an event; `trigger`-ing an event fires all callbacks in
|
|
// succession.
|
|
//
|
|
// var object = {};
|
|
// _.extend(object, Backbone.Events);
|
|
// object.on('expand', function(){ alert('expanded'); });
|
|
// object.trigger('expand');
|
|
//
|
|
var Events = Backbone.Events = {
|
|
|
|
// Bind an event to a `callback` function. Passing `"all"` will bind
|
|
// the callback to all events fired.
|
|
on: function(name, callback, context) {
|
|
if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
|
|
this._events || (this._events = {});
|
|
var events = this._events[name] || (this._events[name] = []);
|
|
events.push({callback: callback, context: context, ctx: context || this});
|
|
return this;
|
|
},
|
|
|
|
// Bind an event to only be triggered a single time. After the first time
|
|
// the callback is invoked, it will be removed.
|
|
once: function(name, callback, context) {
|
|
if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
|
|
var self = this;
|
|
var once = _.once(function() {
|
|
self.off(name, once);
|
|
callback.apply(this, arguments);
|
|
});
|
|
once._callback = callback;
|
|
return this.on(name, once, context);
|
|
},
|
|
|
|
// Remove one or many callbacks. If `context` is null, removes all
|
|
// callbacks with that function. If `callback` is null, removes all
|
|
// callbacks for the event. If `name` is null, removes all bound
|
|
// callbacks for all events.
|
|
off: function(name, callback, context) {
|
|
var retain, ev, events, names, i, l, j, k;
|
|
if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
|
|
if (!name && !callback && !context) {
|
|
this._events = {};
|
|
return this;
|
|
}
|
|
|
|
names = name ? [name] : _.keys(this._events);
|
|
for (i = 0, l = names.length; i < l; i++) {
|
|
name = names[i];
|
|
if (events = this._events[name]) {
|
|
this._events[name] = retain = [];
|
|
if (callback || context) {
|
|
for (j = 0, k = events.length; j < k; j++) {
|
|
ev = events[j];
|
|
if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
|
|
(context && context !== ev.context)) {
|
|
retain.push(ev);
|
|
}
|
|
}
|
|
}
|
|
if (!retain.length) delete this._events[name];
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
// Trigger one or many events, firing all bound callbacks. Callbacks are
|
|
// passed the same arguments as `trigger` is, apart from the event name
|
|
// (unless you're listening on `"all"`, which will cause your callback to
|
|
// receive the true name of the event as the first argument).
|
|
trigger: function(name) {
|
|
if (!this._events) return this;
|
|
var args = slice.call(arguments, 1);
|
|
if (!eventsApi(this, 'trigger', name, args)) return this;
|
|
var events = this._events[name];
|
|
var allEvents = this._events.all;
|
|
if (events) triggerEvents(events, args);
|
|
if (allEvents) triggerEvents(allEvents, arguments);
|
|
return this;
|
|
},
|
|
|
|
// Tell this object to stop listening to either specific events ... or
|
|
// to every object it's currently listening to.
|
|
stopListening: function(obj, name, callback) {
|
|
var listeners = this._listeners;
|
|
if (!listeners) return this;
|
|
var deleteListener = !name && !callback;
|
|
if (typeof name === 'object') callback = this;
|
|
if (obj) (listeners = {})[obj._listenerId] = obj;
|
|
for (var id in listeners) {
|
|
listeners[id].off(name, callback, this);
|
|
if (deleteListener) delete this._listeners[id];
|
|
}
|
|
return this;
|
|
}
|
|
|
|
};
|
|
|
|
// Regular expression used to split event strings.
|
|
var eventSplitter = /\s+/;
|
|
|
|
// Implement fancy features of the Events API such as multiple event
|
|
// names `"change blur"` and jQuery-style event maps `{change: action}`
|
|
// in terms of the existing API.
|
|
var eventsApi = function(obj, action, name, rest) {
|
|
if (!name) return true;
|
|
|
|
// Handle event maps.
|
|
if (typeof name === 'object') {
|
|
for (var key in name) {
|
|
obj[action].apply(obj, [key, name[key]].concat(rest));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Handle space separated event names.
|
|
if (eventSplitter.test(name)) {
|
|
var names = name.split(eventSplitter);
|
|
for (var i = 0, l = names.length; i < l; i++) {
|
|
obj[action].apply(obj, [names[i]].concat(rest));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
// A difficult-to-believe, but optimized internal dispatch function for
|
|
// triggering events. Tries to keep the usual cases speedy (most internal
|
|
// Backbone events have 3 arguments).
|
|
var triggerEvents = function(events, args) {
|
|
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
|
|
switch (args.length) {
|
|
case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
|
|
case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
|
|
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
|
|
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
|
|
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
|
|
}
|
|
};
|
|
|
|
var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
|
|
|
|
// Inversion-of-control versions of `on` and `once`. Tell *this* object to
|
|
// listen to an event in another object ... keeping track of what it's
|
|
// listening to.
|
|
_.each(listenMethods, function(implementation, method) {
|
|
Events[method] = function(obj, name, callback) {
|
|
var listeners = this._listeners || (this._listeners = {});
|
|
var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
|
|
listeners[id] = obj;
|
|
if (typeof name === 'object') callback = this;
|
|
obj[implementation](name, callback, this);
|
|
return this;
|
|
};
|
|
});
|
|
|
|
// Aliases for backwards compatibility.
|
|
Events.bind = Events.on;
|
|
Events.unbind = Events.off;
|
|
|
|
// Allow the `Backbone` object to serve as a global event bus, for folks who
|
|
// want global "pubsub" in a convenient place.
|
|
_.extend(Backbone, Events);
|
|
|
|
// Backbone.Model
|
|
// --------------
|
|
|
|
// Backbone **Models** are the basic data object in the framework --
|
|
// frequently representing a row in a table in a database on your server.
|
|
// A discrete chunk of data and a bunch of useful, related methods for
|
|
// performing computations and transformations on that data.
|
|
|
|
// Create a new model with the specified attributes. A client id (`cid`)
|
|
// is automatically generated and assigned for you.
|
|
var Model = Backbone.Model = function(attributes, options) {
|
|
var defaults;
|
|
var attrs = attributes || {};
|
|
options || (options = {});
|
|
this.cid = _.uniqueId('c');
|
|
this.attributes = {};
|
|
_.extend(this, _.pick(options, modelOptions));
|
|
if (options.parse) attrs = this.parse(attrs, options) || {};
|
|
if (defaults = _.result(this, 'defaults')) {
|
|
attrs = _.defaults({}, attrs, defaults);
|
|
}
|
|
this.set(attrs, options);
|
|
this.changed = {};
|
|
this.initialize.apply(this, arguments);
|
|
};
|
|
|
|
// A list of options to be attached directly to the model, if provided.
|
|
var modelOptions = ['url', 'urlRoot', 'collection'];
|
|
|
|
// Attach all inheritable methods to the Model prototype.
|
|
_.extend(Model.prototype, Events, {
|
|
|
|
// A hash of attributes whose current and previous value differ.
|
|
changed: null,
|
|
|
|
// The value returned during the last failed validation.
|
|
validationError: null,
|
|
|
|
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
|
|
// CouchDB users may want to set this to `"_id"`.
|
|
idAttribute: 'id',
|
|
|
|
// Initialize is an empty function by default. Override it with your own
|
|
// initialization logic.
|
|
initialize: function(){},
|
|
|
|
// Return a copy of the model's `attributes` object.
|
|
toJSON: function(options) {
|
|
return _.clone(this.attributes);
|
|
},
|
|
|
|
// Proxy `Backbone.sync` by default -- but override this if you need
|
|
// custom syncing semantics for *this* particular model.
|
|
sync: function() {
|
|
return Backbone.sync.apply(this, arguments);
|
|
},
|
|
|
|
// Get the value of an attribute.
|
|
get: function(attr) {
|
|
return this.attributes[attr];
|
|
},
|
|
|
|
// Get the HTML-escaped value of an attribute.
|
|
escape: function(attr) {
|
|
return _.escape(this.get(attr));
|
|
},
|
|
|
|
// Returns `true` if the attribute contains a value that is not null
|
|
// or undefined.
|
|
has: function(attr) {
|
|
return this.get(attr) != null;
|
|
},
|
|
|
|
// Set a hash of model attributes on the object, firing `"change"`. This is
|
|
// the core primitive operation of a model, updating the data and notifying
|
|
// anyone who needs to know about the change in state. The heart of the beast.
|
|
set: function(key, val, options) {
|
|
var attr, attrs, unset, changes, silent, changing, prev, current;
|
|
if (key == null) return this;
|
|
|
|
// Handle both `"key", value` and `{key: value}` -style arguments.
|
|
if (typeof key === 'object') {
|
|
attrs = key;
|
|
options = val;
|
|
} else {
|
|
(attrs = {})[key] = val;
|
|
}
|
|
|
|
options || (options = {});
|
|
|
|
// Run validation.
|
|
if (!this._validate(attrs, options)) return false;
|
|
|
|
// Extract attributes and options.
|
|
unset = options.unset;
|
|
silent = options.silent;
|
|
changes = [];
|
|
changing = this._changing;
|
|
this._changing = true;
|
|
|
|
if (!changing) {
|
|
this._previousAttributes = _.clone(this.attributes);
|
|
this.changed = {};
|
|
}
|
|
current = this.attributes, prev = this._previousAttributes;
|
|
|
|
// Check for changes of `id`.
|
|
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
|
|
|
// For each `set` attribute, update or delete the current value.
|
|
for (attr in attrs) {
|
|
val = attrs[attr];
|
|
if (!_.isEqual(current[attr], val)) changes.push(attr);
|
|
if (!_.isEqual(prev[attr], val)) {
|
|
this.changed[attr] = val;
|
|
} else {
|
|
delete this.changed[attr];
|
|
}
|
|
unset ? delete current[attr] : current[attr] = val;
|
|
}
|
|
|
|
// Trigger all relevant attribute changes.
|
|
if (!silent) {
|
|
if (changes.length) this._pending = true;
|
|
for (var i = 0, l = changes.length; i < l; i++) {
|
|
this.trigger('change:' + changes[i], this, current[changes[i]], options);
|
|
}
|
|
}
|
|
|
|
// You might be wondering why there's a `while` loop here. Changes can
|
|
// be recursively nested within `"change"` events.
|
|
if (changing) return this;
|
|
if (!silent) {
|
|
while (this._pending) {
|
|
this._pending = false;
|
|
this.trigger('change', this, options);
|
|
}
|
|
}
|
|
this._pending = false;
|
|
this._changing = false;
|
|
return this;
|
|
},
|
|
|
|
// Remove an attribute from the model, firing `"change"`. `unset` is a noop
|
|
// if the attribute doesn't exist.
|
|
unset: function(attr, options) {
|
|
return this.set(attr, void 0, _.extend({}, options, {unset: true}));
|
|
},
|
|
|
|
// Clear all attributes on the model, firing `"change"`.
|
|
clear: function(options) {
|
|
var attrs = {};
|
|
for (var key in this.attributes) attrs[key] = void 0;
|
|
return this.set(attrs, _.extend({}, options, {unset: true}));
|
|
},
|
|
|
|
// Determine if the model has changed since the last `"change"` event.
|
|
// If you specify an attribute name, determine if that attribute has changed.
|
|
hasChanged: function(attr) {
|
|
if (attr == null) return !_.isEmpty(this.changed);
|
|
return _.has(this.changed, attr);
|
|
},
|
|
|
|
// Return an object containing all the attributes that have changed, or
|
|
// false if there are no changed attributes. Useful for determining what
|
|
// parts of a view need to be updated and/or what attributes need to be
|
|
// persisted to the server. Unset attributes will be set to undefined.
|
|
// You can also pass an attributes object to diff against the model,
|
|
// determining if there *would be* a change.
|
|
changedAttributes: function(diff) {
|
|
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
|
|
var val, changed = false;
|
|
var old = this._changing ? this._previousAttributes : this.attributes;
|
|
for (var attr in diff) {
|
|
if (_.isEqual(old[attr], (val = diff[attr]))) continue;
|
|
(changed || (changed = {}))[attr] = val;
|
|
}
|
|
return changed;
|
|
},
|
|
|
|
// Get the previous value of an attribute, recorded at the time the last
|
|
// `"change"` event was fired.
|
|
previous: function(attr) {
|
|
if (attr == null || !this._previousAttributes) return null;
|
|
return this._previousAttributes[attr];
|
|
},
|
|
|
|
// Get all of the attributes of the model at the time of the previous
|
|
// `"change"` event.
|
|
previousAttributes: function() {
|
|
return _.clone(this._previousAttributes);
|
|
},
|
|
|
|
// Fetch the model from the server. If the server's representation of the
|
|
// model differs from its current attributes, they will be overridden,
|
|
// triggering a `"change"` event.
|
|
fetch: function(options) {
|
|
options = options ? _.clone(options) : {};
|
|
if (options.parse === void 0) options.parse = true;
|
|
var model = this;
|
|
var success = options.success;
|
|
options.success = function(resp) {
|
|
if (!model.set(model.parse(resp, options), options)) return false;
|
|
if (success) success(model, resp, options);
|
|
model.trigger('sync', model, resp, options);
|
|
};
|
|
wrapError(this, options);
|
|
return this.sync('read', this, options);
|
|
},
|
|
|
|
// Set a hash of model attributes, and sync the model to the server.
|
|
// If the server returns an attributes hash that differs, the model's
|
|
// state will be `set` again.
|
|
save: function(key, val, options) {
|
|
var attrs, method, xhr, attributes = this.attributes;
|
|
|
|
// Handle both `"key", value` and `{key: value}` -style arguments.
|
|
if (key == null || typeof key === 'object') {
|
|
attrs = key;
|
|
options = val;
|
|
} else {
|
|
(attrs = {})[key] = val;
|
|
}
|
|
|
|
// If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
|
|
if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
|
|
|
|
options = _.extend({validate: true}, options);
|
|
|
|
// Do not persist invalid models.
|
|
if (!this._validate(attrs, options)) return false;
|
|
|
|
// Set temporary attributes if `{wait: true}`.
|
|
if (attrs && options.wait) {
|
|
this.attributes = _.extend({}, attributes, attrs);
|
|
}
|
|
|
|
// After a successful server-side save, the client is (optionally)
|
|
// updated with the server-side state.
|
|
if (options.parse === void 0) options.parse = true;
|
|
var model = this;
|
|
var success = options.success;
|
|
options.success = function(resp) {
|
|
// Ensure attributes are restored during synchronous saves.
|
|
model.attributes = attributes;
|
|
var serverAttrs = model.parse(resp, options);
|
|
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
|
|
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
|
|
return false;
|
|
}
|
|
if (success) success(model, resp, options);
|
|
model.trigger('sync', model, resp, options);
|
|
};
|
|
wrapError(this, options);
|
|
|
|
method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
|
|
if (method === 'patch') options.attrs = attrs;
|
|
xhr = this.sync(method, this, options);
|
|
|
|
// Restore attributes.
|
|
if (attrs && options.wait) this.attributes = attributes;
|
|
|
|
return xhr;
|
|
},
|
|
|
|
// Destroy this model on the server if it was already persisted.
|
|
// Optimistically removes the model from its collection, if it has one.
|
|
// If `wait: true` is passed, waits for the server to respond before removal.
|
|
destroy: function(options) {
|
|
options = options ? _.clone(options) : {};
|
|
var model = this;
|
|
var success = options.success;
|
|
|
|
var destroy = function() {
|
|
model.trigger('destroy', model, model.collection, options);
|
|
};
|
|
|
|
options.success = function(resp) {
|
|
if (options.wait || model.isNew()) destroy();
|
|
if (success) success(model, resp, options);
|
|
if (!model.isNew()) model.trigger('sync', model, resp, options);
|
|
};
|
|
|
|
if (this.isNew()) {
|
|
options.success();
|
|
return false;
|
|
}
|
|
wrapError(this, options);
|
|
|
|
var xhr = this.sync('delete', this, options);
|
|
if (!options.wait) destroy();
|
|
return xhr;
|
|
},
|
|
|
|
// Default URL for the model's representation on the server -- if you're
|
|
// using Backbone's restful methods, override this to change the endpoint
|
|
// that will be called.
|
|
url: function() {
|
|
var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
|
|
if (this.isNew()) return base;
|
|
return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
|
|
},
|
|
|
|
// **parse** converts a response into the hash of attributes to be `set` on
|
|
// the model. The default implementation is just to pass the response along.
|
|
parse: function(resp, options) {
|
|
return resp;
|
|
},
|
|
|
|
// Create a new model with identical attributes to this one.
|
|
clone: function() {
|
|
return new this.constructor(this.attributes);
|
|
},
|
|
|
|
// A model is new if it has never been saved to the server, and lacks an id.
|
|
isNew: function() {
|
|
return this.id == null;
|
|
},
|
|
|
|
// Check if the model is currently in a valid state.
|
|
isValid: function(options) {
|
|
return this._validate({}, _.extend(options || {}, { validate: true }));
|
|
},
|
|
|
|
// Run validation against the next complete set of model attributes,
|
|
// returning `true` if all is well. Otherwise, fire an `"invalid"` event.
|
|
_validate: function(attrs, options) {
|
|
if (!options.validate || !this.validate) return true;
|
|
attrs = _.extend({}, this.attributes, attrs);
|
|
var error = this.validationError = this.validate(attrs, options) || null;
|
|
if (!error) return true;
|
|
this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
|
|
return false;
|
|
}
|
|
|
|
});
|
|
|
|
// Underscore methods that we want to implement on the Model.
|
|
var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
|
|
|
|
// Mix in each Underscore method as a proxy to `Model#attributes`.
|
|
_.each(modelMethods, function(method) {
|
|
Model.prototype[method] = function() {
|
|
var args = slice.call(arguments);
|
|
args.unshift(this.attributes);
|
|
return _[method].apply(_, args);
|
|
};
|
|
});
|
|
|
|
// Backbone.Collection
|
|
// -------------------
|
|
|
|
// If models tend to represent a single row of data, a Backbone Collection is
|
|
// more analagous to a table full of data ... or a small slice or page of that
|
|
// table, or a collection of rows that belong together for a particular reason
|
|
// -- all of the messages in this particular folder, all of the documents
|
|
// belonging to this particular author, and so on. Collections maintain
|
|
// indexes of their models, both in order, and for lookup by `id`.
|
|
|
|
// Create a new **Collection**, perhaps to contain a specific type of `model`.
|
|
// If a `comparator` is specified, the Collection will maintain
|
|
// its models in sort order, as they're added and removed.
|
|
var Collection = Backbone.Collection = function(models, options) {
|
|
options || (options = {});
|
|
if (options.url) this.url = options.url;
|
|
if (options.model) this.model = options.model;
|
|
if (options.comparator !== void 0) this.comparator = options.comparator;
|
|
this._reset();
|
|
this.initialize.apply(this, arguments);
|
|
if (models) this.reset(models, _.extend({silent: true}, options));
|
|
};
|
|
|
|
// Default options for `Collection#set`.
|
|
var setOptions = {add: true, remove: true, merge: true};
|
|
var addOptions = {add: true, merge: false, remove: false};
|
|
|
|
// Define the Collection's inheritable methods.
|
|
_.extend(Collection.prototype, Events, {
|
|
|
|
// The default model for a collection is just a **Backbone.Model**.
|
|
// This should be overridden in most cases.
|
|
model: Model,
|
|
|
|
// Initialize is an empty function by default. Override it with your own
|
|
// initialization logic.
|
|
initialize: function(){},
|
|
|
|
// The JSON representation of a Collection is an array of the
|
|
// models' attributes.
|
|
toJSON: function(options) {
|
|
return this.map(function(model){ return model.toJSON(options); });
|
|
},
|
|
|
|
// Proxy `Backbone.sync` by default.
|
|
sync: function() {
|
|
return Backbone.sync.apply(this, arguments);
|
|
},
|
|
|
|
// Add a model, or list of models to the set.
|
|
add: function(models, options) {
|
|
return this.set(models, _.defaults(options || {}, addOptions));
|
|
},
|
|
|
|
// Remove a model, or a list of models from the set.
|
|
remove: function(models, options) {
|
|
models = _.isArray(models) ? models.slice() : [models];
|
|
options || (options = {});
|
|
var i, l, index, model;
|
|
for (i = 0, l = models.length; i < l; i++) {
|
|
model = this.get(models[i]);
|
|
if (!model) continue;
|
|
delete this._byId[model.id];
|
|
delete this._byId[model.cid];
|
|
index = this.indexOf(model);
|
|
this.models.splice(index, 1);
|
|
this.length--;
|
|
if (!options.silent) {
|
|
options.index = index;
|
|
model.trigger('remove', model, this, options);
|
|
}
|
|
this._removeReference(model);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Update a collection by `set`-ing a new list of models, adding new ones,
|
|
// removing models that are no longer present, and merging models that
|
|
// already exist in the collection, as necessary. Similar to **Model#set**,
|
|
// the core operation for updating the data contained by the collection.
|
|
set: function(models, options) {
|
|
options = _.defaults(options || {}, setOptions);
|
|
if (options.parse) models = this.parse(models, options);
|
|
if (!_.isArray(models)) models = models ? [models] : [];
|
|
var i, l, model, attrs, existing, sort;
|
|
var at = options.at;
|
|
var sortable = this.comparator && (at == null) && options.sort !== false;
|
|
var sortAttr = _.isString(this.comparator) ? this.comparator : null;
|
|
var toAdd = [], toRemove = [], modelMap = {};
|
|
|
|
// Turn bare objects into model references, and prevent invalid models
|
|
// from being added.
|
|
for (i = 0, l = models.length; i < l; i++) {
|
|
if (!(model = this._prepareModel(models[i], options))) continue;
|
|
|
|
// If a duplicate is found, prevent it from being added and
|
|
// optionally merge it into the existing model.
|
|
if (existing = this.get(model)) {
|
|
if (options.remove) modelMap[existing.cid] = true;
|
|
if (options.merge) {
|
|
existing.set(model.attributes, options);
|
|
if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
|
|
}
|
|
|
|
// This is a new model, push it to the `toAdd` list.
|
|
} else if (options.add) {
|
|
toAdd.push(model);
|
|
|
|
// Listen to added models' events, and index models for lookup by
|
|
// `id` and by `cid`.
|
|
model.on('all', this._onModelEvent, this);
|
|
this._byId[model.cid] = model;
|
|
if (model.id != null) this._byId[model.id] = model;
|
|
}
|
|
}
|
|
|
|
// Remove nonexistent models if appropriate.
|
|
if (options.remove) {
|
|
for (i = 0, l = this.length; i < l; ++i) {
|
|
if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
|
|
}
|
|
if (toRemove.length) this.remove(toRemove, options);
|
|
}
|
|
|
|
// See if sorting is needed, update `length` and splice in new models.
|
|
if (toAdd.length) {
|
|
if (sortable) sort = true;
|
|
this.length += toAdd.length;
|
|
if (at != null) {
|
|
splice.apply(this.models, [at, 0].concat(toAdd));
|
|
} else {
|
|
push.apply(this.models, toAdd);
|
|
}
|
|
}
|
|
|
|
// Silently sort the collection if appropriate.
|
|
if (sort) this.sort({silent: true});
|
|
|
|
if (options.silent) return this;
|
|
|
|
// Trigger `add` events.
|
|
for (i = 0, l = toAdd.length; i < l; i++) {
|
|
(model = toAdd[i]).trigger('add', model, this, options);
|
|
}
|
|
|
|
// Trigger `sort` if the collection was sorted.
|
|
if (sort) this.trigger('sort', this, options);
|
|
return this;
|
|
},
|
|
|
|
// When you have more items than you want to add or remove individually,
|
|
// you can reset the entire set with a new list of models, without firing
|
|
// any granular `add` or `remove` events. Fires `reset` when finished.
|
|
// Useful for bulk operations and optimizations.
|
|
reset: function(models, options) {
|
|
options || (options = {});
|
|
for (var i = 0, l = this.models.length; i < l; i++) {
|
|
this._removeReference(this.models[i]);
|
|
}
|
|
options.previousModels = this.models;
|
|
this._reset();
|
|
this.add(models, _.extend({silent: true}, options));
|
|
if (!options.silent) this.trigger('reset', this, options);
|
|
return this;
|
|
},
|
|
|
|
// Add a model to the end of the collection.
|
|
push: function(model, options) {
|
|
model = this._prepareModel(model, options);
|
|
this.add(model, _.extend({at: this.length}, options));
|
|
return model;
|
|
},
|
|
|
|
// Remove a model from the end of the collection.
|
|
pop: function(options) {
|
|
var model = this.at(this.length - 1);
|
|
this.remove(model, options);
|
|
return model;
|
|
},
|
|
|
|
// Add a model to the beginning of the collection.
|
|
unshift: function(model, options) {
|
|
model = this._prepareModel(model, options);
|
|
this.add(model, _.extend({at: 0}, options));
|
|
return model;
|
|
},
|
|
|
|
// Remove a model from the beginning of the collection.
|
|
shift: function(options) {
|
|
var model = this.at(0);
|
|
this.remove(model, options);
|
|
return model;
|
|
},
|
|
|
|
// Slice out a sub-array of models from the collection.
|
|
slice: function(begin, end) {
|
|
return this.models.slice(begin, end);
|
|
},
|
|
|
|
// Get a model from the set by id.
|
|
get: function(obj) {
|
|
if (obj == null) return void 0;
|
|
return this._byId[obj.id != null ? obj.id : obj.cid || obj];
|
|
},
|
|
|
|
// Get the model at the given index.
|
|
at: function(index) {
|
|
return this.models[index];
|
|
},
|
|
|
|
// Return models with matching attributes. Useful for simple cases of
|
|
// `filter`.
|
|
where: function(attrs, first) {
|
|
if (_.isEmpty(attrs)) return first ? void 0 : [];
|
|
return this[first ? 'find' : 'filter'](function(model) {
|
|
for (var key in attrs) {
|
|
if (attrs[key] !== model.get(key)) return false;
|
|
}
|
|
return true;
|
|
});
|
|
},
|
|
|
|
// Return the first model with matching attributes. Useful for simple cases
|
|
// of `find`.
|
|
findWhere: function(attrs) {
|
|
return this.where(attrs, true);
|
|
},
|
|
|
|
// Force the collection to re-sort itself. You don't need to call this under
|
|
// normal circumstances, as the set will maintain sort order as each item
|
|
// is added.
|
|
sort: function(options) {
|
|
if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
|
|
options || (options = {});
|
|
|
|
// Run sort based on type of `comparator`.
|
|
if (_.isString(this.comparator) || this.comparator.length === 1) {
|
|
this.models = this.sortBy(this.comparator, this);
|
|
} else {
|
|
this.models.sort(_.bind(this.comparator, this));
|
|
}
|
|
|
|
if (!options.silent) this.trigger('sort', this, options);
|
|
return this;
|
|
},
|
|
|
|
// Figure out the smallest index at which a model should be inserted so as
|
|
// to maintain order.
|
|
sortedIndex: function(model, value, context) {
|
|
value || (value = this.comparator);
|
|
var iterator = _.isFunction(value) ? value : function(model) {
|
|
return model.get(value);
|
|
};
|
|
return _.sortedIndex(this.models, model, iterator, context);
|
|
},
|
|
|
|
// Pluck an attribute from each model in the collection.
|
|
pluck: function(attr) {
|
|
return _.invoke(this.models, 'get', attr);
|
|
},
|
|
|
|
// Fetch the default set of models for this collection, resetting the
|
|
// collection when they arrive. If `reset: true` is passed, the response
|
|
// data will be passed through the `reset` method instead of `set`.
|
|
fetch: function(options) {
|
|
options = options ? _.clone(options) : {};
|
|
if (options.parse === void 0) options.parse = true;
|
|
var success = options.success;
|
|
var collection = this;
|
|
options.success = function(resp) {
|
|
var method = options.reset ? 'reset' : 'set';
|
|
collection[method](resp, options);
|
|
if (success) success(collection, resp, options);
|
|
collection.trigger('sync', collection, resp, options);
|
|
};
|
|
wrapError(this, options);
|
|
return this.sync('read', this, options);
|
|
},
|
|
|
|
// Create a new instance of a model in this collection. Add the model to the
|
|
// collection immediately, unless `wait: true` is passed, in which case we
|
|
// wait for the server to agree.
|
|
create: function(model, options) {
|
|
options = options ? _.clone(options) : {};
|
|
if (!(model = this._prepareModel(model, options))) return false;
|
|
if (!options.wait) this.add(model, options);
|
|
var collection = this;
|
|
var success = options.success;
|
|
options.success = function(resp) {
|
|
if (options.wait) collection.add(model, options);
|
|
if (success) success(model, resp, options);
|
|
};
|
|
model.save(null, options);
|
|
return model;
|
|
},
|
|
|
|
// **parse** converts a response into a list of models to be added to the
|
|
// collection. The default implementation is just to pass it through.
|
|
parse: function(resp, options) {
|
|
return resp;
|
|
},
|
|
|
|
// Create a new collection with an identical list of models as this one.
|
|
clone: function() {
|
|
return new this.constructor(this.models);
|
|
},
|
|
|
|
// Private method to reset all internal state. Called when the collection
|
|
// is first initialized or reset.
|
|
_reset: function() {
|
|
this.length = 0;
|
|
this.models = [];
|
|
this._byId = {};
|
|
},
|
|
|
|
// Prepare a hash of attributes (or other model) to be added to this
|
|
// collection.
|
|
_prepareModel: function(attrs, options) {
|
|
if (attrs instanceof Model) {
|
|
if (!attrs.collection) attrs.collection = this;
|
|
return attrs;
|
|
}
|
|
options || (options = {});
|
|
options.collection = this;
|
|
var model = new this.model(attrs, options);
|
|
if (!model._validate(attrs, options)) {
|
|
this.trigger('invalid', this, attrs, options);
|
|
return false;
|
|
}
|
|
return model;
|
|
},
|
|
|
|
// Internal method to sever a model's ties to a collection.
|
|
_removeReference: function(model) {
|
|
if (this === model.collection) delete model.collection;
|
|
model.off('all', this._onModelEvent, this);
|
|
},
|
|
|
|
// Internal method called every time a model in the set fires an event.
|
|
// Sets need to update their indexes when models change ids. All other
|
|
// events simply proxy through. "add" and "remove" events that originate
|
|
// in other collections are ignored.
|
|
_onModelEvent: function(event, model, collection, options) {
|
|
if ((event === 'add' || event === 'remove') && collection !== this) return;
|
|
if (event === 'destroy') this.remove(model, options);
|
|
if (model && event === 'change:' + model.idAttribute) {
|
|
delete this._byId[model.previous(model.idAttribute)];
|
|
if (model.id != null) this._byId[model.id] = model;
|
|
}
|
|
this.trigger.apply(this, arguments);
|
|
}
|
|
|
|
});
|
|
|
|
// Underscore methods that we want to implement on the Collection.
|
|
// 90% of the core usefulness of Backbone Collections is actually implemented
|
|
// right here:
|
|
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
|
|
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
|
|
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
|
|
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
|
|
'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
|
|
'isEmpty', 'chain'];
|
|
|
|
// Mix in each Underscore method as a proxy to `Collection#models`.
|
|
_.each(methods, function(method) {
|
|
Collection.prototype[method] = function() {
|
|
var args = slice.call(arguments);
|
|
args.unshift(this.models);
|
|
return _[method].apply(_, args);
|
|
};
|
|
});
|
|
|
|
// Underscore methods that take a property name as an argument.
|
|
var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
|
|
|
|
// Use attributes instead of properties.
|
|
_.each(attributeMethods, function(method) {
|
|
Collection.prototype[method] = function(value, context) {
|
|
var iterator = _.isFunction(value) ? value : function(model) {
|
|
return model.get(value);
|
|
};
|
|
return _[method](this.models, iterator, context);
|
|
};
|
|
});
|
|
|
|
// Backbone.View
|
|
// -------------
|
|
|
|
// Backbone Views are almost more convention than they are actual code. A View
|
|
// is simply a JavaScript object that represents a logical chunk of UI in the
|
|
// DOM. This might be a single item, an entire list, a sidebar or panel, or
|
|
// even the surrounding frame which wraps your whole app. Defining a chunk of
|
|
// UI as a **View** allows you to define your DOM events declaratively, without
|
|
// having to worry about render order ... and makes it easy for the view to
|
|
// react to specific changes in the state of your models.
|
|
|
|
// Creating a Backbone.View creates its initial element outside of the DOM,
|
|
// if an existing element is not provided...
|
|
var View = Backbone.View = function(options) {
|
|
this.cid = _.uniqueId('view');
|
|
this._configure(options || {});
|
|
this._ensureElement();
|
|
this.initialize.apply(this, arguments);
|
|
this.delegateEvents();
|
|
};
|
|
|
|
// Cached regex to split keys for `delegate`.
|
|
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
|
|
|
|
// List of view options to be merged as properties.
|
|
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
|
|
|
|
// Set up all inheritable **Backbone.View** properties and methods.
|
|
_.extend(View.prototype, Events, {
|
|
|
|
// The default `tagName` of a View's element is `"div"`.
|
|
tagName: 'div',
|
|
|
|
// jQuery delegate for element lookup, scoped to DOM elements within the
|
|
// current view. This should be prefered to global lookups where possible.
|
|
$: function(selector) {
|
|
return this.$el.find(selector);
|
|
},
|
|
|
|
// Initialize is an empty function by default. Override it with your own
|
|
// initialization logic.
|
|
initialize: function(){},
|
|
|
|
// **render** is the core function that your view should override, in order
|
|
// to populate its element (`this.el`), with the appropriate HTML. The
|
|
// convention is for **render** to always return `this`.
|
|
render: function() {
|
|
return this;
|
|
},
|
|
|
|
// Remove this view by taking the element out of the DOM, and removing any
|
|
// applicable Backbone.Events listeners.
|
|
remove: function() {
|
|
this.$el.remove();
|
|
this.stopListening();
|
|
return this;
|
|
},
|
|
|
|
// Change the view's element (`this.el` property), including event
|
|
// re-delegation.
|
|
setElement: function(element, delegate) {
|
|
if (this.$el) this.undelegateEvents();
|
|
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
|
|
this.el = this.$el[0];
|
|
if (delegate !== false) this.delegateEvents();
|
|
return this;
|
|
},
|
|
|
|
// Set callbacks, where `this.events` is a hash of
|
|
//
|
|
// *{"event selector": "callback"}*
|
|
//
|
|
// {
|
|
// 'mousedown .title': 'edit',
|
|
// 'click .button': 'save'
|
|
// 'click .open': function(e) { ... }
|
|
// }
|
|
//
|
|
// pairs. Callbacks will be bound to the view, with `this` set properly.
|
|
// Uses event delegation for efficiency.
|
|
// Omitting the selector binds the event to `this.el`.
|
|
// This only works for delegate-able events: not `focus`, `blur`, and
|
|
// not `change`, `submit`, and `reset` in Internet Explorer.
|
|
delegateEvents: function(events) {
|
|
if (!(events || (events = _.result(this, 'events')))) return this;
|
|
this.undelegateEvents();
|
|
for (var key in events) {
|
|
var method = events[key];
|
|
if (!_.isFunction(method)) method = this[events[key]];
|
|
if (!method) continue;
|
|
|
|
var match = key.match(delegateEventSplitter);
|
|
var eventName = match[1], selector = match[2];
|
|
method = _.bind(method, this);
|
|
eventName += '.delegateEvents' + this.cid;
|
|
if (selector === '') {
|
|
this.$el.on(eventName, method);
|
|
} else {
|
|
this.$el.on(eventName, selector, method);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Clears all callbacks previously bound to the view with `delegateEvents`.
|
|
// You usually don't need to use this, but may wish to if you have multiple
|
|
// Backbone views attached to the same DOM element.
|
|
undelegateEvents: function() {
|
|
this.$el.off('.delegateEvents' + this.cid);
|
|
return this;
|
|
},
|
|
|
|
// Performs the initial configuration of a View with a set of options.
|
|
// Keys with special meaning *(e.g. model, collection, id, className)* are
|
|
// attached directly to the view. See `viewOptions` for an exhaustive
|
|
// list.
|
|
_configure: function(options) {
|
|
if (this.options) options = _.extend({}, _.result(this, 'options'), options);
|
|
_.extend(this, _.pick(options, viewOptions));
|
|
this.options = options;
|
|
},
|
|
|
|
// Ensure that the View has a DOM element to render into.
|
|
// If `this.el` is a string, pass it through `$()`, take the first
|
|
// matching element, and re-assign it to `el`. Otherwise, create
|
|
// an element from the `id`, `className` and `tagName` properties.
|
|
_ensureElement: function() {
|
|
if (!this.el) {
|
|
var attrs = _.extend({}, _.result(this, 'attributes'));
|
|
if (this.id) attrs.id = _.result(this, 'id');
|
|
if (this.className) attrs['class'] = _.result(this, 'className');
|
|
var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
|
|
this.setElement($el, false);
|
|
} else {
|
|
this.setElement(_.result(this, 'el'), false);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
// Backbone.sync
|
|
// -------------
|
|
|
|
// Override this function to change the manner in which Backbone persists
|
|
// models to the server. You will be passed the type of request, and the
|
|
// model in question. By default, makes a RESTful Ajax request
|
|
// to the model's `url()`. Some possible customizations could be:
|
|
//
|
|
// * Use `setTimeout` to batch rapid-fire updates into a single request.
|
|
// * Send up the models as XML instead of JSON.
|
|
// * Persist models via WebSockets instead of Ajax.
|
|
//
|
|
// Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
|
|
// as `POST`, with a `_method` parameter containing the true HTTP method,
|
|
// as well as all requests with the body as `application/x-www-form-urlencoded`
|
|
// instead of `application/json` with the model in a param named `model`.
|
|
// Useful when interfacing with server-side languages like **PHP** that make
|
|
// it difficult to read the body of `PUT` requests.
|
|
Backbone.sync = function(method, model, options) {
|
|
var type = methodMap[method];
|
|
|
|
// Default options, unless specified.
|
|
_.defaults(options || (options = {}), {
|
|
emulateHTTP: Backbone.emulateHTTP,
|
|
emulateJSON: Backbone.emulateJSON
|
|
});
|
|
|
|
// Default JSON-request options.
|
|
var params = {type: type, dataType: 'json'};
|
|
|
|
// Ensure that we have a URL.
|
|
if (!options.url) {
|
|
params.url = _.result(model, 'url') || urlError();
|
|
}
|
|
|
|
// Ensure that we have the appropriate request data.
|
|
if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
|
|
params.contentType = 'application/json';
|
|
params.data = JSON.stringify(options.attrs || model.toJSON(options));
|
|
}
|
|
|
|
// For older servers, emulate JSON by encoding the request into an HTML-form.
|
|
if (options.emulateJSON) {
|
|
params.contentType = 'application/x-www-form-urlencoded';
|
|
params.data = params.data ? {model: params.data} : {};
|
|
}
|
|
|
|
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
|
|
// And an `X-HTTP-Method-Override` header.
|
|
if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
|
|
params.type = 'POST';
|
|
if (options.emulateJSON) params.data._method = type;
|
|
var beforeSend = options.beforeSend;
|
|
options.beforeSend = function(xhr) {
|
|
xhr.setRequestHeader('X-HTTP-Method-Override', type);
|
|
if (beforeSend) return beforeSend.apply(this, arguments);
|
|
};
|
|
}
|
|
|
|
// Don't process data on a non-GET request.
|
|
if (params.type !== 'GET' && !options.emulateJSON) {
|
|
params.processData = false;
|
|
}
|
|
|
|
// If we're sending a `PATCH` request, and we're in an old Internet Explorer
|
|
// that still has ActiveX enabled by default, override jQuery to use that
|
|
// for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
|
|
if (params.type === 'PATCH' && window.ActiveXObject &&
|
|
!(window.external && window.external.msActiveXFilteringEnabled)) {
|
|
params.xhr = function() {
|
|
return new ActiveXObject("Microsoft.XMLHTTP");
|
|
};
|
|
}
|
|
|
|
// Make the request, allowing the user to override any Ajax options.
|
|
var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
|
|
model.trigger('request', model, xhr, options);
|
|
return xhr;
|
|
};
|
|
|
|
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
|
|
var methodMap = {
|
|
'create': 'POST',
|
|
'update': 'PUT',
|
|
'patch': 'PATCH',
|
|
'delete': 'DELETE',
|
|
'read': 'GET'
|
|
};
|
|
|
|
// Set the default implementation of `Backbone.ajax` to proxy through to `$`.
|
|
// Override this if you'd like to use a different library.
|
|
Backbone.ajax = function() {
|
|
return Backbone.$.ajax.apply(Backbone.$, arguments);
|
|
};
|
|
|
|
// Backbone.Router
|
|
// ---------------
|
|
|
|
// Routers map faux-URLs to actions, and fire events when routes are
|
|
// matched. Creating a new one sets its `routes` hash, if not set statically.
|
|
var Router = Backbone.Router = function(options) {
|
|
options || (options = {});
|
|
if (options.routes) this.routes = options.routes;
|
|
this._bindRoutes();
|
|
this.initialize.apply(this, arguments);
|
|
};
|
|
|
|
// Cached regular expressions for matching named param parts and splatted
|
|
// parts of route strings.
|
|
var optionalParam = /\((.*?)\)/g;
|
|
var namedParam = /(\(\?)?:\w+/g;
|
|
var splatParam = /\*\w+/g;
|
|
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
|
|
|
|
// Set up all inheritable **Backbone.Router** properties and methods.
|
|
_.extend(Router.prototype, Events, {
|
|
|
|
// Initialize is an empty function by default. Override it with your own
|
|
// initialization logic.
|
|
initialize: function(){},
|
|
|
|
// Manually bind a single named route to a callback. For example:
|
|
//
|
|
// this.route('search/:query/p:num', 'search', function(query, num) {
|
|
// ...
|
|
// });
|
|
//
|
|
route: function(route, name, callback) {
|
|
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
|
|
if (_.isFunction(name)) {
|
|
callback = name;
|
|
name = '';
|
|
}
|
|
if (!callback) callback = this[name];
|
|
var router = this;
|
|
Backbone.history.route(route, function(fragment) {
|
|
var args = router._extractParameters(route, fragment);
|
|
callback && callback.apply(router, args);
|
|
router.trigger.apply(router, ['route:' + name].concat(args));
|
|
router.trigger('route', name, args);
|
|
Backbone.history.trigger('route', router, name, args);
|
|
});
|
|
return this;
|
|
},
|
|
|
|
// Simple proxy to `Backbone.history` to save a fragment into the history.
|
|
navigate: function(fragment, options) {
|
|
Backbone.history.navigate(fragment, options);
|
|
return this;
|
|
},
|
|
|
|
// Bind all defined routes to `Backbone.history`. We have to reverse the
|
|
// order of the routes here to support behavior where the most general
|
|
// routes can be defined at the bottom of the route map.
|
|
_bindRoutes: function() {
|
|
if (!this.routes) return;
|
|
this.routes = _.result(this, 'routes');
|
|
var route, routes = _.keys(this.routes);
|
|
while ((route = routes.pop()) != null) {
|
|
this.route(route, this.routes[route]);
|
|
}
|
|
},
|
|
|
|
// Convert a route string into a regular expression, suitable for matching
|
|
// against the current location hash.
|
|
_routeToRegExp: function(route) {
|
|
route = route.replace(escapeRegExp, '\\$&')
|
|
.replace(optionalParam, '(?:$1)?')
|
|
.replace(namedParam, function(match, optional){
|
|
return optional ? match : '([^\/]+)';
|
|
})
|
|
.replace(splatParam, '(.*?)');
|
|
return new RegExp('^' + route + '$');
|
|
},
|
|
|
|
// Given a route, and a URL fragment that it matches, return the array of
|
|
// extracted decoded parameters. Empty or unmatched parameters will be
|
|
// treated as `null` to normalize cross-browser behavior.
|
|
_extractParameters: function(route, fragment) {
|
|
var params = route.exec(fragment).slice(1);
|
|
return _.map(params, function(param) {
|
|
return param ? decodeURIComponent(param) : null;
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
// Backbone.History
|
|
// ----------------
|
|
|
|
// Handles cross-browser history management, based on either
|
|
// [pushState](http://diveintohtml5.info/history.html) and real URLs, or
|
|
// [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
|
|
// and URL fragments. If the browser supports neither (old IE, natch),
|
|
// falls back to polling.
|
|
var History = Backbone.History = function() {
|
|
this.handlers = [];
|
|
_.bindAll(this, 'checkUrl');
|
|
|
|
// Ensure that `History` can be used outside of the browser.
|
|
if (typeof window !== 'undefined') {
|
|
this.location = window.location;
|
|
this.history = window.history;
|
|
}
|
|
};
|
|
|
|
// Cached regex for stripping a leading hash/slash and trailing space.
|
|
var routeStripper = /^[#\/]|\s+$/g;
|
|
|
|
// Cached regex for stripping leading and trailing slashes.
|
|
var rootStripper = /^\/+|\/+$/g;
|
|
|
|
// Cached regex for detecting MSIE.
|
|
var isExplorer = /msie [\w.]+/;
|
|
|
|
// Cached regex for removing a trailing slash.
|
|
var trailingSlash = /\/$/;
|
|
|
|
// Has the history handling already been started?
|
|
History.started = false;
|
|
|
|
// Set up all inheritable **Backbone.History** properties and methods.
|
|
_.extend(History.prototype, Events, {
|
|
|
|
// The default interval to poll for hash changes, if necessary, is
|
|
// twenty times a second.
|
|
interval: 50,
|
|
|
|
// Gets the true hash value. Cannot use location.hash directly due to bug
|
|
// in Firefox where location.hash will always be decoded.
|
|
getHash: function(window) {
|
|
var match = (window || this).location.href.match(/#(.*)$/);
|
|
return match ? match[1] : '';
|
|
},
|
|
|
|
// Get the cross-browser normalized URL fragment, either from the URL,
|
|
// the hash, or the override.
|
|
getFragment: function(fragment, forcePushState) {
|
|
if (fragment == null) {
|
|
if (this._hasPushState || !this._wantsHashChange || forcePushState) {
|
|
fragment = this.location.pathname;
|
|
var root = this.root.replace(trailingSlash, '');
|
|
if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
|
|
} else {
|
|
fragment = this.getHash();
|
|
}
|
|
}
|
|
return fragment.replace(routeStripper, '');
|
|
},
|
|
|
|
// Start the hash change handling, returning `true` if the current URL matches
|
|
// an existing route, and `false` otherwise.
|
|
start: function(options) {
|
|
if (History.started) throw new Error("Backbone.history has already been started");
|
|
History.started = true;
|
|
|
|
// Figure out the initial configuration. Do we need an iframe?
|
|
// Is pushState desired ... is it available?
|
|
this.options = _.extend({}, {root: '/'}, this.options, options);
|
|
this.root = this.options.root;
|
|
this._wantsHashChange = this.options.hashChange !== false;
|
|
this._wantsPushState = !!this.options.pushState;
|
|
this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
|
|
var fragment = this.getFragment();
|
|
var docMode = document.documentMode;
|
|
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
|
|
|
|
// Normalize root to always include a leading and trailing slash.
|
|
this.root = ('/' + this.root + '/').replace(rootStripper, '/');
|
|
|
|
if (oldIE && this._wantsHashChange) {
|
|
this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
|
|
this.navigate(fragment);
|
|
}
|
|
|
|
// Depending on whether we're using pushState or hashes, and whether
|
|
// 'onhashchange' is supported, determine how we check the URL state.
|
|
if (this._hasPushState) {
|
|
Backbone.$(window).on('popstate', this.checkUrl);
|
|
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
|
|
Backbone.$(window).on('hashchange', this.checkUrl);
|
|
} else if (this._wantsHashChange) {
|
|
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
|
|
}
|
|
|
|
// Determine if we need to change the base url, for a pushState link
|
|
// opened by a non-pushState browser.
|
|
this.fragment = fragment;
|
|
var loc = this.location;
|
|
var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
|
|
|
|
// If we've started off with a route from a `pushState`-enabled browser,
|
|
// but we're currently in a browser that doesn't support it...
|
|
if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
|
|
this.fragment = this.getFragment(null, true);
|
|
this.location.replace(this.root + this.location.search + '#' + this.fragment);
|
|
// Return immediately as browser will do redirect to new url
|
|
return true;
|
|
|
|
// Or if we've started out with a hash-based route, but we're currently
|
|
// in a browser where it could be `pushState`-based instead...
|
|
} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
|
|
this.fragment = this.getHash().replace(routeStripper, '');
|
|
this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
|
|
}
|
|
|
|
if (!this.options.silent) return this.loadUrl();
|
|
},
|
|
|
|
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
|
|
// but possibly useful for unit testing Routers.
|
|
stop: function() {
|
|
Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
|
|
clearInterval(this._checkUrlInterval);
|
|
History.started = false;
|
|
},
|
|
|
|
// Add a route to be tested when the fragment changes. Routes added later
|
|
// may override previous routes.
|
|
route: function(route, callback) {
|
|
this.handlers.unshift({route: route, callback: callback});
|
|
},
|
|
|
|
// Checks the current URL to see if it has changed, and if it has,
|
|
// calls `loadUrl`, normalizing across the hidden iframe.
|
|
checkUrl: function(e) {
|
|
var current = this.getFragment();
|
|
if (current === this.fragment && this.iframe) {
|
|
current = this.getFragment(this.getHash(this.iframe));
|
|
}
|
|
if (current === this.fragment) return false;
|
|
if (this.iframe) this.navigate(current);
|
|
this.loadUrl() || this.loadUrl(this.getHash());
|
|
},
|
|
|
|
// Attempt to load the current URL fragment. If a route succeeds with a
|
|
// match, returns `true`. If no defined routes matches the fragment,
|
|
// returns `false`.
|
|
loadUrl: function(fragmentOverride) {
|
|
var fragment = this.fragment = this.getFragment(fragmentOverride);
|
|
var matched = _.any(this.handlers, function(handler) {
|
|
if (handler.route.test(fragment)) {
|
|
handler.callback(fragment);
|
|
return true;
|
|
}
|
|
});
|
|
return matched;
|
|
},
|
|
|
|
// Save a fragment into the hash history, or replace the URL state if the
|
|
// 'replace' option is passed. You are responsible for properly URL-encoding
|
|
// the fragment in advance.
|
|
//
|
|
// The options object can contain `trigger: true` if you wish to have the
|
|
// route callback be fired (not usually desirable), or `replace: true`, if
|
|
// you wish to modify the current URL without adding an entry to the history.
|
|
navigate: function(fragment, options) {
|
|
if (!History.started) return false;
|
|
if (!options || options === true) options = {trigger: options};
|
|
fragment = this.getFragment(fragment || '');
|
|
if (this.fragment === fragment) return;
|
|
this.fragment = fragment;
|
|
var url = this.root + fragment;
|
|
|
|
// If pushState is available, we use it to set the fragment as a real URL.
|
|
if (this._hasPushState) {
|
|
this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
|
|
|
|
// If hash changes haven't been explicitly disabled, update the hash
|
|
// fragment to store history.
|
|
} else if (this._wantsHashChange) {
|
|
this._updateHash(this.location, fragment, options.replace);
|
|
if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
|
|
// Opening and closing the iframe tricks IE7 and earlier to push a
|
|
// history entry on hash-tag change. When replace is true, we don't
|
|
// want this.
|
|
if(!options.replace) this.iframe.document.open().close();
|
|
this._updateHash(this.iframe.location, fragment, options.replace);
|
|
}
|
|
|
|
// If you've told us that you explicitly don't want fallback hashchange-
|
|
// based history, then `navigate` becomes a page refresh.
|
|
} else {
|
|
return this.location.assign(url);
|
|
}
|
|
if (options.trigger) this.loadUrl(fragment);
|
|
},
|
|
|
|
// Update the hash location, either replacing the current entry, or adding
|
|
// a new one to the browser history.
|
|
_updateHash: function(location, fragment, replace) {
|
|
if (replace) {
|
|
var href = location.href.replace(/(javascript:|#).*$/, '');
|
|
location.replace(href + '#' + fragment);
|
|
} else {
|
|
// Some browsers require that `hash` contains a leading #.
|
|
location.hash = '#' + fragment;
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
// Create the default Backbone.history.
|
|
Backbone.history = new History;
|
|
|
|
// Helpers
|
|
// -------
|
|
|
|
// Helper function to correctly set up the prototype chain, for subclasses.
|
|
// Similar to `goog.inherits`, but uses a hash of prototype properties and
|
|
// class properties to be extended.
|
|
var extend = function(protoProps, staticProps) {
|
|
var parent = this;
|
|
var child;
|
|
|
|
// The constructor function for the new subclass is either defined by you
|
|
// (the "constructor" property in your `extend` definition), or defaulted
|
|
// by us to simply call the parent's constructor.
|
|
if (protoProps && _.has(protoProps, 'constructor')) {
|
|
child = protoProps.constructor;
|
|
} else {
|
|
child = function(){ return parent.apply(this, arguments); };
|
|
}
|
|
|
|
// Add static properties to the constructor function, if supplied.
|
|
_.extend(child, parent, staticProps);
|
|
|
|
// Set the prototype chain to inherit from `parent`, without calling
|
|
// `parent`'s constructor function.
|
|
var Surrogate = function(){ this.constructor = child; };
|
|
Surrogate.prototype = parent.prototype;
|
|
child.prototype = new Surrogate;
|
|
|
|
// Add prototype properties (instance properties) to the subclass,
|
|
// if supplied.
|
|
if (protoProps) _.extend(child.prototype, protoProps);
|
|
|
|
// Set a convenience property in case the parent's prototype is needed
|
|
// later.
|
|
child.__super__ = parent.prototype;
|
|
|
|
return child;
|
|
};
|
|
|
|
// Set up inheritance for the model, collection, router, view and history.
|
|
Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
|
|
|
|
// Throw an error when a URL is needed, and none is supplied.
|
|
var urlError = function() {
|
|
throw new Error('A "url" property or function must be specified');
|
|
};
|
|
|
|
// Wrap an optional error callback with a fallback error event.
|
|
var wrapError = function (model, options) {
|
|
var error = options.error;
|
|
options.error = function(resp) {
|
|
if (error) error(model, resp, options);
|
|
model.trigger('error', model, resp, options);
|
|
};
|
|
};
|
|
|
|
}).call(this);
|
|
}, "cookie-getter": function(exports, require, module) {// simple commonJS cookie reader, best perf according to http://jsperf.com/cookie-parsing
|
|
module.exports = function (name) {
|
|
var cookie = document.cookie,
|
|
setPos = cookie.indexOf(name + '='),
|
|
stopPos = cookie.indexOf(';', setPos),
|
|
res;
|
|
if (!~setPos) return null;
|
|
res = decodeURIComponent(cookie.substring(setPos, ~stopPos ? stopPos : undefined).split('=')[1]);
|
|
return (res.charAt(0) === '{') ? JSON.parse(res) : res;
|
|
};
|
|
}, "fluidGrid": function(exports, require, module) {(function () {
|
|
// reference to our currently focused element
|
|
var focusedEl;
|
|
|
|
function getFluidGridFunction(selector) {
|
|
return function (focus) {
|
|
reOrganize(selector, focus);
|
|
};
|
|
}
|
|
|
|
function biggestBox(container, aspectRatio) {
|
|
var aspectRatio = aspectRatio || (3 / 4),
|
|
height = (container.width * aspectRatio),
|
|
res = {};
|
|
|
|
if (height > container.height) {
|
|
return {
|
|
height: container.height,
|
|
width: container.height / aspectRatio
|
|
};
|
|
} else {
|
|
return {
|
|
width: container.width,
|
|
height: container.width * aspectRatio
|
|
};
|
|
}
|
|
}
|
|
|
|
function reOrganize(selector, focus) {
|
|
var floor = Math.floor,
|
|
elements = $(selector),
|
|
howMany = elements.length,
|
|
howManyNonFocused = function () {
|
|
var hasFocused = !!elements.find('.focused').length;
|
|
if (hasFocused && howMany > 1) {
|
|
return howMany - 1;
|
|
} else if (hasFocused && howMany === 1) {
|
|
return 1;
|
|
} else {
|
|
return howMany;
|
|
}
|
|
}(),
|
|
|
|
totalAvailableWidth = window.innerWidth,
|
|
totalAvailableHeight = window.innerHeight - 140,
|
|
|
|
availableWidth = totalAvailableWidth,
|
|
availableHeight = totalAvailableHeight,
|
|
|
|
container = {
|
|
width: availableWidth,
|
|
height: availableHeight
|
|
},
|
|
columnPadding = 15,
|
|
minimumWidth = 290,
|
|
aspectRatio = 3 / 4,
|
|
|
|
numberOfColumns,
|
|
numberOfRows,
|
|
|
|
numberOfPaddingColumns,
|
|
numberOfPaddingRows,
|
|
|
|
itemDimensions,
|
|
totalWidth,
|
|
|
|
videoWidth,
|
|
leftMargin,
|
|
|
|
videoHeight,
|
|
usedHeight,
|
|
topMargin,
|
|
|
|
// do we have one selected?
|
|
// this is because having a single
|
|
// focused element is not treated
|
|
// differently, but we don't want to
|
|
// lose that reference.
|
|
haveFocusedEl;
|
|
|
|
|
|
// if we passed in a string here (could be "none")
|
|
// then we want to either set or clear our current
|
|
// focused element.
|
|
if (focus) focusedEl = $(focus)[0];
|
|
|
|
// make sure our cached focused element is still
|
|
// attached.
|
|
if (focusedEl && !$(focusedEl).parent().length) focusedEl = undefined;
|
|
|
|
// figure out if we should consider us as having any
|
|
// special focused elements
|
|
haveFocusedEl = focusedEl && howManyNonFocused > 1;
|
|
|
|
elements.height(availableHeight);
|
|
|
|
// how we want the to stack at different numbers
|
|
if (haveFocusedEl) {
|
|
numberOfColumns = howManyNonFocused - 1;
|
|
numberOfRows = 1;
|
|
availableHeight = totalAvailableHeight * .2;
|
|
} else if (howManyNonFocused === 0) {
|
|
return;
|
|
} else if (howManyNonFocused === 1) {
|
|
numberOfColumns = 1;
|
|
numberOfRows = 1;
|
|
} else if (howManyNonFocused === 2) {
|
|
if (availableWidth > availableHeight) {
|
|
numberOfColumns = 2;
|
|
numberOfRows = 1;
|
|
} else {
|
|
numberOfColumns = 1;
|
|
numberOfRows = 2;
|
|
}
|
|
} else if (howManyNonFocused === 3) {
|
|
if (availableWidth > availableHeight) {
|
|
numberOfColumns = 3;
|
|
numberOfRows = 1;
|
|
} else {
|
|
numberOfColumns = 1;
|
|
numberOfRows = 3;
|
|
}
|
|
} else if (howManyNonFocused === 4) {
|
|
numberOfColumns = 2;
|
|
numberOfRows = 2;
|
|
} else if (howManyNonFocused === 5) {
|
|
numberOfColumns = 3;
|
|
numberOfRows = 2;
|
|
} else if (howManyNonFocused === 6) {
|
|
if (availableWidth > availableHeight) {
|
|
numberOfColumns = 3;
|
|
numberOfRows = 2;
|
|
} else {
|
|
numberOfColumns = 2;
|
|
numberOfRows = 3;
|
|
}
|
|
}
|
|
|
|
itemDimensions = biggestBox({
|
|
width: availableWidth / numberOfColumns,
|
|
height: availableHeight / numberOfRows
|
|
});
|
|
|
|
numberOfPaddingColumns = numberOfColumns - 1;
|
|
numberOfPaddingRows = numberOfRows - 1;
|
|
|
|
totalWidth = itemDimensions.width * numberOfColumns;
|
|
|
|
videoWidth = function () {
|
|
var totalWidthLessPadding = totalWidth - (columnPadding * numberOfPaddingColumns);
|
|
return totalWidthLessPadding / numberOfColumns;
|
|
}();
|
|
|
|
leftMargin = (availableWidth - totalWidth) / 2;
|
|
|
|
videoHeight = itemDimensions.height - ((numberOfRows > 1) ? (columnPadding / numberOfRows) : 0);
|
|
usedHeight = (numberOfRows * videoHeight);
|
|
topMargin = (availableHeight - usedHeight) / 2;
|
|
|
|
if (haveFocusedEl) {
|
|
elements = elements.not('.focused');
|
|
}
|
|
|
|
elements.each(function (index) {
|
|
var order = index,
|
|
row = floor(order / numberOfColumns),
|
|
column = order % numberOfColumns,
|
|
intensity = 12,
|
|
rotation = function () {
|
|
if (numberOfColumns === 3) {
|
|
if (column === 0) {
|
|
return 1;
|
|
} else if (column === 1) {
|
|
return 0;
|
|
} else if (column === 2) {
|
|
return -1
|
|
}
|
|
} else if (numberOfColumns === 2) {
|
|
intensity = 5;
|
|
return column == 1 ? -1 : 1
|
|
} else if (numberOfColumns === 1) {
|
|
return 0;
|
|
}
|
|
}(),
|
|
transformation = 'rotateY(' + (rotation * intensity) + 'deg)';
|
|
|
|
if (rotation === 0) {
|
|
transformation += ' scale(.98)';
|
|
}
|
|
|
|
var calculatedTop;
|
|
if (haveFocusedEl) {
|
|
calculatedTop = (totalAvailableHeight * .8) + topMargin + 'px';
|
|
} else {
|
|
calculatedTop = (row * itemDimensions.height) + topMargin + 'px';
|
|
}
|
|
|
|
$(this).css({
|
|
//transform: transformation,
|
|
top: calculatedTop,
|
|
left: (column * itemDimensions.width) + leftMargin + 'px',
|
|
width: videoWidth + 'px',
|
|
height: videoHeight + 'px',
|
|
position: 'absolute'
|
|
});
|
|
});
|
|
|
|
if (haveFocusedEl) {
|
|
var focusSize = biggestBox({
|
|
height: (totalAvailableHeight * .8),
|
|
width: totalAvailableWidth
|
|
}, focusedEl.videoHeight / focusedEl.videoWidth);
|
|
|
|
$(focusedEl).css({
|
|
top: 0,
|
|
height: focusSize.height - topMargin,
|
|
width: focusSize.width,
|
|
left: (totalAvailableWidth / 2) - (focusSize.width / 2)
|
|
});
|
|
}
|
|
}
|
|
|
|
if (typeof exports !== 'undefined') {
|
|
module.exports = getFluidGridFunction;
|
|
} else {
|
|
window.getFluidGridFunction = getFluidGridFunction;
|
|
}
|
|
|
|
})();
|
|
}, "image-to-data-uri": function(exports, require, module) {// converts a URL of an image into a dataURI
|
|
module.exports = function (url, cb) {
|
|
// Create an empty canvas and image elements
|
|
var canvas = document.createElement('canvas'),
|
|
img = document.createElement('img');
|
|
|
|
img.onload = function () {
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
// match size of image
|
|
canvas.width = img.width;
|
|
canvas.height = img.height;
|
|
|
|
// Copy the image contents to the canvas
|
|
ctx.drawImage(img, 0, 0);
|
|
|
|
// Get the data-URI formatted image
|
|
cb(canvas.toDataURL('image/png'));
|
|
};
|
|
|
|
img.ononerror = function () {
|
|
cb(new Error('FailedToLoadImage'));
|
|
};
|
|
|
|
// canvas is not supported
|
|
if (!canvas.getContext) {
|
|
cb(new Error('CanvasIsNotSupported'));
|
|
} else {
|
|
img.src = url;
|
|
}
|
|
};
|
|
}, "slugger": function(exports, require, module) {// replaces all whitespace with '-' and removes
|
|
// all non-url friendly characters
|
|
(function () {
|
|
var whitespace = /\s+/g,
|
|
nonAscii = /[^A-Za-z0-9_ \-]/g;
|
|
|
|
function slugger(string, opts) {
|
|
var maintainCase = opts && opts.maintainCase || false,
|
|
replacement = opts && opts.replacement || '-',
|
|
key;
|
|
if (typeof string !== 'string') return '';
|
|
if (!maintainCase) string = string.toLowerCase();
|
|
return string.replace(nonAscii, '').replace(whitespace, replacement);
|
|
};
|
|
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = slugger;
|
|
} else {
|
|
window.slugger = slugger;
|
|
}
|
|
})();
|
|
}, "sound-effect-manager": function(exports, require, module) {/*
|
|
SoundEffectManager
|
|
|
|
Loads and plays sound effects useing
|
|
HTML5 Web Audio API (as only available in webkit, at the moment).
|
|
|
|
By @HenrikJoreteg from &yet
|
|
*/
|
|
/*global webkitAudioContext define*/
|
|
(function () {
|
|
var root = this;
|
|
|
|
function SoundEffectManager() {
|
|
this.support = !!window.webkitAudioContext;
|
|
if (this.support) {
|
|
this.context = new webkitAudioContext();
|
|
}
|
|
this.sounds = {};
|
|
}
|
|
|
|
// async load a file at a given URL, store it as 'name'.
|
|
SoundEffectManager.prototype.loadFile = function (url, name, delay, cb) {
|
|
if (this.support) {
|
|
this._loadWebAudioFile(url, name, delay, cb);
|
|
} else {
|
|
this._loadWaveFile(url.replace('.mp3', '.wav'), name, delay, 3, cb);
|
|
}
|
|
};
|
|
|
|
// async load a file at a given URL, store it as 'name'.
|
|
SoundEffectManager.prototype._loadWebAudioFile = function (url, name, delay, cb) {
|
|
if (!this.support) return;
|
|
var self = this,
|
|
request = new XMLHttpRequest();
|
|
|
|
request.open("GET", url, true);
|
|
request.responseType = "arraybuffer";
|
|
request.onload = function () {
|
|
self.sounds[name] = self.context.createBuffer(request.response, true);
|
|
cb && cb();
|
|
};
|
|
|
|
setTimeout(function () {
|
|
request.send();
|
|
}, delay || 0);
|
|
};
|
|
|
|
SoundEffectManager.prototype._loadWaveFile = function (url, name, delay, multiplexLimit, cb) {
|
|
var self = this,
|
|
limit = multiplexLimit || 3;
|
|
setTimeout(function () {
|
|
var a, i = 0;
|
|
|
|
self.sounds[name] = [];
|
|
while (i < limit) {
|
|
a = new Audio();
|
|
a.src = url;
|
|
// for our callback
|
|
if (i === 0 && cb) {
|
|
a.addEventListener('canplaythrough', cb, false);
|
|
}
|
|
a.load();
|
|
self.sounds[name][i++] = a;
|
|
}
|
|
}, delay || 0);
|
|
};
|
|
|
|
SoundEffectManager.prototype._playWebAudio = function (soundName) {
|
|
var buffer = this.sounds[soundName],
|
|
source;
|
|
|
|
if (!buffer) return;
|
|
|
|
// creates a sound source
|
|
source = this.context.createBufferSource();
|
|
// tell the source which sound to play
|
|
source.buffer = buffer;
|
|
// connect the source to the context's destination (the speakers)
|
|
source.connect(this.context.destination);
|
|
// play it
|
|
source.noteOn(0);
|
|
};
|
|
|
|
SoundEffectManager.prototype._playWavAudio = function (soundName, loop) {
|
|
var self = this,
|
|
audio = this.sounds[soundName],
|
|
howMany = audio && audio.length || 0,
|
|
i = 0,
|
|
currSound;
|
|
|
|
if (!audio) return;
|
|
|
|
while (i < howMany) {
|
|
currSound = audio[i++];
|
|
// this covers case where we loaded an unplayable file type
|
|
if (currSound.error) return;
|
|
if (currSound.currentTime === 0 || currSound.currentTime === currSound.duration) {
|
|
currSound.currentTime = 0;
|
|
currSound.loop = !!loop;
|
|
i = howMany;
|
|
return currSound.play();
|
|
}
|
|
}
|
|
};
|
|
|
|
SoundEffectManager.prototype.play = function (soundName, loop) {
|
|
if (this.support) {
|
|
this._playWebAudio(soundName, loop);
|
|
} else {
|
|
return this._playWavAudio(soundName, loop);
|
|
}
|
|
};
|
|
|
|
SoundEffectManager.prototype.stop = function (soundName) {
|
|
if (this.support) {
|
|
// TODO: this
|
|
} else {
|
|
var soundArray = this.sounds[soundName],
|
|
howMany = soundArray && soundArray.length || 0,
|
|
i = 0,
|
|
currSound;
|
|
|
|
while (i < howMany) {
|
|
currSound = soundArray[i++];
|
|
currSound.pause();
|
|
currSound.currentTime = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
// attach to window or export with commonJS
|
|
if (typeof module !== "undefined") {
|
|
module.exports = SoundEffectManager;
|
|
} else if (typeof root.define === "function" && define.amd) {
|
|
root.define(SoundEffectManager);
|
|
} else {
|
|
root.SoundEffectManager = SoundEffectManager;
|
|
}
|
|
|
|
})();
|
|
}, "strictmodel": function(exports, require, module) {// (c) 2013 Henrik Joreteg
|
|
// MIT Licensed
|
|
// For all details and documentation:
|
|
// https://github.com/HenrikJoreteg/StrictModel
|
|
(function () {
|
|
'use strict';
|
|
|
|
// Initial setup
|
|
// -------------
|
|
|
|
// Establish the root object, `window` in the browser, or `global` on the server.
|
|
var root = this;
|
|
|
|
// The top-level namespace. All public Backbone classes and modules will
|
|
// be attached to this. Exported for both CommonJS and the browser.
|
|
var Strict = typeof exports !== 'undefined' ? exports : root.Strict = {},
|
|
toString = Object.prototype.toString,
|
|
slice = Array.prototype.slice;
|
|
|
|
// Current version of the library. Keep in sync with `package.json`.
|
|
Strict.VERSION = '0.0.1';
|
|
|
|
// Require Underscore, if we're on the server, and it's not already present.
|
|
var _ = root._;
|
|
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
|
|
|
|
// Require Backbone, if we're on the server, and it's not already present.
|
|
var Backbone = root.Backbone;
|
|
if (!Backbone && (typeof require !== 'undefined')) Backbone = require('backbone');
|
|
|
|
// Backbone Collection compatibility fix:
|
|
// In backbone, when you add an already instantiated model to a collection
|
|
// the collection checks to see if what you're adding is already a model
|
|
// the problem is, it does this witn an instanceof check. We're wanting to
|
|
// use completely different models so the instanceof will fail even if they
|
|
// are "real" models. So we work around this by overwriting this method from
|
|
// backbone 1.0.0. The only difference is it compares against our Strict.Model
|
|
// instead of backbone's.
|
|
Backbone.Collection.prototype._prepareModel = function (attrs, options) {
|
|
if (attrs instanceof Strict.Model) {
|
|
if (!attrs.collection) attrs.collection = this;
|
|
return attrs;
|
|
}
|
|
options || (options = {});
|
|
options.collection = this;
|
|
var model = new this.model(attrs, options);
|
|
if (!model._validate(attrs, options)) {
|
|
this.trigger('invalid', this, attrs, options);
|
|
return false;
|
|
}
|
|
return model;
|
|
};
|
|
|
|
// Helpers
|
|
// -------
|
|
|
|
// Shared empty constructor function to aid in prototype-chain creation.
|
|
var Constructor = function () {};
|
|
|
|
// Helper function to correctly set up the prototype chain, for subclasses.
|
|
// Similar to `goog.inherits`, but uses a hash of prototype properties and
|
|
// class properties to be extended.
|
|
var inherits = function (parent, protoProps, staticProps) {
|
|
var child;
|
|
|
|
// The constructor function for the new subclass is either defined by you
|
|
// (the "constructor" property in your `extend` definition), or defaulted
|
|
// by us to simply call the parent's constructor.
|
|
if (protoProps && protoProps.hasOwnProperty('constructor')) {
|
|
child = protoProps.constructor;
|
|
} else {
|
|
child = function () { return parent.apply(this, arguments); };
|
|
}
|
|
|
|
// Inherit class (static) properties from parent.
|
|
_.extend(child, parent);
|
|
|
|
// Set the prototype chain to inherit from `parent`, without calling
|
|
// `parent`'s constructor function.
|
|
Constructor.prototype = parent.prototype;
|
|
child.prototype = new Constructor();
|
|
|
|
// Add prototype properties (instance properties) to the subclass,
|
|
// if supplied.
|
|
if (protoProps) _.extend(child.prototype, protoProps);
|
|
|
|
// Add static properties to the constructor function, if supplied.
|
|
if (staticProps) _.extend(child, staticProps);
|
|
|
|
// Correctly set child's `prototype.constructor`.
|
|
child.prototype.constructor = child;
|
|
|
|
// Set a convenience property in case the parent's prototype is needed later.
|
|
child.__super__ = parent.prototype;
|
|
|
|
return child;
|
|
};
|
|
|
|
var extend = function (protoProps, classProps) {
|
|
var child = inherits(this, protoProps, classProps);
|
|
child.extend = this.extend;
|
|
return child;
|
|
};
|
|
|
|
// Mixins
|
|
// ------
|
|
|
|
// Sugar for defining properties a la ES5.
|
|
var Mixins = Strict.Mixins = {
|
|
// shortcut for Object.defineProperty
|
|
define: function (name, def) {
|
|
Object.defineProperty(this, name, def);
|
|
},
|
|
|
|
defineGetter: function (name, handler) {
|
|
this.define(name, {
|
|
get: handler.bind(this)
|
|
});
|
|
},
|
|
|
|
defineSetter: function (name, handler) {
|
|
this.define(name, {
|
|
set: handler.bind(this)
|
|
});
|
|
}
|
|
};
|
|
|
|
// Strict.Registry
|
|
// ---------------
|
|
|
|
// Internal storage for models, seperate namespace
|
|
// storage from default to prevent collision of matching
|
|
// model type+id and namespace name
|
|
|
|
var Registry = Strict.Registry = function () {
|
|
this._cache = {};
|
|
this._namespaces = {};
|
|
};
|
|
|
|
// Attach all inheritable methods to the Registry prototype.
|
|
_.extend(Registry.prototype, {
|
|
// Get the general or namespaced internal cache
|
|
_getCache: function (ns) {
|
|
if (ns) {
|
|
this._namespaces[ns] || (this._namespaces[ns] = {});
|
|
return this._namespaces[ns];
|
|
}
|
|
return this._cache;
|
|
},
|
|
|
|
// Find the cached model
|
|
lookup: function (type, id, ns) {
|
|
var cache = this._getCache(ns);
|
|
return cache && cache[type + id];
|
|
},
|
|
|
|
// Add a model to the cache if it has not already been set
|
|
store: function (model) {
|
|
var cache = this._getCache(model._namespace),
|
|
key = model.type + model.id;
|
|
// Prevent overriding a previously stored model
|
|
cache[key] = cache[key] || model;
|
|
return this;
|
|
},
|
|
|
|
// Remove a stored model from the cache, return `true` if removed
|
|
remove: function (type, id, ns) {
|
|
var cache = this._getCache(ns);
|
|
if (this.lookup.apply(this, arguments)) {
|
|
delete cache[type + id];
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
// Reset internal cache
|
|
clear: function () {
|
|
this._cache = {};
|
|
this._namespaces = {};
|
|
}
|
|
});
|
|
|
|
// Create the default Strict.registry.
|
|
Strict.registry = new Registry();
|
|
|
|
// Strict.Model
|
|
// ------------
|
|
|
|
var Model = Strict.Model = function (attrs, options) {
|
|
attrs = attrs || {};
|
|
options = options || {};
|
|
|
|
var modelFound,
|
|
opts = _.defaults(options || {}, {
|
|
seal: true
|
|
});
|
|
|
|
this._namespace = opts.namespace;
|
|
this._initted = false;
|
|
this._deps = {};
|
|
this._initProperties();
|
|
this._initCollections();
|
|
this._cache = {};
|
|
this._verifyRequired();
|
|
this.set(attrs, {silent: true});
|
|
this.init.apply(this, arguments);
|
|
if (attrs.id) Strict.registry.store(this);
|
|
this._previous = _.clone(this.attributes); // Should this be set right away?
|
|
this._initted = true;
|
|
};
|
|
|
|
// Attach all inheritable methods to the Model prototype.
|
|
_.extend(Model.prototype, Backbone.Events, Mixins, {
|
|
idAttribute: 'id',
|
|
idDefinition: {
|
|
type: 'number',
|
|
setOnce: true
|
|
},
|
|
|
|
// stubbed out to be overwritten
|
|
init: function () {
|
|
return this;
|
|
},
|
|
|
|
// Remove model from the registry and unbind events
|
|
remove: function () {
|
|
if (this.id) {
|
|
Strict.registry.remove(this.type, this.id, this._namespace);
|
|
}
|
|
this.trigger('remove', this);
|
|
this.off();
|
|
return this;
|
|
},
|
|
|
|
set: function (key, value, options) {
|
|
var self = this,
|
|
changing = self._changing,
|
|
opts,
|
|
changes = [],
|
|
newType,
|
|
interpretedType,
|
|
newVal,
|
|
def,
|
|
attr,
|
|
attrs,
|
|
val;
|
|
|
|
self._changing = true;
|
|
|
|
// Handle both `"key", value` and `{key: value}` -style arguments.
|
|
if (_.isObject(key) || key === null) {
|
|
attrs = key;
|
|
options = value;
|
|
} else {
|
|
attrs = {};
|
|
attrs[key] = value;
|
|
}
|
|
|
|
opts = options || {};
|
|
|
|
// For each `set` attribute...
|
|
for (attr in attrs) {
|
|
val = attrs[attr];
|
|
newType = typeof val;
|
|
newVal = val;
|
|
|
|
def = this.definition[attr] || {};
|
|
|
|
// check type if we have one
|
|
if (def.type === 'date') {
|
|
if (!_.isDate(val)) {
|
|
try {
|
|
newVal = (new Date(parseInt(val, 10))).valueOf();
|
|
newType = 'date';
|
|
} catch (e) {
|
|
newType = typeof val;
|
|
}
|
|
} else {
|
|
newType = 'date';
|
|
newVal = val.valueOf();
|
|
}
|
|
} else if (def.type === 'array') {
|
|
newType = _.isArray(val) ? 'array' : typeof val;
|
|
} else if (def.type === 'object') {
|
|
// we have to have a way of supporting "missing" objects.
|
|
// Null is an object, but setting a value to undefined
|
|
// should work too, IMO. We just override it, in that case.
|
|
if (typeof val !== 'object' && _.isUndefined(val)) {
|
|
newVal = null;
|
|
newType = 'object';
|
|
}
|
|
}
|
|
|
|
// If we have a defined type and the new type doesn't match, throw error.
|
|
// Unless it's not required and the value is undefined.
|
|
if (def.type && def.type !== newType && (!def.required && !_.isUndefined(val))) {
|
|
throw new TypeError('Property \'' + attr + '\' must be of type ' + def.type + '. Tried to set ' + val);
|
|
}
|
|
|
|
// if trying to set id after it's already been set
|
|
// reject that
|
|
if (def.setOnce && def.value !== undefined && !_.isEqual(def.value, newVal)) {
|
|
throw new TypeError('Property \'' + key + '\' can only be set once.');
|
|
}
|
|
|
|
// only change if different
|
|
if (!_.isEqual(def.value, newVal)) {
|
|
self._previous && (self._previous[attr] = def.value);
|
|
def.value = newVal;
|
|
changes.push(attr);
|
|
}
|
|
}
|
|
|
|
_.each(changes, function (key) {
|
|
if (!opts.silent) {
|
|
self.trigger('change:' + key, self, self[key]);
|
|
}
|
|
// TODO: ensure that all deps are not undefined before triggering a change event
|
|
(self._deps[key] || []).forEach(function (derTrigger) {
|
|
// blow away our cache
|
|
delete self._cache[derTrigger];
|
|
if (!opts.silent) self.trigger('change:' + derTrigger, self, self.derived[derTrigger]);
|
|
});
|
|
});
|
|
|
|
// fire general change events
|
|
if (changes.length) {
|
|
if (!opts.silent) self.trigger('change', self);
|
|
}
|
|
},
|
|
|
|
get: function (attr) {
|
|
return this[attr];
|
|
},
|
|
|
|
// convenience methods for manipulating array properties
|
|
addListVal: function (prop, value, prepend) {
|
|
var list = _.clone(this[prop]) || [];
|
|
if (!_(list).contains(value)) {
|
|
list[prepend ? 'unshift' : 'push'](value);
|
|
this[prop] = list;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
previous: function (attr) {
|
|
return attr ? this._previous[attr] : _.clone(this._previous);
|
|
},
|
|
|
|
removeListVal: function (prop, value) {
|
|
var list = _.clone(this[prop]) || [];
|
|
if (_(list).contains(value)) {
|
|
this[prop] = _(list).without(value);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
hasListVal: function (prop, value) {
|
|
return _.contains(this[prop] || [], value);
|
|
},
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
_initCollections: function () {
|
|
var coll;
|
|
if (!this.collections) return;
|
|
for (coll in this.collections) {
|
|
this[coll] = new this.collections[coll]();
|
|
this[coll].parent = this;
|
|
}
|
|
},
|
|
|
|
// Check that all required attributes are present
|
|
// TODO: should this throw an error or return boolean?
|
|
_verifyRequired: function () {
|
|
var attrs = this.attributes;
|
|
for (var def in this.definition) {
|
|
if (this.definition[def].required && typeof attrs[def] === 'undefined') {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
_initProperties: function () {
|
|
var self = this,
|
|
definition = this.definition = {},
|
|
val,
|
|
prop,
|
|
item,
|
|
type,
|
|
filler;
|
|
|
|
this.cid = _.uniqueId('model');
|
|
|
|
function addToDef(name, val, isSession) {
|
|
var def = definition[name] = {};
|
|
if (_.isString(val)) {
|
|
// grab our type if all we've got is a string
|
|
type = self._ensureValidType(val);
|
|
if (type) def.type = type;
|
|
} else {
|
|
type = self._ensureValidType(val[0] || val.type);
|
|
if (type) def.type = type;
|
|
if (val[1] || val.required) def.required = true;
|
|
// set default if defined
|
|
def.value = !_.isUndefined(val[2]) ? val[2] : val.default;
|
|
if (isSession) def.session = true;
|
|
if (val.setOnce) def.setOnce = true;
|
|
}
|
|
}
|
|
|
|
// loop through given properties
|
|
for (item in this.props) {
|
|
addToDef(item, this.props[item]);
|
|
}
|
|
// loop through session props
|
|
for (prop in this.session) {
|
|
addToDef(prop, this.session[prop], true);
|
|
}
|
|
|
|
// always add "id" as a definition or make sure it's 'setOnce'
|
|
if (definition.id) {
|
|
definition[this.idAttribute].setOnce = true;
|
|
} else {
|
|
addToDef(this.idAttribute, this.idDefinition);
|
|
}
|
|
|
|
// register derived properties as part of the definition
|
|
this._registerDerived();
|
|
this._createGettersSetters();
|
|
|
|
// freeze attributes used to define object
|
|
if (this.session) Object.freeze(this.session);
|
|
//if (this.derived) Object.freeze(this.derived);
|
|
if (this.props) Object.freeze(this.props);
|
|
},
|
|
|
|
// just makes friendlier errors when trying to define a new model
|
|
// only used when setting up original property definitions
|
|
_ensureValidType: function (type) {
|
|
return _.contains(['string', 'number', 'boolean', 'array', 'object', 'date'], type) ? type : undefined;
|
|
},
|
|
|
|
_validate: function () {
|
|
return true;
|
|
},
|
|
|
|
_createGettersSetters: function () {
|
|
var item, def, desc, self = this;
|
|
|
|
// create getters/setters based on definitions
|
|
for (item in this.definition) {
|
|
def = this.definition[item];
|
|
desc = {};
|
|
// create our setter
|
|
desc.set = function (def, item) {
|
|
return function (val, options) {
|
|
self.set(item, val);
|
|
};
|
|
}(def, item);
|
|
// create our getter
|
|
desc.get = function (def, attributes) {
|
|
return function (val) {
|
|
if (typeof def.value !== 'undefined') {
|
|
if (def.type === 'date') {
|
|
return new Date(def.value);
|
|
}
|
|
return def.value;
|
|
}
|
|
return;
|
|
};
|
|
}(def);
|
|
|
|
// define our property
|
|
this.define(item, desc);
|
|
}
|
|
|
|
this.defineGetter('attributes', function () {
|
|
var res = {};
|
|
for (var item in this.definition) res[item] = this[item];
|
|
return res;
|
|
});
|
|
|
|
this.defineGetter('keys', function () {
|
|
return Object.keys(this.attributes);
|
|
});
|
|
|
|
this.defineGetter('json', function () {
|
|
return JSON.stringify(this._getAttributes(false, true));
|
|
});
|
|
|
|
this.defineGetter('derived', function () {
|
|
var res = {};
|
|
for (var item in this._derived) res[item] = this._derived[item].fn.apply(this);
|
|
return res;
|
|
});
|
|
|
|
this.defineGetter('toTemplate', function () {
|
|
return _.extend(this._getAttributes(true), this.derived);
|
|
});
|
|
},
|
|
|
|
_getAttributes: function (includeSession, raw) {
|
|
var res = {};
|
|
for (var item in this.definition) {
|
|
if (!includeSession) {
|
|
if (!this.definition[item].session) {
|
|
res[item] = (raw) ? this.definition[item].value : this[item];
|
|
}
|
|
} else {
|
|
res[item] = (raw) ? this.definition[item].value : this[item];
|
|
}
|
|
}
|
|
return res;
|
|
},
|
|
|
|
// stores an object of arrays that specifies the derivedProperties
|
|
// that depend on each attribute
|
|
_registerDerived: function () {
|
|
var self = this, depList;
|
|
if (!this.derived) return;
|
|
this._derived = this.derived;
|
|
for (var key in this.derived) {
|
|
depList = this.derived[key].deps || [];
|
|
_.each(depList, function (dep) {
|
|
self._deps[dep] = _(self._deps[dep] || []).union([key]);
|
|
});
|
|
|
|
// defined a top-level getter for derived keys
|
|
this.define(key, {
|
|
get: _.bind(function (key) {
|
|
// is this a derived property we should cache?
|
|
if (this._derived[key].cache) {
|
|
// do we have it?
|
|
if (this._cache.hasOwnProperty(key)) {
|
|
return this._cache[key];
|
|
} else {
|
|
return this._cache[key] = this._derived[key].fn.apply(this);
|
|
}
|
|
} else {
|
|
return this._derived[key].fn.apply(this);
|
|
}
|
|
}, this, key),
|
|
set: _.bind(function (key) {
|
|
var deps = this._derived[key].deps,
|
|
msg = '"' + key + '" is a derived property, you can\'t set it directly.';
|
|
if (deps && deps.length) {
|
|
throw new TypeError(msg + ' It is dependent on "' + deps.join('" and "') + '".');
|
|
} else {
|
|
throw new TypeError(msg);
|
|
}
|
|
}, this, key)
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
// Set up inheritance for the model
|
|
Strict.Model.extend = extend;
|
|
|
|
// Overwrite Backbone.Model so that collections don't need to be modified in Backbone core
|
|
Backbone.Model = Strict.Model;
|
|
|
|
}).call(this);
|
|
}, "strictview": function(exports, require, module) {var Backbone = require('backbone'),
|
|
_ = require('underscore'),
|
|
templates = require('templates');
|
|
|
|
|
|
// the base view we use to build all our other views
|
|
module.exports = Backbone.View.extend({
|
|
// ###handleBindings
|
|
// This makes it simple to bind model attributes to the view.
|
|
// To use it, add a `classBindings` and/or a `contentBindings` attribute
|
|
// to your view and call `this.handleBindings()` at the end of your view's
|
|
// `render` function. It's also used by `basicRender` which lets you do
|
|
// a complete attribute-bound views with just this:
|
|
//
|
|
// var ProfileView = BaseView.extend({
|
|
// template: 'profile',
|
|
// contentBindings: {
|
|
// 'name': '.name'
|
|
// },
|
|
// classBindings: {
|
|
// 'active': ''
|
|
// },
|
|
// render: function () {
|
|
// this.basicRender();
|
|
// return this;
|
|
// }
|
|
// });
|
|
handleBindings: function () {
|
|
var self = this;
|
|
if (this.contentBindings) {
|
|
_.each(this.contentBindings, function (selector, key) {
|
|
var func = function () {
|
|
var el = (selector.length > 0) ? self.$(selector) : $(self.el);
|
|
el.html(self.model[key]);
|
|
};
|
|
self.listenTo(self.model, 'change:' + key, func);
|
|
func();
|
|
});
|
|
}
|
|
if (this.imageBindings) {
|
|
_.each(this.imageBindings, function (selector, key) {
|
|
var func = function () {
|
|
var el = (selector.length > 0) ? self.$(selector) : $(self.el);
|
|
el.attr('src', self.model[key]);
|
|
};
|
|
self.listenTo(self.model, 'change:' + key, func);
|
|
func();
|
|
});
|
|
}
|
|
if (this.hrefBindings) {
|
|
_.each(this.hrefBindings, function (selector, key) {
|
|
var func = function () {
|
|
var el = (selector.length > 0) ? self.$(selector) : $(self.el);
|
|
el.attr('href', self.model[key]);
|
|
};
|
|
self.listenTo(self.model, 'change:' + key, func);
|
|
func();
|
|
});
|
|
}
|
|
if (this.classBindings) {
|
|
_.each(this.classBindings, function (selector, key) {
|
|
var func = function () {
|
|
var newValue = self.model[key],
|
|
prevHash = self.model.previous(),
|
|
prev = _.isFunction(prevHash) ? prevHash(key) : prevHash[key],
|
|
el = (selector.length > 0) ? self.$(selector) : $(self.el);
|
|
if (_.isBoolean(newValue)) {
|
|
if (newValue) {
|
|
el.addClass(key);
|
|
} else {
|
|
el.removeClass(key);
|
|
}
|
|
} else {
|
|
if (prev) el.removeClass(prev);
|
|
el.addClass(newValue);
|
|
}
|
|
};
|
|
self.listenTo(self.model, 'change:' + key, func);
|
|
func();
|
|
});
|
|
}
|
|
if (this.inputBindings) {
|
|
_.each(this.inputBindings, function (selector, key) {
|
|
var func = function () {
|
|
var el = (selector.length > 0) ? self.$(selector) : $(self.el);
|
|
el.val(self.model[key]);
|
|
};
|
|
self.listenTo(self.model, 'change:' + key, func);
|
|
func();
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// ###desist
|
|
// This is method we used to remove/unbind/destroy the view.
|
|
// By default we fade it out this seemed like a reasonable default for realtime apps.
|
|
// So things to just magically disappear and to give some visual indication that
|
|
// it's going away. You can also pass an options hash `{quick: true}` to remove immediately.
|
|
desist: function (opts) {
|
|
opts || (opts = {});
|
|
_.defaults(opts, {
|
|
quick: false,
|
|
animate: true,
|
|
speed: 300,
|
|
animationProps: {
|
|
height: 0,
|
|
opacity: 0
|
|
}
|
|
});
|
|
var el = $(this.el),
|
|
kill = _.bind(this.remove, this);
|
|
if (this.interval) {
|
|
clearInterval(this.interval);
|
|
delete this.interval;
|
|
}
|
|
if (opts.quick) {
|
|
kill();
|
|
} else if (opts.animate) {
|
|
el.animate(opts.animationProps, {
|
|
speed: opts.speed,
|
|
complete: kill
|
|
});
|
|
} else {
|
|
setTimeout(kill, opts.speed);
|
|
}
|
|
},
|
|
|
|
// ###addReferences
|
|
// This is a shortcut for adding reference to specific elements within your view for
|
|
// access later. This is avoids excessive DOM queries and gives makes it easier to update
|
|
// your view if your template changes. You could argue whether this is worth doing or not,
|
|
// but I like it.
|
|
// In your `render` method. Use it like so:
|
|
//
|
|
// render: function () {
|
|
// this.basicRender();
|
|
// this.addReferences({
|
|
// pages: '#pages',
|
|
// chat: '#teamChat',
|
|
// nav: 'nav#views ul',
|
|
// me: '#me',
|
|
// cheatSheet: '#cheatSheet',
|
|
// omniBox: '#awesomeSauce'
|
|
// });
|
|
// }
|
|
//
|
|
// Then later you can access elements by reference like so: `this.$pages`, or `this.$chat`.
|
|
addReferences: function (hash) {
|
|
for (var item in hash) {
|
|
this['$' + item] = $(hash[item], this.el);
|
|
}
|
|
},
|
|
|
|
// ###basicRender
|
|
// All the usual stuff when I render a view. It assumes that the view has a `template` property
|
|
// that is the name of the ICanHaz template. You can also specify the template name by passing
|
|
// it an options hash like so: `{templateKey: 'profile'}`.
|
|
basicRender: function (opts) {
|
|
var newEl;
|
|
opts || (opts = {});
|
|
_.defaults(opts, {
|
|
templateFunc: (typeof this.template === 'string') ? templates[opts.templateKey] : this.template,
|
|
context: false
|
|
});
|
|
newEl = $(opts.templateFunc(opts.contex));
|
|
$(this.el).replaceWith(newEl);
|
|
this.setElement(newEl);
|
|
this.handleBindings();
|
|
this.delegateEvents();
|
|
},
|
|
|
|
// ###subViewRender
|
|
// This is handy for views within collections when you use `collectomatic`. Just like `basicRender` it assumes
|
|
// that the view either has a `template` property or that you pass it an options object with the name of the
|
|
// `templateKey` name of the ICanHaz template.
|
|
// Additionally, it handles appending or prepending the view to its parent container.
|
|
// It takes an options arg where you can optionally specify the `templateKey` and `placement` of the element.
|
|
// If your collections is stacked newest first, just use `{plaement: 'prepend'}`.
|
|
subViewRender: function (opts) {
|
|
opts || (opts = {});
|
|
_.defaults(opts, {
|
|
placement: 'append',
|
|
templateFunc: (typeof this.template === 'string') ? templates[opts.templateKey] : this.template
|
|
});
|
|
var data = _.isFunction(this.model.toTemplate) ? this.model.toTemplate() : this.model.toTemplate,
|
|
newEl = $(opts.templateFunc(opts.context))[0];
|
|
if (!this.el.parentNode) {
|
|
$(this.containerEl)[opts.placement](newEl);
|
|
} else {
|
|
$(this.el).replaceWith(newEl);
|
|
}
|
|
this.setElement(newEl);
|
|
this.handleBindings();
|
|
},
|
|
|
|
// ### bindomatic
|
|
// Shortcut for listening and triggering
|
|
bindomatic: function (object, events, handler, opts) {
|
|
var bound = _.bind(handler, this);
|
|
this.listenTo(object, events, bound);
|
|
if (opts && opts.trigger || opts === true) bound();
|
|
},
|
|
|
|
// ###collectomatic
|
|
// Shorthand for rendering collections and their invividual views.
|
|
// Just pass it the collection, and the view to use for the items in the
|
|
// collection. (anything in the `options` arg just gets passed through to
|
|
// view. Again, props to @natevw for this.
|
|
collectomatic: function (collection, ViewClass, options, desistOptions) {
|
|
var views = {},
|
|
self = this,
|
|
refreshResetHandler;
|
|
function addView(model, collection, opts) {
|
|
var matches = self.matchesFilters ? self.matchesFilters(model) : true;
|
|
if (matches) {
|
|
views[model.cid] = new ViewClass(_({model: model}).extend(options));
|
|
views[model.cid].parent = self;
|
|
}
|
|
}
|
|
this.listenTo(collection, 'add', addView);
|
|
this.listenTo(collection, 'remove', function (model) {
|
|
if (views[model.cid]) {
|
|
views[model.cid].desist(desistOptions);
|
|
delete views[model.cid];
|
|
}
|
|
});
|
|
this.listenTo(collection, 'move', function () {
|
|
_(views).each(function (view) {
|
|
view.desist({quick: true});
|
|
});
|
|
views = {};
|
|
collection.each(addView);
|
|
});
|
|
refreshResetHandler = function (opts) {
|
|
_(views).each(function (view) {
|
|
view.desist({quick: true});
|
|
});
|
|
views = {};
|
|
collection.each(addView);
|
|
};
|
|
this.listenTo(collection, 'refresh reset sort', refreshResetHandler);
|
|
refreshResetHandler();
|
|
}
|
|
});
|
|
}, "templates": function(exports, require, module) {(function () {
|
|
var root = this, exports = {};
|
|
|
|
// The jade runtime:
|
|
var jade=function(exports){Array.isArray||(Array.isArray=function(arr){return"[object Array]"==Object.prototype.toString.call(arr)}),Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(key);return arr}),exports.merge=function merge(a,b){var ac=a["class"],bc=b["class"];if(ac||bc)ac=ac||[],bc=bc||[],Array.isArray(ac)||(ac=[ac]),Array.isArray(bc)||(bc=[bc]),ac=ac.filter(nulls),bc=bc.filter(nulls),a["class"]=ac.concat(bc).join(" ");for(var key in b)key!="class"&&(a[key]=b[key]);return a};function nulls(val){return val!=null}return exports.attrs=function attrs(obj,escaped){var buf=[],terse=obj.terse;delete obj.terse;var keys=Object.keys(obj),len=keys.length;if(len){buf.push("");for(var i=0;i<len;++i){var key=keys[i],val=obj[key];"boolean"==typeof val||null==val?val&&(terse?buf.push(key):buf.push(key+'="'+key+'"')):0==key.indexOf("data")&&"string"!=typeof val?buf.push(key+"='"+JSON.stringify(val)+"'"):"class"==key&&Array.isArray(val)?buf.push(key+'="'+exports.escape(val.join(" "))+'"'):escaped&&escaped[key]?buf.push(key+'="'+exports.escape(val)+'"'):buf.push(key+'="'+val+'"')}}return buf.join(" ")},exports.escape=function escape(html){return String(html).replace(/&(?!(\w+|\#\d+);)/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},exports.rethrow=function rethrow(err,filename,lineno){if(!filename)throw err;var context=3,str=require("fs").readFileSync(filename,"utf8"),lines=str.split("\n"),start=Math.max(lineno-context,0),end=Math.min(lines.length,lineno+context),context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" > ":" ")+curr+"| "+line}).join("\n");throw err.path=filename,err.message=(filename||"Jade")+":"+lineno+"\n"+context+"\n\n"+err.message,err},exports}({});
|
|
|
|
|
|
// create our folder objects
|
|
exports.dialogs = {};
|
|
exports.includes = {};
|
|
exports.pages = {};
|
|
|
|
// contactListItem.jade compiled template
|
|
exports.includes.contactListItem = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<li class="contact"><img' + jade.attrs({
|
|
src: contact.avatar,
|
|
"class": "avatar"
|
|
}, {
|
|
src: true
|
|
}) + '/><div class="name">' + jade.escape(null == (jade.interp = contact.displayName) ? "" : jade.interp) + '</div><div class="status">' + jade.escape(null == (jade.interp = contact.status) ? "" : jade.interp) + "</div></li>");
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
// contactListItemResource.jade compiled template
|
|
exports.includes.contactListItemResource = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<li><p class="jid">' + jade.escape(null == (jade.interp = resource.jid) ? "" : jade.interp) + '</p><p class="status">' + jade.escape(null == (jade.interp = resource.status) ? "" : jade.interp) + "</p></li>");
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
// message.jade compiled template
|
|
exports.includes.message = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<li><div class="message"><span class="timestamp">' + jade.escape(null == (jade.interp = message.created) ? "" : jade.interp) + '</span><p class="body">' + jade.escape(null == (jade.interp = message.body) ? "" : jade.interp) + "</p></div></li>");
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
// layout.jade compiled template
|
|
exports.layout = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<div class="wrap"><header></header><div id="me"><img class="avatar"/><p class="status"></p></div><section id="pages"></section><footer></footer></div>');
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
// info.jade compiled template
|
|
exports.pages.info = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<section class="page info"><nav id="contactList"></nav><h1 class="name"></h1><ul id="conversation"></ul></section>');
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
// main.jade compiled template
|
|
exports.pages.main = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<section class="page main"><nav id="contactList"></nav><div id="log"><h2>Event Log</h2></div></section>');
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
// wrapper.jade compiled template
|
|
exports.pages.wrapper = function anonymous(locals) {
|
|
var buf = [];
|
|
with (locals || {}) {
|
|
buf.push('<div class="page"></div>');
|
|
}
|
|
return buf.join("");
|
|
};
|
|
|
|
|
|
// attach to window or export with commonJS
|
|
if (typeof module !== "undefined") {
|
|
module.exports = exports;
|
|
} else if (typeof define === "function" && define.amd) {
|
|
define(exports);
|
|
} else {
|
|
root.templatizer = exports;
|
|
}
|
|
|
|
})();}, "underscore": function(exports, require, module) {// Underscore.js 1.4.4
|
|
// http://underscorejs.org
|
|
// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
|
// Underscore may be freely distributed under the MIT license.
|
|
|
|
(function() {
|
|
|
|
// Baseline setup
|
|
// --------------
|
|
|
|
// Establish the root object, `window` in the browser, or `global` on the server.
|
|
var root = this;
|
|
|
|
// Save the previous value of the `_` variable.
|
|
var previousUnderscore = root._;
|
|
|
|
// Establish the object that gets returned to break out of a loop iteration.
|
|
var breaker = {};
|
|
|
|
// Save bytes in the minified (but not gzipped) version:
|
|
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
|
|
|
// Create quick reference variables for speed access to core prototypes.
|
|
var push = ArrayProto.push,
|
|
slice = ArrayProto.slice,
|
|
concat = ArrayProto.concat,
|
|
toString = ObjProto.toString,
|
|
hasOwnProperty = ObjProto.hasOwnProperty;
|
|
|
|
// All **ECMAScript 5** native function implementations that we hope to use
|
|
// are declared here.
|
|
var
|
|
nativeForEach = ArrayProto.forEach,
|
|
nativeMap = ArrayProto.map,
|
|
nativeReduce = ArrayProto.reduce,
|
|
nativeReduceRight = ArrayProto.reduceRight,
|
|
nativeFilter = ArrayProto.filter,
|
|
nativeEvery = ArrayProto.every,
|
|
nativeSome = ArrayProto.some,
|
|
nativeIndexOf = ArrayProto.indexOf,
|
|
nativeLastIndexOf = ArrayProto.lastIndexOf,
|
|
nativeIsArray = Array.isArray,
|
|
nativeKeys = Object.keys,
|
|
nativeBind = FuncProto.bind;
|
|
|
|
// Create a safe reference to the Underscore object for use below.
|
|
var _ = function(obj) {
|
|
if (obj instanceof _) return obj;
|
|
if (!(this instanceof _)) return new _(obj);
|
|
this._wrapped = obj;
|
|
};
|
|
|
|
// Export the Underscore object for **Node.js**, with
|
|
// backwards-compatibility for the old `require()` API. If we're in
|
|
// the browser, add `_` as a global object via a string identifier,
|
|
// for Closure Compiler "advanced" mode.
|
|
if (typeof exports !== 'undefined') {
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
exports = module.exports = _;
|
|
}
|
|
exports._ = _;
|
|
} else {
|
|
root._ = _;
|
|
}
|
|
|
|
// Current version.
|
|
_.VERSION = '1.4.4';
|
|
|
|
// Collection Functions
|
|
// --------------------
|
|
|
|
// The cornerstone, an `each` implementation, aka `forEach`.
|
|
// Handles objects with the built-in `forEach`, arrays, and raw objects.
|
|
// Delegates to **ECMAScript 5**'s native `forEach` if available.
|
|
var each = _.each = _.forEach = function(obj, iterator, context) {
|
|
if (obj == null) return;
|
|
if (nativeForEach && obj.forEach === nativeForEach) {
|
|
obj.forEach(iterator, context);
|
|
} else if (obj.length === +obj.length) {
|
|
for (var i = 0, l = obj.length; i < l; i++) {
|
|
if (iterator.call(context, obj[i], i, obj) === breaker) return;
|
|
}
|
|
} else {
|
|
for (var key in obj) {
|
|
if (_.has(obj, key)) {
|
|
if (iterator.call(context, obj[key], key, obj) === breaker) return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Return the results of applying the iterator to each element.
|
|
// Delegates to **ECMAScript 5**'s native `map` if available.
|
|
_.map = _.collect = function(obj, iterator, context) {
|
|
var results = [];
|
|
if (obj == null) return results;
|
|
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
|
each(obj, function(value, index, list) {
|
|
results[results.length] = iterator.call(context, value, index, list);
|
|
});
|
|
return results;
|
|
};
|
|
|
|
var reduceError = 'Reduce of empty array with no initial value';
|
|
|
|
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
|
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
|
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
|
var initial = arguments.length > 2;
|
|
if (obj == null) obj = [];
|
|
if (nativeReduce && obj.reduce === nativeReduce) {
|
|
if (context) iterator = _.bind(iterator, context);
|
|
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
|
}
|
|
each(obj, function(value, index, list) {
|
|
if (!initial) {
|
|
memo = value;
|
|
initial = true;
|
|
} else {
|
|
memo = iterator.call(context, memo, value, index, list);
|
|
}
|
|
});
|
|
if (!initial) throw new TypeError(reduceError);
|
|
return memo;
|
|
};
|
|
|
|
// The right-associative version of reduce, also known as `foldr`.
|
|
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
|
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
|
var initial = arguments.length > 2;
|
|
if (obj == null) obj = [];
|
|
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
|
if (context) iterator = _.bind(iterator, context);
|
|
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
|
}
|
|
var length = obj.length;
|
|
if (length !== +length) {
|
|
var keys = _.keys(obj);
|
|
length = keys.length;
|
|
}
|
|
each(obj, function(value, index, list) {
|
|
index = keys ? keys[--length] : --length;
|
|
if (!initial) {
|
|
memo = obj[index];
|
|
initial = true;
|
|
} else {
|
|
memo = iterator.call(context, memo, obj[index], index, list);
|
|
}
|
|
});
|
|
if (!initial) throw new TypeError(reduceError);
|
|
return memo;
|
|
};
|
|
|
|
// Return the first value which passes a truth test. Aliased as `detect`.
|
|
_.find = _.detect = function(obj, iterator, context) {
|
|
var result;
|
|
any(obj, function(value, index, list) {
|
|
if (iterator.call(context, value, index, list)) {
|
|
result = value;
|
|
return true;
|
|
}
|
|
});
|
|
return result;
|
|
};
|
|
|
|
// Return all the elements that pass a truth test.
|
|
// Delegates to **ECMAScript 5**'s native `filter` if available.
|
|
// Aliased as `select`.
|
|
_.filter = _.select = function(obj, iterator, context) {
|
|
var results = [];
|
|
if (obj == null) return results;
|
|
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
|
|
each(obj, function(value, index, list) {
|
|
if (iterator.call(context, value, index, list)) results[results.length] = value;
|
|
});
|
|
return results;
|
|
};
|
|
|
|
// Return all the elements for which a truth test fails.
|
|
_.reject = function(obj, iterator, context) {
|
|
return _.filter(obj, function(value, index, list) {
|
|
return !iterator.call(context, value, index, list);
|
|
}, context);
|
|
};
|
|
|
|
// Determine whether all of the elements match a truth test.
|
|
// Delegates to **ECMAScript 5**'s native `every` if available.
|
|
// Aliased as `all`.
|
|
_.every = _.all = function(obj, iterator, context) {
|
|
iterator || (iterator = _.identity);
|
|
var result = true;
|
|
if (obj == null) return result;
|
|
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
|
|
each(obj, function(value, index, list) {
|
|
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
|
|
});
|
|
return !!result;
|
|
};
|
|
|
|
// Determine if at least one element in the object matches a truth test.
|
|
// Delegates to **ECMAScript 5**'s native `some` if available.
|
|
// Aliased as `any`.
|
|
var any = _.some = _.any = function(obj, iterator, context) {
|
|
iterator || (iterator = _.identity);
|
|
var result = false;
|
|
if (obj == null) return result;
|
|
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
|
each(obj, function(value, index, list) {
|
|
if (result || (result = iterator.call(context, value, index, list))) return breaker;
|
|
});
|
|
return !!result;
|
|
};
|
|
|
|
// Determine if the array or object contains a given value (using `===`).
|
|
// Aliased as `include`.
|
|
_.contains = _.include = function(obj, target) {
|
|
if (obj == null) return false;
|
|
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
|
return any(obj, function(value) {
|
|
return value === target;
|
|
});
|
|
};
|
|
|
|
// Invoke a method (with arguments) on every item in a collection.
|
|
_.invoke = function(obj, method) {
|
|
var args = slice.call(arguments, 2);
|
|
var isFunc = _.isFunction(method);
|
|
return _.map(obj, function(value) {
|
|
return (isFunc ? method : value[method]).apply(value, args);
|
|
});
|
|
};
|
|
|
|
// Convenience version of a common use case of `map`: fetching a property.
|
|
_.pluck = function(obj, key) {
|
|
return _.map(obj, function(value){ return value[key]; });
|
|
};
|
|
|
|
// Convenience version of a common use case of `filter`: selecting only objects
|
|
// containing specific `key:value` pairs.
|
|
_.where = function(obj, attrs, first) {
|
|
if (_.isEmpty(attrs)) return first ? null : [];
|
|
return _[first ? 'find' : 'filter'](obj, function(value) {
|
|
for (var key in attrs) {
|
|
if (attrs[key] !== value[key]) return false;
|
|
}
|
|
return true;
|
|
});
|
|
};
|
|
|
|
// Convenience version of a common use case of `find`: getting the first object
|
|
// containing specific `key:value` pairs.
|
|
_.findWhere = function(obj, attrs) {
|
|
return _.where(obj, attrs, true);
|
|
};
|
|
|
|
// Return the maximum element or (element-based computation).
|
|
// Can't optimize arrays of integers longer than 65,535 elements.
|
|
// See: https://bugs.webkit.org/show_bug.cgi?id=80797
|
|
_.max = function(obj, iterator, context) {
|
|
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
|
return Math.max.apply(Math, obj);
|
|
}
|
|
if (!iterator && _.isEmpty(obj)) return -Infinity;
|
|
var result = {computed : -Infinity, value: -Infinity};
|
|
each(obj, function(value, index, list) {
|
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
|
computed >= result.computed && (result = {value : value, computed : computed});
|
|
});
|
|
return result.value;
|
|
};
|
|
|
|
// Return the minimum element (or element-based computation).
|
|
_.min = function(obj, iterator, context) {
|
|
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
|
|
return Math.min.apply(Math, obj);
|
|
}
|
|
if (!iterator && _.isEmpty(obj)) return Infinity;
|
|
var result = {computed : Infinity, value: Infinity};
|
|
each(obj, function(value, index, list) {
|
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
|
computed < result.computed && (result = {value : value, computed : computed});
|
|
});
|
|
return result.value;
|
|
};
|
|
|
|
// Shuffle an array.
|
|
_.shuffle = function(obj) {
|
|
var rand;
|
|
var index = 0;
|
|
var shuffled = [];
|
|
each(obj, function(value) {
|
|
rand = _.random(index++);
|
|
shuffled[index - 1] = shuffled[rand];
|
|
shuffled[rand] = value;
|
|
});
|
|
return shuffled;
|
|
};
|
|
|
|
// An internal function to generate lookup iterators.
|
|
var lookupIterator = function(value) {
|
|
return _.isFunction(value) ? value : function(obj){ return obj[value]; };
|
|
};
|
|
|
|
// Sort the object's values by a criterion produced by an iterator.
|
|
_.sortBy = function(obj, value, context) {
|
|
var iterator = lookupIterator(value);
|
|
return _.pluck(_.map(obj, function(value, index, list) {
|
|
return {
|
|
value : value,
|
|
index : index,
|
|
criteria : iterator.call(context, value, index, list)
|
|
};
|
|
}).sort(function(left, right) {
|
|
var a = left.criteria;
|
|
var b = right.criteria;
|
|
if (a !== b) {
|
|
if (a > b || a === void 0) return 1;
|
|
if (a < b || b === void 0) return -1;
|
|
}
|
|
return left.index < right.index ? -1 : 1;
|
|
}), 'value');
|
|
};
|
|
|
|
// An internal function used for aggregate "group by" operations.
|
|
var group = function(obj, value, context, behavior) {
|
|
var result = {};
|
|
var iterator = lookupIterator(value || _.identity);
|
|
each(obj, function(value, index) {
|
|
var key = iterator.call(context, value, index, obj);
|
|
behavior(result, key, value);
|
|
});
|
|
return result;
|
|
};
|
|
|
|
// Groups the object's values by a criterion. Pass either a string attribute
|
|
// to group by, or a function that returns the criterion.
|
|
_.groupBy = function(obj, value, context) {
|
|
return group(obj, value, context, function(result, key, value) {
|
|
(_.has(result, key) ? result[key] : (result[key] = [])).push(value);
|
|
});
|
|
};
|
|
|
|
// Counts instances of an object that group by a certain criterion. Pass
|
|
// either a string attribute to count by, or a function that returns the
|
|
// criterion.
|
|
_.countBy = function(obj, value, context) {
|
|
return group(obj, value, context, function(result, key) {
|
|
if (!_.has(result, key)) result[key] = 0;
|
|
result[key]++;
|
|
});
|
|
};
|
|
|
|
// Use a comparator function to figure out the smallest index at which
|
|
// an object should be inserted so as to maintain order. Uses binary search.
|
|
_.sortedIndex = function(array, obj, iterator, context) {
|
|
iterator = iterator == null ? _.identity : lookupIterator(iterator);
|
|
var value = iterator.call(context, obj);
|
|
var low = 0, high = array.length;
|
|
while (low < high) {
|
|
var mid = (low + high) >>> 1;
|
|
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
|
|
}
|
|
return low;
|
|
};
|
|
|
|
// Safely convert anything iterable into a real, live array.
|
|
_.toArray = function(obj) {
|
|
if (!obj) return [];
|
|
if (_.isArray(obj)) return slice.call(obj);
|
|
if (obj.length === +obj.length) return _.map(obj, _.identity);
|
|
return _.values(obj);
|
|
};
|
|
|
|
// Return the number of elements in an object.
|
|
_.size = function(obj) {
|
|
if (obj == null) return 0;
|
|
return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
|
|
};
|
|
|
|
// Array Functions
|
|
// ---------------
|
|
|
|
// Get the first element of an array. Passing **n** will return the first N
|
|
// values in the array. Aliased as `head` and `take`. The **guard** check
|
|
// allows it to work with `_.map`.
|
|
_.first = _.head = _.take = function(array, n, guard) {
|
|
if (array == null) return void 0;
|
|
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
|
|
};
|
|
|
|
// Returns everything but the last entry of the array. Especially useful on
|
|
// the arguments object. Passing **n** will return all the values in
|
|
// the array, excluding the last N. The **guard** check allows it to work with
|
|
// `_.map`.
|
|
_.initial = function(array, n, guard) {
|
|
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
|
|
};
|
|
|
|
// Get the last element of an array. Passing **n** will return the last N
|
|
// values in the array. The **guard** check allows it to work with `_.map`.
|
|
_.last = function(array, n, guard) {
|
|
if (array == null) return void 0;
|
|
if ((n != null) && !guard) {
|
|
return slice.call(array, Math.max(array.length - n, 0));
|
|
} else {
|
|
return array[array.length - 1];
|
|
}
|
|
};
|
|
|
|
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
|
|
// Especially useful on the arguments object. Passing an **n** will return
|
|
// the rest N values in the array. The **guard**
|
|
// check allows it to work with `_.map`.
|
|
_.rest = _.tail = _.drop = function(array, n, guard) {
|
|
return slice.call(array, (n == null) || guard ? 1 : n);
|
|
};
|
|
|
|
// Trim out all falsy values from an array.
|
|
_.compact = function(array) {
|
|
return _.filter(array, _.identity);
|
|
};
|
|
|
|
// Internal implementation of a recursive `flatten` function.
|
|
var flatten = function(input, shallow, output) {
|
|
each(input, function(value) {
|
|
if (_.isArray(value)) {
|
|
shallow ? push.apply(output, value) : flatten(value, shallow, output);
|
|
} else {
|
|
output.push(value);
|
|
}
|
|
});
|
|
return output;
|
|
};
|
|
|
|
// Return a completely flattened version of an array.
|
|
_.flatten = function(array, shallow) {
|
|
return flatten(array, shallow, []);
|
|
};
|
|
|
|
// Return a version of the array that does not contain the specified value(s).
|
|
_.without = function(array) {
|
|
return _.difference(array, slice.call(arguments, 1));
|
|
};
|
|
|
|
// Produce a duplicate-free version of the array. If the array has already
|
|
// been sorted, you have the option of using a faster algorithm.
|
|
// Aliased as `unique`.
|
|
_.uniq = _.unique = function(array, isSorted, iterator, context) {
|
|
if (_.isFunction(isSorted)) {
|
|
context = iterator;
|
|
iterator = isSorted;
|
|
isSorted = false;
|
|
}
|
|
var initial = iterator ? _.map(array, iterator, context) : array;
|
|
var results = [];
|
|
var seen = [];
|
|
each(initial, function(value, index) {
|
|
if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
|
|
seen.push(value);
|
|
results.push(array[index]);
|
|
}
|
|
});
|
|
return results;
|
|
};
|
|
|
|
// Produce an array that contains the union: each distinct element from all of
|
|
// the passed-in arrays.
|
|
_.union = function() {
|
|
return _.uniq(concat.apply(ArrayProto, arguments));
|
|
};
|
|
|
|
// Produce an array that contains every item shared between all the
|
|
// passed-in arrays.
|
|
_.intersection = function(array) {
|
|
var rest = slice.call(arguments, 1);
|
|
return _.filter(_.uniq(array), function(item) {
|
|
return _.every(rest, function(other) {
|
|
return _.indexOf(other, item) >= 0;
|
|
});
|
|
});
|
|
};
|
|
|
|
// Take the difference between one array and a number of other arrays.
|
|
// Only the elements present in just the first array will remain.
|
|
_.difference = function(array) {
|
|
var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
|
|
return _.filter(array, function(value){ return !_.contains(rest, value); });
|
|
};
|
|
|
|
// Zip together multiple lists into a single array -- elements that share
|
|
// an index go together.
|
|
_.zip = function() {
|
|
var args = slice.call(arguments);
|
|
var length = _.max(_.pluck(args, 'length'));
|
|
var results = new Array(length);
|
|
for (var i = 0; i < length; i++) {
|
|
results[i] = _.pluck(args, "" + i);
|
|
}
|
|
return results;
|
|
};
|
|
|
|
// Converts lists into objects. Pass either a single array of `[key, value]`
|
|
// pairs, or two parallel arrays of the same length -- one of keys, and one of
|
|
// the corresponding values.
|
|
_.object = function(list, values) {
|
|
if (list == null) return {};
|
|
var result = {};
|
|
for (var i = 0, l = list.length; i < l; i++) {
|
|
if (values) {
|
|
result[list[i]] = values[i];
|
|
} else {
|
|
result[list[i][0]] = list[i][1];
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
// If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
|
|
// we need this function. Return the position of the first occurrence of an
|
|
// item in an array, or -1 if the item is not included in the array.
|
|
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
|
|
// If the array is large and already in sort order, pass `true`
|
|
// for **isSorted** to use binary search.
|
|
_.indexOf = function(array, item, isSorted) {
|
|
if (array == null) return -1;
|
|
var i = 0, l = array.length;
|
|
if (isSorted) {
|
|
if (typeof isSorted == 'number') {
|
|
i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
|
|
} else {
|
|
i = _.sortedIndex(array, item);
|
|
return array[i] === item ? i : -1;
|
|
}
|
|
}
|
|
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
|
|
for (; i < l; i++) if (array[i] === item) return i;
|
|
return -1;
|
|
};
|
|
|
|
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
|
_.lastIndexOf = function(array, item, from) {
|
|
if (array == null) return -1;
|
|
var hasIndex = from != null;
|
|
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
|
|
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
|
|
}
|
|
var i = (hasIndex ? from : array.length);
|
|
while (i--) if (array[i] === item) return i;
|
|
return -1;
|
|
};
|
|
|
|
// Generate an integer Array containing an arithmetic progression. A port of
|
|
// the native Python `range()` function. See
|
|
// [the Python documentation](http://docs.python.org/library/functions.html#range).
|
|
_.range = function(start, stop, step) {
|
|
if (arguments.length <= 1) {
|
|
stop = start || 0;
|
|
start = 0;
|
|
}
|
|
step = arguments[2] || 1;
|
|
|
|
var len = Math.max(Math.ceil((stop - start) / step), 0);
|
|
var idx = 0;
|
|
var range = new Array(len);
|
|
|
|
while(idx < len) {
|
|
range[idx++] = start;
|
|
start += step;
|
|
}
|
|
|
|
return range;
|
|
};
|
|
|
|
// Function (ahem) Functions
|
|
// ------------------
|
|
|
|
// Create a function bound to a given object (assigning `this`, and arguments,
|
|
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
|
|
// available.
|
|
_.bind = function(func, context) {
|
|
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
|
var args = slice.call(arguments, 2);
|
|
return function() {
|
|
return func.apply(context, args.concat(slice.call(arguments)));
|
|
};
|
|
};
|
|
|
|
// Partially apply a function by creating a version that has had some of its
|
|
// arguments pre-filled, without changing its dynamic `this` context.
|
|
_.partial = function(func) {
|
|
var args = slice.call(arguments, 1);
|
|
return function() {
|
|
return func.apply(this, args.concat(slice.call(arguments)));
|
|
};
|
|
};
|
|
|
|
// Bind all of an object's methods to that object. Useful for ensuring that
|
|
// all callbacks defined on an object belong to it.
|
|
_.bindAll = function(obj) {
|
|
var funcs = slice.call(arguments, 1);
|
|
if (funcs.length === 0) funcs = _.functions(obj);
|
|
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
|
|
return obj;
|
|
};
|
|
|
|
// Memoize an expensive function by storing its results.
|
|
_.memoize = function(func, hasher) {
|
|
var memo = {};
|
|
hasher || (hasher = _.identity);
|
|
return function() {
|
|
var key = hasher.apply(this, arguments);
|
|
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
|
|
};
|
|
};
|
|
|
|
// Delays a function for the given number of milliseconds, and then calls
|
|
// it with the arguments supplied.
|
|
_.delay = function(func, wait) {
|
|
var args = slice.call(arguments, 2);
|
|
return setTimeout(function(){ return func.apply(null, args); }, wait);
|
|
};
|
|
|
|
// Defers a function, scheduling it to run after the current call stack has
|
|
// cleared.
|
|
_.defer = function(func) {
|
|
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
|
|
};
|
|
|
|
// Returns a function, that, when invoked, will only be triggered at most once
|
|
// during a given window of time.
|
|
_.throttle = function(func, wait) {
|
|
var context, args, timeout, result;
|
|
var previous = 0;
|
|
var later = function() {
|
|
previous = new Date;
|
|
timeout = null;
|
|
result = func.apply(context, args);
|
|
};
|
|
return function() {
|
|
var now = new Date;
|
|
var remaining = wait - (now - previous);
|
|
context = this;
|
|
args = arguments;
|
|
if (remaining <= 0) {
|
|
clearTimeout(timeout);
|
|
timeout = null;
|
|
previous = now;
|
|
result = func.apply(context, args);
|
|
} else if (!timeout) {
|
|
timeout = setTimeout(later, remaining);
|
|
}
|
|
return result;
|
|
};
|
|
};
|
|
|
|
// Returns a function, that, as long as it continues to be invoked, will not
|
|
// be triggered. The function will be called after it stops being called for
|
|
// N milliseconds. If `immediate` is passed, trigger the function on the
|
|
// leading edge, instead of the trailing.
|
|
_.debounce = function(func, wait, immediate) {
|
|
var timeout, result;
|
|
return function() {
|
|
var context = this, args = arguments;
|
|
var later = function() {
|
|
timeout = null;
|
|
if (!immediate) result = func.apply(context, args);
|
|
};
|
|
var callNow = immediate && !timeout;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
if (callNow) result = func.apply(context, args);
|
|
return result;
|
|
};
|
|
};
|
|
|
|
// Returns a function that will be executed at most one time, no matter how
|
|
// often you call it. Useful for lazy initialization.
|
|
_.once = function(func) {
|
|
var ran = false, memo;
|
|
return function() {
|
|
if (ran) return memo;
|
|
ran = true;
|
|
memo = func.apply(this, arguments);
|
|
func = null;
|
|
return memo;
|
|
};
|
|
};
|
|
|
|
// Returns the first function passed as an argument to the second,
|
|
// allowing you to adjust arguments, run code before and after, and
|
|
// conditionally execute the original function.
|
|
_.wrap = function(func, wrapper) {
|
|
return function() {
|
|
var args = [func];
|
|
push.apply(args, arguments);
|
|
return wrapper.apply(this, args);
|
|
};
|
|
};
|
|
|
|
// Returns a function that is the composition of a list of functions, each
|
|
// consuming the return value of the function that follows.
|
|
_.compose = function() {
|
|
var funcs = arguments;
|
|
return function() {
|
|
var args = arguments;
|
|
for (var i = funcs.length - 1; i >= 0; i--) {
|
|
args = [funcs[i].apply(this, args)];
|
|
}
|
|
return args[0];
|
|
};
|
|
};
|
|
|
|
// Returns a function that will only be executed after being called N times.
|
|
_.after = function(times, func) {
|
|
if (times <= 0) return func();
|
|
return function() {
|
|
if (--times < 1) {
|
|
return func.apply(this, arguments);
|
|
}
|
|
};
|
|
};
|
|
|
|
// Object Functions
|
|
// ----------------
|
|
|
|
// Retrieve the names of an object's properties.
|
|
// Delegates to **ECMAScript 5**'s native `Object.keys`
|
|
_.keys = nativeKeys || function(obj) {
|
|
if (obj !== Object(obj)) throw new TypeError('Invalid object');
|
|
var keys = [];
|
|
for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
|
|
return keys;
|
|
};
|
|
|
|
// Retrieve the values of an object's properties.
|
|
_.values = function(obj) {
|
|
var values = [];
|
|
for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
|
|
return values;
|
|
};
|
|
|
|
// Convert an object into a list of `[key, value]` pairs.
|
|
_.pairs = function(obj) {
|
|
var pairs = [];
|
|
for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
|
|
return pairs;
|
|
};
|
|
|
|
// Invert the keys and values of an object. The values must be serializable.
|
|
_.invert = function(obj) {
|
|
var result = {};
|
|
for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
|
|
return result;
|
|
};
|
|
|
|
// Return a sorted list of the function names available on the object.
|
|
// Aliased as `methods`
|
|
_.functions = _.methods = function(obj) {
|
|
var names = [];
|
|
for (var key in obj) {
|
|
if (_.isFunction(obj[key])) names.push(key);
|
|
}
|
|
return names.sort();
|
|
};
|
|
|
|
// Extend a given object with all the properties in passed-in object(s).
|
|
_.extend = function(obj) {
|
|
each(slice.call(arguments, 1), function(source) {
|
|
if (source) {
|
|
for (var prop in source) {
|
|
obj[prop] = source[prop];
|
|
}
|
|
}
|
|
});
|
|
return obj;
|
|
};
|
|
|
|
// Return a copy of the object only containing the whitelisted properties.
|
|
_.pick = function(obj) {
|
|
var copy = {};
|
|
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
|
each(keys, function(key) {
|
|
if (key in obj) copy[key] = obj[key];
|
|
});
|
|
return copy;
|
|
};
|
|
|
|
// Return a copy of the object without the blacklisted properties.
|
|
_.omit = function(obj) {
|
|
var copy = {};
|
|
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
|
for (var key in obj) {
|
|
if (!_.contains(keys, key)) copy[key] = obj[key];
|
|
}
|
|
return copy;
|
|
};
|
|
|
|
// Fill in a given object with default properties.
|
|
_.defaults = function(obj) {
|
|
each(slice.call(arguments, 1), function(source) {
|
|
if (source) {
|
|
for (var prop in source) {
|
|
if (obj[prop] == null) obj[prop] = source[prop];
|
|
}
|
|
}
|
|
});
|
|
return obj;
|
|
};
|
|
|
|
// Create a (shallow-cloned) duplicate of an object.
|
|
_.clone = function(obj) {
|
|
if (!_.isObject(obj)) return obj;
|
|
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
|
|
};
|
|
|
|
// Invokes interceptor with the obj, and then returns obj.
|
|
// The primary purpose of this method is to "tap into" a method chain, in
|
|
// order to perform operations on intermediate results within the chain.
|
|
_.tap = function(obj, interceptor) {
|
|
interceptor(obj);
|
|
return obj;
|
|
};
|
|
|
|
// Internal recursive comparison function for `isEqual`.
|
|
var eq = function(a, b, aStack, bStack) {
|
|
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
|
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
|
|
if (a === b) return a !== 0 || 1 / a == 1 / b;
|
|
// A strict comparison is necessary because `null == undefined`.
|
|
if (a == null || b == null) return a === b;
|
|
// Unwrap any wrapped objects.
|
|
if (a instanceof _) a = a._wrapped;
|
|
if (b instanceof _) b = b._wrapped;
|
|
// Compare `[[Class]]` names.
|
|
var className = toString.call(a);
|
|
if (className != toString.call(b)) return false;
|
|
switch (className) {
|
|
// Strings, numbers, dates, and booleans are compared by value.
|
|
case '[object String]':
|
|
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
|
// equivalent to `new String("5")`.
|
|
return a == String(b);
|
|
case '[object Number]':
|
|
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
|
|
// other numeric values.
|
|
return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
|
|
case '[object Date]':
|
|
case '[object Boolean]':
|
|
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
|
// millisecond representations. Note that invalid dates with millisecond representations
|
|
// of `NaN` are not equivalent.
|
|
return +a == +b;
|
|
// RegExps are compared by their source patterns and flags.
|
|
case '[object RegExp]':
|
|
return a.source == b.source &&
|
|
a.global == b.global &&
|
|
a.multiline == b.multiline &&
|
|
a.ignoreCase == b.ignoreCase;
|
|
}
|
|
if (typeof a != 'object' || typeof b != 'object') return false;
|
|
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
|
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
|
var length = aStack.length;
|
|
while (length--) {
|
|
// Linear search. Performance is inversely proportional to the number of
|
|
// unique nested structures.
|
|
if (aStack[length] == a) return bStack[length] == b;
|
|
}
|
|
// Add the first object to the stack of traversed objects.
|
|
aStack.push(a);
|
|
bStack.push(b);
|
|
var size = 0, result = true;
|
|
// Recursively compare objects and arrays.
|
|
if (className == '[object Array]') {
|
|
// Compare array lengths to determine if a deep comparison is necessary.
|
|
size = a.length;
|
|
result = size == b.length;
|
|
if (result) {
|
|
// Deep compare the contents, ignoring non-numeric properties.
|
|
while (size--) {
|
|
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
|
|
}
|
|
}
|
|
} else {
|
|
// Objects with different constructors are not equivalent, but `Object`s
|
|
// from different frames are.
|
|
var aCtor = a.constructor, bCtor = b.constructor;
|
|
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
|
|
_.isFunction(bCtor) && (bCtor instanceof bCtor))) {
|
|
return false;
|
|
}
|
|
// Deep compare objects.
|
|
for (var key in a) {
|
|
if (_.has(a, key)) {
|
|
// Count the expected number of properties.
|
|
size++;
|
|
// Deep compare each member.
|
|
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
|
|
}
|
|
}
|
|
// Ensure that both objects contain the same number of properties.
|
|
if (result) {
|
|
for (key in b) {
|
|
if (_.has(b, key) && !(size--)) break;
|
|
}
|
|
result = !size;
|
|
}
|
|
}
|
|
// Remove the first object from the stack of traversed objects.
|
|
aStack.pop();
|
|
bStack.pop();
|
|
return result;
|
|
};
|
|
|
|
// Perform a deep comparison to check if two objects are equal.
|
|
_.isEqual = function(a, b) {
|
|
return eq(a, b, [], []);
|
|
};
|
|
|
|
// Is a given array, string, or object empty?
|
|
// An "empty" object has no enumerable own-properties.
|
|
_.isEmpty = function(obj) {
|
|
if (obj == null) return true;
|
|
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
|
for (var key in obj) if (_.has(obj, key)) return false;
|
|
return true;
|
|
};
|
|
|
|
// Is a given value a DOM element?
|
|
_.isElement = function(obj) {
|
|
return !!(obj && obj.nodeType === 1);
|
|
};
|
|
|
|
// Is a given value an array?
|
|
// Delegates to ECMA5's native Array.isArray
|
|
_.isArray = nativeIsArray || function(obj) {
|
|
return toString.call(obj) == '[object Array]';
|
|
};
|
|
|
|
// Is a given variable an object?
|
|
_.isObject = function(obj) {
|
|
return obj === Object(obj);
|
|
};
|
|
|
|
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
|
|
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
|
|
_['is' + name] = function(obj) {
|
|
return toString.call(obj) == '[object ' + name + ']';
|
|
};
|
|
});
|
|
|
|
// Define a fallback version of the method in browsers (ahem, IE), where
|
|
// there isn't any inspectable "Arguments" type.
|
|
if (!_.isArguments(arguments)) {
|
|
_.isArguments = function(obj) {
|
|
return !!(obj && _.has(obj, 'callee'));
|
|
};
|
|
}
|
|
|
|
// Optimize `isFunction` if appropriate.
|
|
if (typeof (/./) !== 'function') {
|
|
_.isFunction = function(obj) {
|
|
return typeof obj === 'function';
|
|
};
|
|
}
|
|
|
|
// Is a given object a finite number?
|
|
_.isFinite = function(obj) {
|
|
return isFinite(obj) && !isNaN(parseFloat(obj));
|
|
};
|
|
|
|
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
|
_.isNaN = function(obj) {
|
|
return _.isNumber(obj) && obj != +obj;
|
|
};
|
|
|
|
// Is a given value a boolean?
|
|
_.isBoolean = function(obj) {
|
|
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
|
|
};
|
|
|
|
// Is a given value equal to null?
|
|
_.isNull = function(obj) {
|
|
return obj === null;
|
|
};
|
|
|
|
// Is a given variable undefined?
|
|
_.isUndefined = function(obj) {
|
|
return obj === void 0;
|
|
};
|
|
|
|
// Shortcut function for checking if an object has a given property directly
|
|
// on itself (in other words, not on a prototype).
|
|
_.has = function(obj, key) {
|
|
return hasOwnProperty.call(obj, key);
|
|
};
|
|
|
|
// Utility Functions
|
|
// -----------------
|
|
|
|
// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
|
|
// previous owner. Returns a reference to the Underscore object.
|
|
_.noConflict = function() {
|
|
root._ = previousUnderscore;
|
|
return this;
|
|
};
|
|
|
|
// Keep the identity function around for default iterators.
|
|
_.identity = function(value) {
|
|
return value;
|
|
};
|
|
|
|
// Run a function **n** times.
|
|
_.times = function(n, iterator, context) {
|
|
var accum = Array(n);
|
|
for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
|
|
return accum;
|
|
};
|
|
|
|
// Return a random integer between min and max (inclusive).
|
|
_.random = function(min, max) {
|
|
if (max == null) {
|
|
max = min;
|
|
min = 0;
|
|
}
|
|
return min + Math.floor(Math.random() * (max - min + 1));
|
|
};
|
|
|
|
// List of HTML entities for escaping.
|
|
var entityMap = {
|
|
escape: {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
'/': '/'
|
|
}
|
|
};
|
|
entityMap.unescape = _.invert(entityMap.escape);
|
|
|
|
// Regexes containing the keys and values listed immediately above.
|
|
var entityRegexes = {
|
|
escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
|
|
unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
|
|
};
|
|
|
|
// Functions for escaping and unescaping strings to/from HTML interpolation.
|
|
_.each(['escape', 'unescape'], function(method) {
|
|
_[method] = function(string) {
|
|
if (string == null) return '';
|
|
return ('' + string).replace(entityRegexes[method], function(match) {
|
|
return entityMap[method][match];
|
|
});
|
|
};
|
|
});
|
|
|
|
// If the value of the named property is a function then invoke it;
|
|
// otherwise, return it.
|
|
_.result = function(object, property) {
|
|
if (object == null) return null;
|
|
var value = object[property];
|
|
return _.isFunction(value) ? value.call(object) : value;
|
|
};
|
|
|
|
// Add your own custom functions to the Underscore object.
|
|
_.mixin = function(obj) {
|
|
each(_.functions(obj), function(name){
|
|
var func = _[name] = obj[name];
|
|
_.prototype[name] = function() {
|
|
var args = [this._wrapped];
|
|
push.apply(args, arguments);
|
|
return result.call(this, func.apply(_, args));
|
|
};
|
|
});
|
|
};
|
|
|
|
// Generate a unique integer id (unique within the entire client session).
|
|
// Useful for temporary DOM ids.
|
|
var idCounter = 0;
|
|
_.uniqueId = function(prefix) {
|
|
var id = ++idCounter + '';
|
|
return prefix ? prefix + id : id;
|
|
};
|
|
|
|
// By default, Underscore uses ERB-style template delimiters, change the
|
|
// following template settings to use alternative delimiters.
|
|
_.templateSettings = {
|
|
evaluate : /<%([\s\S]+?)%>/g,
|
|
interpolate : /<%=([\s\S]+?)%>/g,
|
|
escape : /<%-([\s\S]+?)%>/g
|
|
};
|
|
|
|
// When customizing `templateSettings`, if you don't want to define an
|
|
// interpolation, evaluation or escaping regex, we need one that is
|
|
// guaranteed not to match.
|
|
var noMatch = /(.)^/;
|
|
|
|
// Certain characters need to be escaped so that they can be put into a
|
|
// string literal.
|
|
var escapes = {
|
|
"'": "'",
|
|
'\\': '\\',
|
|
'\r': 'r',
|
|
'\n': 'n',
|
|
'\t': 't',
|
|
'\u2028': 'u2028',
|
|
'\u2029': 'u2029'
|
|
};
|
|
|
|
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
|
|
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
|
// and correctly escapes quotes within interpolated code.
|
|
_.template = function(text, data, settings) {
|
|
var render;
|
|
settings = _.defaults({}, settings, _.templateSettings);
|
|
|
|
// Combine delimiters into one regular expression via alternation.
|
|
var matcher = new RegExp([
|
|
(settings.escape || noMatch).source,
|
|
(settings.interpolate || noMatch).source,
|
|
(settings.evaluate || noMatch).source
|
|
].join('|') + '|$', 'g');
|
|
|
|
// Compile the template source, escaping string literals appropriately.
|
|
var index = 0;
|
|
var source = "__p+='";
|
|
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
|
source += text.slice(index, offset)
|
|
.replace(escaper, function(match) { return '\\' + escapes[match]; });
|
|
|
|
if (escape) {
|
|
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
|
}
|
|
if (interpolate) {
|
|
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
|
}
|
|
if (evaluate) {
|
|
source += "';\n" + evaluate + "\n__p+='";
|
|
}
|
|
index = offset + match.length;
|
|
return match;
|
|
});
|
|
source += "';\n";
|
|
|
|
// If a variable is not specified, place data values in local scope.
|
|
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
|
|
|
source = "var __t,__p='',__j=Array.prototype.join," +
|
|
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
|
source + "return __p;\n";
|
|
|
|
try {
|
|
render = new Function(settings.variable || 'obj', '_', source);
|
|
} catch (e) {
|
|
e.source = source;
|
|
throw e;
|
|
}
|
|
|
|
if (data) return render(data, _);
|
|
var template = function(data) {
|
|
return render.call(this, data, _);
|
|
};
|
|
|
|
// Provide the compiled function source as a convenience for precompilation.
|
|
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
|
|
|
|
return template;
|
|
};
|
|
|
|
// Add a "chain" function, which will delegate to the wrapper.
|
|
_.chain = function(obj) {
|
|
return _(obj).chain();
|
|
};
|
|
|
|
// OOP
|
|
// ---------------
|
|
// If Underscore is called as a function, it returns a wrapped object that
|
|
// can be used OO-style. This wrapper holds altered versions of all the
|
|
// underscore functions. Wrapped objects may be chained.
|
|
|
|
// Helper function to continue chaining intermediate results.
|
|
var result = function(obj) {
|
|
return this._chain ? _(obj).chain() : obj;
|
|
};
|
|
|
|
// Add all of the Underscore functions to the wrapper object.
|
|
_.mixin(_);
|
|
|
|
// Add all mutator Array functions to the wrapper.
|
|
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
|
var method = ArrayProto[name];
|
|
_.prototype[name] = function() {
|
|
var obj = this._wrapped;
|
|
method.apply(obj, arguments);
|
|
if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
|
|
return result.call(this, obj);
|
|
};
|
|
});
|
|
|
|
// Add all accessor Array functions to the wrapper.
|
|
each(['concat', 'join', 'slice'], function(name) {
|
|
var method = ArrayProto[name];
|
|
_.prototype[name] = function() {
|
|
return result.call(this, method.apply(this._wrapped, arguments));
|
|
};
|
|
});
|
|
|
|
_.extend(_.prototype, {
|
|
|
|
// Start chaining a wrapped Underscore object.
|
|
chain: function() {
|
|
this._chain = true;
|
|
return this;
|
|
},
|
|
|
|
// Extracts the result from a wrapped and chained object.
|
|
value: function() {
|
|
return this._wrapped;
|
|
}
|
|
|
|
});
|
|
|
|
}).call(this);
|
|
}, "wildemitter": function(exports, require, module) {/*
|
|
WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based
|
|
on @visionmedia's Emitter from UI Kit.
|
|
|
|
Why? I wanted it standalone.
|
|
|
|
I also wanted support for wildcard emitters like this:
|
|
|
|
emitter.on('*', function (eventName, other, event, payloads) {
|
|
|
|
});
|
|
|
|
emitter.on('somenamespace*', function (eventName, payloads) {
|
|
|
|
});
|
|
|
|
Please note that callbacks triggered by wildcard registered events also get
|
|
the event name as the first argument.
|
|
*/
|
|
module.exports = WildEmitter;
|
|
|
|
function WildEmitter() {
|
|
this.callbacks = {};
|
|
}
|
|
|
|
// Listen on the given `event` with `fn`. Store a group name if present.
|
|
WildEmitter.prototype.on = function (event, groupName, fn) {
|
|
var hasGroup = (arguments.length === 3),
|
|
group = hasGroup ? arguments[1] : undefined,
|
|
func = hasGroup ? arguments[2] : arguments[1];
|
|
func._groupName = group;
|
|
(this.callbacks[event] = this.callbacks[event] || []).push(func);
|
|
return this;
|
|
};
|
|
|
|
// Adds an `event` listener that will be invoked a single
|
|
// time then automatically removed.
|
|
WildEmitter.prototype.once = function (event, groupName, fn) {
|
|
var self = this,
|
|
hasGroup = (arguments.length === 3),
|
|
group = hasGroup ? arguments[1] : undefined,
|
|
func = hasGroup ? arguments[2] : arguments[1];
|
|
function on() {
|
|
self.off(event, on);
|
|
func.apply(this, arguments);
|
|
}
|
|
this.on(event, group, on);
|
|
return this;
|
|
};
|
|
|
|
// Unbinds an entire group
|
|
WildEmitter.prototype.releaseGroup = function (groupName) {
|
|
var item, i, len, handlers;
|
|
for (item in this.callbacks) {
|
|
handlers = this.callbacks[item];
|
|
for (i = 0, len = handlers.length; i < len; i++) {
|
|
if (handlers[i]._groupName === groupName) {
|
|
//console.log('removing');
|
|
// remove it and shorten the array we're looping through
|
|
handlers.splice(i, 1);
|
|
i--;
|
|
len--;
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
// Remove the given callback for `event` or all
|
|
// registered callbacks.
|
|
WildEmitter.prototype.off = function (event, fn) {
|
|
var callbacks = this.callbacks[event],
|
|
i;
|
|
|
|
if (!callbacks) return this;
|
|
|
|
// remove all handlers
|
|
if (arguments.length === 1) {
|
|
delete this.callbacks[event];
|
|
return this;
|
|
}
|
|
|
|
// remove specific handler
|
|
i = callbacks.indexOf(fn);
|
|
callbacks.splice(i, 1);
|
|
return this;
|
|
};
|
|
|
|
// Emit `event` with the given args.
|
|
// also calls any `*` handlers
|
|
WildEmitter.prototype.emit = function (event) {
|
|
var args = [].slice.call(arguments, 1),
|
|
callbacks = this.callbacks[event],
|
|
specialCallbacks = this.getWildcardCallbacks(event),
|
|
i,
|
|
len,
|
|
item;
|
|
|
|
if (callbacks) {
|
|
for (i = 0, len = callbacks.length; i < len; ++i) {
|
|
if (callbacks[i]) {
|
|
callbacks[i].apply(this, args);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (specialCallbacks) {
|
|
for (i = 0, len = specialCallbacks.length; i < len; ++i) {
|
|
if (specialCallbacks[i]) {
|
|
specialCallbacks[i].apply(this, [event].concat(args));
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
// Helper for for finding special wildcard event handlers that match the event
|
|
WildEmitter.prototype.getWildcardCallbacks = function (eventName) {
|
|
var item,
|
|
split,
|
|
result = [];
|
|
|
|
for (item in this.callbacks) {
|
|
split = item.split('*');
|
|
if (item === '*' || (split.length === 2 && eventName.slice(0, split[1].length) === split[1])) {
|
|
result = result.concat(this.callbacks[item]);
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
}, "app": function(exports, require, module) {/*global app*/
|
|
var Backbone = require('backbone');
|
|
var MeModel = require('models/me');
|
|
var MainView = require('views/main');
|
|
var Router = require('router');
|
|
var xmppEventHandlers = require('helpers/xmppEventHandlers');
|
|
|
|
|
|
module.exports = {
|
|
launch: function () {
|
|
window.app = this;
|
|
window.me = new MeModel();
|
|
|
|
new Router();
|
|
app.history = Backbone.history;
|
|
|
|
if (!localStorage.config) {
|
|
return app.navigate('signin');
|
|
}
|
|
|
|
app.view = new MainView({
|
|
el: document.body,
|
|
model: me
|
|
}).render();
|
|
|
|
var config = JSON.parse(localStorage.config);
|
|
window.client = app.client = XMPP.createClient(config);
|
|
xmppEventHandlers(client, app);
|
|
client.connect();
|
|
|
|
// we have what we need, we can now start our router and show the appropriate page
|
|
app.history.start({pushState: true, root: '/'});
|
|
},
|
|
navigate: function (page) {
|
|
var url = (page.charAt(0) === '/') ? page.slice(1) : page;
|
|
app.history.navigate(url, true);
|
|
},
|
|
renderPage: function (view, animation) {
|
|
var container = $('#pages');
|
|
|
|
if (app.currentPage) {
|
|
app.currentPage.hide(animation);
|
|
}
|
|
// we call render, but if animation is none, we want to tell the view
|
|
// to start with the active class already before appending to DOM.
|
|
container.append(view.render(animation === 'none').el);
|
|
view.show(animation);
|
|
}
|
|
};
|
|
}, "helpers/getOrCall": function(exports, require, module) {// get a property that's a function or direct property
|
|
module.exports = function (obj, propName) {
|
|
if (obj[propName] instanceof Function) {
|
|
return obj[propName]();
|
|
} else {
|
|
return obj[propName] || '';
|
|
}
|
|
};
|
|
}, "helpers/xmppEventHandlers": function(exports, require, module) {var crypto = XMPP.crypto;
|
|
|
|
var _ = require('underscore');
|
|
var imageToDataURI = require('image-to-data-uri');
|
|
var Contact = require('models/contact');
|
|
var Resource = require('models/resource');
|
|
var Message = require('models/message');
|
|
|
|
|
|
function logScroll() {
|
|
window.scrollTo(0, document.body.scrollHeight);
|
|
}
|
|
|
|
function log(name, data) {
|
|
var container = document.getElementById('log');
|
|
var logEntry = document.createElement('div'),
|
|
header = document.createElement('h2'),
|
|
entry = document.createElement('p'),
|
|
altEntry = document.createElement('p');
|
|
|
|
header.textContent = name;
|
|
logEntry.appendChild(header);
|
|
|
|
if (data && data.toJSON) {
|
|
var codeJSON = document.createElement('code');
|
|
codeJSON.textContent = JSON.stringify(data.toJSON());
|
|
|
|
altEntry.appendChild(codeJSON);
|
|
logEntry.appendChild(altEntry);
|
|
logEntry.appendChild(document.createElement('hr'));
|
|
}
|
|
|
|
var codeData = document.createElement('code');
|
|
codeData.textContent = data;
|
|
entry.appendChild(codeData);
|
|
logEntry.appendChild(entry);
|
|
|
|
if (container) {
|
|
container.appendChild(logEntry);
|
|
_.throttle(logScroll, 300);
|
|
}
|
|
}
|
|
|
|
|
|
module.exports = function (client, app) {
|
|
|
|
client.on('*', function (name, data) {
|
|
log(name, data);
|
|
|
|
});
|
|
|
|
client.on('disconnected', function () {
|
|
client.connect();
|
|
});
|
|
|
|
client.on('session:started', function (jid) {
|
|
console.log(jid);
|
|
me.jid = jid;
|
|
|
|
client.getRoster(function (err, resp) {
|
|
resp = resp.toJSON();
|
|
_.each(resp.roster.items, function (item) {
|
|
me.contacts.add(item);
|
|
});
|
|
|
|
client.updateCaps();
|
|
client.sendPresence({
|
|
caps: client.disco.caps
|
|
});
|
|
client.enableCarbons();
|
|
});
|
|
});
|
|
|
|
client.on('roster:update', function (iq) {
|
|
var items = iq.toJSON().roster.items;
|
|
_.each(items, function (item) {
|
|
var contact = me.getContact(item.jid);
|
|
|
|
if (item.subscription === 'remove') {
|
|
if (contact) {
|
|
me.contacts.remove(contact);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (contact) {
|
|
contact.set(item);
|
|
} else {
|
|
me.contacts.add(item);
|
|
}
|
|
});
|
|
});
|
|
|
|
client.on('available', function (pres) {
|
|
pres = pres.toJSON();
|
|
var contact = me.getContact(pres.from);
|
|
if (contact) {
|
|
delete pres.id;
|
|
pres.show = pres.show || '';
|
|
pres.status = pres.status || '';
|
|
pres.priority = pres.priority || 0;
|
|
|
|
var resource = contact.resources.get(pres.from);
|
|
if (resource) {
|
|
resource.set(pres);
|
|
} else {
|
|
resource = new Resource(pres);
|
|
resource.cid = pres.from;
|
|
contact.resources.add(resource);
|
|
}
|
|
}
|
|
});
|
|
|
|
client.on('unavailable', function (pres) {
|
|
pres = pres.toJSON();
|
|
var contact = me.getContact(pres.from);
|
|
if (contact) {
|
|
var resource = contact.resources.get(pres.from);
|
|
if (resource) {
|
|
contact.resources.remove(resource);
|
|
}
|
|
|
|
if (contact.resources.length === 0) {
|
|
contact.offlineStatus = pres.status;
|
|
}
|
|
}
|
|
});
|
|
|
|
client.on('avatar', function (info) {
|
|
var contact = me.getContact(info.jid);
|
|
if (contact) {
|
|
if (info.avatars.length > 0) {
|
|
client.getAvatar(info.jid, info.avatars[0].id, function (err, resp) {
|
|
if (err) return;
|
|
resp = resp.toJSON();
|
|
var avatar = resp.pubsub.retrieve.item.avatarData;
|
|
contact.avatar = 'data:' + info.avatars[0].type + ';base64,' + avatar;
|
|
});
|
|
} else {
|
|
contact.useDefaultAvatar();
|
|
}
|
|
}
|
|
});
|
|
|
|
client.on('chatState', function (info) {
|
|
var contact = me.getContact(info.from);
|
|
if (contact) {
|
|
contact.chatState = info.chatState;
|
|
if (info.chatState === 'gone') {
|
|
contact.lockedResource = undefined;
|
|
}
|
|
}
|
|
});
|
|
|
|
client.on('chat', function (msg) {
|
|
msg = msg.toJSON();
|
|
var contact = me.getContact(msg.from, msg.to);
|
|
if (contact && !msg.replace) {
|
|
var message = new Message();
|
|
message.cid = msg.id;
|
|
delete msg.id;
|
|
message.set(msg);
|
|
contact.messages.add(message);
|
|
if (!contact.lockedResource) {
|
|
contact.lockedResource = msg.from;
|
|
} else if (msg.from !== contact.lockedResource) {
|
|
contact.lockedResource = undefined;
|
|
}
|
|
}
|
|
});
|
|
|
|
client.on('replace', function (msg) {
|
|
msg = msg.toJSON();
|
|
var contact = me.getContact(msg.from, msg.to);
|
|
if (!contact) return;
|
|
|
|
var id = msg.replace;
|
|
var original = contact.messages.get(id);
|
|
|
|
if (!original) return;
|
|
|
|
original.correct(msg);
|
|
});
|
|
|
|
client.on('carbon:received', function (carbon) {
|
|
if (!me.isMe(carbon.from)) return;
|
|
|
|
var msg = carbon.carbonReceived.forwarded.message;
|
|
var delay = carbon.carbonReceived.forwarded.delay;
|
|
if (!delay.stamp) {
|
|
delay.stamp = Date.now();
|
|
}
|
|
|
|
if (!msg._extensions.delay) {
|
|
msg.delay = delay;
|
|
}
|
|
|
|
client.emit('message', msg);
|
|
});
|
|
|
|
client.on('carbon:sent', function (carbon) {
|
|
if (!me.isMe(carbon.from)) return;
|
|
|
|
var msg = carbon.carbonSent.forwarded.message;
|
|
var delay = carbon.carbonSent.forwarded.delay;
|
|
console.log(delay.toJSON());
|
|
console.log(carbon.toString());
|
|
if (!delay.stamp) {
|
|
delay.stamp = Date.now();
|
|
}
|
|
|
|
if (!msg._extensions.delay) {
|
|
msg.delay = delay;
|
|
}
|
|
|
|
client.emit('message', msg)
|
|
});
|
|
|
|
client.on('message:sent', function (msg) {
|
|
console.log(msg);
|
|
var contact = me.getContact(msg.to);
|
|
var msg = msg.toJSON();
|
|
if (contact && msg.body) {
|
|
var message = new Message();
|
|
message.cid = msg.id;
|
|
delete msg.id;
|
|
message.set(msg);
|
|
contact.messages.add(message);
|
|
}
|
|
});
|
|
};
|
|
}, "models/baseCollection": function(exports, require, module) {// our base collection
|
|
var Backbone = require('backbone');
|
|
|
|
|
|
module.exports = Backbone.Collection.extend({
|
|
// ###next
|
|
// returns next item when given an item in the collection
|
|
next: function (item, filter, start) {
|
|
var i = this.indexOf(item),
|
|
newItem;
|
|
|
|
if (i === -1) {
|
|
i = 0;
|
|
} else if (i + 1 >= this.length) {
|
|
i = 0;
|
|
} else {
|
|
i = i + 1;
|
|
}
|
|
newItem = this.at(i);
|
|
if (filter && newItem !== start) {
|
|
if (!filter(newItem)) {
|
|
return this.next(newItem, filter, start || item);
|
|
}
|
|
}
|
|
return newItem;
|
|
},
|
|
|
|
// ###prev
|
|
// returns previous item when given an item in the collection
|
|
prev: function (item, filter, start) {
|
|
var i = this.indexOf(item),
|
|
newItem;
|
|
if (i === -1) {
|
|
i = 0;
|
|
} else if (i === 0) {
|
|
i = this.length - 1;
|
|
} else {
|
|
i = i - 1;
|
|
}
|
|
newItem = this.at(i);
|
|
if (filter && newItem !== start) {
|
|
if (!filter(newItem)) {
|
|
return this.prev(newItem, filter, start || item);
|
|
}
|
|
}
|
|
return this.at(i);
|
|
}
|
|
});
|
|
}, "models/contact": function(exports, require, module) {var StrictModel = require('strictmodel').Model;
|
|
var Resources = require('./resources');
|
|
var Messages = require('./messages');
|
|
var Message = require('./message');
|
|
var crypto = XMPP.crypto;
|
|
|
|
|
|
module.exports = StrictModel.extend({
|
|
init: function (attrs) {
|
|
if (attrs.jid) {
|
|
this.cid = attrs.jid;
|
|
}
|
|
if (!attrs.avatar) {
|
|
this.useDefaultAvatar();
|
|
}
|
|
|
|
this.resources.bind('add remove reset change', this.resourceChange, this);
|
|
},
|
|
type: 'contact',
|
|
props: {
|
|
jid: ['string', true],
|
|
name: ['string', true, ''],
|
|
subscription: ['string', true, 'none'],
|
|
groups: ['array', true, []]
|
|
},
|
|
derived: {
|
|
displayName: {
|
|
deps: ['name', 'jid'],
|
|
fn: function () {
|
|
if (this.name) {
|
|
return this.name;
|
|
}
|
|
return this.jid;
|
|
}
|
|
},
|
|
status: {
|
|
deps: ['topResourceStatus', 'offlineStatus'],
|
|
fn: function () {
|
|
if (this.topResourceStatus) {
|
|
return this.topResourceStatus;
|
|
}
|
|
return this.offlineStatus;
|
|
}
|
|
}
|
|
},
|
|
session: {
|
|
topResourceStatus: ['string', true, ''],
|
|
offlineStatus: ['string', true, ''],
|
|
idleSince: 'date',
|
|
avatar: 'string',
|
|
show: ['string', true, 'offline'],
|
|
chatState: ['string', true, 'gone'],
|
|
lockedResource: 'string'
|
|
},
|
|
collections: {
|
|
resources: Resources,
|
|
messages: Messages
|
|
},
|
|
useDefaultAvatar: function () {
|
|
this.avatar = 'https://gravatar.com/avatar/' + crypto.createHash('md5').update(this.jid).digest('hex') + '?s=30&d=mm';
|
|
},
|
|
resourceChange: function () {
|
|
// Manually propagate change events for properties that
|
|
// depend on the resources collection.
|
|
this.resources.sort();
|
|
|
|
var res = this.resources.first();
|
|
if (res) {
|
|
this.offlineStatus = '';
|
|
this.topResourceStatus = res.status;
|
|
this.show = res.show || 'online';
|
|
this.lockedResource = undefined;
|
|
} else {
|
|
this.topResourceStatus = '';
|
|
this.show = 'offline';
|
|
}
|
|
},
|
|
fetchHistory: function () {
|
|
var self = this;
|
|
|
|
var time = new Date(Date.now());
|
|
var yesterday = new Date(time.valueOf() + time.getTimezoneOffset() * 6000 - 86400000);
|
|
|
|
client.getHistory({
|
|
with: this.jid,
|
|
start: yesterday,
|
|
rsm: {
|
|
count: 20,
|
|
before: true
|
|
}
|
|
}, function (err, res) {
|
|
if (err) return;
|
|
|
|
var results = res.mamQuery.results || [];
|
|
results.reverse();
|
|
results.forEach(function (result) {
|
|
result = result.toJSON();
|
|
msg = result.mam.forwarded.message;
|
|
|
|
if (!msg.delay) {
|
|
msg.delay = result.mam.forwarded.delay;
|
|
}
|
|
|
|
if (msg.replace) {
|
|
var original = self.messages.get(msg.replace);
|
|
if (original) {
|
|
return original.correct(msg);
|
|
}
|
|
}
|
|
|
|
var message = new Message();
|
|
console.log(msg);
|
|
message.cid = msg.id;
|
|
delete msg.id;
|
|
message.set(msg);
|
|
self.messages.add(message);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}, "models/contacts": function(exports, require, module) {var BaseCollection = require('./baseCollection');
|
|
var Contact = require('./contact');
|
|
|
|
|
|
module.exports = BaseCollection.extend({
|
|
type: 'contacts',
|
|
model: Contact,
|
|
comparator: function (model1, model2) {
|
|
var show1 = model1.show;
|
|
var show2 = model2.show;
|
|
|
|
var name1 = model1.displayName.toLowerCase();
|
|
var name2 = model2.displayName.toLowerCase();
|
|
|
|
if (show1 === show2) {
|
|
|
|
if (name1 === name2) {
|
|
return 0;
|
|
}
|
|
if (name1 < name2) {
|
|
return -1;
|
|
}
|
|
return 1;
|
|
} else {
|
|
if (show1 === 'offline') {
|
|
return 1;
|
|
}
|
|
if (show2 === 'offline') {
|
|
return -1;
|
|
}
|
|
|
|
if (name1 === name2) {
|
|
return 0;
|
|
}
|
|
if (name1 < name2) {
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
},
|
|
initialize: function (model, options) {
|
|
this.bind('change', this.orderChange, this);
|
|
this.bind('add', this.fetchHistory, this);
|
|
},
|
|
orderChange: function () {
|
|
this.sort();
|
|
},
|
|
fetchHistory: function (contact) {
|
|
contact.fetchHistory();
|
|
}
|
|
});
|
|
}, "models/me": function(exports, require, module) {var StrictModel = require('strictmodel');
|
|
var Contacts = require('./contacts');
|
|
|
|
|
|
module.exports = StrictModel.Model.extend({
|
|
session: {
|
|
jid: ['string', true, ''],
|
|
status: ['string', true, ''],
|
|
avatar: ['string', true, '']
|
|
},
|
|
derived: {
|
|
barejid: {
|
|
deps: ['jid'],
|
|
fn: function () {
|
|
var hasResource = this.jid.indexOf('/') > 0;
|
|
if (hasResource) {
|
|
return this.jid.slice(0, this.jid.indexOf('/'));
|
|
}
|
|
return this.jid;
|
|
}
|
|
}
|
|
},
|
|
collections: {
|
|
contacts: Contacts
|
|
},
|
|
getContact: function (jid, alt) {
|
|
if (this.isMe(jid)) {
|
|
jid = alt || jid;
|
|
}
|
|
|
|
var hasResource = jid.indexOf('/') > 0;
|
|
if (hasResource) {
|
|
jid = jid.slice(0, jid.indexOf('/'));
|
|
}
|
|
return this.contacts.get(jid);
|
|
},
|
|
isMe: function (jid) {
|
|
var hasResource = jid.indexOf('/') > 0;
|
|
if (hasResource) {
|
|
jid = jid.slice(0, jid.indexOf('/'));
|
|
}
|
|
return jid === this.barejid;
|
|
}
|
|
});
|
|
}, "models/message": function(exports, require, module) {var StrictModel = require('strictmodel').Model;
|
|
|
|
|
|
module.exports = StrictModel.extend({
|
|
init: function (attrs) {
|
|
this._created = Date.now();
|
|
},
|
|
type: 'message',
|
|
props: {
|
|
to: ['string', true, ''],
|
|
from: ['string', true, ''],
|
|
body: ['string', true, ''],
|
|
type: ['string', true, 'normal'],
|
|
acked: ['bool', true, false],
|
|
},
|
|
derived: {
|
|
mine: {
|
|
deps: ['from'],
|
|
fn: function () {
|
|
return me.isMe(this.from);
|
|
}
|
|
},
|
|
delayed: {
|
|
deps: ['delay'],
|
|
fn: function () {
|
|
return !!this.delay;
|
|
}
|
|
},
|
|
created: {
|
|
deps: ['delay', '_created'],
|
|
fn: function () {
|
|
if (this.delay && this.delay.stamp) {
|
|
return this.delay.stamp;
|
|
}
|
|
return this._created;
|
|
}
|
|
},
|
|
formattedTime: {
|
|
deps: ['created'],
|
|
fn: function () {
|
|
return this.created.format('{MM}/{dd} {h}:{mm}{t}');
|
|
}
|
|
}
|
|
},
|
|
session: {
|
|
_created: 'date',
|
|
receiptReceived: ['bool', true, false],
|
|
edited: ['bool', true, false],
|
|
delay: 'object',
|
|
},
|
|
correct: function (msg) {
|
|
if (this.from !== msg.from) return;
|
|
|
|
delete msg.id;
|
|
|
|
this.set(msg);
|
|
this._created = Date.now();
|
|
this.edited = true;
|
|
}
|
|
});
|
|
}, "models/messages": function(exports, require, module) {var BaseCollection = require('./baseCollection');
|
|
var Message = require('./message');
|
|
|
|
|
|
module.exports = BaseCollection.extend({
|
|
type: 'messages',
|
|
model: Message,
|
|
comparator: function (msg1, msg2) {
|
|
console.log('comparing', msg1, msg2);
|
|
if (msg1.created < msg2.created) {
|
|
return -1;
|
|
}
|
|
if (msg1.created > msg2.created) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
});
|
|
}, "models/resource": function(exports, require, module) {var StrictModel = require('strictmodel').Model;
|
|
|
|
|
|
module.exports = StrictModel.extend({
|
|
init: function () {},
|
|
type: 'resource',
|
|
session: {
|
|
jid: ['string', true],
|
|
status: ['string', true, ''],
|
|
show: ['string', true, ''],
|
|
priority: ['number', true, 0],
|
|
idleSince: 'date'
|
|
}
|
|
});
|
|
}, "models/resources": function(exports, require, module) {var BaseCollection = require('./baseCollection');
|
|
var Resource = require('./resource');
|
|
|
|
|
|
module.exports = BaseCollection.extend({
|
|
type: 'resources',
|
|
model: Resource,
|
|
comparator: function (res1, res2) {
|
|
if (res1.priority > res2.priority) {
|
|
return -1;
|
|
}
|
|
if (res1.priority < res2.priority) {
|
|
return 1;
|
|
}
|
|
if (res1.show === res2.show) {
|
|
return 0;
|
|
}
|
|
|
|
var ranking = {
|
|
xa: 0,
|
|
away: 1,
|
|
'': 2,
|
|
chat: 3,
|
|
dnd: 3
|
|
};
|
|
var r1 = ranking[res1.show];
|
|
var r2 = ranking[res2.show];
|
|
|
|
if (r1 === r2) {
|
|
return 0;
|
|
}
|
|
if (r1 > r2) {
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
});
|
|
}, "pages/base": function(exports, require, module) {/*global app*/
|
|
var BaseView = require('strictview'),
|
|
getOrCall = require('helpers/getOrCall');
|
|
|
|
|
|
module.exports = BaseView.extend({
|
|
show: function (animation) {
|
|
$('body').scrollTop(0);
|
|
// set the class so it comes into view
|
|
//this.$el.addClass('active');
|
|
// store reference to current page
|
|
app.currentPage = this;
|
|
// set the document title
|
|
document.title = getOrCall(this, 'title') + ' • Stanza.io';
|
|
// trigger an event to the page model in case we want to respond
|
|
this.trigger('pageloaded');
|
|
return this;
|
|
},
|
|
hide: function () {
|
|
var self = this;
|
|
// tell the model we're bailing
|
|
this.trigger('pageunloaded');
|
|
// unbind all events bound for this view
|
|
this.remove();
|
|
return this;
|
|
}
|
|
});
|
|
}, "pages/info": function(exports, require, module) {/*global app*/
|
|
var BasePage = require('pages/base');
|
|
var templates = require('templates');
|
|
var ContactListItem = require('views/contactListItem');
|
|
var ContactListItemResource = require('views/contactListItemResource');
|
|
var Message = require('views/message');
|
|
|
|
|
|
module.exports = BasePage.extend({
|
|
template: templates.pages.info,
|
|
initialize: function (spec) {
|
|
this.render();
|
|
},
|
|
contentBindings: {
|
|
name: 'h1.name'
|
|
},
|
|
render: function () {
|
|
this.basicRender();
|
|
this.collectomatic(me.contacts, ContactListItem, {
|
|
containerEl: this.$('#contactList')
|
|
}, {quick: true});
|
|
this.collectomatic(this.model.messages, Message, {
|
|
containerEl: this.$('#conversation')
|
|
}, {quick: true});
|
|
this.handleBindings();
|
|
return this;
|
|
}
|
|
});
|
|
}, "pages/main": function(exports, require, module) {/*global app*/
|
|
var BasePage = require('pages/base');
|
|
var templates = require('templates');
|
|
var ContactListItem = require('views/contactListItem');
|
|
|
|
|
|
module.exports = BasePage.extend({
|
|
template: templates.pages.main,
|
|
initialize: function (spec) {
|
|
this.render();
|
|
},
|
|
render: function () {
|
|
this.basicRender();
|
|
this.collectomatic(me.contacts, ContactListItem, {
|
|
containerEl: this.$('#contactList')
|
|
}, {quick: true});
|
|
this.handleBindings();
|
|
return this;
|
|
}
|
|
});
|
|
}, "pages/wrapper": function(exports, require, module) {var BasePage = require('pages/base'),
|
|
templates = require('templates');
|
|
|
|
|
|
module.exports = BasePage.extend({
|
|
template: templates.pages.wrapper,
|
|
initialize: function (spec) {
|
|
this.url = spec.url;
|
|
},
|
|
render: function () {
|
|
this.basicRender();
|
|
this.$el.load(this.url);
|
|
return this;
|
|
}
|
|
});
|
|
}, "router": function(exports, require, module) {/*global app*/
|
|
var Backbone = require('backbone'),
|
|
staticPage = function (url) {
|
|
return function () {
|
|
var View = require('pages/wrapper');
|
|
app.renderPage(new View({
|
|
url: url
|
|
}));
|
|
};
|
|
};
|
|
|
|
|
|
|
|
module.exports = Backbone.Router.extend({
|
|
routes: {
|
|
'': 'main',
|
|
'info/:jid': 'info'
|
|
},
|
|
// ------- ROUTE HANDLERS ---------
|
|
main: function () {
|
|
var View = require('pages/main');
|
|
app.renderPage(new View({
|
|
model: me
|
|
}));
|
|
},
|
|
info: function (jid) {
|
|
var View = require('pages/info');
|
|
var contact = me.contacts.get(jid);
|
|
if (contact) {
|
|
app.renderPage(new View({
|
|
model: contact
|
|
}));
|
|
} else {
|
|
app.navigate('/');
|
|
}
|
|
}
|
|
});
|
|
}, "views/contactList": function(exports, require, module) {/*global $*/
|
|
var StrictView = require('strictview');
|
|
var templates = require('templates');
|
|
var _ = require('underscore');
|
|
|
|
|
|
module.exports = StrictView.extend({
|
|
template: templates.includes.contactList,
|
|
initialize: function (opts) {
|
|
this.containerEl = opts.containerEl;
|
|
this.bindomatic(this.collection, 'add', this.handleAddContact);
|
|
},
|
|
render: function () {
|
|
this.handleBindings();
|
|
this.$contactList = this.$('#contactList');
|
|
return this;
|
|
},
|
|
handleAddContact: function (model) {
|
|
var view = new ContactListItem({model: model});
|
|
this.$contactList.append(view.render().el);
|
|
}
|
|
});
|
|
}, "views/contactListItem": function(exports, require, module) {/*global $*/
|
|
var StrictView = require('strictview');
|
|
var templates = require('templates');
|
|
var _ = require('underscore');
|
|
var ContactListItemResource = require('views/contactListItemResource');
|
|
|
|
|
|
module.exports = StrictView.extend({
|
|
template: templates.includes.contactListItem,
|
|
classBindings: {
|
|
show: '',
|
|
subscription: '',
|
|
chatState: ''
|
|
},
|
|
contentBindings: {
|
|
displayName: '.name',
|
|
status: '.status'
|
|
},
|
|
imageBindings: {
|
|
avatar: '.avatar img'
|
|
},
|
|
events: {
|
|
'click': 'getInfo'
|
|
},
|
|
initialize: function (opts) {
|
|
this.containerEl = opts.containerEl;
|
|
this.render();
|
|
},
|
|
render: function () {
|
|
this.subViewRender({context: {contact: this.model}});
|
|
//this.collectomatic(this.model.resources, ContactListItemResource, {
|
|
// containerEl: this.$('.resources')
|
|
//});
|
|
this.handleBindings();
|
|
return this;
|
|
},
|
|
getInfo: function () {
|
|
app.navigate('info/' + this.model.jid);
|
|
}
|
|
});
|
|
}, "views/contactListItemResource": function(exports, require, module) {/*global $*/
|
|
var StrictView = require('strictview');
|
|
var templates = require('templates');
|
|
var _ = require('underscore');
|
|
|
|
|
|
module.exports = StrictView.extend({
|
|
template: templates.includes.contactListItemResource,
|
|
classBindings: {
|
|
show: ''
|
|
},
|
|
contentBindings: {
|
|
jid: '.jid',
|
|
status: '.status'
|
|
},
|
|
initialize: function (opts) {
|
|
this.containerEl = opts.containerEl;
|
|
this.render();
|
|
},
|
|
render: function () {
|
|
this.subViewRender({context: {resource: this.model}});
|
|
this.handleBindings();
|
|
return this;
|
|
}
|
|
});
|
|
}, "views/main": function(exports, require, module) {/*global ui, app*/
|
|
var BasePage = require('pages/base'),
|
|
templates = require('templates');
|
|
|
|
|
|
module.exports = BasePage.extend({
|
|
template: templates.layout,
|
|
classBindings: {
|
|
},
|
|
contentBindings: {
|
|
},
|
|
hrefBindings: {
|
|
},
|
|
events: {
|
|
},
|
|
render: function () {
|
|
this.$el.html(this.template());
|
|
this.handleBindings();
|
|
return this;
|
|
}
|
|
});
|
|
}, "views/message": function(exports, require, module) {/*global $*/
|
|
var StrictView = require('strictview');
|
|
var templates = require('templates');
|
|
var _ = require('underscore');
|
|
|
|
|
|
module.exports = StrictView.extend({
|
|
template: templates.includes.message,
|
|
classBindings: {
|
|
mine: '.message',
|
|
receiptReceived: '',
|
|
acked: '',
|
|
delayed: '',
|
|
edited: ''
|
|
},
|
|
contentBindings: {
|
|
body: '.body',
|
|
formattedTime: '.timestamp'
|
|
},
|
|
initialize: function (opts) {
|
|
this.containerEl = opts.containerEl;
|
|
this.render();
|
|
},
|
|
render: function () {
|
|
this.subViewRender({context: {message: this.model}});
|
|
this.handleBindings();
|
|
return this;
|
|
}
|
|
});
|
|
}});
|