From: David Mark on
The "base" parts.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright 2006 Google Inc. All Rights Reserved.

/**
* @fileoverview Bootstrap for the Google JS Library (Closure).
*
* In uncompiled mode base.js will write out Closure's deps file,
unless the
* global <code>CLOSURE_NO_DEPS</code> is set to true. This allows
projects to
* include their own deps file(s) from different locations.
*
*/

/**
* @define {boolean} Overridden to true by the compiler when --
closure_pass
* or --mark_as_compiled is specified.
*/
var COMPILED = false;

/**
* Base namespace for the Closure library. Checks to see goog is
* already defined in the current scope before assigning to prevent
* clobbering if base.js is loaded more than once.
*/
var goog = goog || {}; // Check to see if already defined in current
scope


/**
* Reference to the global context. In most cases this will be
'window'.
*/
goog.global = this;


/**
* @define {boolean} DEBUG is provided as a convenience so that
debugging code
* that should not be included in a production js_binary can be easily
stripped
* by specifying --define goog.DEBUG=false to the JSCompiler. For
example, most
* toString() methods should be declared inside an "if (goog.DEBUG)"
conditional
* because they are generally used for debugging purposes and it is
difficult
* for the JSCompiler to statically determine whether they are used.
*/
goog.DEBUG = true;


/**
* @define {string} LOCALE defines the locale being used for
compilation. It is
* used to select locale specific data to be compiled in js binary.
BUILD rule
* can specify this value by "--define goog.LOCALE=<locale_name>" as
JSCompiler
* option.
*
* Take into account that the locale code format is important. You
should use
* the canonical Unicode format with hyphen as a delimiter. Language
must be
* lowercase, Language Script - Capitalized, Region - UPPERCASE.
* There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN.
*
* See more info about locale codes here:
* http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers
*
* For language codes you should use values defined by ISO 693-1. See
it here
* http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one
exception from
* this rule: the Hebrew language. For legacy reasons the old code
(iw) should
* be used instead of the new code (he), see http://wiki/Main/IIISynonyms.
*/
goog.LOCALE = 'en'; // default to en


/**
* Indicates whether or not we can call 'eval' directly to eval code
in the
* global scope. Set to a Boolean by the first call to goog.globalEval
(which
* empirically tests whether eval works for globals). @see
goog.globalEval
* @type {boolean?}
* @private
*/
goog.evalWorksForGlobals_ = null;


/**
* Creates object stubs for a namespace. When present in a file,
goog.provide
* also indicates that the file defines the indicated object. Calls to
* goog.provide are resolved by the compiler if --closure_pass is set.
* @param {string} name name of the object that this file defines.
*/
goog.provide = function(name) {
if (!COMPILED) {
// Ensure that the same namespace isn't provided twice. This is
intended
// to teach new developers that 'goog.provide' is effectively a
variable
// declaration. And when JSCompiler transforms goog.provide into a
real
// variable declaration, the compiled JS should work the same as
the raw
// JS--even when the raw JS uses goog.provide incorrectly.
if (goog.getObjectByName(name) && !goog.implicitNamespaces_[name])
{
throw Error('Namespace "' + name + '" already declared.');

Bad form. Throw new Error.

}

var namespace = name;
while ((namespace = namespace.substring(0, namespace.lastIndexOf
('.')))) {
goog.implicitNamespaces_[namespace] = true;
}
}

goog.exportPath_(name);
};


if (!COMPILED) {
/**
* Namespaces implicitly defined by goog.provide. For example,
* goog.provide('goog.events.Event') implicitly declares
* that 'goog' and 'goog.events' must be namespaces.
*
* @type {Object}
* @private
*/
goog.implicitNamespaces_ = {};
}


This is nowhere near as clever as it thinks it is.


/**
* Builds an object structure for the provided namespace path,
* ensuring that names that already exist are not overwritten. For
* example:
* "a.b.c" -> a = {};a.b={};a.b.c={};
* Used by goog.provide and goog.exportSymbol.
* @param {string} name name of the object that this file defines.
* @param {Object} opt_object the object to expose at the end of the
path.
* @param {Object} opt_objectToExportTo The object to add the path to;
default
* is |goog.global|.
* @private
*/
goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) {
var parts = name.split('.');
var cur = opt_objectToExportTo || goog.global;

// Internet Explorer exhibits strange behavior when throwing errors
from
// methods externed in this manner. See the
testExportSymbolExceptions in
// base_test.html for an example.
if (!(parts[0] in cur) && cur.execScript) {
cur.execScript('var ' + parts[0]);
}

// Certain browsers cannot parse code in the form for((a in b); c;);
// This pattern is produced by the JSCompiler when it collapses the
// statement above into the conditional loop below. To prevent this
from
// happening, use a for-loop and reserve the init logic as below.

// Parentheses added to eliminate strict JS warning in Firefox.


Cargo cult. Strict JS warnings are not your master.


for (var part; parts.length && (part = parts.shift());) {
if (!parts.length && goog.isDef(opt_object)) {
// last part and we have an object; use it
cur[part] = opt_object;
} else if (cur[part]) {
cur = cur[part];
} else {
cur = cur[part] = {};
}
}
};


/**
* Returns an object based on its fully qualified external name. If
you are
* using a compilation pass that renames property names beware that
using this
* function will not find renamed properties.
*
* @param {string} name The fully qualified name.
* @param {Object} opt_obj The object within which to look; default is
* |goog.global|.
* @return {Object?} The object or, if not found, null.
*/
goog.getObjectByName = function(name, opt_obj) {
var parts = name.split('.');
var cur = opt_obj || goog.global;
for (var part; part = parts.shift(); ) {
if (cur[part]) {
cur = cur[part];
} else {
return null;
}
}
return cur;
};


/**
* Globalizes a whole namespace, such as goog or goog.lang.
*
* @param {Object} obj The namespace to globalize.
* @param {Object} opt_global The object to add the properties to.
* @deprecated Properties may be explicitly exported to the global
scope, but
* this should no longer be done in bulk.
*/
goog.globalize = function(obj, opt_global) {
var global = opt_global || goog.global;
for (var x in obj) {
global[x] = obj[x];
}
};


Worthless.


/**
* Adds a dependency from a file to the files it requires.
* @param {string} relPath The path to the js file.
* @param {Array} provides An array of strings with the names of the
objects
* this file provides.
* @param {Array} requires An array of strings with the names of the
objects
* this file requires.
*/
goog.addDependency = function(relPath, provides, requires) {
if (!COMPILED) {
var provide, require;
var path = relPath.replace(/\\/g, '/');
var deps = goog.dependencies_;
for (var i = 0; provide = provides[i]; i++) {
deps.nameToPath[provide] = path;
if (!(path in deps.pathToNames)) {
deps.pathToNames[path] = {};
}
deps.pathToNames[path][provide] = true;
}
for (var j = 0; require = requires[j]; j++) {
if (!(path in deps.requires)) {
deps.requires[path] = {};
}
deps.requires[path][require] = true;
}
}
};


/**
* Implements a system for the dynamic resolution of dependencies
* that works in parallel with the BUILD system. Note that all calls
* to goog.require will be stripped by the JSCompiler when the
* --closure_pass option is used.
* @param {string} rule Rule to include, in the form
goog.package.part.
*/
goog.require = function(rule) {

// if the object already exists we do not need do do anything
// TODO: If we start to support require based on file name this has
// to change
// TODO: If we allow goog.foo.* this has to change
// TODO: If we implement dynamic load after page load we should
probably
// not remove this code for the compiled output


Probably not. ;) Lot of TODO's in here too.


if (!COMPILED) {
if (goog.getObjectByName(rule)) {
return;
}
var path = goog.getPathFromDeps_(rule);
if (path) {
goog.included_[path] = true;
goog.writeScripts_();


The trailing underscores are a novelty.


} else {
var errorMessage = 'goog.require could not find: ' + rule;
if (goog.global.console) {
goog.global.console['error'](errorMessage);
}

Console pollution.

throw Error(errorMessage);
}
}
};


/**
* Whether goog.require should throw an exception if it fails.
* @type {boolean}
*/
goog.useStrictRequires = false;


/**
* Path for included scripts
* @type {string}
*/
goog.basePath = '';


/**
* A hook for overriding the base path.
* @type {string|undefined}
*/
goog.global.CLOSURE_BASE_PATH;


/**
* Whether to write out Closure's deps file. By default,
* the deps are written.
* @type {boolean|undefined}
*/
goog.global.CLOSURE_NO_DEPS;


/**
* Null function used for default values of callbacks, etc.
* @type {!Function}
*/
goog.nullFunction = function() {};


/**
* The identity function. Returns its first argument.
*
* @param {*} var_args The arguments of the function.
* @return {*} The first argument.
* @deprecated Use goog.functions.identity instead.
*/
goog.identityFunction = function(var_args) {
return arguments[0];
};


Or use nothing.


/**
* When defining a class Foo with an abstract method bar(), you can
do:
*
* Foo.prototype.bar = goog.abstractMethod
*
* Now if a subclass of Foo fails to override bar(), an error
* will be thrown when bar() is invoked.
*
* Note: This does not take the name of the function to override as
* an argument because that would make it more difficult to obfuscate
* our JavaScript code.
*
* @type {!Function}
* @throws {Error} when invoked to indicate the method should be
* overridden.
*/
goog.abstractMethod = function() {
throw Error('unimplemented abstract method');
};


Much ado about an exception.


/**
* Adds a {@code getInstance} static method that always return the
same instance
* object.
* @param {!Function} ctor The constructor for the class to add the
static
* method to.
*/
goog.addSingletonGetter = function(ctor) {
ctor.getInstance = function() {
return ctor.instance_ || (ctor.instance_ = new ctor());
};
};


Whatever.


if (!COMPILED) {
/**
* Object used to keep track of urls that have already been added.
This
* record allows the prevention of circular dependencies.
* @type {Object}
* @private
*/
goog.included_ = {};


/**
* This object is used to keep track of dependencies and other data
that is
* used for loading scripts
* @private
* @type {Object}
*/
goog.dependencies_ = {
pathToNames: {}, // 1 to many
nameToPath: {}, // 1 to 1
requires: {}, // 1 to many
visited: {}, // used when resolving dependencies to prevent us
from
// visiting the file twice
written: {} // used to keep track of script files we have written
};


/**
* Tries to detect whether is in the context of an HTML document.
* @return {boolean} True if it looks like HTML document.
* @private
*/
goog.inHtmlDocument_ = function() {
var doc = goog.global.document;
return typeof doc != 'undefined' &&
'write' in doc; // XULDocument misses write.
};

/**
* Tries to detect the base path of the base.js script that
bootstraps Closure
* @private
*/
goog.findBasePath_ = function() {
if (!goog.inHtmlDocument_()) {
return;
}
var doc = goog.global.document;
if (goog.global.CLOSURE_BASE_PATH) {
goog.basePath = goog.global.CLOSURE_BASE_PATH;
return;
}
var scripts = doc.getElementsByTagName('script');


And bullshit if this based on Mochikit, unless that thing is based on
Dojo.


// Search backwards since the current script is in almost all
cases the one
// that has base.js.
for (var i = scripts.length - 1; i >= 0; --i) {
var src = scripts[i].src;
var l = src.length;
if (src.substr(l - 7) == 'base.js') {
goog.basePath = src.substr(0, l - 7);

https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/String/substr

"ECMA Version: None, although ECMA-262 ed. 3 has a non-normative
section suggesting uniform semantics for substr"

return;
}
}
};


/**
* Writes a script tag if, and only if, that script hasn't already
been added
* to the document. (Must be called at execution time)
* @param {string} src Script source.
* @private
*/
goog.writeScriptTag_ = function(src) {
if (goog.inHtmlDocument_() &&
!goog.dependencies_.written[src]) {
goog.dependencies_.written[src] = true;
var doc = goog.global.document;
doc.write('<script type="text/javascript" src="' +
src + '"></' + 'script>');

LOL. They do know all the classics.


}
};


/**
* Resolves dependencies based on the dependencies added using
addDependency
* and calls writeScriptTag_ in the correct order.
* @private
*/
goog.writeScripts_ = function() {
// the scripts we need to write this time
var scripts = [];
var seenScript = {};
var deps = goog.dependencies_;

function visitNode(path) {
if (path in deps.written) {
return;
}

// we have already visited this one. We can get here if we have
cyclic
// dependencies
if (path in deps.visited) {
if (!(path in seenScript)) {
seenScript[path] = true;
scripts.push(path);
}
return;
}

deps.visited[path] = true;

if (path in deps.requires) {
for (var requireName in deps.requires[path]) {
if (requireName in deps.nameToPath) {
visitNode(deps.nameToPath[requireName]);
} else if (!goog.getObjectByName(requireName)) {
// If the required name is defined, we assume that this
// dependency was bootstapped by other means. Otherwise,
// throw an exception.
throw Error('Undefined nameToPath for ' + requireName);
}
}
}

if (!(path in seenScript)) {
seenScript[path] = true;
scripts.push(path);
}
}

for (var path in goog.included_) {
if (!deps.written[path]) {
visitNode(path);
}
}

for (var i = 0; i < scripts.length; i++) {
if (scripts[i]) {
goog.writeScriptTag_(goog.basePath + scripts[i]);
} else {
throw Error('Undefined script input');
}
}
};


/**
* Looks at the dependency rules and tries to determine the script
file that
* fulfills a particular rule.
* @param {string} rule In the form goog.namespace.Class or
project.script.
* @return {string?} Url corresponding to the rule, or null.
* @private
*/
goog.getPathFromDeps_ = function(rule) {
if (rule in goog.dependencies_.nameToPath) {
return goog.dependencies_.nameToPath[rule];
} else {


Unneeded else. Bookmark JSLint.


return null;
}
};

goog.findBasePath_();

// Allow projects to manage the deps files themselves.


Getting way ahead of themselves.


if (!goog.global.CLOSURE_NO_DEPS) {
goog.writeScriptTag_(goog.basePath + 'deps.js');
}
}



//
==============================================================================
// Language Enhancements
//
==============================================================================


Grimace.


/**
* This is a "fixed" version of the typeof operator. It differs from
the typeof
* operator in such a way that null returns 'null' and arrays return
'array'.
* @param {*} value The value to get the type of.
* @return {string} The name of the type.
*/


Are host objects allowed?


goog.typeOf = function(value) {


This ought to be good for a laugh.


var s = typeof value;
if (s == 'object') {
if (value) {
// We cannot use constructor == Array or instanceof Array
because
// different frames have different Array objects. In IE6, if the
iframe
// where the array was created is destroyed, the array loses its
// prototype. Then dereferencing val.splice here throws an
exception, so
// we can't use goog.isFunction. Calling typeof directly returns
'unknown'
// so that will work. In this case, this function will return
false and
// most array functions will still work because the array is
still
// array-like (supports length and []) even though it has lost
its
// prototype.
// Mark Miller noticed that Object.prototype.toString


Way late. :)


// allows access to the unforgeable [[Class]] property.
// 15.2.4.2 Object.prototype.toString ( )
// When the toString method is called, the following steps are
taken:
// 1. Get the [[Class]] property of this object.
// 2. Compute a string value by concatenating the three
strings
// "[object ", Result(1), and "]".
// 3. Return Result(2).
// and this behavior survives the destruction of the execution
context.
if (value instanceof Array || // Works quickly in same
execution context.



// If value is from a different execution context then
// !(value instanceof Object), which lets us early out in
the common
// case when value is from the same context but not an
array.
// The {if (value)} check above means we don't have to worry
about
// undefined behavior of Object.prototype.toString on null/
undefined.
//
// HACK: In order to use an Object prototype method on the
arbitrary
// value, the compiler requires the value be cast to type
Object,
// even though the ECMA spec explicitly allows it.


What does that mean?


(!(value instanceof Object) &&
(Object.prototype.toString.call(
/** @type {Object} */ (value)) == '[object Array]') ||

// In IE all non value types are wrapped as objects across
window


Non value types?


// boundaries (not iframe though) so we have to do object
detection
// for this edge case
typeof value.length == 'number' &&
typeof value.splice != 'undefined' &&
typeof value.propertyIsEnumerable != 'undefined' &&
!value.propertyIsEnumerable('splice')

Doesn't look like a duck to me. :)


)) {
return 'array';
}
// HACK: There is still an array case that fails.


Oh, and they know it (yet this design persists).


// function ArrayImpostor() {}
// ArrayImpostor.prototype = [];
// var impostor = new ArrayImpostor;


How very interesting.


// this can be fixed by getting rid of the fast path
// (value instanceof Array) and solely relying on
// (value && Object.prototype.toString.vall(value) === '[object
Array]')
// but that would require many more function calls and is not
warranted
// unless closure code is receiving objects from untrusted
sources.


More hot air. And there's plenty more cases that will break their
duck typing.


// IE in cross-window calls does not correctly marshal the
function type


Marshal? What language do they think they are writing?


// (it appears just as an object) so we cannot use just typeof
val ==
// 'function'. However, if the object has a call property, it is
a
// function.
if (!(value instanceof Object) &&
(Object.prototype.toString.call(
/** @type {Object} */ (value)) == '[object Function]' ||
typeof value.call != 'undefined' &&
typeof value.propertyIsEnumerable != 'undefined' &&
!value.propertyIsEnumerable('call'))) {
return 'function';
}


} else {
return 'null';
}

// In Safari typeof nodeList returns 'function', and on Firefox
// typeof behaves similarly for HTML{Applet,Embed,Object}Elements
// and RegExps.


So what?


// We would like to return object for those and we can


Why?


// detect an invalid function by making sure that the function
// object has a call method.


What is an invalid function? Where is the documentation that defines
its output.


} else if (s == 'function' && typeof value.call == 'undefined') {
return 'object';
}

I knew it. They think this is appropriate for host objects.

return s;
};


/**
* Safe way to test whether a property is enumarable. It allows
testing
* for enumerable on objects where 'propertyIsEnumerable' is
overridden or
* does not exist (like DOM nodes in IE). Does not use browser native
* Object.propertyIsEnumerable.
* @param {Object} object The object to test if the property is
enumerable.
* @param {string} propName The property name to check for.
* @return {boolean} True if the property is enumarable.
* @private
*/


Enumerable.


goog.propertyIsEnumerableCustom_ = function(object, propName) {
// KJS in Safari 2 is not ECMAScript compatible and lacks crucial
methods
// such as propertyIsEnumerable. We therefore use a workaround.
// Does anyone know a more efficient work around?


Yes. Lots of people do, but they don't waste time writing crappy
general-purpose libraries. That's reserved for "hackers".


if (propName in object) {
for (var key in object) {
if (key == propName &&
Object.prototype.hasOwnProperty.call(object, propName)) {


D'oh! Just sank Safari 2 (and others). So why are there sniffs for
Safari 2 in the DOM module?


return true;
}
}
}
return false;
};


/**
* Safe way to test whether a property is enumarable. It allows
testing
* for enumerable on objects where 'propertyIsEnumerable' is
overridden or
* does not exist (like DOM nodes in IE).
* @param {Object} object The object to test if the property is
enumerable.
* @param {string} propName The property name to check for.
* @return {boolean} True if the property is enumarable.
* @private
*/
goog.propertyIsEnumerable_ = function(object, propName) {
// In IE if object is from another window, cannot use
propertyIsEnumerable
// from this window's Object. Will raise a 'JScript object expected'
error.
if (object instanceof Object) {
return Object.prototype.propertyIsEnumerable.call(object,
propName);
} else {
return goog.propertyIsEnumerableCustom_(object, propName);
}
};

Though most of this is a retread. I'll have to admit, I've never seen
anything quite like this bit.

/**
* Returns true if the specified value is not |undefined|.
* WARNING: Do not use this to test if an object has a property. Use
the in
* operator instead. Additionally, this function assumes that the
global
* undefined variable has not been redefined.
* @param {*} val Variable to test.
* @return {boolean} Whether variable is defined.
*/
goog.isDef = function(val) {
return val !== undefined;
};


Worthless waste of time and space.


/**
* Returns true if the specified value is |null|
* @param {*} val Variable to test.
* @return {boolean} Whether variable is null.
*/
goog.isNull = function(val) {
return val === null;
};


And that.


/**
* Returns true if the specified value is defined and not null
* @param {*} val Variable to test.
* @return {boolean} Whether variable is defined and not null.
*/
goog.isDefAndNotNull = function(val) {
// Note that undefined == null.


Noted. :)


return val != null;
};

Also a waste.

/**
* Returns true if the specified value is an array
* @param {*} val Variable to test.
* @return {boolean} Whether variable is an array.
*/
goog.isArray = function(val) {
return goog.typeOf(val) == 'array';

I knew it. If only they had realized they didn't need this (or the
"fixed" typeof) method for anything.

};


/**
* Returns true if the object looks like an array. To qualify as array
like
* the value needs to be either a NodeList or an object with a Number
length
* property.


Well, that's a pretty loose test.


* @param {*} val Variable to test.
* @return {boolean} Whether variable is an array.


Wrong. See three lines up.


*/
goog.isArrayLike = function(val) {
var type = goog.typeOf(val);
return type == 'array' || type == 'object' && typeof val.length ==
'number';
};


Wonder what this is used for? Argument "overloading?"


/**
* Returns true if the object looks like a Date. To qualify as Date-
like
* the value needs to be an object and have a getFullYear() function.
* @param {*} val Variable to test.
* @return {boolean} Whether variable is a like a Date.
*/
goog.isDateLike = function(val) {
return goog.isObject(val) && typeof val.getFullYear == 'function';
};


And this. Odd that in fifteen years I never needed a foundation like
this. I know some might say it is because I didn't write GMail. And
I'm proud to agree that I didn't write _that_, but still...


/**
* Returns true if the specified value is a string
* @param {*} val Variable to test.
* @return {boolean} Whether variable is a string.
*/
goog.isString = function(val) {
return typeof val == 'string';
};


Another waste.


/**
* Returns true if the specified value is a boolean
* @param {*} val Variable to test.
* @return {boolean} Whether variable is boolean.
*/
goog.isBoolean = function(val) {
return typeof val == 'boolean';
};


Again.


/**
* Returns true if the specified value is a number
* @param {*} val Variable to test.
* @return {boolean} Whether variable is a number.
*/
goog.isNumber = function(val) {
return typeof val == 'number';
};


Again.


/**
* Returns true if the specified value is a function

The question is what do the authors think is (or isn't) a function?


* @param {*} val Variable to test.
* @return {boolean} Whether variable is a function.
*/
goog.isFunction = function(val) {
return goog.typeOf(val) == 'function';
};


How do I know that these is* things are used everywhere, testing both
native and host objects? Saw a lot of isArray in the DOM module. All
programming for failure. It's just the sort of design decisions you
might have expected from JS neophytes in 2006. Lots of others came up
with the same schemes around this time (despite the public outcry from
more experienced JS programmers). Most slowly but surely adapted
their designs as much as possible to avoid the "overloading"
discrimination issues inherent to ECMAScript implementations. And
then there's Google, releasing this mess at the end of 2009.


/**
* Returns true if the specified value is an object. This includes
arrays
* and functions.
* @param {*} val Variable to test.
* @return {boolean} Whether variable is an object.
*/
goog.isObject = function(val) {
var type = goog.typeOf(val);
return type == 'object' || type == 'array' || type == 'function';
};


Worthless.


/**
* Adds a hash code field to an object. The hash code is unique for
the
* given object.
* @param {Object} obj The object to get the hash code for.
* @return {number} The hash code for the object.
*/
goog.getHashCode = function(obj) {
// In IE, DOM nodes do not extend Object so they do not have this
method.
// we need to check hasOwnProperty because the proto might have this
set.

// TODO: There is a proposal to add hashcode as a global function to
JS2
// we should keep track of this process so we can use
that whenever
// it starts to show up in the real world.
if (obj.hasOwnProperty && obj.hasOwnProperty
(goog.HASH_CODE_PROPERTY_)) {


Leave hasOwnProperty alone.


return obj[goog.HASH_CODE_PROPERTY_];
}
if (!obj[goog.HASH_CODE_PROPERTY_]) {
obj[goog.HASH_CODE_PROPERTY_] = ++goog.hashCodeCounter_;
}
return obj[goog.HASH_CODE_PROPERTY_];
};


/**
* Removes the hash code field from an object.
* @param {Object} obj The object to remove the field from.
*/
goog.removeHashCode = function(obj) {
// DOM nodes in IE are not instance of Object and throws exception
// for delete. Instead we try to use removeAttribute


The comments read like randomly chosen words. Never revealing the
slightest hint of comprehension. Always explanations of guesswork.


if ('removeAttribute' in obj) {


Don't use - in - with host objects.


obj.removeAttribute(goog.HASH_CODE_PROPERTY_);

Sure, removeAttribute is to DOM nodes as delete is to Object
objects. :)

And the behavior of that method is controlled by a large button next
to Refresh in IE8.

http://www.cinsoft.net/attributes.html

}
/** @preserveTry */
try {
delete obj[goog.HASH_CODE_PROPERTY_];
} catch (ex) {
}
};


/**
* Name for hash code property. Initialized in a way to help avoid
collisions
* with other closure javascript on the same page.
* @type {string}
* @private
*/
goog.HASH_CODE_PROPERTY_ = 'closure_hashCode_' +
Math.floor(Math.random() * 2147483648).toString(36);


/**
* Counter for hash codes.
* @type {number}
* @private
*/
goog.hashCodeCounter_ = 0;


/**
* Clone an object/array (recursively)
* @param {Object} proto Object to clone.
* @return {Object} Clone of x;.
*/
goog.cloneObject = function(proto) {
var type = goog.typeOf(proto);


Never design a system that relies on differentiating between Object
and Array objects. It's just a silly thing to do, knowing the
limitations of the language.


if (type == 'object' || type == 'array') {
if (proto.clone) {
// TODO Change to proto.clone() once # args warn is removed


The minifier (compiler in Google-speak) is not your master.


return proto.clone.call(proto);
}
var clone = type == 'array' ? [] : {};
for (var key in proto) {


For-in on an array (or host object?)


clone[key] = goog.cloneObject(proto[key]);
}
return clone;
}


What is this about? Documentation above said Object or Array.

return proto;
};


/**
* Forward declaration for the clone method. This is necessary until
the
* compiler can better support duck-typing constructs as used in
* goog.cloneObject.
*
* TODO: Remove once the JSCompiler can infer that the check for
* proto.clone is safe in goog.cloneObject.
*
* @type {Function}
*/
Object.prototype.clone;


/**
* Partially applies this function to a particular 'this object' and
zero or
* more arguments. The result is a new function with some arguments of
the first
* function pre-filled and the value of |this| 'pre-
specified'.<br><br>
*
* Remaining arguments specified at call-time are appended to the pre-
* specified ones.<br><br>
*
* Also see: {@link #partial}.<br><br>
*
* Usage:
* <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2');
* barMethBound('arg3', 'arg4');</pre>
*
* @param {Function} fn A function to partially apply.
* @param {Object|undefined} selfObj Specifies the object which |this|
should
* point to when the function is run. If the value is null or
undefined, it
* will default to the global object.
* @param {*} var_args Additional arguments that are partially
* applied to the function.
*
* @return {!Function} A partially-applied form of the function bind()
was
* invoked as a method of.
*/
goog.bind = function(fn, selfObj, var_args) {
var context = selfObj || goog.global;

if (arguments.length > 2) {
var boundArgs = Array.prototype.slice.call(arguments, 2);
return function() {
// Prepend the bound arguments to the current arguments.
var newArgs = Array.prototype.slice.call(arguments);
Array.prototype.unshift.apply(newArgs, boundArgs);
return fn.apply(context, newArgs);
};

} else {
return function() {
return fn.apply(context, arguments);
};
}
};


Looks like the first few links in a chain of references. Bind a
function to a DOM node and attach it as a listener and the circle is
complete.


/**
* Like bind(), except that a 'this object' is not required. Useful
when the
* target function is already bound.
*
* Usage:
* var g = partial(f, arg1, arg2);
* g(arg3, arg4);
*
* @param {Function} fn A function to partially apply.
* @param {*} var_args Additional arguments that are partially
* applied to fn.
* @return {!Function} A partially-applied form of the function bind()
was
* invoked as a method of.
*/
goog.partial = function(fn, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
// Prepend the bound arguments to the current arguments.
var newArgs = Array.prototype.slice.call(arguments);
newArgs.unshift.apply(newArgs, args);
return fn.apply(this, newArgs);
};
};


/**
* Copies all the members of a source object to a target object.
* @param {Object} target Target.
* @param {Object} source Source.
* @deprecated Use goog.object.extend instead.
*/
goog.mixin = function(target, source) {
for (var x in source) {
target[x] = source[x];
}

// For IE the for-in-loop does not contain any properties that are
not
// enumerable on the prototype object (for example, isPrototypeOf
from
// Object.prototype) but also it will not include 'replace' on
objects that
// extend String and change 'replace' (not that it is common for
anyone to
// extend anything except Object).


Is this a library or the diary of a student?


};


/**
* @return {number} An integer value representing the number of
milliseconds
* between midnight, January 1, 1970 and the current time.
*/
goog.now = Date.now || (function() {
// Unary plus operator converts its operand to a number which in the
case of
// a date is done by calling getTime().
return +new Date();
});


/**
* Evals javascript in the global scope. In IE this uses execScript,
other
* browsers use goog.global.eval. If goog.global.eval does not
evaluate in the
* global scope (for example, in Safari), appends a script tag
instead.
* Throws an exception if neither execScript or eval is defined.
* @param {string} script JavaScript string.
*/
goog.globalEval = function(script) {
if (goog.global.execScript) {
goog.global.execScript(script, 'JavaScript');
} else if (goog.global.eval) {
// Test to see if eval works
if (goog.evalWorksForGlobals_ == null) {
goog.global.eval('var _et_ = 1;');
if (typeof goog.global['_et_'] != 'undefined') {
delete goog.global['_et_'];


Delete? They declared it!


goog.evalWorksForGlobals_ = true;
} else {
goog.evalWorksForGlobals_ = false;
}
}

if (goog.evalWorksForGlobals_) {
goog.global.eval(script);
} else {
var doc = goog.global.document;
var scriptElt = doc.createElement('script');
scriptElt.type = 'text/javascript';
scriptElt.defer = false;


Voodoo.


// NOTE: can't use .innerHTML since "t('<test>')" will fail and
// .text doesn't work in Safari 2. Therefore we append a text
node.


Ridiculous explanation for ridiculous code. Easy enough to test if
the text property works.


scriptElt.appendChild(doc.createTextNode(script));

All a bunch of tangled up object inferences. This will throw an
exception in IE, but - by coincidence - IE never gets here. Easy
enough to check the canHaveChildren property of the element.


doc.body.appendChild(scriptElt);
doc.body.removeChild(scriptElt);
}
} else {
throw Error('goog.globalEval not available');


How does that help? This method shouldn't exist if it is unworkable.
Are developers to wrap every low-level API call in a try-catch?


}
};


/**
* A macro for defining composite types.
*
* By assigning goog.typedef to a name, this tells JSCompiler that
this is not
* the name of a class, but rather it's the name of a composite type.
*
* For example,
* /** @type {Array|NodeList} / goog.ArrayLike = goog.typedef;
* will tell JSCompiler to replace all appearances of goog.ArrayLike
in type
* definitions with the union of Array and NodeList.
*
* Does nothing in uncompiled code.
*/
goog.typedef = true;


/**
* Optional map of CSS class names to obfuscated names used with
* goog.getCssName().
* @type {Object|undefined}
* @private
* @see goog.setCssNameMapping
*/
goog.cssNameMapping_;


/**
* Handles strings that are intended to be used as CSS class names.
*
* Without JS Compiler the arguments are simple joined with a hyphen
and passed
* through unaltered.
*
* With the JS Compiler the arguments are inlined, e.g:
* var x = goog.getCssName('foo');
* var y = goog.getCssName(this.baseClass, 'active');
* becomes:
* var x= 'foo';
* var y = this.baseClass + '-active';
*
* If a CSS renaming map is passed to the compiler it will replace
symbols in
* the classname. If one argument is passed it will be processed, if
two are
* passed only the modifier will be processed, as it is assumed the
first
* argument was generated as a result of calling goog.getCssName.
*
* Names are split on 'hyphen' and processed in parts such that the
following
* are equivalent:
* var base = goog.getCssName('baseclass');
* goog.getCssName(base, 'modifier');
* goog.getCSsName('baseclass-modifier');
*
* If any part does not appear in the renaming map a warning is logged
and the
* original, unobfuscated class name is inlined.
*
* @param {string} className The class name.
* @param {string} opt_modifier A modifier to be appended to the class
name.
* @return {string} The class name or the concatenation of the class
name and
* the modifier.
*/
goog.getCssName = function(className, opt_modifier) {
var cssName = className + (opt_modifier ? '-' + opt_modifier : '');
return (goog.cssNameMapping_ && (cssName in goog.cssNameMapping_)) ?
goog.cssNameMapping_[cssName] : cssName;
};


/**
* Sets the map to check when returning a value from goog.getCssName
(). Example:
* <pre>
* goog.setCssNameMapping({
* "goog-menu": "a",
* "goog-menu-disabled": "a-b",
* "CSS_LOGO": "b",
* "hidden": "c"
* });
*
* // The following evaluates to: "a a-b".
* goog.getCssName('goog-menu') + ' ' + goog.getCssName('goog-menu',
'disabled')
* </pre>
* When declared as a map of string literals to string literals, the
JSCompiler
* will replace all calls to goog.getCssName() using the supplied map
if the
* --closure_pass flag is set.
*
* @param {!Object} mapping A map of strings to strings where keys are
possible
* arguments to goog.getCssName() and values are the corresponding
values
* that should be returned.
*/
goog.setCssNameMapping = function(mapping) {
goog.cssNameMapping_ = mapping;
};


/**
* Abstract implementation of goog.getMsg for use with localized
messages.
* @param {string} str Translatable string, places holders in the form
{$foo}.
* @param {Object} opt_values Map of place holder name to value.
* @return {string} message with placeholders filled.
*/
goog.getMsg = function(str, opt_values) {
var values = opt_values || {};
for (var key in values) {
str = str.replace(new RegExp('\\{\\$' + key + '\\}', 'gi'), values
[key]);
}
return str;
};


/**
* Exposes an unobfuscated global namespace path for the given object.
* Note that fields of the exported object *will* be obfuscated,
* unless they are exported in turn via this function or
* goog.exportProperty
*
* <p>Also handy for making public items that are defined in anonymous
* closures.
*
* ex. goog.exportSymbol('Foo', Foo);
*
* ex. goog.exportSymbol('public.path.Foo.staticFunction',
* Foo.staticFunction);
* public.path.Foo.staticFunction();
*
* ex. goog.exportSymbol('public.path.Foo.prototype.myMethod',
* Foo.prototype.myMethod);
* new public.path.Foo().myMethod();
*
* @param {string} publicPath Unobfuscated name to export.
* @param {Object} object Object the name should point to.
* @param {Object} opt_objectToExportTo The object to add the path to;
default
* is |goog.global|.
*/
goog.exportSymbol = function(publicPath, object, opt_objectToExportTo)
{
goog.exportPath_(publicPath, object, opt_objectToExportTo);
};


/**
* Exports a property unobfuscated into the object's namespace.
* ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction);
* ex. goog.exportProperty(Foo.prototype, 'myMethod',
Foo.prototype.myMethod);
* @param {Object} object Object whose static property is being
exported.
* @param {string} publicName Unobfuscated name to export.
* @param {Object} symbol Object the name should point to.
*/
goog.exportProperty = function(object, publicName, symbol) {
object[publicName] = symbol;
};


Why not call this setProperty?


/**
* Inherit the prototype methods from one constructor into another.
*
* Usage:
* <pre>
* function ParentClass(a, b) { }
* ParentClass.prototype.foo = function(a) { }
*
* function ChildClass(a, b, c) {
* ParentClass.call(this, a, b);
* }
*
* goog.inherits(ChildClass, ParentClass);
*
* var child = new ChildClass('a', 'b', 'see');
* child.foo(); // works
* </pre>
*
* In addition, a superclass' implementation of a method can be
invoked
* as follows:
*
* <pre>
* ChildClass.prototype.foo = function(a) {
* ChildClass.superClass_.foo.call(this, a);
* // other code
* };
* </pre>
*
* @param {Function} childCtor Child class.
* @param {Function} parentCtor Parent class.
*/
goog.inherits = function(childCtor, parentCtor) {
/** @constructor */
function tempCtor() {};


Inefficient.


tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};

Baseless.
From: kangax on
David Mark wrote:
> The "base" parts.
[...]
> throw Error('Namespace "' + name + '" already declared.');
>
> Bad form. Throw new Error.

Why? Isn't the result identical (as per 15.11.1)? Or are there
deviations in "real world"?

[...]

> } else {
> var errorMessage = 'goog.require could not find: ' + rule;
> if (goog.global.console) {
> goog.global.console['error'](errorMessage);
> }
>
> Console pollution.

Pollution? Is there an assignment I'm not seeing?

[...]

--
kangax
From: David Mark on
On Nov 19, 12:29 am, kangax <kan...(a)gmail.com> wrote:
> David Mark wrote:
> > The "base" parts.
> [...]
> >       throw Error('Namespace "' + name + '" already declared.');
>
> > Bad form.  Throw new Error.
>
> Why? Isn't the result identical (as per 15.11.1)? Or are there
> deviations in "real world"?

Bad _form_. :)

>
> [...]
>
> >     } else {
> >       var errorMessage = 'goog.require could not find: ' + rule;
> >       if (goog.global.console) {
> >         goog.global.console['error'](errorMessage);
> >       }
>
> > Console pollution.
>
> Pollution? Is there an assignment I'm not seeing?
>

No, the pollution is in the console in the form of an extraneous
entry. And they didn't test console.error. But these two are _very_
minor compared to botching DOM node creation, attributes,
hasOwnProperty, the rampant and ill-advised "overloading", UA
sniffing, etc., etc. The whole thing is polluted with the stench of
overconfidence, as well as apathy. Not at all surprising given the
origins of the code (and how are those seen as a selling point?)
From: Garrett Smith on
David Mark wrote:
> On Nov 19, 12:29 am, kangax <kan...(a)gmail.com> wrote:
>> David Mark wrote:
>>> The "base" parts.
>> [...]
>>> throw Error('Namespace "' + name + '" already declared.');
>>> Bad form. Throw new Error.
>> Why? Isn't the result identical (as per 15.11.1)? Or are there
>> deviations in "real world"?
>
> Bad _form_. :)
>

How do you quantify "bad _form_"?

new Error over Error doesn't seem to make the code any more readable,
doesn't observably affect performance or outcome, AFAIK.

Code review should focus on fewer LOC at a time and take time for enough
proper feedback.

You'll be more likely to get positive feedback from the developers.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: David Mark on
On Nov 19, 2:40 am, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
> David Mark wrote:
> > On Nov 19, 12:29 am, kangax <kan...(a)gmail.com> wrote:
> >> David Mark wrote:
> >>> The "base" parts.
> >> [...]
> >>>       throw Error('Namespace "' + name + '" already declared.');
> >>> Bad form.  Throw new Error.
> >> Why? Isn't the result identical (as per 15.11.1)? Or are there
> >> deviations in "real world"?
>
> > Bad _form_.  :)
>
> How do you quantify "bad _form_"?
>
> new Error over Error doesn't seem to make the code any more readable,
> doesn't observably affect performance or outcome, AFAIK.

This is one where I agree with Crockford. You always use - new - with
Error and never with String, Number, etc. Imagine what String and
Number objects would do to this thing's is* methods.

>
> Code review should focus on fewer LOC at a time and take time for enough
> proper feedback.

Take time for enough proper feedback?

>
> You'll be more likely to get positive feedback from the developers.

I don't know what that means, but I don't want any feedback from the
developers. Though it will be interesting to see if any show up to
defend this thing. ISTM that even Resig and co. know this is a dog.
There has been some negative feedback out there on it, which is
positive in context.