diff --git a/README.md b/README.md
new file mode 100644
index 0000000..281f585
--- /dev/null
+++ b/README.md
@@ -0,0 +1,58 @@
+
+# Secure EcmaScript
+
+SES is a tool that allows mutually suspicious programs to share a single
+EcmaScript 5 compliant JavaScript context without interfering with each
+other.  It does this by freezing everything that is accessible in global
+scope, removing interfaces that would allow programs to interfe with
+each-other, and providing the ability to evaluate arbitrary code in
+isolation.
+
+SES is a part of the Google Caja project.  For JavaScript contexts that
+do not support EcmaScript 5, Caja depends on compiling JavaScript to a
+JavaScript subset with static verification and run-time assertions to
+maintain isolation.  With EcmaScript 5, it is possible to run isolated
+code without a compilation step or run-time checks.
+
+Initialize SES by executing these scripts in order.
+
+-   `logger.js`
+-   `repairES5.js`
+-   `WeakMap.js`
+-   `debug.js`
+-   `StringMap.js`
+-   `whitelist.js`
+-   `atLeastFreeVarNames.js`
+-   `startSES.js`
+-   `ejectorsGuardsTrademarks.js`
+-   `hookupSESPlus.js`
+
+This is an example of initializing SES in a web page.
+
+```html
+<script src="logger.js"></script>
+<script src="repairES5.js"></script>
+<script src="WeakMap.js"></script>
+<script src="debug.js"></script>
+<script src="StringMap.js"></script>
+<script src="whitelist.js"></script>
+<script src="atLeastFreeVarNames.js"></script>
+<script src="startSES.js"></script>
+<script src="ejectorsGuardsTrademarks.js"></script>
+<script src="hookupSESPlus.js"></script>
+```
+
+This is an example of initializing SES in Node.
+
+```javascript
+var FS = require("fs");
+var VM = require("vm");
+ 
+var source = FS.readFileSync("initSes.js");
+var script = new VM.Script(source);
+script.runInThisContext();
+ 
+var f = cajaVM.compileExpr("console.log('hi')");
+f({console: console});
+```
+
diff --git a/StringMap.js b/StringMap.js
new file mode 100644
index 0000000..bd4d51a
--- /dev/null
+++ b/StringMap.js
@@ -0,0 +1,62 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Implements StringMap - a map api for strings.
+ *
+ * @author Mark S. Miller
+ * @author Jasvir Nagra
+ * @overrides StringMap
+ */
+
+var StringMap;
+
+(function() {
+   "use strict";
+
+   var create = Object.create;
+   var freeze = Object.freeze;
+   function constFunc(func) {
+     func.prototype = null;
+     return freeze(func);
+   }
+
+   function assertString(x) {
+     if ('string' !== typeof(x)) {
+       throw new TypeError('Not a string: ' + String(x));
+     }
+     return x;
+   }
+
+   StringMap = function StringMap() {
+
+     var objAsMap = create(null);
+
+     return freeze({
+       get: constFunc(function(key) {
+         return objAsMap[assertString(key) + '$'];
+       }),
+       set: constFunc(function(key, value) {
+         objAsMap[assertString(key) + '$'] = value;
+       }),
+       has: constFunc(function(key) {
+         return (assertString(key) + '$') in objAsMap;
+       }),
+       'delete': constFunc(function(key) {
+         return delete objAsMap[assertString(key) + '$'];
+       })
+     });
+   };
+
+ })();
diff --git a/WeakMap.js b/WeakMap.js
new file mode 100644
index 0000000..a6bf2f5
--- /dev/null
+++ b/WeakMap.js
@@ -0,0 +1,454 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Install a leaky WeakMap emulation on platforms that
+ * don't provide a built-in one.
+ *
+ * <p>Assumes that an ES5 platform where, if {@code WeakMap} is
+ * already present, then it conforms to the anticipated ES6
+ * specification. To run this file on an ES5 or almost ES5
+ * implementation where the {@code WeakMap} specification does not
+ * quite conform, run <code>repairES5.js</code> first.
+ *
+ * @author Mark S. Miller
+ * @requires ses, crypto, ArrayBuffer, Uint8Array
+ * @overrides WeakMap, WeakMapModule
+ */
+
+/**
+ * This {@code WeakMap} emulation is observably equivalent to the
+ * ES-Harmony WeakMap, but with leakier garbage collection properties.
+ *
+ * <p>As with true WeakMaps, in this emulation, a key does not
+ * retain maps indexed by that key and (crucially) a map does not
+ * retain the keys it indexes. A map by itself also does not retain
+ * the values associated with that map.
+ *
+ * <p>However, the values associated with a key in some map are
+ * retained so long as that key is retained and those associations are
+ * not overridden. For example, when used to support membranes, all
+ * values exported from a given membrane will live for the lifetime
+ * they would have had in the absence of an interposed membrane. Even
+ * when the membrane is revoked, all objects that would have been
+ * reachable in the absence of revocation will still be reachable, as
+ * far as the GC can tell, even though they will no longer be relevant
+ * to ongoing computation.
+ *
+ * <p>The API implemented here is approximately the API as implemented
+ * in FF6.0a1 and agreed to by MarkM, Andreas Gal, and Dave Herman,
+ * rather than the offially approved proposal page. TODO(erights):
+ * upgrade the ecmascript WeakMap proposal page to explain this API
+ * change and present to EcmaScript committee for their approval.
+ *
+ * <p>The first difference between the emulation here and that in
+ * FF6.0a1 is the presence of non enumerable {@code get___, has___,
+ * set___, and delete___} methods on WeakMap instances to represent
+ * what would be the hidden internal properties of a primitive
+ * implementation. Whereas the FF6.0a1 WeakMap.prototype methods
+ * require their {@code this} to be a genuine WeakMap instance (i.e.,
+ * an object of {@code [[Class]]} "WeakMap}), since there is nothing
+ * unforgeable about the pseudo-internal method names used here,
+ * nothing prevents these emulated prototype methods from being
+ * applied to non-WeakMaps with pseudo-internal methods of the same
+ * names.
+ *
+ * <p>Another difference is that our emulated {@code
+ * WeakMap.prototype} is not itself a WeakMap. A problem with the
+ * current FF6.0a1 API is that WeakMap.prototype is itself a WeakMap
+ * providing ambient mutability and an ambient communications
+ * channel. Thus, if a WeakMap is already present and has this
+ * problem, repairES5.js wraps it in a safe wrappper in order to
+ * prevent access to this channel. (See
+ * PATCH_MUTABLE_FROZEN_WEAKMAP_PROTO in repairES5.js).
+ */
+var WeakMap;
+
+/**
+ * If this is a full <a href=
+ * "http://code.google.com/p/es-lab/wiki/SecureableES5"
+ * >secureable ES5</a> platform and the ES-Harmony {@code WeakMap} is
+ * absent, install an approximate emulation.
+ *
+ * <p>If this is almost a secureable ES5 platform, then WeakMap.js
+ * should be run after repairES5.js.
+ *
+ * <p>See {@code WeakMap} for documentation of the garbage collection
+ * properties of this WeakMap emulation.
+ */
+(function WeakMapModule() {
+  "use strict";
+
+  if (typeof ses !== 'undefined' && ses.ok && !ses.ok()) {
+    // already too broken, so give up
+    return;
+  }
+
+  if (typeof WeakMap === 'function') {
+    // assumed fine, so we're done.
+    return;
+  }
+
+  var hop = Object.prototype.hasOwnProperty;
+  var gopn = Object.getOwnPropertyNames;
+  var defProp = Object.defineProperty;
+
+  /**
+   * Holds the orginal static properties of the Object constructor,
+   * after repairES5 fixes these if necessary to be a more complete
+   * secureable ES5 environment, but before installing the following
+   * WeakMap emulation overrides and before any untrusted code runs.
+   */
+  var originalProps = {};
+  gopn(Object).forEach(function(name) {
+    originalProps[name] = Object[name];
+  });
+
+  /**
+   * Security depends on HIDDEN_NAME being both <i>unguessable</i> and
+   * <i>undiscoverable</i> by untrusted code.
+   *
+   * <p>Given the known weaknesses of Math.random() on existing
+   * browsers, it does not generate unguessability we can be confident
+   * of.
+   *
+   * <p>It is the monkey patching logic in this file that is intended
+   * to ensure undiscoverability. The basic idea is that there are
+   * three fundamental means of discovering properties of an object:
+   * The for/in loop, Object.keys(), and Object.getOwnPropertyNames(),
+   * as well as some proposed ES6 extensions that appear on our
+   * whitelist. The first two only discover enumerable properties, and
+   * we only use HIDDEN_NAME to name a non-enumerable property, so the
+   * only remaining threat should be getOwnPropertyNames and some
+   * proposed ES6 extensions that appear on our whitelist. We monkey
+   * patch them to remove HIDDEN_NAME from the list of properties they
+   * returns.
+   *
+   * <p>TODO(erights): On a platform with built-in Proxies, proxies
+   * could be used to trap and thereby discover the HIDDEN_NAME, so we
+   * need to monkey patch Proxy.create, Proxy.createFunction, etc, in
+   * order to wrap the provided handler with the real handler which
+   * filters out all traps using HIDDEN_NAME.
+   *
+   * <p>TODO(erights): Revisit Mike Stay's suggestion that we use an
+   * encapsulated function at a not-necessarily-secret name, which
+   * uses the Stiegler shared-state rights amplification pattern to
+   * reveal the associated value only to the WeakMap in which this key
+   * is associated with that value. Since only the key retains the
+   * function, the function can also remember the key without causing
+   * leakage of the key, so this doesn't violate our general gc
+   * goals. In addition, because the name need not be a guarded
+   * secret, we could efficiently handle cross-frame frozen keys.
+   */
+  var HIDDEN_NAME_PREFIX = 'weakmap:';
+  var HIDDEN_NAME = HIDDEN_NAME_PREFIX + 'ident:' + Math.random() + '___';
+
+  if (typeof crypto !== 'undefined' &&
+      typeof crypto.getRandomValues === 'function' &&
+      typeof ArrayBuffer === 'function' &&
+      typeof Uint8Array === 'function') {
+    var ab = new ArrayBuffer(25);
+    var u8s = new Uint8Array(ab);
+    crypto.getRandomValues(u8s);
+    HIDDEN_NAME = HIDDEN_NAME_PREFIX + 'rand:' +
+      Array.prototype.map.call(u8s, function(u8) {
+        return (u8 % 36).toString(36);
+      }).join('') + '___';
+  }
+
+  /**
+   * Monkey patch getOwnPropertyNames to avoid revealing the
+   * HIDDEN_NAME.
+   *
+   * <p>The ES5.1 spec requires each name to appear only once, but as
+   * of this writing, this requirement is controversial for ES6, so we
+   * made this code robust against this case. If the resulting extra
+   * search turns out to be expensive, we can probably relax this once
+   * ES6 is adequately supported on all major browsers, iff no browser
+   * versions we support at that time have relaxed this constraint
+   * without providing built-in ES6 WeakMaps.
+   */
+  defProp(Object, 'getOwnPropertyNames', {
+    value: function fakeGetOwnPropertyNames(obj) {
+      return gopn(obj).filter(function(name) {
+        return !(
+          name.substr(0, HIDDEN_NAME_PREFIX.length) == HIDDEN_NAME_PREFIX &&
+            name.substr(name.length - 3) === '___');
+      });
+    }
+  });
+
+  /**
+   * getPropertyNames is not in ES5 but it is proposed for ES6 and
+   * does appear in our whitelist, so we need to clean it too.
+   */
+  if ('getPropertyNames' in Object) {
+    defProp(Object, 'getPropertyNames', {
+      value: function fakeGetPropertyNames(obj) {
+        return originalProps.getPropertyNames(obj).filter(function(name) {
+          return name !== HIDDEN_NAME;
+        });
+      }
+    });
+  }
+
+  /**
+   * <p>To treat objects as identity-keys with reasonable efficiency
+   * on ES5 by itself (i.e., without any object-keyed collections), we
+   * need to add a hidden property to such key objects when we
+   * can. This raises several issues:
+   * <ul>
+   * <li>Arranging to add this property to objects before we lose the
+   *     chance, and
+   * <li>Hiding the existence of this new property from most
+   *     JavaScript code.
+   * <li>Preventing <i>certification theft</i>, where one object is
+   *     created falsely claiming to be the key of an association
+   *     actually keyed by another object.
+   * <li>Preventing <i>value theft</i>, where untrusted code with
+   *     access to a key object but not a weak map nevertheless
+   *     obtains access to the value associated with that key in that
+   *     weak map.
+   * </ul>
+   * We do so by
+   * <ul>
+   * <li>Making the name of the hidden property unguessable, so "[]"
+   *     indexing, which we cannot intercept, cannot be used to access
+   *     a property without knowing the name.
+   * <li>Making the hidden property non-enumerable, so we need not
+   *     worry about for-in loops or {@code Object.keys},
+   * <li>monkey patching those reflective methods that would
+   *     prevent extensions, to add this hidden property first,
+   * <li>monkey patching those methods that would reveal this
+   *     hidden property.
+   * </ul>
+   * Unfortunately, because of same-origin iframes, we cannot reliably
+   * add this hidden property before an object becomes
+   * non-extensible. Instead, if we encounter a non-extensible object
+   * without a hidden record that we can detect (whether or not it has
+   * a hidden record stored under a name secret to us), then we just
+   * use the key object itself to represent its identity in a brute
+   * force leaky map stored in the weak map, losing all the advantages
+   * of weakness for these.
+   */
+  function getHiddenRecord(key) {
+    if (key !== Object(key)) {
+      throw new TypeError('Not an object: ' + key);
+    }
+    var hiddenRecord = key[HIDDEN_NAME];
+    if (hiddenRecord && hiddenRecord.key === key) { return hiddenRecord; }
+    if (!originalProps.isExtensible(key)) {
+      // Weak map must brute force, as explained in doc-comment above.
+      return void 0;
+    }
+    var gets = [];
+    var vals = [];
+    hiddenRecord = {
+      key: key,   // self pointer for quick own check above.
+      gets: gets, // get___ methods identifying weak maps
+      vals: vals  // values associated with this key in each
+                  // corresponding weak map.
+    };
+    defProp(key, HIDDEN_NAME, {
+      value: hiddenRecord,
+      writable: false,
+      enumerable: false,
+      configurable: false
+    });
+    return hiddenRecord;
+  }
+
+
+  /**
+   * Monkey patch operations that would make their argument
+   * non-extensible.
+   *
+   * <p>The monkey patched versions throw a TypeError if their
+   * argument is not an object, so it should only be done to functions
+   * that should throw a TypeError anyway if their argument is not an
+   * object.
+   */
+  (function(){
+    var oldFreeze = Object.freeze;
+    defProp(Object, 'freeze', {
+      value: function identifyingFreeze(obj) {
+        getHiddenRecord(obj);
+        return oldFreeze(obj);
+      }
+    });
+    var oldSeal = Object.seal;
+    defProp(Object, 'seal', {
+      value: function identifyingSeal(obj) {
+        getHiddenRecord(obj);
+        return oldSeal(obj);
+      }
+    });
+    var oldPreventExtensions = Object.preventExtensions;
+    defProp(Object, 'preventExtensions', {
+      value: function identifyingPreventExtensions(obj) {
+        getHiddenRecord(obj);
+        return oldPreventExtensions(obj);
+      }
+    });
+  })();
+
+
+  function constFunc(func) {
+    func.prototype = null;
+    return Object.freeze(func);
+  }
+
+  // Right now (12/25/2012) the histogram supports the current
+  // representation. We should check this occasionally, as a true
+  // constant time representation is easy.
+  // var histogram = [];
+
+  WeakMap = function() {
+    // We are currently (12/25/2012) never encountering any prematurely
+    // non-extensible keys.
+    var keys = []; // brute force for prematurely non-extensible keys.
+    var vals = []; // brute force for corresponding values.
+
+    function get___(key, opt_default) {
+      var hr = getHiddenRecord(key);
+      var i, vs;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        vs = hr.vals;
+      } else {
+        i = keys.indexOf(key);
+        vs = vals;
+      }
+      return (i >= 0) ? vs[i] : opt_default;
+    }
+
+    function has___(key) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+      } else {
+        i = keys.indexOf(key);
+      }
+      return i >= 0;
+    }
+
+    function set___(key, value) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        if (i >= 0) {
+          hr.vals[i] = value;
+        } else {
+//          i = hr.gets.length;
+//          histogram[i] = (histogram[i] || 0) + 1;
+          hr.gets.push(get___);
+          hr.vals.push(value);
+        }
+      } else {
+        i = keys.indexOf(key);
+        if (i >= 0) {
+          vals[i] = value;
+        } else {
+          keys.push(key);
+          vals.push(value);
+        }
+      }
+    }
+
+    function delete___(key) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        if (i >= 0) {
+          hr.gets.splice(i, 1);
+          hr.vals.splice(i, 1);
+        }
+      } else {
+        i = keys.indexOf(key);
+        if (i >= 0) {
+          keys.splice(i, 1);
+          vals.splice(i, 1);
+        }
+      }
+      return true;
+    }
+
+    return Object.create(WeakMap.prototype, {
+      get___:    { value: constFunc(get___) },
+      has___:    { value: constFunc(has___) },
+      set___:    { value: constFunc(set___) },
+      delete___: { value: constFunc(delete___) }
+    });
+  };
+  WeakMap.prototype = Object.create(Object.prototype, {
+    get: {
+      /**
+       * Return the value most recently associated with key, or
+       * opt_default if none.
+       */
+      value: function get(key, opt_default) {
+        return this.get___(key, opt_default);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    has: {
+      /**
+       * Is there a value associated with key in this WeakMap?
+       */
+      value: function has(key) {
+        return this.has___(key);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    set: {
+      /**
+       * Associate value with key in this WeakMap, overwriting any
+       * previous association if present.
+       */
+      value: function set(key, value) {
+        this.set___(key, value);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    'delete': {
+      /**
+       * Remove any association for key in this WeakMap, returning
+       * whether there was one.
+       *
+       * <p>Note that the boolean return here does not work like the
+       * {@code delete} operator. The {@code delete} operator returns
+       * whether the deletion succeeds at bringing about a state in
+       * which the deleted property is absent. The {@code delete}
+       * operator therefore returns true if the property was already
+       * absent, whereas this {@code delete} method returns false if
+       * the association was already absent.
+       */
+      value: function remove(key) {
+        return this.delete___(key);
+      },
+      writable: true,
+      configurable: true
+    }
+  });
+
+})();
diff --git a/amdTest.js b/amdTest.js
new file mode 100644
index 0000000..1d4cfd6
--- /dev/null
+++ b/amdTest.js
@@ -0,0 +1,28 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Trivial test of simple AMD loader.
+ * Tests anon case. Tests importing other modules.
+ * @requires define
+ */
+
+define(['amdTest1', 'amdTestDir/amdTest2', 'amdTest3'],
+function(amdTest1,              amdTest2,   amdTest3) {
+  "use strict";
+
+  // debugger; // See if we can step into amdTest3.js
+  var text3 = amdTest3();
+  return amdTest1 + amdTest2 + text3;
+});
diff --git a/amdTest1.js b/amdTest1.js
new file mode 100644
index 0000000..2ad9c3d
--- /dev/null
+++ b/amdTest1.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Trivial test of simple AMD loader.
+ * Tests simple named case. No dependencies.
+ * @requires define
+ */
+
+define('amdTest1', [], function() {
+  "use strict";
+
+  return 'this';
+});
diff --git a/amdTest3.js b/amdTest3.js
new file mode 100644
index 0000000..ded1fd7
--- /dev/null
+++ b/amdTest3.js
@@ -0,0 +1,33 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Trivial test of simple AMD loader.
+ * Tests anon case. No dependencies. With Axel's CommonJS Adapter
+ * boilerplate. See http://www.2ality.com/2011/11/module-gap.html
+ *
+ * @requires define, require
+ * @overrides module
+ */
+
+({ define: typeof define === "function" ?
+    define :
+    function(A,F) { module.exports = F.apply(null, A.map(require)); }}).
+define([], function() {
+  "use strict";
+
+  return function() {
+    return 'test';
+  };
+});
diff --git a/amdTestDir/amdTest2.js b/amdTestDir/amdTest2.js
new file mode 100644
index 0000000..40ad558
--- /dev/null
+++ b/amdTestDir/amdTest2.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Trivial test of simple AMD loader.
+ * Nested named module. No dependencies.
+ * @requires define
+ */
+
+define('amdTestDir/amdTest2', [], function() {
+  "use strict";
+
+  return ' is a ';
+});
diff --git a/atLeastFreeVarNames.js b/atLeastFreeVarNames.js
new file mode 100644
index 0000000..2b21102
--- /dev/null
+++ b/atLeastFreeVarNames.js
@@ -0,0 +1,157 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Export a {@code ses.atLeastFreeVarNames} function for
+ * internal use by the SES-on-ES5 implementation, which enumerates at
+ * least the identifiers which occur freely in a source text string.
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * // provides ses.atLeastFreeVarNames
+ * @author Mark S. Miller
+ * @requires StringMap
+ * @overrides ses, atLeastFreeVarNamesModule
+ */
+var ses;
+
+/**
+ * Calling {@code ses.atLeastFreeVarNames} on a {@code programSrc}
+ * string argument, the result should include at least all the free
+ * variable names of {@code programSrc} as own properties. It is
+ * harmless to include other strings as well.
+ *
+ * <p>Assuming a programSrc that parses as a strict Program,
+ * atLeastFreeVarNames(programSrc) returns a Record whose enumerable
+ * own property names must include the names of all the free variables
+ * occuring in programSrc. It can include as many other strings as is
+ * convenient so long as it includes these. The value of each of these
+ * properties should be {@code true}.
+ *
+ * <p>TODO(erights): On platforms that support Proxies (currently only
+ * FF4 and later), we should stop using atLeastFreeVarNames, since a
+ * {@code with(aProxy) {...}} should reliably intercept all free
+ * variable accesses without needing any prior scan.
+ */
+(function atLeastFreeVarNamesModule() {
+  "use strict";
+
+   if (!ses) { ses = {}; }
+
+  /////////////// KLUDGE SWITCHES ///////////////
+
+  // Section 7.2 ES5 recognizes the following whitespace characters
+  // FEFF           ; BOM
+  // 0009 000B 000C ; White_Space # Cc
+  // 0020           ; White_Space # Zs       SPACE
+  // 00A0           ; White_Space # Zs       NO-BREAK SPACE
+  // 1680           ; White_Space # Zs       OGHAM SPACE MARK
+  // 180E           ; White_Space # Zs       MONGOLIAN VOWEL SEPARATOR
+  // 2000..200A     ; White_Space # Zs  [11] EN QUAD..HAIR SPACE
+  // 2028           ; White_Space # Zl       LINE SEPARATOR
+  // 2029           ; White_Space # Zp       PARAGRAPH SEPARATOR
+  // 202F           ; White_Space # Zs       NARROW NO-BREAK SPACE
+  // 205F           ; White_Space # Zs       MEDIUM MATHEMATICAL SPACE
+  // 3000           ; White_Space # Zs       IDEOGRAPHIC SPACE
+
+  // Unicode characters which have the Zs property are an open set and can
+  // grow.  Not all versions of a browser treat Zs characters the same.
+  // The trade off is as follows:
+  //   * if SES treats a character as non-whitespace which the browser
+  //      treats as whitespace, a sandboxed program would be able to
+  //      break out of the sandbox.  SES avoids this by encoding any
+  //      characters outside the range of well understood characters
+  //      and disallowing unusual whitespace characters which are
+  //      rarely used and may be treated non-uniformly by browsers.
+  //   * if SES treats a character as whitespace which the browser
+  //      treats as non-whitespace, a sandboxed program will be able
+  //      to break out of the SES sandbox.  However, at worst it might
+  //      be able to read, write and execute globals which have the
+  //      corresponding whitespace character.  This is a limited
+  //      breach because it is exceedingly rare for browser functions
+  //      or powerful host functions to have names which contain
+  //      potential whitespace characters.  At worst, sandboxed
+  //      programs would be able to communicate with each other.
+  //
+  // We are conservative with the whitespace characters we accept.  We
+  // deny whitespace > u00A0 to make unexpected functional differences
+  // in sandboxed programs on browsers even if it was safe to allow them.
+  var OTHER_WHITESPACE = new RegExp(
+    '[\\uFEFF\\u1680\\u180E\\u2000-\\u2009\\u200a'
+    + '\\u2028\\u2029\\u200f\\u205F\\u3000]');
+
+  /**
+   * We use this to limit the input text to ascii only text.  All other
+   * characters are encoded using backslash-u escapes.
+   */
+  function LIMIT_SRC(programSrc) {
+    if (OTHER_WHITESPACE.test(programSrc)) {
+      throw new EvalError(
+        'Disallowing unusual unicode whitespace characters');
+    }
+    programSrc = programSrc.replace(/([\u0080-\u009f\u00a1-\uffff])/g,
+      function(_, u) {
+        return '\\u' + ('0000' + u.charCodeAt(0).toString(16)).slice(-4);
+      });
+    return programSrc;
+  }
+
+  /**
+   * Return a regexp that can be used repeatedly to scan for the next
+   * identifier. It works correctly in concert with LIMIT_SRC above.
+   *
+   * If this regexp is changed compileExprLater.js should be checked for
+   * correct escaping of freeNames.
+   */
+  function SHOULD_MATCH_IDENTIFIER() {
+    return /(\w|\\u\d{4}|\$)+/g;
+  }
+
+  //////////////// END KLUDGE SWITCHES ///////////
+
+  ses.DISABLE_SECURITY_FOR_DEBUGGER = false;
+
+  ses.atLeastFreeVarNames = function atLeastFreeVarNames(programSrc) {
+    programSrc = String(programSrc);
+    programSrc = LIMIT_SRC(programSrc);
+    // Now that we've temporarily limited our attention to ascii...
+    var regexp = SHOULD_MATCH_IDENTIFIER();
+    // Once we decide this file can depends on ES5, the following line
+    // should say "... = Object.create(null);" rather than "... = {};"
+    var result = [];
+    var found = StringMap();
+    // webkit js debuggers rely on ambient global eval
+    // http://code.google.com/p/chromium/issues/detail?id=145871
+    if (ses.DISABLE_SECURITY_FOR_DEBUGGER) {
+      found.set('eval', true);
+    }
+    var a;
+    while ((a = regexp.exec(programSrc))) {
+      // Note that we could have avoided the while loop by doing
+      // programSrc.match(regexp), except that then we'd need
+      // temporary storage proportional to the total number of
+      // apparent identifiers, rather than the total number of
+      // apparently unique identifiers.
+      var name = a[0];
+
+      if (!found.has(name)) {
+        result.push(name);
+        found.set(name, true);
+      }
+    }
+    return result;
+  };
+
+})();
diff --git a/compileExprLater.js b/compileExprLater.js
new file mode 100644
index 0000000..762dfd3
--- /dev/null
+++ b/compileExprLater.js
@@ -0,0 +1,140 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Makes a "compileExprLater" function which acts like
+ * "cajaVM.compileExpr", except that it returns a promise for the
+ * outcome of attempting to compile the argument expression.
+ *
+ * //provides ses.compileExprLater
+ * @author Mark S. Miller
+ * @overrides ses
+ * @requires Q, cajaVM, document, URI
+ */
+
+
+/* See
+http://webreflection.blogspot.com/2011/08/simulate-script-injection-via-data-uri.html
+*/
+
+var ses;
+
+(function(global) {
+   "use strict";
+
+   if (ses && !ses.ok()) { return; }
+
+   /**
+    * This implementation works and satisfies the semantics, but
+    * bottoms out in the built-in, which currently does not work well
+    * with the Chrome debugger.
+    *
+    * <p>Since SES is independent of the hosting environment, we
+    * feature test on the global named "document". If it is absent,
+    * then we fall back to this implementation which works in any
+    * standard ES5 environment.
+    *
+    * <p>Eventually, we should check whether we're in an ES5/3
+    * environment, in which case our choice for compileExprLater would
+    * be one that sends the expression back up the server to be
+    * cajoled.
+    */
+   function compileExprLaterFallback(exprSrc, opt_sourcePosition) {
+     // Coercing an object to a string may observably run code, so do
+     // this now rather than in any later turn.
+     exprSrc = ''+exprSrc;
+
+     return Q(cajaVM).send('compileExpr', exprSrc, opt_sourcePosition);
+   }
+
+   if (typeof document === 'undefined') {
+     ses.compileExprLater = compileExprLaterFallback;
+     return;
+   }
+
+   var resolvers = [];
+   var lastResolverTicket = -1;
+
+   function getResolverTicket(resolver) {
+     ++lastResolverTicket;
+     resolvers[lastResolverTicket] = resolver;
+     return lastResolverTicket;
+   }
+
+   ses.redeemResolver = function(i) {
+     var resolver = resolvers[i];
+     delete resolvers[i];
+     return resolver;
+   };
+
+   /**
+    *
+    */
+   function compileLaterInScript(exprSrc, opt_sourceUrl) {
+
+     var result = Q.defer();
+
+     // The portion of the pattern in compileExpr which is appropriate
+     // here as well.
+     var wrapperSrc = ses.securableWrapperSrc(exprSrc, opt_sourceUrl);
+     var freeNames = ses.atLeastFreeVarNames(exprSrc);
+
+     var head = document.getElementsByTagName("head")[0];
+     var script = document.createElement("script");
+     head.insertBefore(script, head.lastChild);
+
+     var resolverTicket = getResolverTicket(result.resolve);
+
+     var scriptSrc = 'ses.redeemResolver(' + resolverTicket + ')(' +
+       'Object.freeze(ses.makeCompiledExpr(' + wrapperSrc + ',\n' +
+       // Freenames consist solely of identifier characters (\w|\$)+
+       // which do not need to be escaped further
+       '["' + freeNames.join('", "') + '"])));';
+
+     if (opt_sourceUrl) {
+       // See http://code.google.com/p/google-caja/wiki/SES#typeof_variable
+       if (typeof global.URI !== 'undefined' && URI.parse) {
+         var parsed = URI.parse(String(opt_sourceUrl));
+         parsed = null === parsed ? null : parsed.toString();
+
+         // Note we could try to encode these characters or search specifically
+         // for */ as a pair of characters but since it is for debugging only
+         // choose to avoid
+         if (null !== parsed &&
+             parsed.indexOf("<") < 0 &&
+             parsed.indexOf(">") < 0 &&
+             parsed.indexOf("*") < 0) {
+           scriptSrc = '/* from ' + parsed + ' */ ' + scriptSrc;
+         }
+       }
+     }
+
+     // TODO(erights): It seems that on Chrome at least, the injected
+     // script actually executes synchronously *now*. Is this
+     // generally true? If so, perhaps we can even make synchronous
+     // eval debuggable? Is such synchronous eval ok for the use case
+     // here, or do we need to postpone this to another turn just in
+     // case?
+     script.appendChild(document.createTextNode(scriptSrc));
+
+     function deleteScriptNode() { script.parentNode.removeChild(script); }
+
+     Q(result.promise).when(deleteScriptNode, deleteScriptNode).end();
+
+     return result.promise;
+   }
+
+   ses.compileExprLater = compileLaterInScript;
+
+ })(this);
diff --git a/contract.html b/contract.html
new file mode 100644
index 0000000..cebbe0f
--- /dev/null
+++ b/contract.html
@@ -0,0 +1,241 @@
+<!DOCTYPE HTML>
+
+<!--
+ - Copyright (C) 2011 Google Inc.
+ -
+ - 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.
+-->
+
+<html>
+<head>
+<title>Testing SES/5</title>
+<style type="text/css">
+.log { color: black; }
+.info { color: navy; }
+.warn { color: olive; }
+.error { color: maroon; }
+.reports-text p { margin-top: 0.05em; margin-bottom: 0.05em; }
+.console-text p { margin-top: 0.05em; margin-bottom: 0.05em; }
+</style>
+</head>
+<body>
+<div id="reports" class="reports-text"><b>Repair Reports</b></div>
+<div id="console" class="console-text"><hr></div>
+<div id="exprTest">exprTest...</div>
+<div id="moduleTest">moduleTest...</div>
+<div id="scriptTest">scriptTest...</div>
+<div id="amdLoaderTest">AMD loader test...</div>
+<div id="contractTest">contract test...</div>
+
+<script src="useHTMLLogger.js"></script>
+<script>
+  /*console.profile('explicit SES init');*/
+  function gebi(id) {
+    return document.getElementById(id);
+  };
+  useHTMLLogger(gebi("reports"), gebi("console"));
+  // This severity is too high for any use other than development.
+  ses.maxAcceptableSeverityName = 'NEW_SYMPTOM';
+</script>
+<!--
+The <script src=... tags below, from "logger.js" to "hookupSESPlus.js", is
+  equivalent to <script src="initSESPlus.js"></script>, but is more
+  pleasant to debug.
+
+The <script src="useHTMLLogger.js"> and the inline script above advises
+  the scripts below, overriding the default logger, and overriding the
+  default maxAcceptableSeverityName.
+-->
+<script src="logger.js"></script>
+<script src="repairES5.js"></script>
+<script src="WeakMap.js"></script>
+<script src="debug.js"></script>
+<script src="StringMap.js"></script>
+<script src="whitelist.js"></script>
+<script src="atLeastFreeVarNames.js"></script>
+<script src="startSES.js"></script>
+<script src="ejectorsGuardsTrademarks.js"></script>
+<script src="hookupSESPlus.js"></script>
+
+<script>
+  var amdLoaderTest = gebi('amdLoaderTest');
+  var contractTest = gebi('contractTest');
+  function appendText(node, text) {
+    "use strict";
+    node.appendChild(document.createTextNode(text));
+  }
+  (function() {
+    "use strict";
+    var exprTest = gebi('exprTest');
+    var moduleTest = gebi('moduleTest');
+    var scriptTest = gebi('scriptTest');
+    if (!ses.ok()) {
+      appendText(exprTest, 'cancelled');
+      appendText(moduleTest, 'cancelled');
+      appendText(scriptTest, 'cancelled');
+      appendText(amdLoaderTest, 'cancelled');
+      appendText(contractTest, 'cancelled');
+      return;
+    }
+
+    var imports = cajaVM.makeImports();
+    cajaVM.copyToImports(imports, {window: 6});
+
+    var output = cajaVM.eval('3+4') * cajaVM.compileExpr('window')(imports);
+    var text1 = output === 42 ? 'succeeded' : 'failed: ' + output;
+    appendText(exprTest, text1);
+
+    // Test ability to bootstrap support for a limited form of
+    // CommonJS modules.
+    var modSrc = '"use noise"; exports.x = \n' +
+                 'require("foo.bar/baz"); return 77;';
+    var modMaker = cajaVM.compileModule(modSrc);
+    var required = modMaker.requirements;
+    var exported = {};
+    var returned = modMaker(cajaVM.copyToImports(imports, {
+      require: function(id) { return { foo: 88, id: id}; },
+      exports: exported
+    }));
+    var did = JSON.stringify(cajaVM.def({
+      required: required,
+      exported: exported,
+      returned: returned
+    }), void 0, ' ');
+    var should = JSON.stringify({
+      "required": [ "foo.bar/baz" ],
+      "exported": { "x": { "foo": 88, "id": "foo.bar/baz" } },
+      "returned": 77
+    }, void 0, ' ');
+    var text2 = did === should ? 'succeeded' : 'failed: ' + did;
+    appendText(moduleTest, text2);
+
+    // Tests the ability to do inter-module linkage as scripts
+    // traditionally did, by modification of (virtual) shared
+    // globals. Unfortunately, rather than say "var x = 88;" below, we
+    // must say "this.x = 88;" in order to export a global.
+    cajaVM.compileModule('this.x = 88;')(imports);
+    var text3 = cajaVM.compileExpr('x')(imports) === 88 ?
+      'succeeded' : 'failed';
+    appendText(scriptTest, text3);
+
+  })();
+</script>
+
+<script src="makeQ.js"></script>
+<script src="makeFarResourceMaker.js"></script>
+<script src="compileExprLater.js"></script>
+<script>
+  var Q;
+  (function() {
+    "use strict";
+
+    if (!ses.ok()) { return; }
+
+    /* TODO(erights): Extract the reusable boilerplate below into a
+       reusable abstraction. */
+
+    function mySetTimeout(func, millis) {
+      return setTimeout(function() {
+        try {
+          func();
+        } catch (reason) {
+          ses.logger.log('uncaught: ', reason);
+          throw reason;
+        }
+      }, millis);
+    }
+    Q = ses.makeQ(mySetTimeout);
+
+    var makeTextResource = ses.makeFarResourceMaker();
+
+    var url = './makeSimpleAMDLoader.js';
+    var makeSimpleAMDLoaderFileP = makeTextResource(url);
+    var makeSimpleAMDLoaderSrcP = makeSimpleAMDLoaderFileP.get();
+
+    /* We really are evaluating makeSimpleAMDModuleLoader with least
+       authority. Even though there's a global compileExprLater, if
+       you don't provide it here, makeSimpleAMDModuleLoader will
+       fail. */
+    var imports = cajaVM.makeImports();
+    cajaVM.copyToImports(imports, {
+      Q: Q,
+      compileExprLater: ses.compileExprLater
+    });
+
+    var makeSimpleAMDLoaderP = Q(makeSimpleAMDLoaderSrcP).when(function(src) {
+      var exprSrc = '(function() {' + src + '}).call(this)';
+      var compiledExprP = ses.compileExprLater(exprSrc, url);
+      return Q(compiledExprP).when(function(compiledExpr) {
+        compiledExpr(imports);
+        return imports.makeSimpleAMDLoader;
+      });
+    });
+
+
+    /**
+     * What we should do is accept any legal module identifier according
+     * to the AMD definition and encode it into a legal URL. Instead,
+     * for now, we just conservatively accept an ascii subset of both
+     * that does not need any encoding.
+     *
+     * See https://github.com/amdjs/amdjs-api/wiki/AMD#wiki-define-id-notes
+     */
+    var isModuleId = Object.freeze(/^[a-zA-Z0-9_/]*$/);
+
+    function fetch(id) {
+      if (!isModuleId.test(id)) {
+        throw new Error('illegal module id: ' + id);
+      }
+      return makeTextResource('./' + id + '.js').get();
+    }
+
+    var moduleMap = StringMap();
+    moduleMap.set('Q', Q);
+    moduleMap.set('def', cajaVM.def);
+    var loaderP = Q(makeSimpleAMDLoaderP).send(void 0, fetch, moduleMap);
+    var amdTestP = Q(loaderP).send(void 0, 'amdTest');
+    Q(amdTestP).when(function(amdTest) {
+      var amdTestStatus = amdTest === 'this is a test' ?
+        'succeeded' : 'failed, unexpected: ' + amdTest;
+      /*console.profileEnd();*/
+      appendText(amdLoaderTest, amdTestStatus);
+    }, function(reason) {
+      /*console.profileEnd();*/
+      appendText(amdLoaderTest, 'failed: ' + reason);
+    }).end();
+
+    var cTestP = Q(loaderP).send(void 0, 'contractTest');
+    Q(cTestP).when(function(cTest) {
+      appendText(contractTest, 'ok');
+    }, function(reason) {
+      appendText(contractTest, 'oops');
+    }).end();
+
+  })();
+</script>
+
+<p>
+Using <span id="browserName">unknown</span>
+ <span id="browserVersion">unknown</span>
+on <span id="browserOS">unknown</span>
+<script src="detect.js"></script>
+<script>
+  (function(){
+    "use strict"
+    gebi('browserName').textContent = BrowserDetect.browser;
+    gebi('browserVersion').textContent = BrowserDetect.version;
+    gebi('browserOS').textContent = BrowserDetect.OS;
+  })();
+</script>
+</body>
+</html>
diff --git a/contract/escrowExchange.js b/contract/escrowExchange.js
new file mode 100644
index 0000000..5fadcd0
--- /dev/null
+++ b/contract/escrowExchange.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2012 Google Inc.
+//
+// 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.
+
+function escrowExchange(argA, argB) {   // argA from Alice, argB from Bob
+
+  function failOnly(cordP) {
+    return Q(cordP).when(function(cord) { throw cord; });
+  }
+
+  function makeTransfer(makeEscrowPurseP) {
+
+    return function transfer(decisionP, srcPurseP, dstPurseP, amount) {
+      var escrowPurseP = Q(makeEscrowPurseP).send();
+
+        Q(decisionP).when(function(_) {                        // setup phase 2
+          Q(dstPurseP).send('deposit', amount, escrowPurseP);
+        }, function(reason) {
+          Q(srcPurseP).send('deposit', amount, escrowPurseP);
+        });
+
+        return Q(escrowPurseP).send('deposit', amount, srcPurseP);   // phase 1
+    };
+  }
+
+  var transferMoney = makeTransfer(Q.join(argA.makeMoneyEscrowP,
+                                          argB.makeMoneyEscrowP));
+  var transferStock = makeTransfer(Q.join(argB.makeStockEscrowP,
+                                          argA.makeStockEscrowP));
+  var d = Q.defer();
+  d.resolve(Q.race([Q.all([
+     transferMoney(d.promise, argA.moneySrcP, argB.moneyDstP, argB.moneyNeeded),
+     transferStock(d.promise, argB.stockSrcP, argA.stockDstP, argA.stockNeeded)
+   ]),
+   failOnly(argA.cordP),
+   failOnly(argB.cordP)]));
+  return d.promise;
+}
+
diff --git a/contract/makeContractHost.js b/contract/makeContractHost.js
new file mode 100644
index 0000000..ca325fe
--- /dev/null
+++ b/contract/makeContractHost.js
@@ -0,0 +1,129 @@
+// Copyright (C) 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Simple AMD module exports a {@code makeContractHost}
+ * function, which makes a contract host, which makes and runs a
+ * contract. Requires SES. Specifically, requires the {@code eval}
+ * function in scope to be a SES confining eval.
+ * @requires WeakMap, define, Q, eval
+ * @author Mark S. Miller erights@gmail.com
+ */
+define('contract/makeContractHost', ['Q', 'def'], function(Q, def) {
+  "use strict";
+
+  /**
+   * A contract host as a mutually trusted third party for honestly
+   * running whatever smart contract code its customers agree on.
+   *
+   * <p>When mutually suspicious parties wish to engage in a joint
+   * contract, if they can agree on a contract host to be run the
+   * following code honestly, agree on the code that represents their
+   * smart contract, and agree on which side of the contract they each
+   * play, then they can validly engage in the contract.
+   *
+   * <p>The {@code contractSrc} is assumed to be the source code for a
+   * closed SES function, where each of the parties to the contract is
+   * supposed to provide their respective fulfilled arguments. Once
+   * all these arguments are fulfilled, then the contract is run.
+   *
+   * <p>There are two "roles" for participating in the protocol:
+   * contract initiator, who calls the contract host's {@code setup}
+   * method, and contract participants, who call the contract host's
+   * {@code redeem} method. For example, let's say the contract in
+   * question is the board manager for playing chess. The initiator
+   * instantiates a new chess game, whose board manager is a two
+   * argument function, where argument zero is provided by the player
+   * playing "white" and argument one is provided by the player
+   * playing "black".
+   *
+   * <p>The {@code setup} method returns an array of tokens, one per
+   * argument, where each token represents the exclusive right to
+   * provide that argument. The initiator would then distribute these
+   * tokens to each of the players, together with the alleged source
+   * for the game they would be playing, and their alleged side, i.e.,
+   * which argument position they are responsible for providing.
+   *
+   * <pre>
+   *   // Contract initiator
+   *   const tokensP = contractHostP ! setup(chessSrc);
+   *   const whiteTokenP = tokensP ! [0];
+   *   const blackTokenP = tokensP ! [1];
+   *   whitePlayer ! play(whiteTokenP, chessSrc, 0);
+   *   blackPlayer ! play(blackTokenP, chessSrc, 1);
+   * </pre>
+   *
+   * <p>Each player, on receiving the token, alleged game source, and
+   * alleged argument index, would first decide (e.g., with the {@code
+   * check} function below) whether this is a game they would be
+   * interested in playing. If so, the redeem the token to get a
+   * function they can invoke to provide their argument, in order to
+   * start playing their side of the game -- but only if the contract
+   * host verifies that they are playing the side of the game that
+   * they think they are.
+   *
+   * <pre>
+   *   // Contract participant
+   *   function play(tokenP, allegedChessSrc, allegedSide) {
+   *     check(allegedChessSrc, allegedSide);
+   *     const chairP = contractHostP ! redeem(tokenP);
+   *     const outcomeP = chairP ! (allegedChessSrc, allegedSide, player);
+   *   }
+   * </pre>
+   */
+  return function makeContractHost() {
+    var amp = WeakMap();
+
+    return def({
+      setup: function(contractSrc) {
+        contractSrc = String(contractSrc);
+        var contract = Function('Q', 'def', 
+                                'return (' + contractSrc + '\n);')(Q, def);
+        var result = Q.defer();
+        var tokens = [];
+        var argPs = [];
+
+        function addParam(i, token, argPair) {
+          tokens[i] = token;
+          argPs[i] = argPair.promise;
+          amp.set(token, def(function(allegedSrc, allegedI, arg) {
+            if (contractSrc !== allegedSrc) {
+              throw new Error('unexpected contract: ' + contractSrc);
+            }
+            if (i !== allegedI) {
+              throw new Error('unexpected player number: ' + i);
+            }
+            argPair.resolve(arg);
+            return result.promise;
+          }));
+        }
+        for (var i = 0; i < contract.length; i++) {
+          addParam(i, def({}), Q.defer());
+        }
+
+        result.resolve(Q.all(argPs).when(function(args) {
+          return contract.apply(void 0, args);
+        }));
+        return tokens;
+      },
+      redeem: function(tokenP) {
+        return Q(tokenP).when(function(token) {
+          var result = amp.get(token);
+          amp.delete(token);
+          return result;
+        });
+      }
+    });
+  };
+});
diff --git a/contract/makeMint.js b/contract/makeMint.js
new file mode 100644
index 0000000..31ce778
--- /dev/null
+++ b/contract/makeMint.js
@@ -0,0 +1,46 @@
+// Copyright (C) 2012 Google Inc.
+//
+// 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.
+
+function makeMint() {
+  function Nat(allegedNum) {
+    if (typeof allegedNum !== 'number') { throw new Error("not a number"); }
+    if (allegedNum !== allegedNum) { throw new Error("number not a number"); }
+    if (allegedNumber < 0)         { throw new Error("negative"); }
+    if (allegedNumber % 1 !== 0)   { throw new Error("not integral"); }
+    if (allegedNumber > MAX_NAT)   { throw new Error("too big"); }
+    return allegedNum;
+  }
+
+  var amp = WeakMap();
+  return function mint(balance) {
+    var purse = def({
+      getBalance: function() { return balance; },
+      makePurse: function() { return mint(0); },
+      deposit: function(amount, src) {
+        Nat(balance + amount);
+        amp.get(src)(Nat(amount));
+        balance += amount;
+      }
+    });
+    function decr(amount) {
+      balance = Nat(balance - amount);
+    }
+    amp.set(purse, decr);
+    return purse;
+  };
+}
+
+function makePurseMaker(purse) {
+  return function makePurse() { return purse.makePurse(); };
+}
diff --git a/contractTest.js b/contractTest.js
new file mode 100644
index 0000000..dc1d463
--- /dev/null
+++ b/contractTest.js
@@ -0,0 +1,40 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Test simple contract code
+ * @requires define
+ */
+
+define(['Q', 'contract/makeContractHost'],
+function(Q, makeContractHostFar) {
+  "use strict";
+
+  var contractHostP = Q(makeContractHostFar).send(void 0);
+
+  function trivContract(whiteP, blackP) {
+    return 8;
+  }
+  var contractSrc = '' + trivContract;
+
+  var tokensP = Q(contractHostP).send('setup', contractSrc);
+
+  var whiteTokenP = Q(tokensP).get(0);
+  var whiteChairP = Q(contractHostP).send('redeem', whiteTokenP);
+  Q(whiteChairP).send(void 0, contractSrc, 0, {});
+
+  var blackTokenP = Q(tokensP).get(1);
+  var blackChairP = Q(contractHostP).send('redeem', blackTokenP);
+  return Q(blackChairP).send(void 0, contractSrc, 1, {});
+});
diff --git a/debug.js b/debug.js
new file mode 100644
index 0000000..81d3998
--- /dev/null
+++ b/debug.js
@@ -0,0 +1,217 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview An optional part of the SES initialization process
+ * that saves potentially valuable debugging aids on the side before
+ * startSES.js would remove these, and adds a debugging API which uses
+ * these without compromising SES security.
+ *
+ * <p>NOTE: The currently exposed debugging API is far from
+ * settled. This module is currently in an exploratory phase.
+ *
+ * <p>Meant to be run sometime after repairs are done and a working
+ * WeakMap is available, but before startSES.js. initSES.js includes
+ * this. initSESPlus.js does not.
+ *
+ * //provides ses.UnsafeError,
+ * //provides ses.getCWStack ses.stackString ses.getStack
+ * @author Mark S. Miller
+ * @requires WeakMap, this
+ * @overrides Error, ses, debugModule
+ */
+
+var Error;
+var ses;
+
+(function debugModule(global) {
+   "use strict";
+
+
+   /**
+    * Save away the original Error constructor as ses.UnsafeError and
+    * make it otherwise unreachable. Replace it with a reachable
+    * wrapping constructor with the same standard behavior.
+    *
+    * <p>When followed by the rest of SES initialization, the
+    * UnsafeError we save off here is exempt from whitelist-based
+    * extra property removal and primordial freezing. Thus, we can
+    * use any platform specific APIs defined on Error for privileged
+    * debugging operations, unless explicitly turned off below.
+    */
+   var UnsafeError = Error;
+   ses.UnsafeError = Error;
+   function FakeError(message) {
+     return UnsafeError(message);
+   }
+   FakeError.prototype = UnsafeError.prototype;
+   FakeError.prototype.constructor = FakeError;
+
+   Error = FakeError;
+
+   /**
+    * Should be a function of an argument object (normally an error
+    * instance) that returns the stack trace associated with argument
+    * in Causeway format.
+    *
+    * <p>See http://wiki.erights.org/wiki/Causeway_Platform_Developer
+    *
+    * <p>Currently, there is no one portable technique for doing
+    * this. So instead, each platform specific branch of the if below
+    * should assign something useful to getCWStack.
+    */
+   ses.getCWStack = function uselessGetCWStack(err) { return void 0; };
+
+   if ('captureStackTrace' in UnsafeError) {
+     (function() {
+       // Assuming http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+       // So this section is v8 specific.
+
+       UnsafeError.prepareStackTrace = function(err, sst) {
+         ssts.set(err, sst);
+         return void 0;
+       };
+
+       var unsafeCaptureStackTrace = UnsafeError.captureStackTrace;
+
+       // TODO(erights): This seems to be write only. Can this be made
+       // safe enough to expose to untrusted code?
+       UnsafeError.captureStackTrace = function(obj, opt_MyError) {
+         var wasFrozen = Object.isFrozen(obj);
+         var stackDesc = Object.getOwnPropertyDescriptor(obj, 'stack');
+         try {
+           var result = unsafeCaptureStackTrace(obj, opt_MyError);
+           var ignore = obj.stack;
+           return result;
+         } finally {
+           if (wasFrozen && !Object.isFrozen(obj)) {
+             if (stackDesc) {
+               Object.defineProperty(obj, 'stack', stackDesc);
+             } else {
+               delete obj.stack;
+             }
+             Object.freeze(obj);
+           }
+         }
+       };
+
+       var ssts = WeakMap(); // error -> sst
+
+       /**
+        * Returns a stack in Causeway format.
+        *
+        * <p>Based on
+        * http://code.google.com/p/causeway/source/browse/trunk/src/js/com/teleometry/causeway/purchase_example/workers/makeCausewayLogger.js
+        */
+       function getCWStack(err) {
+         var sst = ssts.get(err);
+         if (sst === void 0 && err instanceof Error) {
+           // We hope it triggers prepareStackTrace
+           var ignore = err.stack;
+           sst = ssts.get(err);
+         }
+         if (sst === void 0) { return void 0; }
+
+         return { calls: sst.map(function(frame) {
+           return {
+             name: '' + (frame.getFunctionName() ||
+                         frame.getMethodName() || '?'),
+             source: '' + (frame.getFileName() || '?'),
+             span: [ [ frame.getLineNumber(), frame.getColumnNumber() ] ]
+           };
+         })};
+       };
+       ses.getCWStack = getCWStack;
+     })();
+
+   } else if (global.opera) {
+     (function() {
+       // Since pre-ES5 browsers are disqualified, we can assume a
+       // minimum of Opera 11.60.
+     })();
+
+
+   } else if (new Error().stack) {
+     (function() {
+       var FFFramePattern = (/^([^@]*)@(.*?):?(\d*)$/);
+
+       // stacktracejs.org suggests that this indicates FF. Really?
+       function getCWStack(err) {
+         var stack = err.stack;
+         if (!stack) { return void 0; }
+         var lines = stack.split('\n');
+         var frames = lines.map(function(line) {
+           var match = FFFramePattern.exec(line);
+           if (match) {
+             return {
+               name: match[1].trim() || '?',
+               source: match[2].trim() || '?',
+               span: [[+match[3]]]
+             };
+           } else {
+             return {
+               name: line.trim() || '?',
+               source: '?',
+               span: []
+             };
+           }
+         });
+         return { calls: frames };
+       }
+
+       ses.getCWStack = getCWStack;
+     })();
+
+   } else {
+     (function() {
+       // Including Safari and IE10.
+     })();
+
+   }
+
+   /**
+    * Turn a Causeway stack into a v8-like stack traceback string.
+    */
+   function stackString(cwStack) {
+     if (!cwStack) { return void 0; }
+     var calls = cwStack.calls;
+
+     var result = calls.map(function(call) {
+
+       var spanString = call.span.map(function(subSpan) {
+         return subSpan.join(':');
+       }).join('::');
+       if (spanString) { spanString = ':' + spanString; }
+
+       return '  at ' + call.name + ' (' + call.source + spanString + ')';
+
+     });
+     return result.join('\n');
+   };
+   ses.stackString = stackString;
+
+   /**
+    * Return the v8-like stack traceback string associated with err.
+    */
+   function getStack(err) {
+     if (err !== Object(err)) { return void 0; }
+     var cwStack = ses.getCWStack(err);
+     if (!cwStack) { return void 0; }
+     var result = ses.stackString(cwStack);
+     if (err instanceof Error) { result = err + '\n' + result; }
+     return result;
+   };
+   ses.getStack = getStack;
+
+ })(this);
diff --git a/detect.js b/detect.js
new file mode 100644
index 0000000..7bc391d
--- /dev/null
+++ b/detect.js
@@ -0,0 +1,145 @@
+// Derived from http://www.quirksmode.org/js/detect.html by Peter-Paul Koch.
+// License terms at http://www.quirksmode.org/about/copyright.html
+
+/**
+ * @fileoverview Tries to figure out what browser we're on.
+ *
+ * @author Peter-Paul Koch, with modifications by Mark S. Miller
+ * @provides BrowserDetect
+ * @requires navigator
+ * @overrides window
+ */
+
+var BrowserDetect;
+
+(function() {
+  "use strict";
+
+  BrowserDetect = {
+    init: function() {
+      this.browser = this.searchString(this.dataBrowser) ||
+        "An unknown browser";
+      this.version = this.searchVersion(navigator.userAgent) ||
+        this.searchVersion(navigator.appVersion) ||
+        "an unknown version";
+      this.OS = this.searchString(this.dataOS) || "an unknown OS";
+    },
+    searchString: function(data) {
+      for (var i = 0; i < data.length; i++) {
+        var dataString = data[i].string;
+        var dataProp = data[i].prop;
+        this.versionSearchString = data[i].versionSearch || data[i].identity;
+        if (dataString) {
+          if (dataString.indexOf(data[i].subString) != -1) {
+            return data[i].identity;
+          }
+        } else if (dataProp) {
+          return data[i].identity;
+        }
+      }
+      return void 0;
+    },
+    searchVersion: function(dataString) {
+      var index = dataString.indexOf(this.versionSearchString);
+      if (index == -1) { return void 0; }
+      var startsWithVersion = dataString.substring(
+        index + this.versionSearchString.length + 1);
+      var match = (/^([0-9\.]*)/).exec(startsWithVersion);
+      return match && match[1];
+    },
+    dataBrowser: [
+      {
+        string: navigator.userAgent,
+        subString: "Chrome",
+        identity: "Chrome"
+      },
+      {   string: navigator.userAgent,
+          subString: "OmniWeb",
+          versionSearch: "OmniWeb/",
+          identity: "OmniWeb"
+      },
+      {
+        string: navigator.vendor,
+        subString: "Apple",
+        identity: "Safari",
+        versionSearch: "Version"
+      },
+      {
+        prop: window.opera,
+        identity: "Opera",
+        versionSearch: "Version"
+      },
+      {
+        string: navigator.vendor,
+        subString: "iCab",
+        identity: "iCab"
+      },
+      {
+        string: navigator.vendor,
+        subString: "KDE",
+        identity: "Konqueror"
+      },
+      {
+        string: navigator.userAgent,
+        subString: "Firefox",
+        identity: "Firefox"
+      },
+      {
+        string: navigator.vendor,
+        subString: "Camino",
+        identity: "Camino"
+      },
+      {           // for newer Netscapes (6+)
+        string: navigator.userAgent,
+        subString: "Netscape",
+        identity: "Netscape"
+      },
+      {
+        string: navigator.userAgent,
+        subString: "MSIE",
+        identity: "Explorer",
+        versionSearch: "MSIE"
+      },
+      {
+        string: navigator.userAgent,
+        subString: "Gecko",
+        identity: "Mozilla",
+        versionSearch: "rv"
+      },
+      {           // for older Netscapes (4-)
+        string: navigator.userAgent,
+        subString: "Mozilla",
+        identity: "Netscape",
+        versionSearch: "Mozilla"
+      }
+    ],
+    dataOS : [
+      {
+        string: navigator.platform,
+        subString: "Win",
+        identity: "Windows"
+      },
+      {
+        string: navigator.platform,
+        subString: "Mac",
+        identity: "Mac"
+      },
+      {
+        string: navigator.userAgent,
+        subString: "iPhone",
+        identity: "iPhone/iPod"
+      },
+      {
+        string: navigator.platform,
+        subString: "Linux",
+        identity: "Linux"
+      }
+    ]
+  };
+  BrowserDetect.init();
+})();
+
+// Exports for closure compiler.
+if (typeof window !== 'undefined') {
+  window['BrowserDetect'] = BrowserDetect;
+}
diff --git a/ejectorsGuardsTrademarks.js b/ejectorsGuardsTrademarks.js
new file mode 100644
index 0000000..27d6203
--- /dev/null
+++ b/ejectorsGuardsTrademarks.js
@@ -0,0 +1,375 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview
+ * This is a pure-ES5 implementation of ejectors, guards, and trademarks as
+ * otherwise provided by ES5/3. It is incorporated into the cajaVM object by
+ * hookupSESPlus.js.
+ *
+ * <p>Assumes ES5. Compatible with ES5-strict.
+ *
+ * // provides ses.ejectorsGuardsTrademarks
+ * @author kpreid@switchb.org
+ * @requires WeakMap, cajaVM
+ * @overrides ses, ejectorsGuardsTrademarksModule
+ */
+var ses;
+
+(function ejectorsGuardsTrademarksModule(){
+  "use strict";
+
+  ses.ejectorsGuardsTrademarks = function ejectorsGuardsTrademarks() {
+
+    /**
+     * During the call to {@code ejectorsGuardsTrademarks}, {@code
+     * ejectorsGuardsTrademarks} must not call {@code cajaVM.def},
+     * since startSES.js has not yet finished cleaning things. See the
+     * doc-comments on the {@code extensions} parameter of
+     * startSES.js.
+     *
+     * <p>Instead, we define here some conveniences for freezing just
+     * enough without prematurely freezing primodial objects
+     * transitively reachable from these.
+     */
+    var freeze = Object.freeze;
+    var constFunc = cajaVM.constFunc;
+
+
+    /**
+     * Returns a new object whose only utility is its identity and (for
+     * diagnostic purposes only) its name.
+     */
+    function Token(name) {
+      name = '' + name;
+      return freeze({
+        toString: constFunc(function tokenToString() {
+          return name;
+        })
+      });
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////
+    // Ejectors
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * One-arg form is known in scheme as "call with escape
+     * continuation" (call/ec).
+     *
+     * <p>In this analogy, a call to {@code callWithEjector} emulates a
+     * labeled statement. The ejector passed to the {@code attemptFunc}
+     * emulates the label part. The {@code attemptFunc} itself emulates
+     * the statement being labeled. And a call to {@code eject} with
+     * this ejector emulates the return-to-label statement.
+     *
+     * <p>We extend the normal notion of call/ec with an
+     * {@code opt_failFunc} in order to give more the sense of a
+     * {@code try/catch} (or similarly, the {@code escape} special
+     * form in E). The {@code attemptFunc} is like the {@code try}
+     * clause and the {@code opt_failFunc} is like the {@code catch}
+     * clause. If omitted, {@code opt_failFunc} defaults to the
+     * {@code identity} function.
+     *
+     * <p>{@code callWithEjector} creates a fresh ejector -- a one
+     * argument function -- for exiting from this attempt. It then calls
+     * {@code attemptFunc} passing that ejector as argument. If
+     * {@code attemptFunc} completes without calling the ejector, then
+     * this call to {@code callWithEjector} completes
+     * likewise. Otherwise, if the ejector is called with an argument,
+     * then {@code opt_failFunc} is called with that argument. The
+     * completion of {@code opt_failFunc} is then the completion of the
+     * {@code callWithEjector} as a whole.
+     *
+     * <p>The ejector stays live until {@code attemptFunc} is exited,
+     * at which point the ejector is disabled. Calling a disabled
+     * ejector throws.
+     *
+     * <p>Historic note: This was first invented by John C. Reynolds in
+     * <a href="http://doi.acm.org/10.1145/800194.805852"
+     * >Definitional interpreters for higher-order programming
+     * languages</a>. Reynold's invention was a special form as in E,
+     * rather than a higher order function as here and in call/ec.
+     */
+    function callWithEjector(attemptFunc, opt_failFunc) {
+      var failFunc = opt_failFunc || function (x) { return x; };
+      var disabled = false;
+      var token = new Token('ejection');
+      var stash = void 0;
+      function ejector(result) {
+        if (disabled) {
+          throw new Error('ejector disabled');
+        } else {
+          // don't disable here.
+          stash = result;
+          throw token;
+        }
+      }
+      constFunc(ejector);
+      try {
+        try {
+          return attemptFunc(ejector);
+        } finally {
+          disabled = true;
+        }
+      } catch (e) {
+        if (e === token) {
+          return failFunc(stash);
+        } else {
+          throw e;
+        }
+      }
+    }
+
+    /**
+     * Safely invokes {@code opt_ejector} with {@code result}.
+     * <p>
+     * If {@code opt_ejector} is falsy, disabled, or returns
+     * normally, then {@code eject} throws. Under no conditions does
+     * {@code eject} return normally.
+     */
+    function eject(opt_ejector, result) {
+      if (opt_ejector) {
+        opt_ejector(result);
+        throw new Error('Ejector did not exit: ', opt_ejector);
+      } else {
+        throw new Error(result);
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Sealing and Unsealing
+    ////////////////////////////////////////////////////////////////////////
+
+    function makeSealerUnsealerPair() {
+      var boxValues = new WeakMap(true); // use key lifetime
+
+      function seal(value) {
+        var box = freeze({});
+        boxValues.set(box, value);
+        return box;
+      }
+      function optUnseal(box) {
+        return boxValues.has(box) ? [boxValues.get(box)] : null;
+      }
+      function unseal(box) {
+        var result = optUnseal(box);
+        if (result === null) {
+          throw new Error("That wasn't one of my sealed boxes!");
+        } else {
+          return result[0];
+        }
+      }
+      return freeze({
+        seal: constFunc(seal),
+        unseal: constFunc(unseal),
+        optUnseal: constFunc(optUnseal)
+      });
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////
+    // Trademarks
+    ////////////////////////////////////////////////////////////////////////
+
+    var stampers = new WeakMap(true);
+
+    /**
+     * Internal routine for making a trademark from a table.
+     *
+     * <p>To untangle a cycle, the guard made by {@code makeTrademark}
+     * is not yet stamped. The caller of {@code makeTrademark} must
+     * stamp it before allowing the guard to escape.
+     *
+     * <p>Note that {@code makeTrademark} is called during the call to
+     * {@code ejectorsGuardsTrademarks}, and so must not call {@code
+     * cajaVM.def}.
+     */
+    function makeTrademark(typename, table) {
+      typename = '' + typename;
+
+      var stamp = freeze({
+        toString: constFunc(function() { return typename + 'Stamp'; })
+      });
+
+      stampers.set(stamp, function(obj) {
+        table.set(obj, true);
+        return obj;
+      });
+
+      return freeze({
+        toString: constFunc(function() { return typename + 'Mark'; }),
+        stamp: stamp,
+        guard: freeze({
+          toString: constFunc(function() { return typename + 'T'; }),
+          coerce: constFunc(function(specimen, opt_ejector) {
+            if (!table.get(specimen)) {
+              eject(opt_ejector,
+                    'Specimen does not have the "' + typename + '" trademark');
+            }
+            return specimen;
+          })
+        })
+      });
+    }
+
+    /**
+     * Objects representing guards should be marked as such, so that
+     * they will pass the {@code GuardT} guard.
+     * <p>
+     * {@code GuardT} is generally accessible as
+     * {@code cajaVM.GuardT}. However, {@code GuardStamp} must not be
+     * made generally accessible, but rather only given to code trusted
+     * to use it to deem as guards things that act in a guard-like
+     * manner: A guard MUST be immutable and SHOULD be idempotent. By
+     * "idempotent", we mean that<pre>
+     *     var x = g(specimen, ej); // may fail
+     *     // if we're still here, then without further failure
+     *     g(x) === x
+     * </pre>
+     */
+    var GuardMark = makeTrademark('Guard', new WeakMap());
+    var GuardT = GuardMark.guard;
+    var GuardStamp = GuardMark.stamp;
+    stampers.get(GuardStamp)(GuardT);
+
+    /**
+     * The {@code Trademark} constructor makes a trademark, which is a
+     * guard/stamp pair, where the stamp marks and freezes unfrozen
+     * records as carrying that trademark and the corresponding guard
+     * cerifies objects as carrying that trademark (and therefore as
+     * having been marked by that stamp).
+     *
+     * <p>By convention, a guard representing the type-like concept
+     * 'Foo' is named 'FooT'. The corresponding stamp is
+     * 'FooStamp'. And the record holding both is 'FooMark'. Many
+     * guards also have {@code of} methods for making guards like
+     * themselves but parameterized by further constraints, which are
+     * usually other guards. For example, {@code T.ListT} is the guard
+     * representing frozen array, whereas {@code
+     * T.ListT.of(cajaVM.GuardT)} represents frozen arrays of guards.
+     */
+    function Trademark(typename) {
+      var result = makeTrademark(typename, new WeakMap());
+      stampers.get(GuardStamp)(result.guard);
+      return result;
+    };
+
+    /**
+     * Given that {@code stamps} is a list of stamps and
+     * {@code record} is a non-frozen object, this marks record with
+     * the trademarks of all of these stamps, and then freezes and
+     * returns the record.
+     * <p>
+     * If any of these conditions do not hold, this throws.
+     */
+    function stamp(stamps, record) {
+      // TODO: Should nonextensible objects be stampable?
+      if (Object.isFrozen(record)) {
+        throw new TypeError("Can't stamp frozen objects: " + record);
+      }
+      stamps = Array.prototype.slice.call(stamps, 0);
+      var numStamps = stamps.length;
+      // First ensure that we will succeed before applying any stamps to
+      // the record.
+      var i;
+      for (i = 0; i < numStamps; i++) {
+        if (!stampers.has(stamps[i])) {
+          throw new TypeError("Can't stamp with a non-stamp: " + stamps[i]);
+        }
+      }
+      for (i = 0; i < numStamps; i++) {
+        // Only works for real stamps, postponing the need for a
+        // user-implementable auditing protocol.
+        stampers.get(stamps[i])(record);
+      }
+      return freeze(record);
+    };
+
+    ////////////////////////////////////////////////////////////////////////
+    // Guards
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * First ensures that g is a guard; then does
+     * {@code g.coerce(specimen, opt_ejector)}.
+     */
+    function guard(g, specimen, opt_ejector) {
+      g = GuardT.coerce(g); // failure throws rather than ejects
+      return g.coerce(specimen, opt_ejector);
+    }
+
+    /**
+     * First ensures that g is a guard; then checks whether the specimen
+     * passes that guard.
+     * <p>
+     * If g is a coercing guard, this only checks that g coerces the
+     * specimen to something rather than failing. Note that trademark
+     * guards are non-coercing, so if specimen passes a trademark guard,
+     * then specimen itself has been marked with that trademark.
+     */
+    function passesGuard(g, specimen) {
+      g = GuardT.coerce(g); // failure throws rather than ejects
+      return callWithEjector(
+        constFunc(function(opt_ejector) {
+          g.coerce(specimen, opt_ejector);
+          return true;
+        }),
+        constFunc(function(ignored) {
+          return false;
+        })
+      );
+    }
+
+
+    /**
+     * Create a guard which passes all objects present in {@code table}.
+     * This may be used to define trademark-like systems which do not require
+     * the object to be frozen.
+     *
+     * {@code typename} is used for toString and {@code errorMessage} is used
+     * when an object does not pass the guard.
+     */
+    function makeTableGuard(table, typename, errorMessage) {
+      var g = {
+        toString: constFunc(function() { return typename + 'T'; }),
+        coerce: constFunc(function(specimen, opt_ejector) {
+          if (Object(specimen) === specimen && table.get(specimen)) {
+            return specimen;
+          }
+          eject(opt_ejector, errorMessage);
+        })
+      };
+      stamp([GuardStamp], g);
+      return freeze(g);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Exporting
+    ////////////////////////////////////////////////////////////////////////
+
+    return freeze({
+      callWithEjector: constFunc(callWithEjector),
+      eject: constFunc(eject),
+      makeSealerUnsealerPair: constFunc(makeSealerUnsealerPair),
+      GuardT: GuardT,
+      makeTableGuard: constFunc(makeTableGuard),
+      Trademark: constFunc(Trademark),
+      guard: constFunc(guard),
+      passesGuard: constFunc(passesGuard),
+      stamp: constFunc(stamp)
+    });
+  };
+})();
diff --git a/explicit.html b/explicit.html
new file mode 100644
index 0000000..c2962c8
--- /dev/null
+++ b/explicit.html
@@ -0,0 +1,228 @@
+<!DOCTYPE HTML>
+
+<!--
+ - Copyright (C) 2011 Google Inc.
+ -
+ - 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.
+-->
+
+<html>
+<head>
+<title>Testing SES/5</title>
+<style type="text/css">
+.log { color: black; }
+.info { color: navy; }
+.warn { color: olive; }
+.error { color: maroon; }
+.reports-text p { margin-top: 0.05em; margin-bottom: 0.05em; }
+.console-text p { margin-top: 0.05em; margin-bottom: 0.05em; }
+</style>
+</head>
+<body>
+<div id="reports" class="reports-text"><b>Repair Reports</b></div>
+<div id="console" class="console-text"><hr></div>
+<div id="exprTest">exprTest...</div>
+<div id="moduleTest">moduleTest...</div>
+<div id="scriptTest">scriptTest...</div>
+<div id="amdLoaderTest">AMD loader test...</div>
+
+<script src="useHTMLLogger.js"></script>
+<script>
+  /*console.profile('explicit SES init');*/
+  function gebi(id) {
+    return document.getElementById(id);
+  };
+  useHTMLLogger(gebi("reports"), gebi("console"));
+  // This severity is too high for any use other than development.
+  ses.maxAcceptableSeverityName = 'NEW_SYMPTOM';
+</script>
+<!--
+The <script src=... tags below, from "logger.js" to "hookupSESPlus.js", is
+  equivalent to <script src="initSESPlus.js"></script>, but is more
+  pleasant to debug.
+
+The <script src="useHTMLLogger.js"> and the inline script above advises
+  the scripts below, overriding the default logger, and overriding the
+  default maxAcceptableSeverityName.
+-->
+<script src="logger.js"></script>
+<script src="repairES5.js"></script>
+<script src="WeakMap.js"></script>
+<script src="debug.js"></script>
+<script src="StringMap.js"></script>
+<script src="whitelist.js"></script>
+<script src="atLeastFreeVarNames.js"></script>
+<script src="startSES.js"></script>
+<script src="ejectorsGuardsTrademarks.js"></script>
+<script src="hookupSESPlus.js"></script>
+
+<script>
+  var amdLoaderTest = gebi('amdLoaderTest');
+  function appendText(node, text) {
+    "use strict";
+    node.appendChild(document.createTextNode(text));
+  }
+  (function() {
+    "use strict";
+    var exprTest = gebi('exprTest');
+    var moduleTest = gebi('moduleTest');
+    var scriptTest = gebi('scriptTest');
+    if (!ses.ok()) {
+      appendText(exprTest, 'cancelled');
+      appendText(moduleTest, 'cancelled');
+      appendText(scriptTest, 'cancelled');
+      appendText(amdLoaderTest, 'cancelled');
+      return;
+    }
+
+    var imports = cajaVM.makeImports();
+    cajaVM.copyToImports(imports, {window: 6});
+
+    var output = cajaVM.eval('3+4') * cajaVM.compileExpr('window')(imports);
+    var text1 = output === 42 ? 'succeeded' : 'failed: ' + output;
+    appendText(exprTest, text1);
+
+    // Test ability to bootstrap support for a limited form of
+    // CommonJS modules.
+    var modSrc = '"use noise"; exports.x = \n' +
+                 'require("foo.bar/baz"); return 77;';
+    var modMaker = cajaVM.compileModule(modSrc);
+    var required = modMaker.requirements;
+    var exported = {};
+    var returned = modMaker(cajaVM.copyToImports(imports, {
+      require: function(id) { return { foo: 88, id: id}; },
+      exports: exported
+    }));
+    var did = JSON.stringify(cajaVM.def({
+      required: required,
+      exported: exported,
+      returned: returned
+    }), void 0, ' ');
+    var should = JSON.stringify({
+      "required": [ "foo.bar/baz" ],
+      "exported": { "x": { "foo": 88, "id": "foo.bar/baz" } },
+      "returned": 77
+    }, void 0, ' ');
+    var text2 = did === should ? 'succeeded' : 'failed: ' + did;
+    appendText(moduleTest, text2);
+
+    // Tests the ability to do inter-module linkage as scripts
+    // traditionally did, by modification of (virtual) shared
+    // globals. Unfortunately, rather than say "var x = 88;" below, we
+    // must say "this.x = 88;" in order to export a global.
+    cajaVM.compileModule('this.x = 88;')(imports);
+    var text3 = cajaVM.compileExpr('x')(imports) === 88 ?
+      'succeeded' : 'failed';
+    appendText(scriptTest, text3);
+
+  })();
+</script>
+
+<script src="makeQ.js"></script>
+<script src="makeFarResourceMaker.js"></script>
+<script src="compileExprLater.js"></script>
+<script>
+  var Q;
+  (function() {
+    "use strict";
+
+    if (!ses.ok()) { return; }
+
+    /* TODO(erights): Extract the reusable boilerplate below into a
+       reusable abstraction. */
+
+    function mySetTimeout(func, millis) {
+      return setTimeout(function() {
+        try {
+          func();
+        } catch (reason) {
+          ses.logger.log('uncaught: ', reason);
+        }
+      }, millis);
+    }
+    Q = ses.makeQ(mySetTimeout);
+
+    var makeTextResource = ses.makeFarResourceMaker();
+
+    var url = './makeSimpleAMDLoader.js';
+    var makeSimpleAMDLoaderFileP = makeTextResource(url);
+    var makeSimpleAMDLoaderSrcP = makeSimpleAMDLoaderFileP.get();
+
+    /* We really are evaluating makeSimpleAMDModuleLoader with least
+       authority. Even though there's a global compileExprLater, if
+       you don't provide it here, makeSimpleAMDModuleLoader will
+       fail. */
+    var imports = cajaVM.makeImports();
+    cajaVM.copyToImports(imports, {
+      Q: Q,
+      compileExprLater: ses.compileExprLater
+    });
+
+    var makeSimpleAMDLoaderP = Q(makeSimpleAMDLoaderSrcP).when(function(src) {
+      var exprSrc = '(function() {' + src + '}).call(this)';
+      var compiledExprP = ses.compileExprLater(exprSrc, url);
+      return Q(compiledExprP).when(function(compiledExpr) {
+        compiledExpr(imports);
+        return imports.makeSimpleAMDLoader;
+      });
+    });
+
+
+    /**
+     * What we should do is accept any legal module identifier according
+     * to the AMD definition and encode it into a legal URL. Instead,
+     * for now, we just conservatively accept an ascii subset of both
+     * that does not need any encoding.
+     *
+     * See https://github.com/amdjs/amdjs-api/wiki/AMD#wiki-define-id-notes
+     */
+    var isModuleId = Object.freeze(/^[a-zA-Z0-9_/]*$/);
+
+    function fetch(id) {
+      if (!isModuleId.test(id)) {
+        throw new Error('illegal module id: ' + id);
+      }
+      return makeTextResource('./' + id + '.js').get();
+    }
+
+    var moduleMap = StringMap();
+    moduleMap.set('Q', Q);
+    var loaderP = Q(makeSimpleAMDLoaderP).send(void 0, fetch, moduleMap);
+    var amdTestP = Q(loaderP).send(void 0, 'amdTest');
+    Q(amdTestP).when(function(amdTest) {
+      var amdTestStatus = amdTest === 'this is a test' ?
+        'succeeded' : 'failed, unexpected: ' + amdTest;
+      /*console.profileEnd();*/
+      appendText(amdLoaderTest, amdTestStatus);
+    }, function(reason) {
+      /*console.profileEnd();*/
+      appendText(amdLoaderTest, 'failed: ' + reason);
+    }).end();
+  })();
+</script>
+
+<p>
+Using <span id="browserName">unknown</span>
+ <span id="browserVersion">unknown</span>
+on <span id="browserOS">unknown</span>
+<script src="detect.js"></script>
+<script>
+  (function(){
+    "use strict"
+    gebi('browserName').textContent = BrowserDetect.browser;
+    gebi('browserVersion').textContent = BrowserDetect.version;
+    gebi('browserOS').textContent = BrowserDetect.OS;
+  })();
+</script>
+</body>
+</html>
diff --git a/hookupSES.js b/hookupSES.js
new file mode 100644
index 0000000..3a9559e
--- /dev/null
+++ b/hookupSES.js
@@ -0,0 +1,43 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Call {@code ses.startSES} to turn this frame into a
+ * SES environment following object-capability rules.
+ *
+ * <p>Assumes ES5 plus WeakMap. Compatible with ES5-strict or
+ * anticipated ES6.
+ *
+ * @author Mark S. Miller
+ * @requires this
+ * @overrides ses, hookupSESModule
+ */
+
+(function hookupSESModule(global) {
+  "use strict";
+
+  if (!ses.ok()) {
+    return;
+  }
+
+  try {
+    ses.startSES(global,
+                 ses.whitelist,
+                 ses.atLeastFreeVarNames,
+                 function () { return {}; });
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    ses.logger.error('hookupSES failed with: ', err);
+  }
+})(this);
diff --git a/hookupSESPlus.js b/hookupSESPlus.js
new file mode 100644
index 0000000..fb68568
--- /dev/null
+++ b/hookupSESPlus.js
@@ -0,0 +1,43 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Call {@code ses.startSES} to turn this frame into a
+ * SES environment following object-capability rules.
+ *
+ * <p>Assumes ES5 plus WeakMap. Compatible with ES5-strict or
+ * anticipated ES6.
+ *
+ * @author Mark S. Miller
+ * @requires this
+ * @overrides ses, hookupSESPlusModule
+ */
+
+(function hookupSESPlusModule(global) {
+  "use strict";
+
+  if (!ses.ok()) {
+    return;
+  }
+
+  try {
+    ses.startSES(global,
+                 ses.whitelist,
+                 ses.atLeastFreeVarNames,
+                 ses.ejectorsGuardsTrademarks);
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    ses.logger.error('hookupSESPlus failed with: ', err);
+  }
+})(this);
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..0429ee7
--- /dev/null
+++ b/index.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+
+<!--
+ - Copyright (C) 2011 Google Inc.
+ -
+ - 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.
+-->
+
+<html>
+<head>
+<title>Testing SES/5</title>
+<style type="text/css">
+.log { color: black; }
+.info { color: navy; }
+.warn { color: olive; }
+.error { color: maroon; }
+.reports-text p { margin-top: 0.05em; margin-bottom: 0.05em; }
+.console-text p { margin-top: 0.05em; margin-bottom: 0.05em; }
+</style>
+</head>
+<body>
+<div id="reports" class="reports-text"><b>Repair Reports</b></div>
+<div id="console" class="console-text"><hr></div>
+<div id="show1">test1...</div>
+<div id="show2">test2...</div>
+<script src="useHTMLLogger.js"></script>
+<script>
+  function gebi(id) { 
+    return document.getElementById(id); 
+  };
+  useHTMLLogger(gebi("reports"), gebi("console"));
+  // This severity is too high for any use other than development.
+  ses.maxAcceptableSeverityName = 'NEW_SYMPTOM';
+</script>
+<script src="initSES.js"></script>
+<script>
+  (function() {
+    "use strict";
+    var show1 = gebi('show1');
+    var show2 = gebi('show2');
+    if (!ses.ok()) {
+      show1.appendChild(document.createTextNode('cancelled'));
+      show2.appendChild(document.createTextNode('cancelled'));
+      return;
+    }
+
+    var output = cajaVM.eval('3+4') * cajaVM.compile('window')({window: 6});
+    var text1 = output === 42 ? 'succeeded' : 'failed: ' + output;
+    show1.appendChild(document.createTextNode(text1));
+
+    // Test ability to bootstrap support for a limited form of
+    // CommonJS modules. 
+    var modSrc = '"use noise"; exports.x = \n' +
+                 'require("foo.bar/baz"); return 77;';
+    var modMaker = cajaVM.compileModule(modSrc);
+    var required = modMaker.requirements;
+    var exported = {};
+    var returned = modMaker({
+      require: function(id) { return { foo: 88, id: id}; }, 
+      exports: exported
+    });
+    var did = JSON.stringify(cajaVM.def({
+      required: required,
+      exported: exported, 
+      returned: returned
+    }), void 0, ' ');
+    var should = JSON.stringify({ 
+      "required": [ "foo.bar/baz" ], 
+      "exported": { "x": { "foo": 88, "id": "foo.bar/baz" } }, 
+      "returned": 77 
+    }, void 0, ' ');
+    var text2 = did === should ? 'succeeded' : 'failed: ' + did;
+    show2.appendChild(document.createTextNode(text2));
+  })();
+</script>
+</body>
+</html>
diff --git a/initSES-minified.js b/initSES-minified.js
new file mode 100644
index 0000000..51b4902
--- /dev/null
+++ b/initSES-minified.js
@@ -0,0 +1,336 @@
+{var Function,RegExp,StringMap,WeakMap,cajaVM,eval,ses;ses||(ses={}),(function loggerModule(){'use strict';var
+apply,forward,logger,slice;function logNowhere(str){}slice=[].slice,apply=slice.apply,ses.logger?(logger=ses.logger):typeof
+console!=='undefined'&&'log'in console?(forward=function(level,args){var getStack,i,len,stack;args=slice.call(args,0),apply.call(console[level],console,[''].concat(args)),getStack=ses.getStack;if(getStack)for(i=0,len=args.length;i<len;++i)stack=getStack(args[i]),stack&&console[level]('',stack)},logger={'log':function
+log(var_args){forward('log',arguments)},'info':function info(var_args){forward('info',arguments)},'warn':function
+warn(var_args){forward('warn',arguments)},'error':function error(var_args){forward('error',arguments)}}):(logger={'log':logNowhere,'info':logNowhere,'warn':logNowhere,'error':logNowhere});function
+defaultClassify(postSeverity){var MAX_SES_SAFE=ses.severities.SAFE_SPEC_VIOLATION,consoleLevel='log',note='';return postSeverity.level>ses.severities.SAFE.level&&(consoleLevel='info',note=postSeverity.description+'('+postSeverity.level+')',postSeverity.level>ses.maxAcceptableSeverity.level?(consoleLevel='error',note+=' is not suitable for SES'):postSeverity.level>MAX_SES_SAFE.level&&(consoleLevel='warn',note+=' is not SES-safe'),note+='.'),{'consoleLevel':consoleLevel,'note':note}}logger.classify||(logger.classify=defaultClassify);function
+defaultReportRepairs(reports){}logger.reportRepairs||(logger.reportRepairs=defaultReportRepairs);function
+defaultReportMax(){var maxClassification;ses.maxSeverity.level>ses.severities.SAFE.level&&(maxClassification=ses.logger.classify(ses.maxSeverity),logger[maxClassification.consoleLevel]('Max Severity: '+maxClassification.note))}logger.reportMax||(logger.reportMax=defaultReportMax);function
+defaultReportDiagnosis(severity,status,problemList){var classification=ses.logger.classify(severity);ses.logger[classification.consoleLevel](problemList.length+' '+status)}logger.reportDiagnosis||(logger.reportDiagnosis=defaultReportDiagnosis),ses.logger=logger})(),(function
+repairES5Module(global){'use strict';var NEEDS_DUMMY_SETTER_repaired,aboutTo,apply,baseKludges,builtInForEach,builtInMapMethod,call,concat,during,errorInstanceBlacklist,errorInstanceWhitelist,getPrototypeOf,hop,is,logger,makeTamperProof,maxSev,needToTamperProof,objToString,reports,severities,slice,statuses,strictThis,supportedKludges;ses.severities={'SAFE':{'level':0,'description':'Safe'},'SAFE_SPEC_VIOLATION':{'level':1,'description':'Safe spec violation'},'UNSAFE_SPEC_VIOLATION':{'level':2,'description':'Unsafe spec violation'},'NOT_OCAP_SAFE':{'level':3,'description':'Not ocap safe'},'NOT_ISOLATED':{'level':4,'description':'Not isolated'},'NEW_SYMPTOM':{'level':5,'description':'New symptom'},'NOT_SUPPORTED':{'level':6,'description':'Not supported'}},ses.statuses={'ALL_FINE':'All fine','REPAIR_FAILED':'Repair failed','NOT_REPAIRED':'Not repaired','REPAIRED_UNSAFELY':'Repaired unsafely','REPAIRED':'Repaired','ACCIDENTALLY_REPAIRED':'Accidentally repaired','BROKEN_BY_OTHER_ATTEMPTED_REPAIRS':'Broken by other attempted repairs'},logger=ses.logger,ses.maxSeverity=ses.severities.SAFE;if(ses.maxAcceptableSeverityName){maxSev=ses.severities[ses.maxAcceptableSeverityName];if(maxSev&&typeof
+maxSev.level==='number'&&maxSev.level>=ses.severities.SAFE.level&&maxSev.level<ses.severities.NOT_SUPPORTED.level);else
+logger.error('Ignoring bad maxAcceptableSeverityName: '+ses.maxAcceptableSeverityName+'.'),ses.maxAcceptableSeverityName='SAFE_SPEC_VIOLATION'}else
+ses.maxAcceptableSeverityName='SAFE_SPEC_VIOLATION';ses.maxAcceptableSeverity=ses.severities[ses.maxAcceptableSeverityName],ses.ok=function
+ok(){return ses.maxSeverity.level<=ses.maxAcceptableSeverity.level},ses.updateMaxSeverity=function
+updateMaxSeverity(severity){severity.level>ses.maxSeverity.level&&(ses.maxSeverity=severity)};function
+strictForEachFn(list,callback){var i,len;for(i=0,len=list.length;i<len;++i)callback(list[i],i)}function
+strictMapFn(list,callback){var result=[],i,len;for(i=0,len=list.length;i<len;++i)result.push(callback(list[i],i));return result}objToString=Object.prototype.toString,builtInMapMethod=Array.prototype.map,builtInForEach=Array.prototype.forEach,is=ses.is=Object.is||function(x,y){return x===y?x!==0||1/x===1/y:x!==x&&y!==y},ses.makeCallerHarmless=function
+assumeCallerHarmless(func,path){return'Apparently fine'},ses.makeArgumentsHarmless=function
+assumeArgumentsHarmless(func,path){return'Apparently fine'},makeTamperProof=function
+defaultMakeTamperProof(){var gopd=Object.getOwnPropertyDescriptor,gopn=Object.getOwnPropertyNames,getProtoOf=Object.getPrototypeOf,freeze=Object.freeze,isFrozen=Object.isFrozen,defProp=Object.defineProperty;function
+tamperProof(obj){var func;return obj!==Object(obj)?obj:(typeof obj==='object'&&!!gopd(obj,'constructor')&&typeof(func=obj.constructor)==='function'&&func.prototype===obj&&!isFrozen(obj)&&strictForEachFn(gopn(obj),function(name){var
+desc,value;function getter(){var thisObj;return obj===this?value:this===void 0||this===null?void
+0:(thisObj=Object(this),gopd(thisObj,name)?this[name]:getter.call(getProtoOf(thisObj)))}function
+setter(newValue){if(obj===this)throw new TypeError('Cannot set virtually frozen property: '+name);!gopd(this,name)||(this[name]=newValue),defProp(this,name,{'value':newValue,'writable':true,'enumerable':true,'configurable':true})}desc=gopd(obj,name),desc.configurable&&'value'in
+desc&&(value=desc.value,getter.prototype=null,setter.prototype=null,defProp(obj,name,{'get':getter,'set':setter,'enumerable':desc.enumerable,'configurable':false}))}),freeze(obj))}return tamperProof},needToTamperProof=[];function
+rememberToTamperProof(obj){needToTamperProof.push(obj)}ses.makeDelayedTamperProof=function
+makeDelayedTamperProof(){var tamperProof=makeTamperProof();return strictForEachFn(needToTamperProof,tamperProof),needToTamperProof=void
+0,tamperProof};function testGlobalLeak(desc,that){return that===void 0?false:that===global?true:({}).toString.call(that)==='[object Window]'?true:desc+' leaked as: '+that}function
+test_MISSING_GETOWNPROPNAMES(){return!('getOwnPropertyNames'in Object)}function
+test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS(){var that;return global.___global_test_function___=function(){return this},that=___global_test_function___(),delete
+global.___global_test_function___,testGlobalLeak('Global func \"this\"',that)}function
+test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS(){var that=(function(){return this})();return testGlobalLeak('Anon func \"this\"',that)}strictThis=this;function
+test_GLOBAL_LEAKS_FROM_STRICT_THIS(){return testGlobalLeak('Strict \"this\"',strictThis)}function
+test_GLOBAL_LEAKS_FROM_BUILTINS(){var v=({}).valueOf,that='dummy';try{that=v()}catch(err){return err
+instanceof TypeError?false:'valueOf() threw: '+err}return that===void 0?false:testGlobalLeak('valueOf()',that)}function
+test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS(){var that;global.___global_valueOf_function___=({}).valueOf,that='dummy';try{that=___global_valueOf_function___()}catch(err){return err
+instanceof TypeError?false:'valueOf() threw: '+err}finally{delete global.___global_valueOf_function___}return that===void
+0?false:testGlobalLeak('Global valueOf()',that)}function test_MISSING_FREEZE_ETC(){return!('freeze'in
+Object)}function test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES(){function foo(){}return Object.defineProperty(foo,'prototype',{'value':{}}),foo.prototype!==Object.getOwnPropertyDescriptor(foo,'prototype').value}function
+test_MISSING_CALLEE_DESCRIPTOR(){function foo(){}return Object.getOwnPropertyNames(foo).indexOf('callee')<0?false:foo.hasOwnProperty('callee')?'Empty strict function has own callee':true}function
+test_STRICT_DELETE_RETURNS_FALSE(){var deleted;if(!RegExp.hasOwnProperty('rightContext'))return false;try{deleted=delete
+RegExp.rightContext}catch(err){return err instanceof TypeError?false:'Deletion failed with: '+err}return!deleted}function
+test_REGEXP_CANT_BE_NEUTERED(){var deleted;if(!RegExp.hasOwnProperty('leftContext'))return false;try{deleted=delete
+RegExp.leftContext}catch(err){return err instanceof TypeError?true:'Deletion failed with: '+err}return RegExp.hasOwnProperty('leftContext')?deleted?'Deletion of RegExp.leftContext did not succeed.':true:false}function
+test_REGEXP_TEST_EXEC_UNSAFE(){var match;return/foo/.test('xfoox'),match=(new RegExp('(.|\r|\n)*','').exec())[0],match==='undefined'?false:match==='xfoox'?true:'regExp.exec() does not match against \"undefined\".'}function
+test_MISSING_BIND(){return!('bind'in Function.prototype)}function test_BIND_CALLS_APPLY(){var
+answer,applyCalled,b;if(!('bind'in Function.prototype))return false;applyCalled=false;function
+foo(){return[].slice.call(arguments,0).join(',')}return foo.apply=function fakeApply(self,args){return applyCalled=true,Function.prototype.apply.call(this,self,args)},b=foo.bind(33,44),answer=b(55,66),applyCalled?true:answer==='44,55,66'?false:'Bind test returned \"'+answer+'\" instead of \"44,55,66\".'}function
+test_BIND_CANT_CURRY_NEW(){var d,str;function construct(f,args){var bound=Function.prototype.bind.apply(f,[null].concat(args));return new
+bound}try{d=construct(Date,[1957,4,27])}catch(err){return err instanceof TypeError?true:'Curries construction failed with: '+err}return typeof
+d==='string'?true:(str=objToString.call(d),str==='[object Date]'?false:'Unexpected '+str+': '+d)}function
+test_MUTABLE_DATE_PROTO(){var v;try{Date.prototype.setFullYear(1957)}catch(err){return err
+instanceof TypeError?false:'Mutating Date.prototype failed with: '+err}return v=Date.prototype.getFullYear(),Date.prototype.setFullYear(NaN),v!==v&&typeof
+v==='number'?false:v===1957?true:'Mutating Date.prototype did not throw'}function
+test_MUTABLE_WEAKMAP_PROTO(){var v,x;if(typeof WeakMap!=='function')return false;x={};try{WeakMap.prototype.set(x,86)}catch(err){return err
+instanceof TypeError?false:'Mutating WeakMap.prototype failed with: '+err}return v=WeakMap.prototype.get(x),v===86?true:'Mutating WeakMap.prototype did not throw'}function
+test_NEED_TO_WRAP_FOREACH(){if(!('freeze'in Object))return false;if(Array.prototype.forEach!==builtInForEach)return false;try{return['z'].forEach(function(){Object.freeze(Array.prototype.forEach)}),false}catch(err){return err
+instanceof TypeError?true:'freezing forEach failed with '+err}}function test_NEEDS_DUMMY_SETTER(){var
+ChromeMajorVersionPattern,match,ver;return NEEDS_DUMMY_SETTER_repaired?false:typeof
+navigator==='undefined'?false:(ChromeMajorVersionPattern=/Chrome\/(\d*)\./,match=ChromeMajorVersionPattern.exec(navigator.userAgent),match?(ver=+match[1],ver<=17):false)}NEEDS_DUMMY_SETTER_repaired=false;function
+test_FORM_GETTERS_DISAPPEAR(){var desc,f;function getter(){return'gotten'}if(typeof
+document==='undefined'||typeof document.createElement!=='function')return false;f=document.createElement('form');try{Object.defineProperty(f,'foo',{'get':getter,'set':void
+0})}catch(err){return'defining accessor on form failed with: '+err}return desc=Object.getOwnPropertyDescriptor(f,'foo'),desc.get===getter?false:desc.get===void
+0?true:'Getter became '+desc.get}function test_ACCESSORS_INHERIT_AS_OWN(){var base={},derived=Object.create(base);function
+getter(){return'gotten'}return Object.defineProperty(base,'foo',{'get':getter}),!derived.hasOwnProperty('foo')&&Object.getOwnPropertyDescriptor(derived,'foo')===void
+0&&Object.getOwnPropertyNames(derived).indexOf('foo')<0?false:!derived.hasOwnProperty('foo')||Object.getOwnPropertyDescriptor(derived,'foo').get!==getter||Object.getOwnPropertyNames(derived).indexOf('foo')<0?'Accessor properties partially inherit as own properties.':(Object.defineProperty(base,'bar',{'get':getter,'configurable':true}),!derived.hasOwnProperty('bar')&&Object.getOwnPropertyDescriptor(derived,'bar')===void
+0&&Object.getOwnPropertyNames(derived).indexOf('bar')<0?true:'Accessor properties inherit as own even if configurable.')}function
+test_SORT_LEAKS_GLOBAL(){var that='dummy';return[2,3].sort(function(x,y){return that=this,x-y}),that===void
+0?false:that===global?true:'sort called comparefn with \"this\" === '+that}function
+test_REPLACE_LEAKS_GLOBAL(){var that='dummy';function capture(){return that=this,'y'}return'x'.replace(/x/,capture),that===void
+0?false:that===capture?true:that===global?true:'Replace called replaceValue function with \"this\" === '+that}function
+test_CANT_GOPD_CALLER(){var desc=null;try{desc=Object.getOwnPropertyDescriptor(function(){},'caller')}catch(err){return err
+instanceof TypeError?true:'getOwnPropertyDescriptor failed with: '+err}return desc&&typeof
+desc.get==='function'&&typeof desc.set==='function'&&!desc.configurable?false:desc&&desc.value===null&&!desc.writable&&!desc.configurable?false:'getOwnPropertyDesciptor returned unexpected caller descriptor'}function
+test_CANT_HASOWNPROPERTY_CALLER(){var answer=void 0;try{answer=(function(){}).hasOwnProperty('caller')}catch(err){return err
+instanceof TypeError?true:'hasOwnProperty failed with: '+err}return answer?false:'strict_function.hasOwnProperty(\"caller\") was false'}function
+has(base,name,baseDesc){var result=void 0,finallySkipped=true;try{result=name in
+base}catch(err){return logger.error('New symptom (a): (\''+name+'\' in <'+baseDesc+'>) threw: ',err),result=false,false}finally{finallySkipped=false,result===void
+0&&logger.error('New symptom (b): (\''+name+'\' in <'+baseDesc+'>) failed')}return finallySkipped&&logger.error('New symptom (e): (\''+name+'\' in <'+baseDesc+'>) inner finally skipped'),!!result}function
+has2(base,name,baseDesc){var result=void 0,finallySkipped=true;try{result=has(base,name,baseDesc)}catch(err){return logger.error('New symptom (c): (\''+name+'\' in <'+baseDesc+'>) threw: ',err),result=false,false}finally{finallySkipped=false,result===void
+0&&logger.error('New symptom (d): (\''+name+'\' in <'+baseDesc+'>) failed')}return finallySkipped&&logger.error('New symptom (f): (\''+name+'\' in <'+baseDesc+'>) outer finally skipped'),!!result}function
+test_CANT_IN_CALLER(){var answer=void 0;try{answer=has2(function(){},'caller','strict_function')}catch(err){return err
+instanceof TypeError?true:'(\"caller\" in strict_func) failed with: '+err}finally{}return answer?false:'(\"caller\" in strict_func) was false.'}function
+test_CANT_IN_ARGUMENTS(){var answer=void 0;try{answer=has2(function(){},'arguments','strict_function')}catch(err){return err
+instanceof TypeError?true:'(\"arguments\" in strict_func) failed with: '+err}finally{}return answer?false:'(\"arguments\" in strict_func) was false.'}function
+test_STRICT_CALLER_NOT_POISONED(){var caller,testfn;if(!has2(strictMapFn,'caller','a strict function'))return false;function
+foo(m){return m.caller}testfn=Function('m','f','return m([m], f)[0];');try{caller=testfn(strictMapFn,foo)}catch(err){return err
+instanceof TypeError?false:'Strict \"caller\" failed with: '+err}return testfn===caller?true:'Unexpected \"caller\": '+caller}function
+test_STRICT_ARGUMENTS_NOT_POISONED(){var args,testfn;if(!has2(strictMapFn,'arguments','a strict function'))return false;function
+foo(m){return m.arguments}testfn=Function('m','f','return m([m], f)[0];');try{args=testfn(strictMapFn,foo)}catch(err){return err
+instanceof TypeError?false:'Strict \"arguments\" failed with: '+err}return args[1]===foo?true:'Unexpected arguments: '+arguments}function
+test_BUILTIN_LEAKS_CALLER(){var a,caller,testfn;if(!has2(builtInMapMethod,'caller','a builtin'))return false;function
+foo(m){return m.caller}testfn=Function('a','f','return a.map(f)[0];'),a=[builtInMapMethod],a.map=builtInMapMethod;try{caller=testfn(a,foo)}catch(err){return err
+instanceof TypeError?false:'Built-in \"caller\" failed with: '+err}return null===caller||void
+0===caller?false:testfn===caller?true:'Unexpected \"caller\": '+caller}function
+test_BUILTIN_LEAKS_ARGUMENTS(){var a,args,testfn;if(!has2(builtInMapMethod,'arguments','a builtin'))return false;function
+foo(m){return m.arguments}testfn=Function('a','f','return a.map(f)[0];'),a=[builtInMapMethod],a.map=builtInMapMethod;try{args=testfn(a,foo)}catch(err){return err
+instanceof TypeError?false:'Built-in \"arguments\" failed with: '+err}return!(args===void
+0||args===null)}function test_BOUND_FUNCTION_LEAKS_CALLER(){var bar,caller,testfn;if(!('bind'in
+Function.prototype))return false;function foo(){return bar.caller}bar=foo.bind({});if(!has2(bar,'caller','a bound function'))return false;testfn=Function('b','return b();');try{caller=testfn(bar)}catch(err){return err
+instanceof TypeError?false:'Bound function \"caller\" failed with: '+err}return caller===void
+0||caller===null?false:caller===testfn?true:'Unexpected \"caller\": '+caller}function
+test_BOUND_FUNCTION_LEAKS_ARGUMENTS(){var args,bar,testfn;if(!('bind'in Function.prototype))return false;function
+foo(){return bar.arguments}bar=foo.bind({});if(!has2(bar,'arguments','a bound function'))return false;testfn=Function('b','return b();');try{args=testfn(bar)}catch(err){return err
+instanceof TypeError?false:'Bound function \"arguments\" failed with: '+err}return!(args===void
+0||args===null)}function test_DELETED_BUILTINS_IN_OWN_NAMES(){var desc,names;if(!('__defineSetter__'in
+Object.prototype))return false;desc=Object.getOwnPropertyDescriptor(Object.prototype,'__defineSetter__');try{try{delete
+Object.prototype.__defineSetter__}catch(err1){return false}return names=Object.getOwnPropertyNames(Object.prototype),names.indexOf('__defineSetter__')===-1?false:!('__defineSetter__'in
+Object.prototype)}finally{Object.defineProperty(Object.prototype,'__defineSetter__',desc)}}function
+test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS(){try{Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptor,'caller')}catch(err){return err
+instanceof TypeError?true:'getOwnPropertyDescriptor threw: '+err}return false}function
+test_JSON_PARSE_PROTO_CONFUSION(){var x;try{x=JSON.parse('{\"__proto__\":[]}')}catch(err){return err
+instanceof TypeError?false:'JSON.parse failed with: '+err}return Object.getPrototypeOf(x)!==Object.prototype?true:Array.isArray(x.__proto__)?false:'JSON.parse did not set \"__proto__\" as a regular property'}function
+test_PROTO_NOT_FROZEN(){var x,y;if(!('freeze'in Object))return false;x=Object.preventExtensions({});if(x.__proto__===void
+0&&!('__proto__'in x))return false;y={};try{x.__proto__=y}catch(err){return err
+instanceof TypeError?false:'Mutating __proto__ failed with: '+err}return y.isPrototypeOf(x)?true:'Mutating __proto__ neither failed nor succeeded'}function
+test_PROTO_REDEFINABLE(){var x,y;if(!('freeze'in Object))return false;x=Object.preventExtensions({});if(x.__proto__===void
+0&&!('__proto__'in x))return false;y={};try{Object.defineProperty(x,'__proto__',{'value':y})}catch(err){return err
+instanceof TypeError?false:'Defining __proto__ failed with: '+err}return y.isPrototypeOf(x)?true:'Defining __proto__ neither failed nor succeeded'}function
+test_STRICT_EVAL_LEAKS_GLOBALS(){return eval('\"use strict\"; var ___global_test_variable___ = 88;'),'___global_test_variable___'in
+global?(delete global.___global_test_variable___,true):false}function test_PARSEINT_STILL_PARSING_OCTAL(){var
+n=parseInt('010');return n===10?false:n===8?true:'parseInt(\"010\") returned '+n}function
+test_STRICT_E4X_LITERALS_ALLOWED(){var x;try{x=eval('\"use strict\";(<foo/>);')}catch(err){return err
+instanceof SyntaxError?false:'E4X test failed with: '+err}return x!==void 0?true:'E4X literal expression had no value'}function
+test_ASSIGN_CAN_OVERRIDE_FROZEN(){var x=Object.freeze({'foo':88}),y=Object.create(x);try{y.foo=99}catch(err){return err
+instanceof TypeError?false:'Override failed with: '+err}return y.foo===99?true:y.foo===88?'Override failed silently':'Unexpected override outcome: '+y.foo}function
+test_CANT_REDEFINE_NAN_TO_ITSELF(){var descNaN=Object.getOwnPropertyDescriptor(global,'NaN');try{Object.defineProperty(global,'NaN',descNaN)}catch(err){return err
+instanceof TypeError?true:'defineProperty of NaN failed with: '+err}return false}errorInstanceWhitelist=['arguments','message','stack','type','fileName','lineNumber','message','stack','line','message','sourceId','sourceURL','description','message','number','message','stack','stacktrace'],errorInstanceBlacklist=['category','context','href','lineNo','msgId','source','trace','correctSourcePoint','correctWithStackTrace','getSourceLine','resetSource'];function
+freshErrorInstanceWhiteMap(){var result=Object.create(null);return strictForEachFn(errorInstanceWhitelist,function(name){result[name]=true}),result}function
+freshHiddenPropertyCandidates(){var result=freshErrorInstanceWhiteMap();return strictForEachFn(errorInstanceBlacklist,function(name){result[name]=true}),result}function
+test_UNEXPECTED_ERROR_PROPERTIES(){var errs=[new Error('e1')],approvedNames,result;try{null.foo=3}catch(err){errs.push(err)}return result=false,approvedNames=freshErrorInstanceWhiteMap(),strictForEachFn(errs,function(err){strictForEachFn(Object.getOwnPropertyNames(err),function(name){name
+in approvedNames||(result='Unexpected error instance property: '+name)})}),result}function
+test_GET_OWN_PROPERTY_NAME_LIES(){var gopn=Object.getOwnPropertyNames,gopd=Object.getOwnPropertyDescriptor,suspects=[new
+Error('e1')],unreported,unreportedNames;try{null.foo=3}catch(err){suspects.push(err)}return unreported=Object.create(null),strictForEachFn(suspects,function(suspect){var
+candidates=freshHiddenPropertyCandidates();strictForEachFn(gopn(suspect),function(name){delete
+candidates[name]}),strictForEachFn(gopn(candidates),function(name){gopd(suspect,name)||delete
+candidates[name]}),strictForEachFn(gopn(candidates),function(name){unreported[name]=true})}),unreportedNames=gopn(unreported),unreportedNames.length===0?false:'Error own properties unreported by getOwnPropertyNames: '+unreportedNames.sort().join(',')}call=Function.prototype.call,apply=Function.prototype.apply,hop=Object.prototype.hasOwnProperty,slice=Array.prototype.slice,concat=Array.prototype.concat,getPrototypeOf=Object.getPrototypeOf;function
+patchMissingProp(base,name,missingFunc){name in base||Object.defineProperty(base,name,{'value':missingFunc,'writable':true,'enumerable':false,'configurable':true})}function
+repair_MISSING_FREEZE_ETC(){patchMissingProp(Object,'freeze',function fakeFreeze(obj){return obj}),patchMissingProp(Object,'seal',function
+fakeSeal(obj){return obj}),patchMissingProp(Object,'preventExtensions',function
+fakePreventExtensions(obj){return obj}),patchMissingProp(Object,'isFrozen',function
+fakeIsFrozen(obj){return false}),patchMissingProp(Object,'isSealed',function fakeIsSealed(obj){return false}),patchMissingProp(Object,'isExtensible',function
+fakeIsExtensible(obj){return true})}function repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES(){var
+unsafeDefProp=Object.defineProperty;function repairedDefineProperty(base,name,desc){if(typeof
+base==='function'&&name==='prototype'&&'value'in desc)try{base.prototype=desc.value}catch(err){logger.warn('prototype fixup failed',err)}return unsafeDefProp(base,name,desc)}Object.defineProperty(Object,'defineProperty',{'value':repairedDefineProperty})}function
+repair_MISSING_CALLEE_DESCRIPTOR(){var realGOPN=Object.getOwnPropertyNames;Object.defineProperty(Object,'getOwnPropertyNames',{'value':function
+calleeFix(base){var result=realGOPN(base),i;return typeof base==='function'&&(i=result.indexOf('callee'),i>=0&&!hop.call(base,'callee')&&result.splice(i,1)),result}})}function
+repair_REGEXP_CANT_BE_NEUTERED(){var UnsafeRegExp=RegExp,FakeRegExp=function RegExpWrapper(pattern,flags){switch(arguments.length){case
+0:return UnsafeRegExp();case 1:return UnsafeRegExp(pattern);default:return UnsafeRegExp(pattern,flags)}};Object.defineProperty(FakeRegExp,'prototype',{'value':UnsafeRegExp.prototype}),Object.defineProperty(FakeRegExp.prototype,'constructor',{'value':FakeRegExp}),RegExp=FakeRegExp}function
+repair_REGEXP_TEST_EXEC_UNSAFE(){var unsafeRegExpExec=RegExp.prototype.exec,unsafeRegExpTest=RegExp.prototype.test;Object.defineProperty(RegExp.prototype,'exec',{'value':function
+fakeExec(specimen){return unsafeRegExpExec.call(this,String(specimen))}}),Object.defineProperty(RegExp.prototype,'test',{'value':function
+fakeTest(specimen){return unsafeRegExpTest.call(this,String(specimen))}})}function
+repair_MISSING_BIND(){var BOGUS_BOUND_PROTOTYPE={'toString':function BBPToString(){return'bogus bound prototype'}},defProp;rememberToTamperProof(BOGUS_BOUND_PROTOTYPE),BOGUS_BOUND_PROTOTYPE.toString.prototype=null,rememberToTamperProof(BOGUS_BOUND_PROTOTYPE.toString),defProp=Object.defineProperty,defProp(Function.prototype,'bind',{'value':function
+fakeBind(self,var_args){var thisFunc=this,leftArgs=slice.call(arguments,1);function
+funcBound(var_args){var args;if(this===Object(this)&&getPrototypeOf(this)===BOGUS_BOUND_PROTOTYPE)throw new
+TypeError('Cannot emulate \"new\" on pseudo-bound function.');return args=concat.call(leftArgs,slice.call(arguments,0)),apply.call(thisFunc,self,args)}return defProp(funcBound,'prototype',{'value':BOGUS_BOUND_PROTOTYPE,'writable':false,'configurable':false}),funcBound},'writable':true,'enumerable':false,'configurable':true})}function
+makeMutableProtoPatcher(constr,classString){var proto=constr.prototype,baseToString=objToString.call(proto),grandBaseToString,grandProto;if(baseToString!=='[object '+classString+']')throw new
+TypeError('unexpected: '+baseToString);grandProto=getPrototypeOf(proto),grandBaseToString=objToString.call(grandProto);if(grandBaseToString==='[object '+classString+']')throw new
+TypeError('malformed inheritance: '+classString);grandProto!==Object.prototype&&logger.log('unexpected inheritance: '+classString);function
+mutableProtoPatcher(name){var originalMethod;if(!hop.call(proto,name))return;originalMethod=proto[name];function
+replacement(var_args){var parent=getPrototypeOf(this),thisToString;if(parent!==proto){if(objToString.call(parent)!==baseToString)throw thisToString=objToString.call(this),thisToString===baseToString?new
+TypeError('May not mutate internal state of a '+classString+'.prototype'):new TypeError('Unexpected: '+thisToString)};return originalMethod.apply(this,arguments)}Object.defineProperty(proto,name,{'value':replacement})}return mutableProtoPatcher}function
+repair_MUTABLE_DATE_PROTO(){['setYear','setTime','setFullYear','setUTCFullYear','setMonth','setUTCMonth','setDate','setUTCDate','setHours','setUTCHours','setMinutes','setUTCMinutes','setSeconds','setUTCSeconds','setMilliseconds','setUTCMilliseconds'].forEach(makeMutableProtoPatcher(Date,'Date'))}function
+repair_MUTABLE_WEAKMAP_PROTO(){['set','delete'].forEach(makeMutableProtoPatcher(WeakMap,'WeakMap'))}function
+repair_NEED_TO_WRAP_FOREACH(){var forEach=Array.prototype.forEach;Object.defineProperty(Array.prototype,'forEach',{'value':function
+forEachWrapper(callbackfn,opt_thisArg){return forEach.apply(this,arguments)}})}function
+repair_NEEDS_DUMMY_SETTER(){var defProp=Object.defineProperty,gopd=Object.getOwnPropertyDescriptor;function
+dummySetter(newValue){throw new TypeError('no setter for assigning: '+newValue)}dummySetter.prototype=null,rememberToTamperProof(dummySetter),defProp(Object,'defineProperty',{'value':function
+setSetterDefProp(base,name,desc){var desc2,newDesc,oldDesc,result,testBase;if(typeof
+desc.get==='function'&&desc.set===void 0){oldDesc=gopd(base,name);if(oldDesc)testBase={},defProp(testBase,name,oldDesc),defProp(testBase,name,desc),desc=gopd(testBase,name),desc.set===void
+0&&(desc.set=dummySetter);else{if(objToString.call(base)==='[object HTMLFormElement]'){desc2={'get':desc.get},'enumerable'in
+desc&&(desc2.enumerable=desc.enumerable),'configurable'in desc&&(desc2.configurable=desc.configurable),result=defProp(base,name,desc2),newDesc=gopd(base,name);if(newDesc.get===desc.get)return result}desc.set=dummySetter}}return defProp(base,name,desc)}}),NEEDS_DUMMY_SETTER_repaired=true}function
+repair_ACCESSORS_INHERIT_AS_OWN(){var defProp=Object.defineProperty,freeze=Object.freeze,seal=Object.seal,gopn=Object.getOwnPropertyNames,gopd=Object.getOwnPropertyDescriptor,complaint='Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=637994  prohibits enumerable non-configurable accessor properties.';function
+isBadAccessor(derived,name){var desc=gopd(derived,name),base,superDesc;return!desc||!('get'in
+desc)?false:(base=getPrototypeOf(derived),base?(superDesc=gopd(base,name),!superDesc||!('get'in
+superDesc)?false:desc.get&&!desc.configurable&&!superDesc.configurable&&desc.get===superDesc.get&&desc.set===superDesc.set&&desc.enumerable===superDesc.enumerable):false)}defProp(Object,'defineProperty',{'value':function
+definePropertyWrapper(base,name,desc){var oldDesc=gopd(base,name),testBase={},fullDesc;oldDesc&&!isBadAccessor(base,name)&&defProp(testBase,name,oldDesc),defProp(testBase,name,desc),fullDesc=gopd(testBase,name);if('get'in
+fullDesc&&fullDesc.enumerable&&!fullDesc.configurable)throw logger.warn(complaint),new
+TypeError(complaint+' (Object: '+base+' Property: '+name+')');return defProp(base,name,fullDesc)}});function
+ensureSealable(base){gopn(base).forEach(function(name){var desc=gopd(base,name);if('get'in
+desc&&desc.enumerable)throw desc.configurable||logger.error('New symptom: \"'+name+'\" already non-configurable'),logger.warn(complaint),new
+TypeError(complaint+' (During sealing. Object: '+base+' Property: '+name+')')})}defProp(Object,'freeze',{'value':function
+freezeWrapper(base){return ensureSealable(base),freeze(base)}}),defProp(Object,'seal',{'value':function
+sealWrapper(base){return ensureSealable(base),seal(base)}}),defProp(Object.prototype,'hasOwnProperty',{'value':function
+hasOwnPropertyWrapper(name){return hop.call(this,name)&&!isBadAccessor(this,name)}}),defProp(Object,'getOwnPropertyDescriptor',{'value':function
+getOwnPropertyDescriptorWrapper(base,name){return isBadAccessor(base,name)?void 0:gopd(base,name)}}),defProp(Object,'getOwnPropertyNames',{'value':function
+getOwnPropertyNamesWrapper(base){return gopn(base).filter(function(name){return!isBadAccessor(base,name)})}})}function
+repair_SORT_LEAKS_GLOBAL(){var unsafeSort=Array.prototype.sort;function sortWrapper(opt_comparefn){function
+comparefnWrapper(x,y){return opt_comparefn(x,y)}return arguments.length===0?unsafeSort.call(this):unsafeSort.call(this,comparefnWrapper)}Object.defineProperty(Array.prototype,'sort',{'value':sortWrapper})}function
+repair_REPLACE_LEAKS_GLOBAL(){var unsafeReplace=String.prototype.replace;function
+replaceWrapper(searchValue,replaceValue){var safeReplaceValue=replaceValue;function
+replaceValueWrapper(m1,m2,m3){return replaceValue(m1,m2,m3)}return typeof replaceValue==='function'&&(safeReplaceValue=replaceValueWrapper),unsafeReplace.call(this,searchValue,safeReplaceValue)}Object.defineProperty(String.prototype,'replace',{'value':replaceWrapper})}function
+repair_CANT_GOPD_CALLER(){var unsafeGOPD=Object.getOwnPropertyDescriptor;function
+gopdWrapper(base,name){try{return unsafeGOPD(base,name)}catch(err){if(err instanceof
+TypeError&&typeof base==='function'&&(name==='caller'||name==='arguments'))return(function(message){function
+fakePoison(){throw new TypeError(message)}return fakePoison.prototype=null,{'get':fakePoison,'set':fakePoison,'enumerable':false,'configurable':false}})(err.message);throw err}}Object.defineProperty(Object,'getOwnPropertyDescriptor',{'value':gopdWrapper})}function
+repair_CANT_HASOWNPROPERTY_CALLER(){Object.defineProperty(Object.prototype,'hasOwnProperty',{'value':function
+hopWrapper(name){return!!Object.getOwnPropertyDescriptor(this,name)}})}function
+makeHarmless(magicName,func,path){var desc;function poison(){throw new TypeError('Cannot access property '+path)}poison.prototype=null,desc=Object.getOwnPropertyDescriptor(func,magicName);if(!desc&&Object.isExtensible(func)||desc.configurable){try{Object.defineProperty(func,magicName,{'get':poison,'set':poison,'configurable':false})}catch(cantPoisonErr){return'Poisoning failed with '+cantPoisonErr}return desc=Object.getOwnPropertyDescriptor(func,magicName),desc&&desc.get===poison&&desc.set===poison&&!desc.configurable?'Apparently poisoned':'Not poisoned'}if('get'in
+desc||'set'in desc)return'Apparently safe';try{Object.defineProperty(func,magicName,{'value':desc.value===null?null:void
+0,'writable':false,'configurable':false})}catch(cantFreezeHarmlessErr){return'Freezing harmless failed with '+cantFreezeHarmlessErr}return desc=Object.getOwnPropertyDescriptor(func,magicName),desc&&(desc.value===null||desc.value===void
+0)&&!desc.writable&&!desc.configurable?'Apparently frozen harmless':'Did not freeze harmless'}function
+repair_BUILTIN_LEAKS_CALLER(){ses.makeCallerHarmless=makeHarmless.bind(void 0,'caller')}function
+repair_BUILTIN_LEAKS_ARGUMENTS(){ses.makeArgumentsHarmless=makeHarmless.bind(void
+0,'arguments')}function repair_DELETED_BUILTINS_IN_OWN_NAMES(){var realGOPN=Object.getOwnPropertyNames,repairedHop=Object.prototype.hasOwnProperty;function
+getOnlyRealOwnPropertyNames(base){return realGOPN(base).filter(function(name){return repairedHop.call(base,name)})}Object.defineProperty(Object,'getOwnPropertyNames',{'value':getOnlyRealOwnPropertyNames})}function
+repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS(){var realGOPD=Object.getOwnPropertyDescriptor;function
+GOPDWrapper(base,name){return realGOPD(base,name)}Object.defineProperty(Object,'getOwnPropertyDescriptor',{'value':GOPDWrapper})}function
+repair_JSON_PARSE_PROTO_CONFUSION(){var unsafeParse=JSON.parse;function validate(plainJSON){var
+proto;if(plainJSON!==Object(plainJSON))return;proto=getPrototypeOf(plainJSON);if(proto!==Object.prototype&&proto!==Array.prototype)throw new
+TypeError('Parse resulted in invalid JSON. See http://code.google.com/p/v8/issues/detail?id=621');Object.keys(plainJSON).forEach(function(key){validate(plainJSON[key])})}Object.defineProperty(JSON,'parse',{'value':function
+parseWrapper(text,opt_reviver){var result=unsafeParse(text);return validate(result),opt_reviver?unsafeParse(text,opt_reviver):result},'writable':true,'enumerable':false,'configurable':true})}function
+repair_PARSEINT_STILL_PARSING_OCTAL(){var badParseInt=parseInt;function goodParseInt(n,radix){var
+isHexOrOctal,isOct;return n=''+n,radix=+radix,isHexOrOctal=/^\s*[+-]?\s*0(x?)/.exec(n),isOct=isHexOrOctal?isHexOrOctal[1]!=='x':false,isOct&&(radix!==radix||0===radix)?badParseInt(n,10):badParseInt(n,radix)}parseInt=goodParseInt}function
+repair_ASSIGN_CAN_OVERRIDE_FROZEN(){makeTamperProof=function simpleMakeTamperProof(){return Object.freeze}}function
+repair_CANT_REDEFINE_NAN_TO_ITSELF(){var defProp=Object.defineProperty,attrs=['writable','get','set','enumerable','configurable'];defProp(Object,'defineProperty',{'value':function(base,name,desc){var
+attr,i,len,oldDesc;try{return defProp(base,name,desc)}catch(err){oldDesc=Object.getOwnPropertyDescriptor(base,name);for(i=0,len=attrs.length;i<len;++i){attr=attrs[i];if(attr
+in desc&&desc[attr]!==oldDesc[attr])throw err}if(!('value'in desc)||is(desc.value,oldDesc.value))return base;throw err}}})}severities=ses.severities,statuses=ses.statuses,baseKludges=[{'description':'Missing getOwnPropertyNames','test':test_MISSING_GETOWNPROPNAMES,'repair':void
+0,'preSeverity':severities.NOT_SUPPORTED,'canRepair':false,'urls':[],'sections':['15.2.3.4'],'tests':['15.2.3.4-0-1']}],supportedKludges=[{'description':'Global object leaks from global function calls','test':test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=64250'],'sections':['10.2.1.2','10.2.1.2.6'],'tests':['10.4.3-1-8gs']},{'description':'Global object leaks from anonymous function calls','test':test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':[],'sections':['10.4.3'],'tests':['S10.4.3_A1']},{'description':'Global leaks through strict this','test':test_GLOBAL_LEAKS_FROM_STRICT_THIS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':[],'sections':['10.4.3'],'tests':['10.4.3-1-8gs','10.4.3-1-8-s']},{'description':'Global object leaks from built-in methods','test':test_GLOBAL_LEAKS_FROM_BUILTINS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=51097','https://bugs.webkit.org/show_bug.cgi?id=58338','http://code.google.com/p/v8/issues/detail?id=1437','https://connect.microsoft.com/IE/feedback/details/685430/global-object-leaks-from-built-in-methods'],'sections':['15.2.4.4'],'tests':['S15.2.4.4_A14']},{'description':'Global object leaks from globally called built-in methods','test':test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':[],'sections':['10.2.1.2','10.2.1.2.6','15.2.4.4'],'tests':['S15.2.4.4_A15']},{'description':'Object.freeze is missing','test':test_MISSING_FREEZE_ETC,'repair':repair_MISSING_FREEZE_ETC,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=55736'],'sections':['15.2.3.9'],'tests':['15.2.3.9-0-1']},{'description':'A function.prototype\'s descriptor lies','test':test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,'repair':repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1530','http://code.google.com/p/v8/issues/detail?id=1570'],'sections':['15.2.3.3','15.2.3.6','15.3.5.2'],'tests':['S15.3.3.1_A4']},{'description':'Phantom callee on strict functions','test':test_MISSING_CALLEE_DESCRIPTOR,'repair':repair_MISSING_CALLEE_DESCRIPTOR,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=55537'],'sections':['15.2.3.4'],'tests':['S15.2.3.4_A1_T1']},{'description':'Strict delete returned false rather than throwing','test':test_STRICT_DELETE_RETURNS_FALSE,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://connect.microsoft.com/IE/feedback/details/685432/strict-delete-sometimes-returns-false-rather-than-throwing'],'sections':['11.4.1'],'tests':['S11.4.1_A5']},{'description':'Non-deletable RegExp statics are a global communication channel','test':test_REGEXP_CANT_BE_NEUTERED,'repair':repair_REGEXP_CANT_BE_NEUTERED,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=591846','http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable','https://connect.microsoft.com/IE/feedback/details/685439/non-deletable-regexp-statics-are-a-global-communication-channel'],'sections':['11.4.1'],'tests':['S11.4.1_A5']},{'description':'RegExp.exec leaks match globally','test':test_REGEXP_TEST_EXEC_UNSAFE,'repair':repair_REGEXP_TEST_EXEC_UNSAFE,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1393','http://code.google.com/p/chromium/issues/detail?id=75740','https://bugzilla.mozilla.org/show_bug.cgi?id=635017','http://code.google.com/p/google-caja/issues/detail?id=528'],'sections':['15.10.6.2'],'tests':['S15.10.6.2_A12']},{'description':'Function.prototype.bind is missing','test':test_MISSING_BIND,'repair':repair_MISSING_BIND,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=26382','https://bugs.webkit.org/show_bug.cgi?id=42371'],'sections':['15.3.4.5'],'tests':['S15.3.4.5_A3']},{'description':'Function.prototype.bind calls .apply rather than [[Call]]','test':test_BIND_CALLS_APPLY,'repair':repair_MISSING_BIND,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=892','http://code.google.com/p/v8/issues/detail?id=828'],'sections':['15.3.4.5.1'],'tests':['S15.3.4.5_A4']},{'description':'Function.prototype.bind does not curry construction','test':test_BIND_CANT_CURRY_NEW,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=26382#c29'],'sections':['15.3.4.5.2'],'tests':['S15.3.4.5_A5']},{'description':'Date.prototype is a global communication channel','test':test_MUTABLE_DATE_PROTO,'repair':repair_MUTABLE_DATE_PROTO,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/google-caja/issues/detail?id=1362'],'sections':['15.9.5'],'tests':[]},{'description':'WeakMap.prototype is a global communication channel','test':test_MUTABLE_WEAKMAP_PROTO,'repair':repair_MUTABLE_WEAKMAP_PROTO,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=656828'],'sections':[],'tests':[]},{'description':'Array forEach cannot be frozen while in progress','test':test_NEED_TO_WRAP_FOREACH,'repair':repair_NEED_TO_WRAP_FOREACH,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1447'],'sections':['15.4.4.18'],'tests':['S15.4.4.18_A1','S15.4.4.18_A2']},{'description':'Workaround undiagnosed need for dummy setter','test':test_NEEDS_DUMMY_SETTER,'repair':repair_NEEDS_DUMMY_SETTER,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':[],'sections':[],'tests':[]},{'description':'Getter on HTMLFormElement disappears','test':test_FORM_GETTERS_DISAPPEAR,'repair':repair_NEEDS_DUMMY_SETTER,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/chromium/issues/detail?id=94666','http://code.google.com/p/v8/issues/detail?id=1651','http://code.google.com/p/google-caja/issues/detail?id=1401'],'sections':['15.2.3.6'],'tests':['S15.2.3.6_A1']},{'description':'Accessor properties inherit as own properties','test':test_ACCESSORS_INHERIT_AS_OWN,'repair':repair_ACCESSORS_INHERIT_AS_OWN,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=637994'],'sections':['8.6.1','15.2.3.6'],'tests':['S15.2.3.6_A2']},{'description':'Array sort leaks global','test':test_SORT_LEAKS_GLOBAL,'repair':repair_SORT_LEAKS_GLOBAL,'preSeverity':severities.NOT_ISOLATED,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1360'],'sections':['15.4.4.11'],'tests':['S15.4.4.11_A8']},{'description':'String replace leaks global','test':test_REPLACE_LEAKS_GLOBAL,'repair':repair_REPLACE_LEAKS_GLOBAL,'preSeverity':severities.NOT_ISOLATED,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1360','https://connect.microsoft.com/IE/feedback/details/685928/bad-this-binding-for-callback-in-string-prototype-replace'],'sections':['15.5.4.11'],'tests':['S15.5.4.11_A12']},{'description':'getOwnPropertyDescriptor on strict \"caller\" throws','test':test_CANT_GOPD_CALLER,'repair':repair_CANT_GOPD_CALLER,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://connect.microsoft.com/IE/feedback/details/685436/getownpropertydescriptor-on-strict-caller-throws'],'sections':['15.2.3.3','13.2','13.2.3'],'tests':['S13.2_A6_T1']},{'description':'strict_function.hasOwnProperty(\"caller\") throws','test':test_CANT_HASOWNPROPERTY_CALLER,'repair':repair_CANT_HASOWNPROPERTY_CALLER,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=63398#c3'],'sections':['15.2.4.5','13.2','13.2.3'],'tests':['S13.2_A7_T1']},{'description':'Cannot \"in\" caller on strict function','test':test_CANT_IN_CALLER,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['11.8.7','13.2','13.2.3'],'tests':['S13.2_A8_T1']},{'description':'Cannot \"in\" arguments on strict function','test':test_CANT_IN_ARGUMENTS,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['11.8.7','13.2','13.2.3'],'tests':['S13.2_A8_T2']},{'description':'Strict \"caller\" not poisoned','test':test_STRICT_CALLER_NOT_POISONED,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':[],'sections':['13.2'],'tests':['S13.2.3_A1']},{'description':'Strict \"arguments\" not poisoned','test':test_STRICT_ARGUMENTS_NOT_POISONED,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':[],'sections':['13.2'],'tests':['S13.2.3_A1']},{'description':'Built in functions leak \"caller\"','test':test_BUILTIN_LEAKS_CALLER,'repair':repair_BUILTIN_LEAKS_CALLER,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1643','http://code.google.com/p/v8/issues/detail?id=1548','https://bugzilla.mozilla.org/show_bug.cgi?id=591846','http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable'],'sections':[],'tests':['Sbp_A10_T1']},{'description':'Built in functions leak \"arguments\"','test':test_BUILTIN_LEAKS_ARGUMENTS,'repair':repair_BUILTIN_LEAKS_ARGUMENTS,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1643','http://code.google.com/p/v8/issues/detail?id=1548','https://bugzilla.mozilla.org/show_bug.cgi?id=591846','http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable'],'sections':[],'tests':['Sbp_A10_T2']},{'description':'Bound functions leak \"caller\"','test':test_BOUND_FUNCTION_LEAKS_CALLER,'repair':repair_MISSING_BIND,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=893','https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['15.3.4.5'],'tests':['S13.2.3_A1','S15.3.4.5_A1']},{'description':'Bound functions leak \"arguments\"','test':test_BOUND_FUNCTION_LEAKS_ARGUMENTS,'repair':repair_MISSING_BIND,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=893','https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['15.3.4.5'],'tests':['S13.2.3_A1','S15.3.4.5_A2']},{'description':'Deleting built-in leaves phantom behind','test':test_DELETED_BUILTINS_IN_OWN_NAMES,'repair':repair_DELETED_BUILTINS_IN_OWN_NAMES,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=70207'],'sections':['15.2.3.4'],'tests':[]},{'description':'getOwnPropertyDescriptor on its own \"caller\" fails','test':test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,'repair':repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1769'],'sections':['13.2','15.2.3.3'],'tests':[]},{'description':'JSON.parse confused by \"__proto__\"','test':test_JSON_PARSE_PROTO_CONFUSION,'repair':repair_JSON_PARSE_PROTO_CONFUSION,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=621','http://code.google.com/p/v8/issues/detail?id=1310'],'sections':['15.12.2'],'tests':['S15.12.2_A1']},{'description':'Prototype still mutable on non-extensible object','test':test_PROTO_NOT_FROZEN,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=65832','https://bugs.webkit.org/show_bug.cgi?id=78438'],'sections':['8.6.2'],'tests':['S8.6.2_A8']},{'description':'Prototype still redefinable on non-extensible object','test':test_PROTO_REDEFINABLE,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=65832'],'sections':['8.6.2'],'tests':['S8.6.2_A8']},{'description':'Strict eval function leaks variable definitions','test':test_STRICT_EVAL_LEAKS_GLOBALS,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['http://code.google.com/p/v8/issues/detail?id=1624'],'sections':['10.4.2.1'],'tests':['S10.4.2.1_A1']},{'description':'parseInt still parsing octal','test':test_PARSEINT_STILL_PARSING_OCTAL,'repair':repair_PARSEINT_STILL_PARSING_OCTAL,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1645'],'sections':['15.1.2.2'],'tests':['S15.1.2.2_A5.1_T1']},{'description':'E4X literals allowed in strict code','test':test_STRICT_E4X_LITERALS_ALLOWED,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=695577','https://bugzilla.mozilla.org/show_bug.cgi?id=695579'],'sections':[],'tests':[]},{'description':'Assignment can override frozen inherited property','test':test_ASSIGN_CAN_OVERRIDE_FROZEN,'repair':repair_ASSIGN_CAN_OVERRIDE_FROZEN,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['http://code.google.com/p/v8/issues/detail?id=1169','https://mail.mozilla.org/pipermail/es-discuss/2011-November/017997.html'],'sections':['8.12.4'],'tests':['15.2.3.6-4-405']},{'description':'Cannot redefine global NaN to itself','test':test_CANT_REDEFINE_NAN_TO_ITSELF,'repair':repair_CANT_REDEFINE_NAN_TO_ITSELF,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':[],'sections':['8.12.9','15.1.1.1'],'tests':[]},{'description':'Error instances have unexpected properties','test':test_UNEXPECTED_ERROR_PROPERTIES,'repair':void
+0,'preSeverity':severities.NEW_SYMPTOM,'canRepair':false,'urls':[],'sections':[],'tests':[]},{'description':'getOwnPropertyNames lies, hiding some own properties','test':test_GET_OWN_PROPERTY_NAME_LIES,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=726477'],'sections':[],'tests':[]}],aboutTo=void
+0;function testRepairReport(kludges){var beforeFailures=strictMapFn(kludges,function(kludge){return aboutTo=['pre test: ',kludge.description],kludge.test()}),repairs=[],afterFailures;return strictForEachFn(kludges,function(kludge,i){var
+repair;beforeFailures[i]&&(repair=kludge.repair,repair&&repairs.lastIndexOf(repair)===-1&&(aboutTo=['repair: ',kludge.description],repair(),repairs.push(repair)))}),afterFailures=strictMapFn(kludges,function(kludge){return aboutTo=['post test: ',kludge.description],kludge.test()}),Object.isFrozen&&Object.isFrozen(Array.prototype.forEach)&&repair_NEED_TO_WRAP_FOREACH(),strictMapFn(kludges,function(kludge,i){var
+status=statuses.ALL_FINE,postSeverity=severities.SAFE,beforeFailure=beforeFailures[i],afterFailure=afterFailures[i];if(beforeFailure)afterFailure?kludge.repair?(postSeverity=kludge.preSeverity,status=statuses.REPAIR_FAILED):(kludge.canRepair||(postSeverity=kludge.preSeverity),status=statuses.NOT_REPAIRED):kludge.repair?kludge.canRepair?(status=statuses.REPAIRED):(postSeverity=kludge.preSeverity,status=statuses.REPAIRED_UNSAFELY):(status=statuses.ACCIDENTALLY_REPAIRED);else
+if(afterFailure)(kludge.repair||!kludge.canRepair)&&(postSeverity=kludge.preSeverity),status=statuses.BROKEN_BY_OTHER_ATTEMPTED_REPAIRS;return(typeof
+beforeFailure==='string'||typeof afterFailure==='string')&&(postSeverity=severities.NEW_SYMPTOM),ses.updateMaxSeverity(postSeverity),{'description':kludge.description,'preSeverity':kludge.preSeverity,'canRepair':kludge.canRepair,'urls':kludge.urls,'sections':kludge.sections,'tests':kludge.tests,'status':status,'postSeverity':postSeverity,'beforeFailure':beforeFailure,'afterFailure':afterFailure}})}try{reports=testRepairReport(baseKludges),ses.ok()&&reports.push.apply(reports,testRepairReport(supportedKludges)),logger.reportRepairs(reports)}catch(err){ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED),during=aboutTo?'('+aboutTo.join('')+') ':'',logger.error('ES5 Repair '+during+'failed with: ',err)}logger.reportMax()})(this),(function
+WeakMapModule(){'use strict';var HIDDEN_NAME,ab,defProp,gopn,hop,originalProps,u8s;if(typeof
+ses!=='undefined'&&ses.ok&&!ses.ok())return;if(typeof WeakMap==='function')return;hop=Object.prototype.hasOwnProperty,gopn=Object.getOwnPropertyNames,defProp=Object.defineProperty,originalProps={},gopn(Object).forEach(function(name){originalProps[name]=Object[name]}),HIDDEN_NAME='ident:'+Math.random()+'___',typeof
+crypto!=='undefined'&&typeof crypto.getRandomValues==='function'&&typeof ArrayBuffer==='function'&&typeof
+Uint8Array==='function'&&(ab=new ArrayBuffer(25),u8s=new Uint8Array(ab),crypto.getRandomValues(u8s),HIDDEN_NAME='rand:'+Array.prototype.map.call(u8s,function(u8){return(u8%36).toString(36)}).join('')+'___'),defProp(Object,'getOwnPropertyNames',{'value':function
+fakeGetOwnPropertyNames(obj){return gopn(obj).filter(function(name){return name!==HIDDEN_NAME})}}),'getPropertyNames'in
+Object&&defProp(Object,'getPropertyNames',{'value':function fakeGetPropertyNames(obj){return originalProps.getPropertyNames(obj).filter(function(name){return name!==HIDDEN_NAME})}});function
+getHiddenRecord(key){var gets,hiddenRecord,vals;if(key!==Object(key))throw new TypeError('Not an object: '+key);return hiddenRecord=key[HIDDEN_NAME],hiddenRecord&&hiddenRecord.key===key?hiddenRecord:originalProps.isExtensible(key)?(gets=[],vals=[],hiddenRecord={'key':key,'gets':gets,'vals':vals},defProp(key,HIDDEN_NAME,{'value':hiddenRecord,'writable':false,'enumerable':false,'configurable':false}),hiddenRecord):void
+0}(function(){var oldFreeze=Object.freeze,oldPreventExtensions,oldSeal;defProp(Object,'freeze',{'value':function
+identifyingFreeze(obj){return getHiddenRecord(obj),oldFreeze(obj)}}),oldSeal=Object.seal,defProp(Object,'seal',{'value':function
+identifyingSeal(obj){return getHiddenRecord(obj),oldSeal(obj)}}),oldPreventExtensions=Object.preventExtensions,defProp(Object,'preventExtensions',{'value':function
+identifyingPreventExtensions(obj){return getHiddenRecord(obj),oldPreventExtensions(obj)}})})();function
+constFunc(func){return func.prototype=null,Object.freeze(func)}WeakMap=function(){var
+keys=[],vals=[];function get___(key,opt_default){var hr=getHiddenRecord(key),i,vs;return hr?(i=hr.gets.indexOf(get___),vs=hr.vals):(i=keys.indexOf(key),vs=vals),i>=0?vs[i]:opt_default}function
+has___(key){var hr=getHiddenRecord(key),i;return i=hr?hr.gets.indexOf(get___):keys.indexOf(key),i>=0}function
+set___(key,value){var hr=getHiddenRecord(key),i;hr?(i=hr.gets.indexOf(get___),i>=0?(hr.vals[i]=value):(hr.gets.push(get___),hr.vals.push(value))):(i=keys.indexOf(key),i>=0?(vals[i]=value):(keys.push(key),vals.push(value)))}function
+delete___(key){var hr=getHiddenRecord(key),i;return hr?(i=hr.gets.indexOf(get___),i>=0&&(hr.gets.splice(i,1),hr.vals.splice(i,1))):(i=keys.indexOf(key),i>=0&&(keys.splice(i,1),vals.splice(i,1))),true}return Object.create(WeakMap.prototype,{'get___':{'value':constFunc(get___)},'has___':{'value':constFunc(has___)},'set___':{'value':constFunc(set___)},'delete___':{'value':constFunc(delete___)}})},WeakMap.prototype=Object.create(Object.prototype,{'get':{'value':function
+get(key,opt_default){return this.get___(key,opt_default)},'writable':true,'configurable':true},'has':{'value':function
+has(key){return this.has___(key)},'writable':true,'configurable':true},'set':{'value':function
+set(key,value){this.set___(key,value)},'writable':true,'configurable':true},'delete':{'value':function
+remove(key){return this.delete___(key)},'writable':true,'configurable':true}})})(),(function(){'use strict';var
+create,freeze;create=Object.create,freeze=Object.freeze;function constFunc(func){return func.prototype=null,freeze(func)}function
+assertString(x){if('string'!==typeof x)throw new TypeError('Not a string: '+String(x));return x}StringMap=function
+StringMap(){var objAsMap=create(null);return freeze({'get':constFunc(function(key){return objAsMap[assertString(key)+'$']}),'set':constFunc(function(key,value){objAsMap[assertString(key)+'$']=value}),'has':constFunc(function(key){return assertString(key)+'$'in
+objAsMap}),'delete':constFunc(function(key){return delete objAsMap[assertString(key)+'$']})})}})(),(function
+whitelistModule(){'use strict';var t;ses||(ses={}),t=true,ses.whitelist={'cajaVM':{'log':t,'tamperProof':t,'constFunc':t,'def':t,'is':t,'compileExpr':t,'compileModule':t,'compileProgram':t,'eval':t,'Function':t,'sharedImports':t,'makeImports':t,'copyToImports':t,'callWithEjector':t,'eject':t,'GuardT':{'coerce':t},'makeTableGuard':t,'Trademark':{'stamp':t},'guard':t,'passesGuard':t,'stamp':t,'makeSealerUnsealerPair':t,'makeArrayLike':{}},'WeakMap':{'prototype':{'get':t,'set':t,'has':t,'delete':t}},'StringMap':{'prototype':{}},'escape':t,'unescape':t,'Object':{'getPropertyDescriptor':t,'getPropertyNames':t,'is':t,'prototype':{'__defineGetter__':t,'__defineSetter__':t,'__lookupGetter__':t,'__lookupSetter__':t,'constructor':'*','toString':'*','toLocaleString':'*','valueOf':t,'hasOwnProperty':t,'isPrototypeOf':t,'propertyIsEnumerable':t},'getPrototypeOf':t,'getOwnPropertyDescriptor':t,'getOwnPropertyNames':t,'create':t,'defineProperty':t,'defineProperties':t,'seal':t,'freeze':t,'preventExtensions':t,'isSealed':t,'isFrozen':t,'isExtensible':t,'keys':t},'NaN':t,'Infinity':t,'undefined':t,'parseInt':t,'parseFloat':t,'isNaN':t,'isFinite':t,'decodeURI':t,'decodeURIComponent':t,'encodeURI':t,'encodeURIComponent':t,'Function':{'prototype':{'apply':t,'call':t,'bind':t,'prototype':'*','length':'*','arity':'*','name':'*'}},'Array':{'prototype':{'concat':t,'join':t,'pop':t,'push':t,'reverse':t,'shift':t,'slice':t,'sort':t,'splice':t,'unshift':t,'indexOf':t,'lastIndexOf':t,'every':t,'some':t,'forEach':t,'map':t,'filter':t,'reduce':t,'reduceRight':t,'length':'skip'},'isArray':t},'String':{'prototype':{'substr':t,'anchor':t,'big':t,'blink':t,'bold':t,'fixed':t,'fontcolor':t,'fontsize':t,'italics':t,'link':t,'small':t,'strike':t,'sub':t,'sup':t,'trimLeft':t,'trimRight':t,'valueOf':t,'charAt':t,'charCodeAt':t,'concat':t,'indexOf':t,'lastIndexOf':t,'localeCompare':t,'match':t,'replace':t,'search':t,'slice':t,'split':t,'substring':t,'toLowerCase':t,'toLocaleLowerCase':t,'toUpperCase':t,'toLocaleUpperCase':t,'trim':t,'length':'*'},'fromCharCode':t},'Boolean':{'prototype':{'valueOf':t}},'Number':{'prototype':{'valueOf':t,'toFixed':t,'toExponential':t,'toPrecision':t},'MAX_VALUE':t,'MIN_VALUE':t,'NaN':t,'NEGATIVE_INFINITY':t,'POSITIVE_INFINITY':t},'Math':{'E':t,'LN10':t,'LN2':t,'LOG2E':t,'LOG10E':t,'PI':t,'SQRT1_2':t,'SQRT2':t,'abs':t,'acos':t,'asin':t,'atan':t,'atan2':t,'ceil':t,'cos':t,'exp':t,'floor':t,'log':t,'max':t,'min':t,'pow':t,'random':t,'round':t,'sin':t,'sqrt':t,'tan':t},'Date':{'prototype':{'getYear':t,'setYear':t,'toGMTString':t,'toDateString':t,'toTimeString':t,'toLocaleString':t,'toLocaleDateString':t,'toLocaleTimeString':t,'getTime':t,'getFullYear':t,'getUTCFullYear':t,'getMonth':t,'getUTCMonth':t,'getDate':t,'getUTCDate':t,'getDay':t,'getUTCDay':t,'getHours':t,'getUTCHours':t,'getMinutes':t,'getUTCMinutes':t,'getSeconds':t,'getUTCSeconds':t,'getMilliseconds':t,'getUTCMilliseconds':t,'getTimezoneOffset':t,'setTime':t,'setFullYear':t,'setUTCFullYear':t,'setMonth':t,'setUTCMonth':t,'setDate':t,'setUTCDate':t,'setHours':t,'setUTCHours':t,'setMinutes':t,'setUTCMinutes':t,'setSeconds':t,'setUTCSeconds':t,'setMilliseconds':t,'setUTCMilliseconds':t,'toUTCString':t,'toISOString':t,'toJSON':t},'parse':t,'UTC':t,'now':t},'RegExp':{'prototype':{'exec':t,'test':t,'source':'*','global':'*','ignoreCase':'*','multiline':'*','lastIndex':'*','sticky':'*'}},'Error':{'prototype':{'name':'*','message':'*'}},'EvalError':{'prototype':t},'RangeError':{'prototype':t},'ReferenceError':{'prototype':t},'SyntaxError':{'prototype':t},'TypeError':{'prototype':t},'URIError':{'prototype':t},'JSON':{'parse':t,'stringify':t}}})(),(function
+atLeastFreeVarNamesModule(){'use strict';ses||(ses={});function LIMIT_SRC(programSrc){if(/[^\u0000-\u007f]/.test(programSrc))throw new
+EvalError('Non-ascii text not yet supported');if(/\\u/.test(programSrc))throw new
+EvalError('Backslash-u escape encoded text not yet supported')}function SHOULD_MATCH_IDENTIFIER(){return/(\w|\$)+/g}ses.atLeastFreeVarNames=function
+atLeastFreeVarNames(programSrc){var a,found,name,regexp,result;programSrc=String(programSrc),LIMIT_SRC(programSrc),regexp=SHOULD_MATCH_IDENTIFIER(),result=[],found=StringMap();while(a=regexp.exec(programSrc))name=a[0],found.has(name)||(result.push(name),found.set(name,true));return result}})(),ses.startSES=function(global,whitelist,atLeastFreeVarNames,extensions){'use strict';var
+EMULATE_LEGACY_GETTERS_SETTERS,TAME_GLOBAL_EVAL,cleaning,create,defProp,dirty,freeze,getProto,gopd,gopn,hop,keys,propertyReports,sharedImports,tamperProof,whiteTable;TAME_GLOBAL_EVAL=false,EMULATE_LEGACY_GETTERS_SETTERS=true,dirty=true,hop=Object.prototype.hasOwnProperty,getProto=Object.getPrototypeOf,defProp=Object.defineProperty,gopd=Object.getOwnPropertyDescriptor,gopn=Object.getOwnPropertyNames,keys=Object.keys,freeze=Object.freeze,create=Object.create;function
+constFunc(func){return func.prototype=null,freeze(func)}function fail(str){debugger;throw new
+EvalError(str)}typeof WeakMap==='undefined'&&fail('No built-in WeakMaps, so WeakMap.js must be loaded first'),EMULATE_LEGACY_GETTERS_SETTERS?(function(){function
+legacyDefineGetter(sprop,getter){sprop=''+sprop,hop.call(this,sprop)?defProp(this,sprop,{'get':getter}):defProp(this,sprop,{'get':getter,'set':undefined,'enumerable':true,'configurable':true})}legacyDefineGetter.prototype=null,defProp(Object.prototype,'__defineGetter__',{'value':legacyDefineGetter,'writable':false,'enumerable':false,'configurable':false});function
+legacyDefineSetter(sprop,setter){sprop=''+sprop,hop.call(this,sprop)?defProp(this,sprop,{'set':setter}):defProp(this,sprop,{'get':undefined,'set':setter,'enumerable':true,'configurable':true})}legacyDefineSetter.prototype=null,defProp(Object.prototype,'__defineSetter__',{'value':legacyDefineSetter,'writable':false,'enumerable':false,'configurable':false});function
+legacyLookupGetter(sprop){var base,desc;sprop=''+sprop,base=this,desc=void 0;while(base&&!(desc=gopd(base,sprop)))base=getProto(base);return desc&&desc.get}legacyLookupGetter.prototype=null,defProp(Object.prototype,'__lookupGetter__',{'value':legacyLookupGetter,'writable':false,'enumerable':false,'configurable':false});function
+legacyLookupSetter(sprop){var base,desc;sprop=''+sprop,base=this,desc=void 0;while(base&&!(desc=gopd(base,sprop)))base=getProto(base);return desc&&desc.set}legacyLookupSetter.prototype=null,defProp(Object.prototype,'__lookupSetter__',{'value':legacyLookupSetter,'writable':false,'enumerable':false,'configurable':false})})():(delete
+Object.prototype.__defineGetter__,delete Object.prototype.__defineSetter__,delete
+Object.prototype.__lookupGetter__,delete Object.prototype.__lookupSetter__),tamperProof=ses.makeDelayedTamperProof(),sharedImports=create(null),(function
+startSESPrelude(){var unsafeEval=eval,UnsafeFunction=Function,defended,defending,directivePattern,extensionsRecord,makeArrayLike,requirePattern;function
+verifyStrictProgram(programSrc){try{UnsafeFunction('\"use strict\";'+programSrc)}catch(err){throw err}}function
+verifyStrictExpression(exprSrc){verifyStrictProgram(exprSrc+';'),verifyStrictProgram('( '+exprSrc+'\n);')}function
+makeImports(){var imports=create(null);return copyToImports(imports,sharedImports),imports}function
+copyToImports(imports,from){return gopn(from).forEach(function(name){var desc=gopd(from,name);desc.enumerable=false,desc.configurable=true,defProp(imports,name,desc)}),imports}function
+makeScopeObject(imports,freeNames){var scopeObject=create(null);return freeNames.forEach(function
+interceptName(name){var desc=gopd(imports,name);(!desc||desc.writable!==false||desc.configurable)&&(desc={'get':function
+scopedGet(){var result;if(name in imports){result=imports[name];if(typeof result==='function');return result}throw new
+ReferenceError('\"'+name+'\" not in scope')},'set':function scopedSet(newValue){throw name
+in imports&&(imports[name]=newValue),new TypeError('Cannot set \"'+name+'\"')},'enumerable':false}),desc.enumerable=false,defProp(scopeObject,name,desc)}),freeze(scopeObject)}function
+securableWrapperSrc(exprSrc,opt_sourcePosition){return verifyStrictExpression(exprSrc),'(function() {   with (this) {     return function() {       \"use strict\";       return (         '+exprSrc+'\n'+'      );\n'+'    };\n'+'  }\n'+'})'}ses.securableWrapperSrc=securableWrapperSrc;function
+makeCompiledExpr(wrapper,freeNames){dirty&&fail('Initial cleaning failed');function
+compiledCode(imports){var scopeObject=makeScopeObject(imports,freeNames);return wrapper.call(scopeObject).call(imports)}return compiledCode.prototype=null,compiledCode}ses.makeCompiledExpr=makeCompiledExpr;function
+compileExpr(exprSrc,opt_sourcePosition){var wrapperSrc=securableWrapperSrc(exprSrc,opt_sourcePosition),wrapper=unsafeEval(wrapperSrc),freeNames=atLeastFreeVarNames(exprSrc),result=makeCompiledExpr(wrapper,freeNames);return freeze(result)}directivePattern=/^['"](?:\w|\s)*['"]$/m,requirePattern=/^(?:\w*\s*(?:\w|\$|\.)*\s*=)?\s*require\s*\(\s*['"]((?:\w|\$|\.|\/)+)['"]\s*\)$/m;function
+getRequirements(modSrc){var result=[],stmts=modSrc.split(';'),i=0,ilen=stmts.length,m,stmt;for(;i<ilen;++i){stmt=stmts[i].trim();if(stmt!==''){if(!directivePattern.test(stmt))break}}for(;i<ilen;++i){stmt=stmts[i].trim();if(stmt!==''){m=requirePattern.exec(stmt);if(!m)break;result.push(m[1])}}return freeze(result)}function
+compileModule(modSrc,opt_sourcePosition){var exprSrc='(function() {'+modSrc+'}).call(this)',wrapperSrc=securableWrapperSrc(exprSrc,opt_sourcePosition),wrapper=unsafeEval(wrapperSrc),freeNames=atLeastFreeVarNames(exprSrc),moduleMaker=makeCompiledExpr(wrapper,freeNames);return moduleMaker.requirements=getRequirements(modSrc),freeze(moduleMaker)}function
+FakeFunction(var_args){var params=[].slice.call(arguments,0),body=params.pop(),exprSrc;return body=String(body||''),params=params.join(','),exprSrc='(function('+params+'\n){'+body+'})',compileExpr(exprSrc)(sharedImports)}FakeFunction.prototype=UnsafeFunction.prototype,FakeFunction.prototype.constructor=FakeFunction,global.Function=FakeFunction;function
+fakeEval(src){try{verifyStrictExpression(src)}catch(x){src='(function() {'+src+'\n}).call(this)'}return compileExpr(src)(sharedImports)}TAME_GLOBAL_EVAL&&(global.eval=fakeEval),defended=WeakMap(),defending=WeakMap();function
+def(node){var defendingList=[];function recur(val){var t;if(!val)return;t=typeof
+val;if(t==='number'||t==='string'||t==='boolean')return;if(defended.get(val)||defending.get(val))return;defending.set(val,true),defendingList.push(val),tamperProof(val),recur(getProto(val)),gopn(val).forEach(function(p){var
+desc;if(typeof val==='function'&&(p==='caller'||p==='arguments'))return;desc=gopd(val,p),recur(desc.value),recur(desc.get),recur(desc.set)})}try{recur(node)}catch(err){throw defending=WeakMap(),err}return defendingList.forEach(function(obj){defended.set(obj,true)}),node}(function(){var
+itemMap=WeakMap(),lengthMap=WeakMap(),nativeProxies;function lengthGetter(){var getter=lengthMap.get(this);return getter?getter():void
+0}constFunc(lengthGetter),nativeProxies=global.Proxy&&(function(){var obj={'0':'hi'},p=global.Proxy.create({'get':function(){var
+P=arguments[0];return typeof P!=='string'&&(P=arguments[1]),obj[P]}});return p[0]==='hi'})(),nativeProxies?(function(){function
+ArrayLike(proto,getItem,getLength){var obj;if(typeof proto!=='object')throw new TypeError('Expected proto to be an object.');if(!(proto
+instanceof ArrayLike))throw new TypeError('Expected proto to be instanceof ArrayLike.');return obj=create(proto),itemMap.set(obj,getItem),lengthMap.set(obj,getLength),obj}function
+ownPropDesc(P){return P=''+P,P==='length'?{'get':lengthGetter}:typeof P==='number'||P===''+
++P?{'get':constFunc(function(){var getter=itemMap.get(this);return getter?getter(+P):void
+0}),'enumerable':true,'configurable':true}:void 0}function propDesc(P){var opd=ownPropDesc(P);return opd||gopd(Object.prototype,P)}function
+has(P){return P=''+P,P==='length'||typeof P==='number'||P===''+ +P||P in Object.prototype}function
+hasOwn(P){return P=''+P,P==='length'||typeof P==='number'||P===''+ +P}function getPN(){var
+result=getOwnPN(),objPropNames=gopn(Object.prototype);return result.push.apply(result,objPropNames),result}function
+getOwnPN(){var lenGetter=lengthMap.get(this),i,len,result;if(!lenGetter)return;len=lenGetter(),result=['length'];for(i=0;i<len;++i)result.push(''+i);return result}function
+del(P){return P=''+P,!(P==='length'||''+ +P===P)}ArrayLike.prototype=global.Proxy.create({'getPropertyDescriptor':propDesc,'getOwnPropertyDescriptor':ownPropDesc,'has':has,'hasOwn':hasOwn,'getPropertyNames':getPN,'getOwnPropertyNames':getOwnPN,'delete':del,'fix':function(){return}},Object.prototype),tamperProof(ArrayLike),makeArrayLike=function(){return ArrayLike}})():(function(){var
+BiggestArrayLike,maxLen;function nextUInt31PowerOf2(v){return v&=2147483647,v|=v>>1,v|=v>>2,v|=v>>4,v|=v>>8,v|=v>>16,v+1}BiggestArrayLike=void
+0,maxLen=0,makeArrayLike=function(length){var BAL,i,len;if(!BiggestArrayLike||length>maxLen){len=nextUInt31PowerOf2(length),BAL=function(proto,getItem,getLength){var
+obj;if(typeof proto!=='object')throw new TypeError('Expected proto to be an object.');if(!(proto
+instanceof BAL))throw new TypeError('Expected proto to be instanceof ArrayLike.');return obj=create(proto),itemMap.set(obj,getItem),lengthMap.set(obj,getLength),obj};for(i=0;i<len;++i)(function(j){function
+get(){return itemMap.get(this)(j)}defProp(BAL.prototype,j,{'get':constFunc(get),'enumerable':true})})(i);defProp(BAL.prototype,'length',{'get':lengthGetter}),tamperProof(BAL),tamperProof(BAL.prototype),BiggestArrayLike=BAL,maxLen=len}return BiggestArrayLike}})()})(),global.cajaVM={'log':constFunc(function
+log(str){typeof console!=='undefined'&&'log'in console&&console.log(str)}),'tamperProof':constFunc(tamperProof),'constFunc':constFunc(constFunc),'is':constFunc(ses.is),'compileExpr':constFunc(compileExpr),'compileModule':constFunc(compileModule),'eval':fakeEval,'Function':FakeFunction,'sharedImports':sharedImports,'makeImports':constFunc(makeImports),'copyToImports':constFunc(copyToImports),'makeArrayLike':constFunc(makeArrayLike)},extensionsRecord=extensions(),gopn(extensionsRecord).forEach(function(p){defProp(cajaVM,p,gopd(extensionsRecord,p))}),global.cajaVM.def=constFunc(def)})(),propertyReports={};function
+reportProperty(severity,status,path){var group;ses.updateMaxSeverity(severity),group=propertyReports[status]||(propertyReports[status]={'severity':severity,'list':[]}),group.list.push(path)}keys(whitelist).forEach(function(name){var
+desc=gopd(global,name),newDesc,permit;if(desc){permit=whitelist[name];if(permit){newDesc={'value':global[name],'writable':false,'configurable':false};try{defProp(global,name,newDesc)}catch(err){reportProperty(ses.severities.NEW_SYMPTOM,'Global '+name+' cannot be made readonly: '+err)}defProp(sharedImports,name,newDesc)}}}),TAME_GLOBAL_EVAL&&defProp(sharedImports,'eval',{'value':cajaVM.eval,'writable':false,'enumerable':false,'configurable':false}),whiteTable=WeakMap();function
+register(value,permit){var oldPermit;if(value!==Object(value))return;if(typeof permit!=='object')return;oldPermit=whiteTable.get(value),oldPermit&&fail('primordial reachable through multiple paths'),whiteTable.set(value,permit),keys(permit).forEach(function(name){var
+sub;permit[name]!=='skip'&&(sub=value[name],register(sub,permit[name]))})}register(sharedImports,whitelist);function
+getPermit(base,name){var permit=whiteTable.get(base),result;if(permit){if(hop.call(permit,name))return permit[name]};while(true){base=getProto(base);if(base===null)return false;permit=whiteTable.get(base);if(permit&&hop.call(permit,name))return result=permit[name],result==='*'||result==='skip'?result:false}}cleaning=WeakMap();function
+cleanProperty(base,name,path){var deleted,desc2,diagnostic,dummy2,err,exists,value;function
+poison(){throw new TypeError('Cannot access property '+path)}if(typeof base==='function'){if(name==='caller')return diagnostic=ses.makeCallerHarmless(base,path),reportProperty(ses.severities.SAFE,diagnostic,path),true;if(name==='arguments')return diagnostic=ses.makeArgumentsHarmless(base,path),reportProperty(ses.severities.SAFE,diagnostic,path),true}deleted=void
+0,err=void 0;try{deleted=delete base[name]}catch(er){err=er}exists=hop.call(base,name);if(deleted){if(!exists)return reportProperty(ses.severities.SAFE,'Deleted',path),true;reportProperty(ses.severities.SAFE_SPEC_VIOLATION,'Bounced back',path)}else
+if(deleted===false)reportProperty(ses.severities.SAFE_SPEC_VIOLATION,'Strict delete returned false rather than throwing',path);else
+if(err instanceof TypeError);else reportProperty(ses.severities.NEW_SYMPTOM,'Delete failed with'+err,path);try{defProp(base,name,{'get':poison,'set':poison,'enumerable':false,'configurable':false})}catch(cantPoisonErr){try{value=gopd(base,name).value,defProp(base,name,{'value':value===null?null:void
+0,'writable':false,'configurable':false})}catch(cantFreezeHarmless){return reportProperty(ses.severities.NOT_ISOLATED,'Cannot be poisoned',path),false}}desc2=gopd(base,name);if(desc2.get===poison&&desc2.set===poison&&!desc2.configurable)try{dummy2=base[name]}catch(expectedErr){if(expectedErr
+instanceof TypeError)return reportProperty(ses.severities.SAFE,'Successfully poisoned',path),true}else
+if((desc2.value===void 0||desc2.value===null)&&!desc2.writable&&!desc2.configurable)return reportProperty(ses.severities.SAFE,'Frozen harmless',path),false;return reportProperty(ses.severities.NEW_SYMTOM,'Failed to be poisoned',path),false}function
+clean(value,prefix){if(value!==Object(value))return;if(cleaning.get(value))return;cleaning.set(value,true),gopn(value).forEach(function(name){var
+path=prefix+(prefix?'.':'')+name,p=getPermit(value,name),sub;p?p==='skip'?reportProperty(ses.severities.SAFE,'Skipped',path):(sub=value[name],clean(sub,path)):cleanProperty(value,name,path)})}clean(sharedImports,''),cajaVM.def(sharedImports),keys(propertyReports).sort().forEach(function(status){var
+group=propertyReports[status];ses.logger.reportDiagnosis(group.severity,status,group.list)}),ses.logger.reportMax(),ses.ok()?(dirty=false,ses.logger.log('initSES succeeded.')):ses.logger.error('initSES failed.')},(function
+hookupSESModule(global){'use strict';if(!ses.ok())return;try{ses.startSES(global,ses.whitelist,ses.atLeastFreeVarNames,function(){return{}})}catch(err){ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED),ses.logger.error('hookupSES failed with: ',err)}})(this)}
\ No newline at end of file
diff --git a/initSES.js b/initSES.js
new file mode 100644
index 0000000..e563340
--- /dev/null
+++ b/initSES.js
@@ -0,0 +1,5748 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports a {@code ses.logger} which logs to the
+ * console if one exists.
+ *
+ * <p>This <code>logger.js</code> file both defines the logger API and
+ * provides default implementations for its methods. Because
+ * <code>logger.js</code> is normally packaged in
+ * <code>initSES.js</code>, it is built to support being overridden by
+ * a script run <i>earlier</i>. For example, for better diagnostics,
+ * consider loading and initializing <code>useHTMLLogger.js</code> first.
+ *
+ * <p>The {@code ses.logger} API consists of
+ * <dl>
+ *   <dt>log, info, warn, and error methods</dt>
+ *     <dd>each of which take a list of arguments which should be
+ *         stringified and appended together. The logger should
+ *         display this string associated with that severity level. If
+ *         any of the arguments has an associated stack trace
+ *         (presumably Error objects), then the logger <i>may</i> also
+ *         show this stack trace. If no {@code ses.logger} already
+ *         exists, the default provided here forwards to the
+ *         pre-existing global {@code console} if one
+ *         exists. Otherwise, all four of these do nothing. If we
+ *         default to forwarding to the pre-existing {@code console} ,
+ *         we prepend an empty string as first argument since we do
+ *         not want to obligate all loggers to implement the console's
+ *         "%" formatting. </dd>
+ *   <dt>classify(postSeverity)</dt>
+ *     <dd>where postSeverity is a severity
+ *         record as defined by {@code ses.severities} in
+ *         <code>repairES5.js</code>, and returns a helpful record
+ *         consisting of a
+ *         <dl>
+ *           <dt>consoleLevel:</dt>
+ *             <dd>which is one of 'log', 'info', 'warn', or
+ *                 'error', which can be used to select one of the above
+ *                 methods.</dd>
+ *           <dt>note:</dt>
+ *             <dd>containing some helpful text to display
+ *                 explaining the impact of this severity on SES.</dd>
+ *         </dl>
+ *   <dt>reportRepairs(reports)</dt>
+ *     <dd>where {@code reports} is the list of repair reports, each
+ *         of which contains
+ *       <dl>
+ *         <dt>description:</dt>
+ *           <dd>a string describing the problem</dd>
+ *         <dt>preSeverity:</dt>
+ *           <dd>a severity record (as defined by {@code
+ *               ses.severities} in <code>repairES5.js</code>)
+ *               indicating the level of severity of this problem if
+ *               unrepaired. Or, if !canRepair, then the severity
+ *               whether or not repaired.</dd>
+ *         <dt>canRepair:</dt>
+ *           <dd>a boolean indicating "if the repair exists and the test
+ *               subsequently does not detect a problem, are we now ok?"</dd>
+ *         <dt>urls:</dt>
+ *           <dd>a list of URL strings, each of which points at a page
+ *               relevant for documenting or tracking the bug in
+ *               question. These are typically into bug-threads in issue
+ *               trackers for the various browsers.</dd>
+ *         <dt>sections:</dt>
+ *           <dd>a list of strings, each of which is a relevant ES5.1
+ *               section number.</dd>
+ *         <dt>tests:</dt>
+ *           <dd>a list of strings, each of which is the name of a
+ *               relevant test262 or sputnik test case.</dd>
+ *         <dt>postSeverity:</dt>
+ *           <dd>a severity record (as defined by {@code
+ *               ses.severities} in <code>repairES5.js</code>)
+ *               indicating the level of severity of this problem
+ *               after all repairs have been attempted.</dd>
+ *         <dt>beforeFailure:</dt>
+ *           <dd>The outcome of the test associated with this record
+ *               as run before any attempted repairs. If {@code
+ *               false}, it means there was no failure. If {@code
+ *               true}, it means that the test fails in some way that
+ *               the authors of <code>repairES5.js</code>
+ *               expected. Otherwise it returns a string describing
+ *               the symptoms of an unexpected form of failure. This
+ *               is typically considered a more severe form of failure
+ *               than {@code true}, since the authors have not
+ *               anticipated the consequences and safety
+ *               implications.</dd>
+ *         <dt>afterFailure:</dt>
+ *           <dd>The outcome of the test associated with this record
+ *               as run after all attempted repairs.</dd>
+ *       </dl>
+ *       The default behavior here is to be silent.</dd>
+ *   <dt>reportMax()</dt>
+ *     <dd>Displays only a summary of the worst case
+ *         severity seen so far, according to {@code ses.maxSeverity} as
+ *         interpreted by {@code ses.logger.classify}.</dd>
+ *   <dt>reportDiagnosis(severity, status, problemList)</dt>
+ *     <dd>where {@code severity} is a severity record, {@code status}
+ *         is a brief string description of a list of problems, and
+ *         {@code problemList} is a list of strings, each of which is
+ *         one occurrence of the described problem.
+ *         The default behavior here should only the number of
+ *         problems, not the individual problems.</dd>
+ * </dl>
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * //provides ses.logger
+ * @author Mark S. Miller
+ * @requires console
+ * @overrides ses, loggerModule
+ */
+var ses;
+if (!ses) { ses = {}; }
+
+(function loggerModule() {
+  "use strict";
+
+  var logger;
+  function logNowhere(str) {}
+
+  var slice = [].slice;
+  var apply = slice.apply;
+
+
+
+  if (ses.logger) {
+    logger = ses.logger;
+
+  } else if (typeof console !== 'undefined' && 'log' in console) {
+    // We no longer test (typeof console.log === 'function') since,
+    // on IE9 and IE10preview, in violation of the ES5 spec, it
+    // is callable but has typeof "object".
+    // See https://connect.microsoft.com/IE/feedback/details/685962/
+    //   console-log-and-others-are-callable-but-arent-typeof-function
+
+    // We manually wrap each call to a console method because <ul>
+    // <li>On some platforms, these methods depend on their
+    //     this-binding being the console.
+    // <li>All this has to work on platforms that might not have their
+    //     own {@code Function.prototype.bind}, and has to work before
+    //     we install an emulated bind.
+    // </ul>
+
+    var forward = function(level, args) {
+      args = slice.call(args, 0);
+      // We don't do "console.apply" because "console" is not a function
+      // on IE 10 preview 2 and it has no apply method. But it is a
+      // callable that Function.prototype.apply can successfully apply.
+      // This code most work on ES3 where there's no bind. When we
+      // decide support defensiveness in contexts (frames) with mutable
+      // primordials, we will need to revisit the "call" below.
+      apply.call(console[level], console, [''].concat(args));
+
+      // See debug.js
+      var getStack = ses.getStack;
+      if (getStack) {
+        for (var i = 0, len = args.length; i < len; i++) {
+          var stack = getStack(args[i]);
+          if (stack) {
+            console[level]('', stack);
+          }
+        }
+      }
+    };
+
+    logger = {
+      log:   function log(var_args)   { forward('log', arguments); },
+      info:  function info(var_args)  { forward('info', arguments); },
+      warn:  function warn(var_args)  { forward('warn', arguments); },
+      error: function error(var_args) { forward('error', arguments); }
+    };
+  } else {
+    logger = {
+      log:   logNowhere,
+      info:  logNowhere,
+      warn:  logNowhere,
+      error: logNowhere
+    };
+  }
+
+  /**
+   * Returns a record that's helpful for displaying a severity.
+   *
+   * <p>The record contains {@code consoleLevel} and {@code note}
+   * properties whose values are strings. The {@code consoleLevel} is
+   * {@code "log", "info", "warn", or "error"}, which can be used as
+   * method names for {@code logger}, or, in an html context, as a css
+   * class name. The {@code note} is a string stating the severity
+   * level and its consequences for SES.
+   */
+  function defaultClassify(postSeverity) {
+    var MAX_SES_SAFE = ses.severities.SAFE_SPEC_VIOLATION;
+
+    var consoleLevel = 'log';
+    var note = '';
+    if (postSeverity.level > ses.severities.SAFE.level) {
+      consoleLevel = 'info';
+      note = postSeverity.description + '(' + postSeverity.level + ')';
+      if (postSeverity.level > ses.maxAcceptableSeverity.level) {
+        consoleLevel = 'error';
+        note += ' is not suitable for SES';
+      } else if (postSeverity.level > MAX_SES_SAFE.level) {
+        consoleLevel = 'warn';
+        note += ' is not SES-safe';
+      }
+      note += '.';
+    }
+    return {
+      consoleLevel: consoleLevel,
+      note: note
+    };
+  }
+
+  if (!logger.classify) {
+    logger.classify = defaultClassify;
+  }
+
+  /**
+   * By default is silent
+   */
+  function defaultReportRepairs(reports) {}
+
+  if (!logger.reportRepairs) {
+    logger.reportRepairs = defaultReportRepairs;
+  }
+
+  /**
+   * By default, logs a report suitable for display on the console.
+   */
+  function defaultReportMax() {
+    if (ses.maxSeverity.level > ses.severities.SAFE.level) {
+      var maxClassification = ses.logger.classify(ses.maxSeverity);
+      logger[maxClassification.consoleLevel](
+        'Max Severity: ' + maxClassification.note);
+    }
+  }
+
+  if (!logger.reportMax) {
+    logger.reportMax = defaultReportMax;
+  }
+
+  function defaultReportDiagnosis(severity, status, problemList) {
+    var classification = ses.logger.classify(severity);
+    ses.logger[classification.consoleLevel](
+      problemList.length + ' ' + status);
+  }
+
+  if (!logger.reportDiagnosis) {
+    logger.reportDiagnosis = defaultReportDiagnosis;
+  }
+
+  ses.logger = logger;
+
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Monkey patch almost ES5 platforms into a closer
+ * emulation of full <a href=
+ * "http://code.google.com/p/es-lab/wiki/SecureableES5">Secureable
+ * ES5</a>.
+ *
+ * <p>Assumes only ES3, but only proceeds to do useful repairs when
+ * the platform is close enough to ES5 to be worth attempting
+ * repairs. Compatible with almost-ES5, ES5, ES5-strict, and
+ * anticipated ES6.
+ *
+ * <p>Ignore the "...requires ___global_test_function___" below. We
+ * create it, use it, and delete it all within this module. But we
+ * need to lie to the linter since it can't tell.
+ *
+ * //provides ses.statuses, ses.ok, ses.is, ses.makeDelayedTamperProof
+ * //provides ses.makeCallerHarmless, ses.makeArgumentsHarmless
+ * //provides ses.severities, ses.maxSeverity, ses.updateMaxSeverity
+ * //provides ses.maxAcceptableSeverityName, ses.maxAcceptableSeverity
+ *
+ * @author Mark S. Miller
+ * @requires ___global_test_function___, ___global_valueOf_function___
+ * @requires JSON, navigator, this, eval, document
+ * @overrides ses, RegExp, WeakMap, Object, parseInt, repairES5Module
+ */
+var RegExp;
+var ses;
+
+/**
+ * <p>Qualifying platforms generally include all JavaScript platforms
+ * shown on <a href="http://kangax.github.com/es5-compat-table/"
+ * >ECMAScript 5 compatibility table</a> that implement {@code
+ * Object.getOwnPropertyNames}. At the time of this writing,
+ * qualifying browsers already include the latest released versions of
+ * Internet Explorer (9), Firefox (4), Chrome (11), and Safari
+ * (5.0.5), their corresponding standalone (e.g., server-side) JavaScript
+ * engines, Rhino 1.73, and BESEN.
+ *
+ * <p>On such not-quite-ES5 platforms, some elements of these
+ * emulations may lose SES safety, as enumerated in the comment on
+ * each kludge record in the {@code kludges} array below. The platform
+ * must at least provide {@code Object.getOwnPropertyNames}, because
+ * it cannot reasonably be emulated.
+ *
+ * <p>This file is useful by itself, as it has no dependencies on the
+ * rest of SES. It creates no new global bindings, but merely repairs
+ * standard globals or standard elements reachable from standard
+ * globals. If the future-standard {@code WeakMap} global is present,
+ * as it is currently on FF7.0a1, then it will repair it in place. The
+ * one non-standard element that this file uses is {@code console} if
+ * present, in order to report the repairs it found necessary, in
+ * which case we use its {@code log, info, warn}, and {@code error}
+ * methods. If {@code console.log} is absent, then this file performs
+ * its repairs silently.
+ *
+ * <p>Generally, this file should be run as the first script in a
+ * JavaScript context (i.e. a browser frame), as it relies on other
+ * primordial objects and methods not yet being perturbed.
+ *
+ * <p>TODO(erights): This file tries to protect itself from some
+ * post-initialization perturbation by stashing some of the
+ * primordials it needs for later use, but this attempt is currently
+ * incomplete. We need to revisit this when we support Confined-ES5,
+ * as a variant of SES in which the primordials are not frozen. See
+ * previous failed attempt at <a
+ * href="http://codereview.appspot.com/5278046/" >Speeds up
+ * WeakMap. Preparing to support unfrozen primordials.</a>. From
+ * analysis of this failed attempt, it seems that the only practical
+ * way to support CES is by use of two frames, where most of initSES
+ * runs in a SES frame, and so can avoid worrying about most of these
+ * perturbations.
+ */
+(function repairES5Module(global) {
+  "use strict";
+
+  /**
+   * The severity levels.
+   *
+   * <dl>
+   *   <dt>SAFE</dt><dd>no problem.
+   *   <dt>SAFE_SPEC_VIOLATION</dt>
+   *     <dd>safe (in an integrity sense) even if unrepaired. May
+   *         still lead to inappropriate failures.</dd>
+   *   <dt>UNSAFE_SPEC_VIOLATION</dt>
+   *     <dd>a safety issue only indirectly, in that this spec
+   *         violation may lead to the corruption of assumptions made
+   *         by other security critical or defensive code.</dd>
+   *   <dt>NOT_OCAP_SAFE</dt>
+   *     <dd>a violation of object-capability rules among objects
+   *         within a coarse-grained unit of isolation.</dd>
+   *   <dt>NOT_ISOLATED</dt>
+   *     <dd>an inability to reliably sandbox even coarse-grain units
+   *         of isolation.</dd>
+   *   <dt>NEW_SYMPTOM</dt>
+   *     <dd>some test failed in a way we did not expect.</dd>
+   *   <dt>NOT_SUPPORTED</dt>
+   *     <dd>this platform cannot even support SES development in an
+   *         unsafe manner.</dd>
+   * </dl>
+   */
+  ses.severities = {
+    SAFE:                  { level: 0, description: 'Safe' },
+    SAFE_SPEC_VIOLATION:   { level: 1, description: 'Safe spec violation' },
+    UNSAFE_SPEC_VIOLATION: { level: 2, description: 'Unsafe spec violation' },
+    NOT_OCAP_SAFE:         { level: 3, description: 'Not ocap safe' },
+    NOT_ISOLATED:          { level: 4, description: 'Not isolated' },
+    NEW_SYMPTOM:           { level: 5, description: 'New symptom' },
+    NOT_SUPPORTED:         { level: 6, description: 'Not supported' }
+  };
+
+  /**
+   * Statuses.
+   *
+   * <dl>
+   *   <dt>ALL_FINE</dt>
+   *     <dd>test passed before and after.</dd>
+   *   <dt>REPAIR_FAILED</dt>
+   *     <dd>test failed before and after repair attempt.</dd>
+   *   <dt>NOT_REPAIRED</dt>
+   *     <dd>test failed before and after, with no repair to attempt.</dd>
+   *   <dt>REPAIRED_UNSAFELY</dt>
+   *     <dd>test failed before and passed after repair attempt, but
+   *         the repair is known to be inadequate for security, so the
+   *         real problem remains.</dd>
+   *   <dt>REPAIRED</dt>
+   *     <dd>test failed before and passed after repair attempt,
+   *         repairing the problem (canRepair was true).</dd>
+   *   <dt>ACCIDENTALLY_REPAIRED</dt>
+   *      <dd>test failed before and passed after, despite no repair
+   *          to attempt. (Must have been fixed by some other
+   *          attempted repair.)</dd>
+   *   <dt>BROKEN_BY_OTHER_ATTEMPTED_REPAIRS</dt>
+   *      <dd>test passed before and failed after, indicating that
+   *          some other attempted repair created the problem.</dd>
+   * </dl>
+   */
+  ses.statuses = {
+    ALL_FINE:                          'All fine',
+    REPAIR_FAILED:                     'Repair failed',
+    NOT_REPAIRED:                      'Not repaired',
+    REPAIRED_UNSAFELY:                 'Repaired unsafely',
+    REPAIRED:                          'Repaired',
+    ACCIDENTALLY_REPAIRED:             'Accidentally repaired',
+    BROKEN_BY_OTHER_ATTEMPTED_REPAIRS: 'Broken by other attempted repairs'
+  };
+
+
+  var logger = ses.logger;
+
+  /**
+   * As we start to repair, this will track the worst post-repair
+   * severity seen so far.
+   */
+  ses.maxSeverity = ses.severities.SAFE;
+
+  /**
+   * {@code ses.maxAcceptableSeverity} is the max post-repair severity
+   * that is considered acceptable for proceeding with the SES
+   * verification-only strategy.
+   *
+   * <p>Although <code>repairES5.js</code> can be used standalone for
+   * partial ES5 repairs, its primary purpose is to repair as a first
+   * stage of <code>initSES.js</code> for purposes of supporting SES
+   * security. In support of that purpose, we initialize
+   * {@code ses.maxAcceptableSeverity} to the post-repair severity
+   * level at which we should report that we are unable to adequately
+   * support SES security. By default, this is set to
+   * {@code ses.severities.SAFE_SPEC_VIOLATION}, which is the maximum
+   * severity that we believe results in no loss of SES security.
+   *
+   * <p>If {@code ses.maxAcceptableSeverityName} is already set (to a
+   * severity property name of a severity below {@code
+   * ses.NOT_SUPPORTED}), then we use that setting to initialize
+   * {@code ses.maxAcceptableSeverity} instead. For example, if we are
+   * using SES only for isolation, then we could set it to
+   * 'NOT_OCAP_SAFE', in which case repairs that are inadequate for
+   * object-capability (ocap) safety would still be judged safe for
+   * our purposes.
+   *
+   * <p>As repairs proceed, they update {@code ses.maxSeverity} to
+   * track the worst case post-repair severity seen so far. When
+   * {@code ses.ok()} is called, it return whether {@code
+   * ses.maxSeverity} is still less than or equal to
+   * {@code ses.maxAcceptableSeverity}, indicating that this platform
+   * still seems adequate for supporting SES. In the Caja context, we
+   * have the choice of using SES on those platforms which we judge to
+   * be adequately repairable, or otherwise falling back to Caja's
+   * ES5/3 translator.
+   */
+  if (ses.maxAcceptableSeverityName) {
+    var maxSev = ses.severities[ses.maxAcceptableSeverityName];
+    if (maxSev && typeof maxSev.level === 'number' &&
+        maxSev.level >= ses.severities.SAFE.level &&
+        maxSev.level < ses.severities.NOT_SUPPORTED.level) {
+      // do nothing
+    } else {
+      logger.error('Ignoring bad maxAcceptableSeverityName: ' +
+                   ses.maxAcceptableSeverityName + '.') ;
+      ses.maxAcceptableSeverityName = 'SAFE_SPEC_VIOLATION';
+    }
+  } else {
+    ses.maxAcceptableSeverityName = 'SAFE_SPEC_VIOLATION';
+  }
+  ses.maxAcceptableSeverity = ses.severities[ses.maxAcceptableSeverityName];
+
+  /**
+   * Once this returns false, we can give up on the SES
+   * verification-only strategy and fall back to ES5/3 translation.
+   */
+  ses.ok = function ok() {
+    return ses.maxSeverity.level <= ses.maxAcceptableSeverity.level;
+  };
+
+  /**
+   * Update the max based on the provided severity.
+   *
+   * <p>If the provided severity exceeds the max so far, update the
+   * max to match.
+   */
+  ses.updateMaxSeverity = function updateMaxSeverity(severity) {
+    if (severity.level > ses.maxSeverity.level) {
+      ses.maxSeverity = severity;
+    }
+  };
+
+  //////// Prepare for "caller" and "argument" testing and repair /////////
+
+  /**
+   * Needs to work on ES3, since repairES5.js may be run on an ES3
+   * platform.
+   */
+  function strictForEachFn(list, callback) {
+    for (var i = 0, len = list.length; i < len; i++) {
+      callback(list[i], i);
+    }
+  }
+
+  /**
+   * Needs to work on ES3, since repairES5.js may be run on an ES3
+   * platform.
+   *
+   * <p>Also serves as our representative strict function, by contrast
+   * to builtInMapMethod below, for testing what the "caller" and
+   * "arguments" properties of a strict function reveals.
+   */
+  function strictMapFn(list, callback) {
+    var result = [];
+    for (var i = 0, len = list.length; i < len; i++) {
+      result.push(callback(list[i], i));
+    }
+    return result;
+  }
+
+  var objToString = Object.prototype.toString;
+
+  /**
+   * Sample map early, to obtain a representative built-in for testing.
+   *
+   * <p>There is no reliable test for whether a function is a
+   * built-in, and it is possible some of the tests below might
+   * replace the built-in Array.prototype.map, though currently none
+   * do. Since we <i>assume</i> (but with no reliable way to check)
+   * that repairES5.js runs in its JavaScript context before anything
+   * which might have replaced map, we sample it now. The map method
+   * is a particularly nice one to sample, since it can easily be used
+   * to test what the "caller" and "arguments" properties on a
+   * in-progress built-in method reveals.
+   */
+  var builtInMapMethod = Array.prototype.map;
+
+  var builtInForEach = Array.prototype.forEach;
+
+  /**
+   * http://wiki.ecmascript.org/doku.php?id=harmony:egal
+   */
+  var is = ses.is = Object.is || function(x, y) {
+    if (x === y) {
+      // 0 === -0, but they are not identical
+      return x !== 0 || 1 / x === 1 / y;
+    }
+
+    // NaN !== NaN, but they are identical.
+    // NaNs are the only non-reflexive value, i.e., if x !== x,
+    // then x is a NaN.
+    // isNaN is broken: it converts its argument to number, so
+    // isNaN("foo") => true
+    return x !== x && y !== y;
+  };
+
+
+  /**
+   * By the time this module exits, either this is repaired to be a
+   * function that is adequate to make the "caller" property of a
+   * strict or built-in function harmess, or this module has reported
+   * a failure to repair.
+   *
+   * <p>Start off with the optimistic assumption that nothing is
+   * needed to make the "caller" property of a strict or built-in
+   * function harmless. We are not concerned with the "caller"
+   * property of non-strict functions. It is not the responsibility of
+   * this module to actually make these "caller" properties
+   * harmless. Rather, this module only provides this function so
+   * clients such as startSES.js can use it to do so on the functions
+   * they whitelist.
+   *
+   * <p>If the "caller" property of strict functions are not already
+   * harmless, then this platform cannot be repaired to be
+   * SES-safe. The only reason why {@code makeCallerHarmless} must
+   * work on strict functions in addition to built-in is that some of
+   * the other repairs below will replace some of the built-ins with
+   * strict functions, so startSES.js will apply {@code
+   * makeCallerHarmless} blindly to both strict and built-in
+   * functions. {@code makeCallerHarmless} simply need not to complete
+   * without breaking anything when given a strict function argument.
+   */
+  ses.makeCallerHarmless = function assumeCallerHarmless(func, path) {
+    return 'Apparently fine';
+  };
+
+  /**
+   * By the time this module exits, either this is repaired to be a
+   * function that is adequate to make the "arguments" property of a
+   * strict or built-in function harmess, or this module has reported
+   * a failure to repair.
+   *
+   * Exactly analogous to {@code makeCallerHarmless}, but for
+   * "arguments" rather than "caller".
+   */
+  ses.makeArgumentsHarmless = function assumeArgumentsHarmless(func, path) {
+    return 'Apparently fine';
+  };
+
+  /**
+   * "makeTamperProof()" returns a "tamperProof(obj)" function that
+   * acts like "Object.freeze(obj)", except that, if obj is a
+   * <i>prototypical</i> object (defined below), it ensures that the
+   * effect of freezing properties of obj does not suppress the
+   * ability to override these properties on derived objects by simple
+   * assignment.
+   *
+   * <p>Because of lack of sufficient foresight at the time, ES5
+   * unifortunately specified that a simple assignment to a
+   * non-existent property must fail if it would override a
+   * non-writable data property of the same name. (In retrospect, this
+   * was a mistake, but it is now too late and we must live with the
+   * consequences.) As a result, simply freezing an object to make it
+   * tamper proof has the unfortunate side effect of breaking
+   * previously correct code that is considered to have followed JS
+   * best practices, of this previous code used assignment to
+   * override.
+   *
+   * <p>To work around this mistake, tamperProof(obj) detects if obj
+   * is <i>prototypical</i>, i.e., is an object whose own
+   * "constructor" is a function whose "prototype" is this obj. If so,
+   * then when tamper proofing it, prior to freezing, replace all its
+   * configurable own data properties with accessor properties which
+   * simulate what we should have specified -- that assignments to
+   * derived objects succeed if otherwise possible.
+   *
+   * <p>Some platforms (Chrome and Safari as of this writing)
+   * implement the assignment semantics ES5 should have specified
+   * rather than what it did specify.
+   * "test_ASSIGN_CAN_OVERRIDE_FROZEN()" below tests whether we are on
+   * such a platform. If so, "repair_ASSIGN_CAN_OVERRIDE_FROZEN()"
+   * replaces "makeTamperProof" with a function that simply returns
+   * "Object.freeze", since the complex workaround here is not needed
+   * on those platforms.
+   *
+   * <p>"makeTamperProof" should only be called after the trusted
+   * initialization has done all the monkey patching that it is going
+   * to do on the Object.* methods, but before any untrusted code runs
+   * in this context.
+   */
+  var makeTamperProof = function defaultMakeTamperProof() {
+
+    // Sample these after all trusted monkey patching initialization
+    // but before any untrusted code runs in this frame.
+    var gopd = Object.getOwnPropertyDescriptor;
+    var gopn = Object.getOwnPropertyNames;
+    var getProtoOf = Object.getPrototypeOf;
+    var freeze = Object.freeze;
+    var isFrozen = Object.isFrozen;
+    var defProp = Object.defineProperty;
+
+    function tamperProof(obj) {
+      if (obj !== Object(obj)) { return obj; }
+      var func;
+      if (typeof obj === 'object' &&
+          !!gopd(obj, 'constructor') &&
+          typeof (func = obj.constructor) === 'function' &&
+          func.prototype === obj &&
+          !isFrozen(obj)) {
+        strictForEachFn(gopn(obj), function(name) {
+          var value;
+          function getter() {
+            if (obj === this) { return value; }
+            if (this === void 0 || this === null) { return void 0; }
+            var thisObj = Object(this);
+            if (!!gopd(thisObj, name)) { return this[name]; }
+            // TODO(erights): If we can reliably uncurryThis() in
+            // repairES5.js, the next line should be:
+            //   return callFn(getter, getProtoOf(thisObj));
+            return getter.call(getProtoOf(thisObj));
+          }
+          function setter(newValue) {
+            if (obj === this) {
+              throw new TypeError('Cannot set virtually frozen property: ' +
+                                  name);
+            }
+            if (!!gopd(this, name)) {
+              this[name] = newValue;
+            }
+            // TODO(erights): Do all the inherited property checks
+            defProp(this, name, {
+              value: newValue,
+              writable: true,
+              enumerable: true,
+              configurable: true
+            });
+          }
+          var desc = gopd(obj, name);
+          if (desc.configurable && 'value' in desc) {
+            value = desc.value;
+            getter.prototype = null;
+            setter.prototype = null;
+            defProp(obj, name, {
+              get: getter,
+              set: setter,
+              // We should be able to omit the enumerable line, since it
+              // should default to its existing setting.
+              enumerable: desc.enumerable,
+              configurable: false
+            });
+          }
+        });
+      }
+      return freeze(obj);
+    }
+    return tamperProof;
+  };
+
+
+  var needToTamperProof = [];
+  /**
+   * Various repairs may expose non-standard objects that are not
+   * reachable from startSES's root, and therefore not freezable by
+   * startSES's normal whitelist traversal. However, freezing these
+   * during repairES5.js may be too early, as it is before WeakMap.js
+   * has had a chance to monkey patch Object.freeze if necessary, in
+   * order to install hidden properties for its own use before the
+   * object becomes non-extensible.
+   */
+  function rememberToTamperProof(obj) {
+    needToTamperProof.push(obj);
+  }
+
+  /**
+   * Makes and returns a tamperProof(obj) function, and uses it to
+   * tamper proof all objects whose tamper proofing had been delayed.
+   *
+   * <p>"makeDelayedTamperProof()" must only be called once.
+   */
+  ses.makeDelayedTamperProof = function makeDelayedTamperProof() {
+    var tamperProof = makeTamperProof();
+    strictForEachFn(needToTamperProof, tamperProof);
+    needToTamperProof = void 0;
+    return tamperProof;
+  };
+
+  /**
+   * Where the "that" parameter represents a "this" that should have
+   * been bound to "undefined" but may be bound to a global or
+   * globaloid object.
+   *
+   * <p>The "desc" parameter is a string to describe the "that" if it
+   * is something unexpected.
+   */
+  function testGlobalLeak(desc, that) {
+    if (that === void 0) { return false; }
+    if (that === global) { return true; }
+    if ({}.toString.call(that) === '[object Window]') { return true; }
+    return desc + ' leaked as: ' + that;
+  }
+
+  ////////////////////// Tests /////////////////////
+  //
+  // Each test is a function of no arguments that should not leave any
+  // significant side effects, which tests for the presence of a
+  // problem. It returns either
+  // <ul>
+  // <li>false, meaning that the problem does not seem to be present.
+  // <li>true, meaning that the problem is present in a form that we expect.
+  // <li>a non-empty string, meaning that there seems to be a related
+  //     problem, but we're seeing a symptom different than what we
+  //     expect. The string should describe the new symptom. It must
+  //     be non-empty so that it is truthy.
+  // </ul>
+  // All the tests are run first to determine which corresponding
+  // repairs to attempt. Then these repairs are run. Then all the
+  // tests are rerun to see how they were effected by these repair
+  // attempts. Finally, we report what happened.
+
+  /**
+   * If {@code Object.getOwnPropertyNames} is missing, we consider
+   * this to be an ES3 browser which is unsuitable for attempting to
+   * run SES.
+   *
+   * <p>If {@code Object.getOwnPropertyNames} is missing, there is no
+   * way to emulate it.
+   */
+  function test_MISSING_GETOWNPROPNAMES() {
+    return !('getOwnPropertyNames' in Object);
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=64250
+   *
+   * <p>No workaround attempted. Just reporting that this platform is
+   * not SES-safe.
+   */
+  function test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS() {
+    global.___global_test_function___ = function() { return this; };
+    var that = ___global_test_function___();
+    delete global.___global_test_function___;
+    return testGlobalLeak('Global func "this"', that);
+  }
+
+  /**
+   * Detects whether the most painful ES3 leak is still with us.
+   */
+  function test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS() {
+    var that = (function(){ return this; })();
+    return testGlobalLeak('Anon func "this"', that);
+  }
+
+  var strictThis = this;
+
+  /**
+   *
+   */
+  function test_GLOBAL_LEAKS_FROM_STRICT_THIS() {
+    return testGlobalLeak('Strict "this"', strictThis);
+  }
+
+  /**
+   * Detects
+   * https://bugs.webkit.org/show_bug.cgi?id=51097
+   * https://bugs.webkit.org/show_bug.cgi?id=58338
+   * http://code.google.com/p/v8/issues/detail?id=1437
+   *
+   * <p>No workaround attempted. Just reporting that this platform is
+   * not SES-safe.
+   */
+  function test_GLOBAL_LEAKS_FROM_BUILTINS() {
+    var v = {}.valueOf;
+    var that = 'dummy';
+    try {
+      that = v();
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'valueOf() threw: ' + err;
+    }
+    if (that === void 0) {
+      // Should report as a safe spec violation
+      return false;
+    }
+    return testGlobalLeak('valueOf()', that);
+  }
+
+  /**
+   *
+   */
+  function test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS() {
+    global.___global_valueOf_function___ = {}.valueOf;
+    var that = 'dummy';
+    try {
+      that = ___global_valueOf_function___();
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'valueOf() threw: ' + err;
+    } finally {
+      delete global.___global_valueOf_function___;
+    }
+    if (that === void 0) {
+      // Should report as a safe spec violation
+      return false;
+    }
+    return testGlobalLeak('Global valueOf()', that);
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=55736
+   *
+   * <p>As of this writing, the only major browser that does implement
+   * Object.getOwnPropertyNames but not Object.freeze etc is the
+   * released Safari 5 (JavaScriptCore). The Safari beta 5.0.4
+   * (5533.20.27, r84622) already does implement freeze, which is why
+   * this WebKit bug is listed as closed. When the released Safari has
+   * this fix, we can retire this kludge.
+   *
+   * <p>This kludge is <b>not</b> safety preserving. The emulations it
+   * installs if needed do not actually provide the safety that the
+   * rest of SES relies on.
+   */
+  function test_MISSING_FREEZE_ETC() {
+    return !('freeze' in Object);
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1530
+   *
+   * <p>Detects whether the value of a function's "prototype" property
+   * as seen by normal object operations might deviate from the value
+   * as seem by the reflective {@code Object.getOwnPropertyDescriptor}
+   */
+  function test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES() {
+    function foo() {}
+    Object.defineProperty(foo, 'prototype', { value: {} });
+    return foo.prototype !==
+      Object.getOwnPropertyDescriptor(foo, 'prototype').value;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=55537
+   *
+   * This bug is fixed on the latest Safari beta 5.0.5 (5533.21.1,
+   * r88603). When the released Safari has this fix, we can retire
+   * this kludge.
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_MISSING_CALLEE_DESCRIPTOR() {
+    function foo(){}
+    if (Object.getOwnPropertyNames(foo).indexOf('callee') < 0) { return false; }
+    if (foo.hasOwnProperty('callee')) {
+      return 'Empty strict function has own callee';
+    }
+    return true;
+  }
+
+  /**
+   * A strict delete should either succeed, returning true, or it
+   * should fail by throwing a TypeError. Under no circumstances
+   * should a strict delete return false.
+   *
+   * <p>This case occurs on IE10preview2.
+   */
+  function test_STRICT_DELETE_RETURNS_FALSE() {
+    if (!RegExp.hasOwnProperty('rightContext')) { return false; }
+    var deleted;
+    try {
+      deleted = delete RegExp.rightContext;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Deletion failed with: ' + err;
+    }
+    if (deleted) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846
+   * as applied to the RegExp constructor.
+   *
+   * <p>Note that Mozilla lists this bug as closed. But reading that
+   * bug thread clarifies that is partially because the code in {@code
+   * repair_REGEXP_CANT_BE_NEUTERED} enables us to work around the
+   * non-configurability of the RegExp statics.
+   */
+  function test_REGEXP_CANT_BE_NEUTERED() {
+    if (!RegExp.hasOwnProperty('leftContext')) { return false; }
+    var deleted;
+    try {
+      deleted = delete RegExp.leftContext;
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'Deletion failed with: ' + err;
+    }
+    if (!RegExp.hasOwnProperty('leftContext')) { return false; }
+    if (deleted) {
+      return 'Deletion of RegExp.leftContext did not succeed.';
+    } else {
+      // This case happens on IE10preview2, as demonstrated by
+      // test_STRICT_DELETE_RETURNS_FALSE.
+      return true;
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1393
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_REGEXP_TEST_EXEC_UNSAFE() {
+    (/foo/).test('xfoox');
+    var match = new RegExp('(.|\r|\n)*','').exec()[0];
+    if (match === 'undefined') { return false; }
+    if (match === 'xfoox') { return true; }
+    return 'regExp.exec() does not match against "undefined".';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=26382
+   *
+   * <p>As of this writing, the only major browser that does implement
+   * Object.getOwnPropertyNames but not Function.prototype.bind is
+   * Safari 5 (JavaScriptCore), including the current Safari beta
+   * 5.0.4 (5533.20.27, r84622).
+   *
+   * <p>This kludge is safety preserving. But see
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c25 for why this
+   * kludge cannot faithfully implement the specified semantics.
+   *
+   * <p>See also https://bugs.webkit.org/show_bug.cgi?id=42371
+   */
+  function test_MISSING_BIND() {
+    return !('bind' in Function.prototype);
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=892
+   *
+   * <p>This tests whether the built-in bind method violates the spec
+   * by calling the original using its current .apply method rather
+   * than the internal [[Call]] method. The workaround is the same as
+   * for test_MISSING_BIND -- to replace the built-in bind with one
+   * written in JavaScript. This introduces a different bug though: As
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c29 explains, a
+   * bind written in JavaScript cannot emulate the specified currying
+   * over the construct behavior, and so fails to enable a var-args
+   * {@code new} operation.
+   */
+  function test_BIND_CALLS_APPLY() {
+    if (!('bind' in Function.prototype)) { return false; }
+    var applyCalled = false;
+    function foo() { return [].slice.call(arguments,0).join(','); }
+    foo.apply = function fakeApply(self, args) {
+      applyCalled = true;
+      return Function.prototype.apply.call(this, self, args);
+    };
+    var b = foo.bind(33,44);
+    var answer = b(55,66);
+    if (applyCalled) { return true; }
+    if (answer === '44,55,66') { return false; }
+    return 'Bind test returned "' + answer + '" instead of "44,55,66".';
+  }
+
+  /**
+   * Demonstrates the point made by comment 29
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c29
+   *
+   * <p>Tests whether Function.prototype.bind curries over
+   * construction ({@code new}) behavior. A built-in bind should. A
+   * bind emulation written in ES5 can't.
+   */
+  function test_BIND_CANT_CURRY_NEW() {
+    function construct(f, args) {
+      var bound = Function.prototype.bind.apply(f, [null].concat(args));
+      return new bound();
+    }
+    var d;
+    try {
+      d = construct(Date, [1957, 4, 27]);
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'Curries construction failed with: ' + err;
+    }
+    if (typeof d === 'string') { return true; } // Opera
+    var str = objToString.call(d);
+    if (str === '[object Date]') { return false; }
+    return 'Unexpected ' + str + ': ' + d;
+  }
+
+  /**
+   * Detects http://code.google.com/p/google-caja/issues/detail?id=1362
+   *
+   * <p>This is an unfortunate oversight in the ES5 spec: Even if
+   * Date.prototype is frozen, it is still defined to be a Date, and
+   * so has mutable state in internal properties that can be mutated
+   * by the primordial mutation methods on Date.prototype, such as
+   * {@code Date.prototype.setFullYear}.
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_MUTABLE_DATE_PROTO() {
+    try {
+      Date.prototype.setFullYear(1957);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating Date.prototype failed with: ' + err;
+    }
+    var v = Date.prototype.getFullYear();
+    Date.prototype.setFullYear(NaN); // hopefully undoes the damage
+    if (v !== v && typeof v === 'number') {
+      // NaN indicates we're probably ok.
+      // TODO(erights) Should we report this as a symptom anyway, so
+      // that we get the repair which gives us a reliable TypeError?
+      return false;
+    }
+    if (v === 1957) { return true; }
+    return 'Mutating Date.prototype did not throw';
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=656828
+   *
+   * <p>A bug in the current FF6.0a1 implementation: Even if
+   * WeakMap.prototype is frozen, it is still defined to be a WeakMap,
+   * and so has mutable state in internal properties that can be
+   * mutated by the primordial mutation methods on WeakMap.prototype,
+   * such as {@code WeakMap.prototype.set}.
+   *
+   * <p>This kludge is safety preserving.
+   *
+   * <p>TODO(erights): Update the ES spec page to reflect the current
+   * agreement with Mozilla.
+   */
+  function test_MUTABLE_WEAKMAP_PROTO() {
+    if (typeof WeakMap !== 'function') { return false; }
+    var x = {};
+    try {
+      WeakMap.prototype.set(x, 86);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating WeakMap.prototype failed with: ' + err;
+    }
+    var v = WeakMap.prototype.get(x);
+    // Since x cannot escape, there's no observable damage to undo.
+    if (v === 86) { return true; }
+    return 'Mutating WeakMap.prototype did not throw';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1447
+   *
+   * <p>This bug is fixed as of V8 r8258 bleeding-edge, but is not yet
+   * available in the latest dev-channel Chrome (13.0.782.15 dev).
+   *
+   * <p>Unfortunately, an ES5 strict method wrapper cannot emulate
+   * absence of a [[Construct]] behavior, as specified for the Chapter
+   * 15 built-in methods. The installed wrapper relies on {@code
+   * Function.prototype.apply}, as inherited by original, obeying its
+   * contract.
+   *
+   * <p>This kludge is safety preserving but non-transparent, in that
+   * the real forEach is frozen even in the success case, since we
+   * have to freeze it in order to test for this failure. We could
+   * repair this non-transparency by replacing it with a transparent
+   * wrapper (as http://codereview.appspot.com/5278046/ does), but
+   * since the SES use of this will freeze it anyway and the
+   * indirection is costly, we choose not to for now.
+   */
+  function test_NEED_TO_WRAP_FOREACH() {
+    if (!('freeze' in Object)) {
+      // Object.freeze is still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    if (Array.prototype.forEach !== builtInForEach) {
+      // If it is already wrapped, we are confident the problem does
+      // not occur, and we need to skip the test to avoid freezing the
+      // wrapper.
+      return false;
+    }
+    try {
+      ['z'].forEach(function(){ Object.freeze(Array.prototype.forEach); });
+      return false;
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'freezing forEach failed with ' + err;
+    }
+  }
+
+  /**
+   * <p>Sometimes, when trying to freeze an object containing an
+   * accessor property with a getter but no setter, Chrome <= 17 fails
+   * with <blockquote>Uncaught TypeError: Cannot set property ident___
+   * of #<Object> which has only a getter</blockquote>. So if
+   * necessary, this kludge overrides {@code Object.defineProperty} to
+   * always install a dummy setter in lieu of the absent one.
+   *
+   * <p>Since this problem seems to have gone away as of Chrome 18, it
+   * is no longer as important to isolate and report it.
+   *
+   * <p>TODO(erights): We should also override {@code
+   * Object.getOwnPropertyDescriptor} to hide the presence of the
+   * dummy setter, and instead report an absent setter.
+   */
+  function test_NEEDS_DUMMY_SETTER() {
+    if (NEEDS_DUMMY_SETTER_repaired) { return false; }
+    if (typeof navigator === 'undefined') { return false; }
+    var ChromeMajorVersionPattern = (/Chrome\/(\d*)\./);
+    var match = ChromeMajorVersionPattern.exec(navigator.userAgent);
+    if (!match) { return false; }
+    var ver = +match[1];
+    return ver <= 17;
+  }
+  /** we use this variable only because we haven't yet isolated a test
+   * for the problem. */
+  var NEEDS_DUMMY_SETTER_repaired = false;
+
+  /**
+   * Detects http://code.google.com/p/chromium/issues/detail?id=94666
+   */
+  function test_FORM_GETTERS_DISAPPEAR() {
+    function getter() { return 'gotten'; }
+
+    if (typeof document === 'undefined' ||
+       typeof document.createElement !== 'function') {
+      // likely not a browser environment
+      return false;
+    }
+    var f = document.createElement("form");
+    try {
+      Object.defineProperty(f, 'foo', {
+        get: getter,
+        set: void 0
+      });
+    } catch (err) {
+      // Happens on Safari 5.0.2 on IPad2.
+      return 'defining accessor on form failed with: ' + err;
+    }
+    var desc = Object.getOwnPropertyDescriptor(f, 'foo');
+    if (desc.get === getter) { return false; }
+    if (desc.get === void 0) { return true; }
+    return 'Getter became ' + desc.get;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=637994
+   *
+   * <p>On Firefox 4 an inherited non-configurable accessor property
+   * appears to be an own property of all objects which inherit this
+   * accessor property. This is fixed as of Forefox Nightly 7.0a1
+   * (2011-06-21).
+   *
+   * <p>Our workaround wraps hasOwnProperty, getOwnPropertyNames, and
+   * getOwnPropertyDescriptor to heuristically decide when an accessor
+   * property looks like it is apparently own because of this bug, and
+   * suppress reporting its existence.
+   *
+   * <p>However, it is not feasible to likewise wrap JSON.stringify,
+   * and this bug will cause JSON.stringify to be misled by inherited
+   * enumerable non-configurable accessor properties. To prevent this,
+   * we wrap defineProperty, freeze, and seal to prevent the creation
+   * of <i>enumerable</i> non-configurable accessor properties on
+   * those platforms with this bug.
+   *
+   * <p>A little known fact about JavaScript is that {@code
+   * Object.prototype.propertyIsEnumerable} actually tests whether a
+   * property is both own and enumerable. Assuming that our wrapping
+   * of defineProperty, freeze, and seal prevents the occurrence of an
+   * enumerable non-configurable accessor property, it should also
+   * prevent the occurrence of this bug for any enumerable property,
+   * and so we do not need to wrap propertyIsEnumerable.
+   *
+   * <p>This kludge seems to be safety preserving, but the issues are
+   * delicate and not well understood.
+   */
+  function test_ACCESSORS_INHERIT_AS_OWN() {
+    var base = {};
+    var derived = Object.create(base);
+    function getter() { return 'gotten'; }
+    Object.defineProperty(base, 'foo', { get: getter });
+    if (!derived.hasOwnProperty('foo') &&
+        Object.getOwnPropertyDescriptor(derived, 'foo') === void 0 &&
+        Object.getOwnPropertyNames(derived).indexOf('foo') < 0) {
+      return false;
+    }
+    if (!derived.hasOwnProperty('foo') ||
+        Object.getOwnPropertyDescriptor(derived, 'foo').get !== getter ||
+        Object.getOwnPropertyNames(derived).indexOf('foo') < 0) {
+      return 'Accessor properties partially inherit as own properties.';
+    }
+    Object.defineProperty(base, 'bar', { get: getter, configurable: true });
+    if (!derived.hasOwnProperty('bar') &&
+        Object.getOwnPropertyDescriptor(derived, 'bar') === void 0 &&
+        Object.getOwnPropertyNames(derived).indexOf('bar') < 0) {
+      return true;
+    }
+    return 'Accessor properties inherit as own even if configurable.';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1360
+   *
+   * Our workaround wraps {@code sort} to wrap the comparefn.
+   */
+  function test_SORT_LEAKS_GLOBAL() {
+    var that = 'dummy';
+    [2,3].sort(function(x,y) { that = this; return x - y; });
+    if (that === void 0) { return false; }
+    if (that === global) { return true; }
+    return 'sort called comparefn with "this" === ' + that;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1360
+   *
+   * <p>Our workaround wraps {@code replace} to wrap the replaceValue
+   * if it's a function.
+   */
+  function test_REPLACE_LEAKS_GLOBAL() {
+    var that = 'dummy';
+    function capture() { that = this; return 'y';}
+    'x'.replace(/x/, capture);
+    if (that === void 0) { return false; }
+    if (that === capture) {
+      // This case happens on IE10preview2. See
+      // https://connect.microsoft.com/IE/feedback/details/685928/
+      //   bad-this-binding-for-callback-in-string-prototype-replace
+      // TODO(erights): When this happens, the kludge.description is
+      // wrong.
+      return true;
+    }
+    if (that === global) { return true; }
+    return 'Replace called replaceValue function with "this" === ' + that;
+  }
+
+  /**
+   * Detects
+   * https://connect.microsoft.com/IE/feedback/details/
+   *   685436/getownpropertydescriptor-on-strict-caller-throws
+   *
+   * <p>Object.getOwnPropertyDescriptor must work even on poisoned
+   * "caller" properties.
+   */
+  function test_CANT_GOPD_CALLER() {
+    var desc = null;
+    try {
+      desc = Object.getOwnPropertyDescriptor(function(){}, 'caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'getOwnPropertyDescriptor failed with: ' + err;
+    }
+    if (desc &&
+        typeof desc.get === 'function' &&
+        typeof desc.set === 'function' &&
+        !desc.configurable) {
+      return false;
+    }
+    if (desc &&
+        desc.value === null &&
+        !desc.writable &&
+        !desc.configurable) {
+      // Seen in IE9. Harmless by itself
+      return false;
+    }
+    return 'getOwnPropertyDesciptor returned unexpected caller descriptor';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>A strict function's caller should be poisoned only in a way
+   * equivalent to an accessor property with a throwing getter and
+   * setter.
+   *
+   * <p>Seen on Safari 5.0.6 through WebKit Nightly r93670
+   */
+  function test_CANT_HASOWNPROPERTY_CALLER() {
+    var answer = void 0;
+    try {
+      answer = function(){}.hasOwnProperty('caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'hasOwnProperty failed with: ' + err;
+    }
+    if (answer) { return false; }
+    return 'strict_function.hasOwnProperty("caller") was false';
+  }
+
+  /**
+   * Protect an 'in' with a try/catch to workaround a bug in Safari
+   * WebKit Nightly Version 5.0.5 (5533.21.1, r89741).
+   *
+   * <p>See https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>Notes: We're seeing exactly
+   * <blockquote>
+   *   New symptom (c): ('caller' in &lt;a bound function&gt;) threw:
+   *   TypeError: Cannot access caller property of a strict mode
+   *   function<br>
+   *   New symptom (c): ('arguments' in &lt;a bound function&gt;)
+   *   threw: TypeError: Can't access arguments object of a strict
+   *   mode function
+   * </blockquote>
+   * which means we're skipping both the catch and the finally in
+   * {@code has} while hitting the catch in {@code has2}. Further, if
+   * we remove one of these finally clauses (forget which) and rerun
+   * the example, if we're under the debugger the browser crashes. If
+   * we're not, then the TypeError escapes both catches.
+   */
+  function has(base, name, baseDesc) {
+    var result = void 0;
+    var finallySkipped = true;
+    try {
+      result = name in base;
+    } catch (err) {
+      logger.error('New symptom (a): (\'' +
+                   name + '\' in <' + baseDesc + '>) threw: ', err);
+      // treat this as a safe absence
+      result = false;
+      return false;
+    } finally {
+      finallySkipped = false;
+      if (result === void 0) {
+        logger.error('New symptom (b): (\'' +
+                     name + '\' in <' + baseDesc + '>) failed');
+      }
+    }
+    if (finallySkipped) {
+      logger.error('New symptom (e): (\'' +
+                   name + '\' in <' + baseDesc +
+                   '>) inner finally skipped');
+    }
+    return !!result;
+  }
+
+  function has2(base, name, baseDesc) {
+    var result = void 0;
+    var finallySkipped = true;
+    try {
+      result = has(base, name, baseDesc);
+    } catch (err) {
+      logger.error('New symptom (c): (\'' +
+                   name + '\' in <' + baseDesc + '>) threw: ', err);
+      // treat this as a safe absence
+      result = false;
+      return false;
+    } finally {
+      finallySkipped = false;
+      if (result === void 0) {
+        logger.error('New symptom (d): (\'' +
+                     name + '\' in <' + baseDesc + '>) failed');
+      }
+    }
+    if (finallySkipped) {
+      logger.error('New symptom (f): (\'' +
+                   name + '\' in <' + baseDesc +
+                   '>) outer finally skipped');
+    }
+    return !!result;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>If this reports a problem in the absence of "New symptom (a)",
+   * it means the error thrown by the "in" in {@code has} is skipping
+   * past the first layer of "catch" surrounding that "in". This is in
+   * fact what we're currently seeing on Safari WebKit Nightly Version
+   * 5.0.5 (5533.21.1, r91108).
+   */
+  function test_CANT_IN_CALLER() {
+    var answer = void 0;
+    try {
+      answer = has2(function(){}, 'caller', 'strict_function');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return '("caller" in strict_func) failed with: ' + err;
+    } finally {}
+    if (answer) { return false; }
+    return '("caller" in strict_func) was false.';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>If this reports a problem in the absence of "New symptom (a)",
+   * it means the error thrown by the "in" in {@code has} is skipping
+   * past the first layer of "catch" surrounding that "in". This is in
+   * fact what we're currently seeing on Safari WebKit Nightly Version
+   * 5.0.5 (5533.21.1, r91108).
+   */
+  function test_CANT_IN_ARGUMENTS() {
+    var answer = void 0;
+    try {
+      answer = has2(function(){}, 'arguments', 'strict_function');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return '("arguments" in strict_func) failed with: ' + err;
+    } finally {}
+    if (answer) { return false; }
+    return '("arguments" in strict_func) was false.';
+  }
+
+  /**
+   * Detects whether strict function violate caller anonymity.
+   */
+  function test_STRICT_CALLER_NOT_POISONED() {
+    if (!has2(strictMapFn, 'caller', 'a strict function')) { return false; }
+    function foo(m) { return m.caller; }
+    // using Function so it'll be non-strict
+    var testfn = Function('m', 'f', 'return m([m], f)[0];');
+    var caller;
+    try {
+      caller = testfn(strictMapFn, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Strict "caller" failed with: ' + err;
+    }
+    if (testfn === caller) {
+      // Seen on IE 9
+      return true;
+    }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects whether strict functions are encapsulated.
+   */
+  function test_STRICT_ARGUMENTS_NOT_POISONED() {
+    if (!has2(strictMapFn, 'arguments', 'a strict function')) { return false; }
+    function foo(m) { return m.arguments; }
+    // using Function so it'll be non-strict
+    var testfn = Function('m', 'f', 'return m([m], f)[0];');
+    var args;
+    try {
+      args = testfn(strictMapFn, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Strict "arguments" failed with: ' + err;
+    }
+    if (args[1] === foo) {
+      // Seen on IE 9
+      return true;
+    }
+    return 'Unexpected arguments: ' + arguments;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846 as
+   * applied to "caller"
+   */
+  function test_BUILTIN_LEAKS_CALLER() {
+    if (!has2(builtInMapMethod, 'caller', 'a builtin')) { return false; }
+    function foo(m) { return m.caller; }
+    // using Function so it'll be non-strict
+    var testfn = Function('a', 'f', 'return a.map(f)[0];');
+    var a = [builtInMapMethod];
+    a.map = builtInMapMethod;
+    var caller;
+    try {
+      caller = testfn(a, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Built-in "caller" failed with: ' + err;
+    }
+    if (null === caller || void 0 === caller) { return false; }
+    if (testfn === caller) { return true; }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846 as
+   * applied to "arguments"
+   */
+  function test_BUILTIN_LEAKS_ARGUMENTS() {
+    if (!has2(builtInMapMethod, 'arguments', 'a builtin')) { return false; }
+    function foo(m) { return m.arguments; }
+    // using Function so it'll be non-strict
+    var testfn = Function('a', 'f', 'return a.map(f)[0];');
+    var a = [builtInMapMethod];
+    a.map = builtInMapMethod;
+    var args;
+    try {
+      args = testfn(a, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Built-in "arguments" failed with: ' + err;
+    }
+    if (args === void 0 || args === null) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=893
+   */
+  function test_BOUND_FUNCTION_LEAKS_CALLER() {
+    if (!('bind' in Function.prototype)) { return false; }
+    function foo() { return bar.caller; }
+    var bar = foo.bind({});
+    if (!has2(bar, 'caller', 'a bound function')) { return false; }
+    // using Function so it'll be non-strict
+    var testfn = Function('b', 'return b();');
+    var caller;
+    try {
+      caller = testfn(bar);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Bound function "caller" failed with: ' + err;
+    }
+    if (caller === void 0 || caller === null) { return false; }
+    if (caller === testfn) { return true; }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=893
+   */
+  function test_BOUND_FUNCTION_LEAKS_ARGUMENTS() {
+    if (!('bind' in Function.prototype)) { return false; }
+    function foo() { return bar.arguments; }
+    var bar = foo.bind({});
+    if (!has2(bar, 'arguments', 'a bound function')) { return false; }
+    // using Function so it'll be non-strict
+    var testfn = Function('b', 'return b();');
+    var args;
+    try {
+      args = testfn(bar);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Bound function "arguments" failed with: ' + err;
+    }
+    if (args === void 0 || args === null) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=70207
+   *
+   * <p>After deleting a built-in, the problem is that
+   * getOwnPropertyNames still lists the name as present, but it seems
+   * absent in all other ways.
+   */
+  function test_DELETED_BUILTINS_IN_OWN_NAMES() {
+    if (!('__defineSetter__' in Object.prototype)) { return false; }
+    var desc = Object.getOwnPropertyDescriptor(Object.prototype,
+                                               '__defineSetter__');
+    try {
+      try {
+        delete Object.prototype.__defineSetter__;
+      } catch (err1) {
+        return false;
+      }
+      var names = Object.getOwnPropertyNames(Object.prototype);
+      if (names.indexOf('__defineSetter__') === -1) { return false; }
+      if ('__defineSetter__' in Object.prototype) {
+        // If it's still there, it bounced back. Which is still a
+        // problem, but not the problem we're testing for here.
+        return false;
+      }
+      return true;
+    } finally {
+      Object.defineProperty(Object.prototype, '__defineSetter__', desc);
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1769
+   */
+  function test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS() {
+    try {
+      Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptor,
+                                      'caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'getOwnPropertyDescriptor threw: ' + err;
+    }
+    return false;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=621
+   *
+   */
+  function test_JSON_PARSE_PROTO_CONFUSION() {
+    var x;
+    try {
+      x = JSON.parse('{"__proto__":[]}');
+    } catch (err) {
+      if (err instanceof TypeError) {
+        // We consider it acceptable to fail this case with a
+        // TypeError, as our repair below will cause it to do.
+        return false;
+      }
+      return 'JSON.parse failed with: ' + err;
+    }
+    if (Object.getPrototypeOf(x) !== Object.prototype) { return true; }
+    if (Array.isArray(x.__proto__)) { return false; }
+    return 'JSON.parse did not set "__proto__" as a regular property';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=65832
+   *
+   * <p>On a non-extensible object, it must not be possible to change
+   * its internal [[Prototype]] property, i.e., which object it
+   * inherits from.
+   *
+   * TODO(erights): investigate the following:
+   * At http://goo.gl/ycCmo Mike Stay says
+   * <blockquote>
+   * Kevin notes in domado.js that on some versions of FF, event
+   * objects switch prototypes when moving between frames. You should
+   * probably check out their behavior around freezing and sealing.
+   * </blockquote>
+   * But I couldn't find it.
+   */
+  function test_PROTO_NOT_FROZEN() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      x.__proto__ = y;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating __proto__ failed with: ' + err;
+    }
+    if (y.isPrototypeOf(x)) { return true; }
+    return 'Mutating __proto__ neither failed nor succeeded';
+  }
+
+  /**
+   * Like test_PROTO_NOT_FROZEN but using defineProperty rather than
+   * assignment.
+   */
+  function test_PROTO_REDEFINABLE() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      Object.defineProperty(x, '__proto__', { value: y });
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Defining __proto__ failed with: ' + err;
+    }
+    if (y.isPrototypeOf(x)) { return true; }
+    return 'Defining __proto__ neither failed nor succeeded';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1624
+   *
+   * <p>Both a direct strict eval operator and an indirect strict eval
+   * function must not leak top level declarations in the string being
+   * evaluated into their containing context.
+   */
+  function test_STRICT_EVAL_LEAKS_GLOBALS() {
+    (1,eval)('"use strict"; var ___global_test_variable___ = 88;');
+    if ('___global_test_variable___' in global) {
+      delete global.___global_test_variable___;
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1645
+   */
+  function test_PARSEINT_STILL_PARSING_OCTAL() {
+    var n = parseInt('010');
+    if (n === 10) { return false; }
+    if (n === 8)  { return true; }
+    return 'parseInt("010") returned ' + n;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=695577
+   *
+   * <p>When E4X syntax is accepted in strict code, then without
+   * parsing, we cannot prevent untrusted code from expressing E4X
+   * literals and so obtaining access to shared E4X prototypes,
+   * despite the absence of these prototypes from our whitelist. While
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=695579 is also
+   * open, we cannot even repair the situation, leading to unpluggable
+   * capability leaks. However, we do not test for this additional
+   * problem, since E4X is such a can of worms that 695577 is adequate
+   * by itself for us to judge this platform to be insecurable without
+   * parsing.
+   */
+  function test_STRICT_E4X_LITERALS_ALLOWED() {
+    var x;
+    try {
+      x = eval('"use strict";(<foo/>);');
+    } catch (err) {
+      if (err instanceof SyntaxError) { return false; }
+      return 'E4X test failed with: ' + err;
+    }
+    if (x !== void 0) { return true; }
+    return 'E4X literal expression had no value';
+  }
+
+  /**
+   * Detects whether assignment can override an inherited
+   * non-writable, non-configurable data property.
+   *
+   * <p>According to ES5.1, assignment should not be able to do so,
+   * which is unfortunate for SES, as the tamperProof function must
+   * kludge expensively to ensure that legacy assignments that don't
+   * violate best practices continue to work. Ironically, on platforms
+   * in which this bug is present, tamperProof can just be cheaply
+   * equivalent to Object.freeze.
+   */
+  function test_ASSIGN_CAN_OVERRIDE_FROZEN() {
+    var x = Object.freeze({foo: 88});
+    var y = Object.create(x);
+    try {
+      y.foo = 99;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Override failed with: ' + err;
+    }
+    if (y.foo === 99) { return true; }
+    if (y.foo === 88) { return 'Override failed silently'; }
+    return 'Unexpected override outcome: ' + y.foo;
+  }
+
+  /**
+   *
+   */
+  function test_CANT_REDEFINE_NAN_TO_ITSELF() {
+    var descNaN = Object.getOwnPropertyDescriptor(global, 'NaN');
+    try {
+      Object.defineProperty(global, 'NaN', descNaN);
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'defineProperty of NaN failed with: ' + err;
+    }
+    return false;
+  }
+
+  /**
+   * These are all the own properties that appear on Error instances
+   * on various ES5 platforms as of this writing.
+   *
+   * <p>Due to browser bugs, some of these are absent from
+   * getOwnPropertyNames (gopn). TODO(erights): File bugs with various
+   * browser makers for any own properties that we know to be present
+   * but not reported by gopn.
+   *
+   * <p>TODO(erights): do intelligence with the various browser
+   * implementors to find out what other properties are provided by
+   * their implementation but absent from gopn, whether on Errors or
+   * anything else. Every one of these are potentially fatal to our
+   * security until we can examine these.
+   *
+   * <p>The source form is a list rather than a map so that we can list a
+   * name like "message" for each browser section we think it goes in.
+   *
+   * <p>We thank the following people, projects, and websites for
+   * providing some useful intelligence of what property names we
+   * should suspect:<ul>
+   * <li><a href="http://stacktracejs.org">stacktracejs.org</a>
+   * <li>TODO(erights): find message on es-discuss list re
+   * "   stack". credit author.
+   * </ul>
+   */
+  var errorInstanceWhitelist = [
+    // at least Chrome 16
+    'arguments',
+    'message',
+    'stack',
+    'type',
+
+    // at least FF 9
+    'fileName',
+    'lineNumber',
+    'message',
+    'stack',
+
+    // at least Safari, WebKit 5.1
+    'line',
+    'message',
+    'sourceId',
+    'sourceURL',
+
+    // at least IE 10 preview 2
+    'description',
+    'message',
+    'number',
+
+    // at least Opera 11.60
+    'message',
+    'stack',
+    'stacktrace'
+  ];
+
+  var errorInstanceBlacklist = [
+    // seen in a Firebug on FF
+    'category',
+    'context',
+    'href',
+    'lineNo',
+    'msgId',
+    'source',
+    'trace',
+    'correctSourcePoint',
+    'correctWithStackTrace',
+    'getSourceLine',
+    'resetSource'
+  ];
+
+  /** Return a fresh one so client can mutate freely */
+  function freshErrorInstanceWhiteMap() {
+    var result = Object.create(null);
+    strictForEachFn(errorInstanceWhitelist, function(name) {
+      // We cannot yet use StringMap so do it manually
+      // We do this naively here assuming we don't need to worry about
+      // __proto__
+      result[name] = true;
+    });
+    return result;
+  }
+
+  function freshHiddenPropertyCandidates() {
+    var result = freshErrorInstanceWhiteMap();
+    strictForEachFn(errorInstanceBlacklist, function(name) {
+      result[name] = true;
+    });
+    return result;
+  }
+
+  /**
+   * Do Error instances on thos platform carry own properties that we
+   * haven't yet examined and determined to be SES-safe?
+   *
+   * <p>A new property should only be added to the
+   * errorInstanceWhitelist after inspecting the consequences of that
+   * property to determine that it does not compromise SES safety. If
+   * some platform maker does add an Error own property that does
+   * compromise SES safety, that might be a severe problem, if we
+   * can't find a way to deny untrusted code access to that property.
+   */
+  function test_UNEXPECTED_ERROR_PROPERTIES() {
+    var errs = [new Error('e1')];
+    try { null.foo = 3; } catch (err) { errs.push(err); }
+    var result = false;
+
+    var approvedNames = freshErrorInstanceWhiteMap();
+
+    strictForEachFn(errs, function(err) {
+      strictForEachFn(Object.getOwnPropertyNames(err), function(name) {
+         if (!(name in approvedNames)) {
+           result = 'Unexpected error instance property: ' + name;
+           // would be good to terminate early
+         }
+      });
+    });
+    return result;
+  }
+
+  /**
+   *
+   */
+  function test_GET_OWN_PROPERTY_NAME_LIES() {
+    var gopn = Object.getOwnPropertyNames;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    var suspects = [new Error('e1')];
+    try { null.foo = 3; } catch (err) { suspects.push(err); }
+
+    var unreported = Object.create(null);
+
+    strictForEachFn(suspects, function(suspect) {
+      var candidates = freshHiddenPropertyCandidates();
+      strictForEachFn(gopn(suspect), function(name) {
+        // Delete the candidates that are reported
+        delete candidates[name];
+      });
+      strictForEachFn(gopn(candidates), function(name) {
+        if (!gopd(suspect, name)) {
+          // Delete the candidates that are not own properties
+          delete candidates[name];
+        }
+      });
+      strictForEachFn(gopn(candidates), function(name) {
+        unreported[name] = true;
+      });
+    });
+
+    var unreportedNames = gopn(unreported);
+    if (unreportedNames.length === 0) { return false; }
+    return 'Error own properties unreported by getOwnPropertyNames: ' +
+      unreportedNames.sort().join(',');
+  }
+
+
+  ////////////////////// Repairs /////////////////////
+  //
+  // Each repair_NAME function exists primarily to repair the problem
+  // indicated by the corresponding test_NAME function. But other test
+  // failures can still trigger a given repair.
+
+
+  var call = Function.prototype.call;
+  var apply = Function.prototype.apply;
+
+  var hop = Object.prototype.hasOwnProperty;
+  var slice = Array.prototype.slice;
+  var concat = Array.prototype.concat;
+  var getPrototypeOf = Object.getPrototypeOf;
+
+  function patchMissingProp(base, name, missingFunc) {
+    if (!(name in base)) {
+      Object.defineProperty(base, name, {
+        value: missingFunc,
+        writable: true,
+        enumerable: false,
+        configurable: true
+      });
+    }
+  }
+
+  function repair_MISSING_FREEZE_ETC() {
+    patchMissingProp(Object, 'freeze',
+                     function fakeFreeze(obj) { return obj; });
+    patchMissingProp(Object, 'seal',
+                     function fakeSeal(obj) { return obj; });
+    patchMissingProp(Object, 'preventExtensions',
+                     function fakePreventExtensions(obj) { return obj; });
+    patchMissingProp(Object, 'isFrozen',
+                     function fakeIsFrozen(obj) { return false; });
+    patchMissingProp(Object, 'isSealed',
+                     function fakeIsSealed(obj) { return false; });
+    patchMissingProp(Object, 'isExtensible',
+                     function fakeIsExtensible(obj) { return true; });
+  }
+
+  function repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES() {
+    var unsafeDefProp = Object.defineProperty;
+    function repairedDefineProperty(base, name, desc) {
+      if (typeof base === 'function' &&
+          name === 'prototype' &&
+          'value' in desc) {
+        try {
+          base.prototype = desc.value;
+        } catch (err) {
+          logger.warn('prototype fixup failed', err);
+        }
+      }
+      return unsafeDefProp(base, name, desc);
+    }
+    Object.defineProperty(Object, 'defineProperty', {
+      value: repairedDefineProperty
+    });
+  }
+
+  function repair_MISSING_CALLEE_DESCRIPTOR() {
+    var realGOPN = Object.getOwnPropertyNames;
+    Object.defineProperty(Object, 'getOwnPropertyNames', {
+      value: function calleeFix(base) {
+        var result = realGOPN(base);
+        if (typeof base === 'function') {
+          var i = result.indexOf('callee');
+          if (i >= 0 && !hop.call(base, 'callee')) {
+            result.splice(i, 1);
+          }
+        }
+        return result;
+      }
+    });
+  }
+
+  function repair_REGEXP_CANT_BE_NEUTERED() {
+    var UnsafeRegExp = RegExp;
+    var FakeRegExp = function RegExpWrapper(pattern, flags) {
+      switch (arguments.length) {
+        case 0: {
+          return UnsafeRegExp();
+        }
+        case 1: {
+          return UnsafeRegExp(pattern);
+        }
+        default: {
+          return UnsafeRegExp(pattern, flags);
+        }
+      }
+    };
+    Object.defineProperty(FakeRegExp, 'prototype', {
+      value: UnsafeRegExp.prototype
+    });
+    Object.defineProperty(FakeRegExp.prototype, 'constructor', {
+      value: FakeRegExp
+    });
+    RegExp = FakeRegExp;
+  }
+
+  function repair_REGEXP_TEST_EXEC_UNSAFE() {
+    var unsafeRegExpExec = RegExp.prototype.exec;
+    var unsafeRegExpTest = RegExp.prototype.test;
+
+    Object.defineProperty(RegExp.prototype, 'exec', {
+      value: function fakeExec(specimen) {
+        return unsafeRegExpExec.call(this, String(specimen));
+      }
+    });
+    Object.defineProperty(RegExp.prototype, 'test', {
+      value: function fakeTest(specimen) {
+        return unsafeRegExpTest.call(this, String(specimen));
+      }
+    });
+  }
+
+  function repair_MISSING_BIND() {
+
+    /**
+     * Actual bound functions are not supposed to have a prototype, and
+     * are supposed to curry over both the [[Call]] and [[Construct]]
+     * behavior of their original function. However, in ES5,
+     * functions written in JavaScript cannot avoid having a 'prototype'
+     * property, and cannot reliably distinguish between being called as
+     * a function vs as a constructor, i.e., by {@code new}.
+     *
+     * <p>Since the repair_MISSING_BIND emulation produces a bound
+     * function written in JavaScript, it cannot faithfully emulate
+     * either the lack of a 'prototype' property nor the currying of the
+     * [[Construct]] behavior. So instead, we use BOGUS_BOUND_PROTOTYPE
+     * to reliably give an error for attempts to {@code new} a bound
+     * function. Since we cannot avoid exposing BOGUS_BOUND_PROTOTYPE
+     * itself, it is possible to pass in a this-binding which inherits
+     * from it without using {@code new}, which will also trigger our
+     * error case. Whether this latter error is appropriate or not, it
+     * still fails safe.
+     *
+     * <p>By making the 'prototype' of the bound function be the same as
+     * the current {@code thisFunc.prototype}, we could have emulated
+     * the [[HasInstance]] property of bound functions. But even this
+     * would have been inaccurate, since we would be unable to track
+     * changes to the original {@code thisFunc.prototype}. (We cannot
+     * make 'prototype' into an accessor to do this tracking, since
+     * 'prototype' on a function written in JavaScript is
+     * non-configurable.) And this one partially faithful emulation
+     * would have come at the cost of no longer being able to reasonably
+     * detect construction, in order to safely reject it.
+     */
+    var BOGUS_BOUND_PROTOTYPE = {
+      toString: function BBPToString() { return 'bogus bound prototype'; }
+    };
+    rememberToTamperProof(BOGUS_BOUND_PROTOTYPE);
+    BOGUS_BOUND_PROTOTYPE.toString.prototype = null;
+    rememberToTamperProof(BOGUS_BOUND_PROTOTYPE.toString);
+
+    var defProp = Object.defineProperty;
+    defProp(Function.prototype, 'bind', {
+      value: function fakeBind(self, var_args) {
+        var thisFunc = this;
+        var leftArgs = slice.call(arguments, 1);
+        function funcBound(var_args) {
+          if (this === Object(this) &&
+              getPrototypeOf(this) === BOGUS_BOUND_PROTOTYPE) {
+            throw new TypeError(
+              'Cannot emulate "new" on pseudo-bound function.');
+          }
+          var args = concat.call(leftArgs, slice.call(arguments, 0));
+          return apply.call(thisFunc, self, args);
+        }
+        defProp(funcBound, 'prototype', {
+          value: BOGUS_BOUND_PROTOTYPE,
+          writable: false,
+          configurable: false
+        });
+        return funcBound;
+      },
+      writable: true,
+      enumerable: false,
+      configurable: true
+    });
+  }
+
+  /**
+   * Return a function suitable for using as a forEach argument on a
+   * list of method names, where that function will monkey patch each
+   * of these names methods on {@code constr.prototype} so that they
+   * can't be called on a {@code constr.prototype} itself even across
+   * frames.
+   *
+   * <p>This only works when {@code constr} corresponds to an internal
+   * [[Class]] property whose value is {@code classString}. To test
+   * for {@code constr.prototype} cross-frame, we observe that for all
+   * objects of this [[Class]], only the prototypes directly inherit
+   * from an object that does not have this [[Class]].
+   */
+  function makeMutableProtoPatcher(constr, classString) {
+    var proto = constr.prototype;
+    var baseToString = objToString.call(proto);
+    if (baseToString !== '[object ' + classString + ']') {
+      throw new TypeError('unexpected: ' + baseToString);
+    }
+    var grandProto = getPrototypeOf(proto);
+    var grandBaseToString = objToString.call(grandProto);
+    if (grandBaseToString === '[object ' + classString + ']') {
+      throw new TypeError('malformed inheritance: ' + classString);
+    }
+    if (grandProto !== Object.prototype) {
+      logger.log('unexpected inheritance: ' + classString);
+    }
+    function mutableProtoPatcher(name) {
+      if (!hop.call(proto, name)) { return; }
+      var originalMethod = proto[name];
+      function replacement(var_args) {
+        var parent = getPrototypeOf(this);
+        if (parent !== proto) {
+          // In the typical case, parent === proto, so the above test
+          // lets the typical case succeed quickly.
+          // Note that, even if parent === proto, that does not
+          // necessarily mean that the method application will
+          // succeed, since, for example, a non-Date can still inherit
+          // from Date.prototype. However, in such cases, the built-in
+          // method application will fail on its own without our help.
+          if (objToString.call(parent) !== baseToString) {
+            // As above, === baseToString does not necessarily mean
+            // success, but the built-in failure again would not need
+            // our help.
+            var thisToString = objToString.call(this);
+            if (thisToString === baseToString) {
+              throw new TypeError('May not mutate internal state of a ' +
+                                  classString + '.prototype');
+            } else {
+              throw new TypeError('Unexpected: ' + thisToString);
+            }
+          }
+        }
+        return originalMethod.apply(this, arguments);
+      }
+      Object.defineProperty(proto, name, { value: replacement });
+    }
+    return mutableProtoPatcher;
+  }
+
+
+  function repair_MUTABLE_DATE_PROTO() {
+    // Note: coordinate this list with maintenance of whitelist.js
+    ['setYear',
+     'setTime',
+     'setFullYear',
+     'setUTCFullYear',
+     'setMonth',
+     'setUTCMonth',
+     'setDate',
+     'setUTCDate',
+     'setHours',
+     'setUTCHours',
+     'setMinutes',
+     'setUTCMinutes',
+     'setSeconds',
+     'setUTCSeconds',
+     'setMilliseconds',
+     'setUTCMilliseconds'].forEach(makeMutableProtoPatcher(Date, 'Date'));
+  }
+
+  function repair_MUTABLE_WEAKMAP_PROTO() {
+    // Note: coordinate this list with maintanence of whitelist.js
+    ['set',
+     'delete'].forEach(makeMutableProtoPatcher(WeakMap, 'WeakMap'));
+  }
+
+  function repair_NEED_TO_WRAP_FOREACH() {
+    var forEach = Array.prototype.forEach;
+    Object.defineProperty(Array.prototype, 'forEach', {
+      value: function forEachWrapper(callbackfn, opt_thisArg) {
+        return forEach.apply(this, arguments);
+      }
+    });
+  }
+
+
+  function repair_NEEDS_DUMMY_SETTER() {
+    var defProp = Object.defineProperty;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    function dummySetter(newValue) {
+      throw new TypeError('no setter for assigning: ' + newValue);
+    }
+    dummySetter.prototype = null;
+    rememberToTamperProof(dummySetter);
+
+    defProp(Object, 'defineProperty', {
+      value: function setSetterDefProp(base, name, desc) {
+        if (typeof desc.get === 'function' && desc.set === void 0) {
+          var oldDesc = gopd(base, name);
+          if (oldDesc) {
+            var testBase = {};
+            defProp(testBase, name, oldDesc);
+            defProp(testBase, name, desc);
+            desc = gopd(testBase, name);
+            if (desc.set === void 0) { desc.set = dummySetter; }
+          } else {
+            if (objToString.call(base) === '[object HTMLFormElement]') {
+              // This repair was triggering bug
+              // http://code.google.com/p/chromium/issues/detail?id=94666
+              // on Chrome, causing
+              // http://code.google.com/p/google-caja/issues/detail?id=1401
+              // so if base is an HTMLFormElement we skip this
+              // fix. Since this repair and this situation are both
+              // Chrome only, it is ok that we're conditioning this on
+              // the unspecified [[Class]] value of base.
+              //
+              // To avoid the further bug identified at Comment 2
+              // http://code.google.com/p/chromium/issues/detail?id=94666#c2
+              // We also have to reconstruct the requested desc so that
+              // the setter is absent. This is why we additionally
+              // condition this special case on the absence of an own
+              // name property on base.
+              var desc2 = { get: desc.get };
+              if ('enumerable' in desc) {
+                desc2.enumerable = desc.enumerable;
+              }
+              if ('configurable' in desc) {
+                desc2.configurable = desc.configurable;
+              }
+              var result = defProp(base, name, desc2);
+              var newDesc = gopd(base, name);
+              if (newDesc.get === desc.get) {
+                return result;
+              }
+            }
+            desc.set = dummySetter;
+          }
+        }
+        return defProp(base, name, desc);
+      }
+    });
+    NEEDS_DUMMY_SETTER_repaired = true;
+  }
+
+
+  function repair_ACCESSORS_INHERIT_AS_OWN() {
+    // restrict these
+    var defProp = Object.defineProperty;
+    var freeze = Object.freeze;
+    var seal = Object.seal;
+
+    // preserve illusion
+    var gopn = Object.getOwnPropertyNames;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    var complaint = 'Workaround for ' +
+      'https://bugzilla.mozilla.org/show_bug.cgi?id=637994 ' +
+      ' prohibits enumerable non-configurable accessor properties.';
+
+    function isBadAccessor(derived, name) {
+      var desc = gopd(derived, name);
+      if (!desc || !('get' in desc)) { return false; }
+      var base = getPrototypeOf(derived);
+      if (!base) { return false; }
+      var superDesc = gopd(base, name);
+      if (!superDesc || !('get' in superDesc)) { return false; }
+      return (desc.get &&
+              !desc.configurable && !superDesc.configurable &&
+              desc.get === superDesc.get &&
+              desc.set === superDesc.set &&
+              desc.enumerable === superDesc.enumerable);
+    }
+
+    defProp(Object, 'defineProperty', {
+      value: function definePropertyWrapper(base, name, desc) {
+        var oldDesc = gopd(base, name);
+        var testBase = {};
+        if (oldDesc && !isBadAccessor(base, name)) {
+          defProp(testBase, name, oldDesc);
+        }
+        defProp(testBase, name, desc);
+        var fullDesc = gopd(testBase, name);
+         if ('get' in fullDesc &&
+            fullDesc.enumerable &&
+            !fullDesc.configurable) {
+          logger.warn(complaint);
+          throw new TypeError(complaint
+              + " (Object: " + base + " Property: " + name + ")");
+        }
+        return defProp(base, name, fullDesc);
+      }
+    });
+
+    function ensureSealable(base) {
+      gopn(base).forEach(function(name) {
+        var desc = gopd(base, name);
+        if ('get' in desc && desc.enumerable) {
+          if (!desc.configurable) {
+            logger.error('New symptom: ' +
+                         '"' + name + '" already non-configurable');
+          }
+          logger.warn(complaint);
+          throw new TypeError(complaint + " (During sealing. Object: "
+              + base + " Property: " + name + ")");
+        }
+      });
+    }
+
+    defProp(Object, 'freeze', {
+      value: function freezeWrapper(base) {
+        ensureSealable(base);
+        return freeze(base);
+      }
+    });
+
+    defProp(Object, 'seal', {
+      value: function sealWrapper(base) {
+        ensureSealable(base);
+        return seal(base);
+      }
+    });
+
+    defProp(Object.prototype, 'hasOwnProperty', {
+      value: function hasOwnPropertyWrapper(name) {
+        return hop.call(this, name) && !isBadAccessor(this, name);
+      }
+    });
+
+    defProp(Object, 'getOwnPropertyDescriptor', {
+      value: function getOwnPropertyDescriptorWrapper(base, name) {
+        if (isBadAccessor(base, name)) { return void 0; }
+        return gopd(base, name);
+      }
+    });
+
+    defProp(Object, 'getOwnPropertyNames', {
+      value: function getOwnPropertyNamesWrapper(base) {
+        return gopn(base).filter(function(name) {
+          return !isBadAccessor(base, name);
+        });
+      }
+    });
+  }
+
+  function repair_SORT_LEAKS_GLOBAL() {
+    var unsafeSort = Array.prototype.sort;
+    function sortWrapper(opt_comparefn) {
+      function comparefnWrapper(x, y) {
+        return opt_comparefn(x, y);
+      }
+      if (arguments.length === 0) {
+        return unsafeSort.call(this);
+      } else {
+        return unsafeSort.call(this, comparefnWrapper);
+      }
+    }
+    Object.defineProperty(Array.prototype, 'sort', {
+      value: sortWrapper
+    });
+  }
+
+  function repair_REPLACE_LEAKS_GLOBAL() {
+    var unsafeReplace = String.prototype.replace;
+    function replaceWrapper(searchValue, replaceValue) {
+      var safeReplaceValue = replaceValue;
+      function replaceValueWrapper(m1, m2, m3) {
+        return replaceValue(m1, m2, m3);
+      }
+      if (typeof replaceValue === 'function') {
+        safeReplaceValue = replaceValueWrapper;
+      }
+      return unsafeReplace.call(this, searchValue, safeReplaceValue);
+    }
+    Object.defineProperty(String.prototype, 'replace', {
+      value: replaceWrapper
+    });
+  }
+
+  function repair_CANT_GOPD_CALLER() {
+    var unsafeGOPD = Object.getOwnPropertyDescriptor;
+    function gopdWrapper(base, name) {
+      try {
+        return unsafeGOPD(base, name);
+      } catch (err) {
+        if (err instanceof TypeError &&
+            typeof base === 'function' &&
+            (name === 'caller' || name === 'arguments')) {
+          return (function(message) {
+             function fakePoison() { throw new TypeError(message); }
+             fakePoison.prototype = null;
+             return {
+               get: fakePoison,
+               set: fakePoison,
+               enumerable: false,
+               configurable: false
+             };
+           })(err.message);
+        }
+        throw err;
+      }
+    }
+    Object.defineProperty(Object, 'getOwnPropertyDescriptor', {
+      value: gopdWrapper
+    });
+  }
+
+  function repair_CANT_HASOWNPROPERTY_CALLER() {
+    Object.defineProperty(Object.prototype, 'hasOwnProperty', {
+      value: function hopWrapper(name) {
+        return !!Object.getOwnPropertyDescriptor(this, name);
+      }
+    });
+  }
+
+  function makeHarmless(magicName, func, path) {
+    function poison() {
+      throw new TypeError('Cannot access property ' + path);
+    }
+    poison.prototype = null;
+    var desc = Object.getOwnPropertyDescriptor(func, magicName);
+    if ((!desc && Object.isExtensible(func)) || desc.configurable) {
+      try {
+        Object.defineProperty(func, magicName, {
+          get: poison,
+          set: poison,
+          configurable: false
+        });
+      } catch (cantPoisonErr) {
+        return 'Poisoning failed with ' + cantPoisonErr;
+      }
+      desc = Object.getOwnPropertyDescriptor(func, magicName);
+      if (desc &&
+          desc.get === poison &&
+          desc.set === poison &&
+          !desc.configurable) {
+        return 'Apparently poisoned';
+      }
+      return 'Not poisoned';
+    }
+    if ('get' in desc || 'set' in desc) {
+      return 'Apparently safe';
+    }
+    try {
+      Object.defineProperty(func, magicName, {
+        value: desc.value === null ? null : void 0,
+        writable: false,
+        configurable: false
+      });
+    } catch (cantFreezeHarmlessErr) {
+      return 'Freezing harmless failed with ' + cantFreezeHarmlessErr;
+    }
+    desc = Object.getOwnPropertyDescriptor(func, magicName);
+    if (desc &&
+        (desc.value === null || desc.value === void 0) &&
+        !desc.writable &&
+        !desc.configurable) {
+      return 'Apparently frozen harmless';
+    }
+    return 'Did not freeze harmless';
+  }
+
+  function repair_BUILTIN_LEAKS_CALLER() {
+    // The call to .bind as a method here is fine since it happens
+    // after all repairs which might fix .bind and before any
+    // untrusted code runs.
+    ses.makeCallerHarmless = makeHarmless.bind(void 0, 'caller');
+    //logger.info(ses.makeCallerHarmless(builtInMapMethod));
+  }
+
+  function repair_BUILTIN_LEAKS_ARGUMENTS() {
+    // The call to .bind as a method here is fine since it happens
+    // after all repairs which might fix .bind and before any
+    // untrusted code runs.
+    ses.makeArgumentsHarmless = makeHarmless.bind(void 0, 'arguments');
+    //logger.info(ses.makeArgumentsHarmless(builtInMapMethod));
+  }
+
+  function repair_DELETED_BUILTINS_IN_OWN_NAMES() {
+    var realGOPN = Object.getOwnPropertyNames;
+    var repairedHop = Object.prototype.hasOwnProperty;
+    function getOnlyRealOwnPropertyNames(base) {
+      return realGOPN(base).filter(function(name) {
+        return repairedHop.call(base, name);
+      });
+    }
+    Object.defineProperty(Object, 'getOwnPropertyNames', {
+      value: getOnlyRealOwnPropertyNames
+    });
+  }
+
+  function repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS() {
+    var realGOPD = Object.getOwnPropertyDescriptor;
+    function GOPDWrapper(base, name) {
+      return realGOPD(base, name);
+    }
+    Object.defineProperty(Object, 'getOwnPropertyDescriptor', {
+      value: GOPDWrapper
+    });
+  }
+
+  function repair_JSON_PARSE_PROTO_CONFUSION() {
+    var unsafeParse = JSON.parse;
+    function validate(plainJSON) {
+      if (plainJSON !== Object(plainJSON)) {
+        // If we were trying to do a full validation, we would
+        // validate that it is not NaN, Infinity, -Infinity, or
+        // (if nested) undefined. However, we are currently only
+        // trying to repair
+        // http://code.google.com/p/v8/issues/detail?id=621
+        // That's why this special case validate function is private
+        // to this repair.
+        return;
+      }
+      var proto = getPrototypeOf(plainJSON);
+      if (proto !== Object.prototype && proto !== Array.prototype) {
+        throw new TypeError(
+          'Parse resulted in invalid JSON. ' +
+            'See http://code.google.com/p/v8/issues/detail?id=621');
+      }
+      Object.keys(plainJSON).forEach(function(key) {
+        validate(plainJSON[key]);
+      });
+    }
+    Object.defineProperty(JSON, 'parse', {
+      value: function parseWrapper(text, opt_reviver) {
+        var result = unsafeParse(text);
+        validate(result);
+        if (opt_reviver) {
+          return unsafeParse(text, opt_reviver);
+        } else {
+          return result;
+        }
+      },
+      writable: true,
+      enumerable: false,
+      configurable: true
+    });
+  }
+
+  function repair_PARSEINT_STILL_PARSING_OCTAL() {
+    var badParseInt = parseInt;
+    function goodParseInt(n, radix) {
+      n = '' + n;
+      // This turns an undefined radix into a NaN but is ok since NaN
+      // is treated as undefined by badParseInt
+      radix = +radix;
+      var isHexOrOctal = /^\s*[+-]?\s*0(x?)/.exec(n);
+      var isOct = isHexOrOctal ? isHexOrOctal[1] !== 'x' : false;
+
+      if (isOct && (radix !== radix || 0 === radix)) {
+        return badParseInt(n, 10);
+      }
+      return badParseInt(n, radix);
+    }
+    parseInt = goodParseInt;
+  }
+
+  function repair_ASSIGN_CAN_OVERRIDE_FROZEN() {
+    makeTamperProof = function simpleMakeTamperProof() {
+      return Object.freeze;
+    };
+  }
+
+  function repair_CANT_REDEFINE_NAN_TO_ITSELF() {
+    var defProp = Object.defineProperty;
+    // 'value' handled separately
+    var attrs = ['writable', 'get', 'set', 'enumerable', 'configurable'];
+
+    defProp(Object, 'defineProperty', {
+      value: function(base, name, desc) {
+        try {
+          return defProp(base, name, desc);
+        } catch (err) {
+          var oldDesc = Object.getOwnPropertyDescriptor(base, name);
+          for (var i = 0, len = attrs.length; i < len; i++) {
+            var attr = attrs[i];
+            if (attr in desc && desc[attr] !== oldDesc[attr]) { throw err; }
+          }
+          if (!('value' in desc) || is(desc.value, oldDesc.value)) {
+            return base;
+          }
+          throw err;
+        }
+      }
+    });
+  }
+
+
+  ////////////////////// Kludge Records /////////////////////
+  //
+  // Each kludge record has a <dl>
+  //   <dt>description:</dt>
+  //     <dd>a string describing the problem</dd>
+  //   <dt>test:</dt>
+  //     <dd>a predicate testing for the presence of the problem</dd>
+  //   <dt>repair:</dt>
+  //     <dd>a function which attempts repair, or undefined if no
+  //         repair is attempted for this problem</dd>
+  //   <dt>preSeverity:</dt>
+  //     <dd>an enum (see below) indicating the level of severity of
+  //         this problem if unrepaired. Or, if !canRepair, then
+  //         the severity whether or not repaired.</dd>
+  //   <dt>canRepair:</dt>
+  //     <dd>a boolean indicating "if the repair exists and the test
+  //         subsequently does not detect a problem, are we now ok?"</dd>
+  //   <dt>urls:</dt>
+  //     <dd>a list of URL strings, each of which points at a page
+  //         relevant for documenting or tracking the bug in
+  //         question. These are typically into bug-threads in issue
+  //         trackers for the various browsers.</dd>
+  //   <dt>sections:</dt>
+  //     <dd>a list of strings, each of which is a relevant ES5.1
+  //         section number.</dd>
+  //   <dt>tests:</dt>
+  //     <dd>a list of strings, each of which is the name of a
+  //         relevant test262 or sputnik test case.</dd>
+  // </dl>
+  // These kludge records are the meta-data driving the testing and
+  // repairing.
+
+  var severities = ses.severities;
+  var statuses = ses.statuses;
+
+  /**
+   * First test whether the platform can even support our repair
+   * attempts.
+   */
+  var baseKludges = [
+    {
+      description: 'Missing getOwnPropertyNames',
+      test: test_MISSING_GETOWNPROPNAMES,
+      repair: void 0,
+      preSeverity: severities.NOT_SUPPORTED,
+      canRepair: false,
+      urls: [],
+      sections: ['15.2.3.4'],
+      tests: ['15.2.3.4-0-1']
+    }
+  ];
+
+  /**
+   * Run these only if baseKludges report success.
+   */
+  var supportedKludges = [
+    {
+      description: 'Global object leaks from global function calls',
+      test: test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=64250'],
+      sections: ['10.2.1.2', '10.2.1.2.6'],
+      tests: ['10.4.3-1-8gs']
+    },
+    {
+      description: 'Global object leaks from anonymous function calls',
+      test: test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.4.3'],
+      tests: ['S10.4.3_A1']
+    },
+    {
+      description: 'Global leaks through strict this',
+      test: test_GLOBAL_LEAKS_FROM_STRICT_THIS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.4.3'],
+      tests: ['10.4.3-1-8gs', '10.4.3-1-8-s']
+    },
+    {
+      description: 'Global object leaks from built-in methods',
+      test: test_GLOBAL_LEAKS_FROM_BUILTINS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=51097',
+             'https://bugs.webkit.org/show_bug.cgi?id=58338',
+             'http://code.google.com/p/v8/issues/detail?id=1437',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685430/global-object-leaks-from-built-in-methods'],
+      sections: ['15.2.4.4'],
+      tests: ['S15.2.4.4_A14']
+    },
+    {
+      description: 'Global object leaks from globally called built-in methods',
+      test: test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.2.1.2', '10.2.1.2.6', '15.2.4.4'],
+      tests: ['S15.2.4.4_A15']
+    },
+    {
+      description: 'Object.freeze is missing',
+      test: test_MISSING_FREEZE_ETC,
+      repair: repair_MISSING_FREEZE_ETC,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,           // repair for development, not safety
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=55736'],
+      sections: ['15.2.3.9'],
+      tests: ['15.2.3.9-0-1']
+    },
+    {
+      description: 'A function.prototype\'s descriptor lies',
+      test: test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,
+      repair: repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1530',
+             'http://code.google.com/p/v8/issues/detail?id=1570'],
+      sections: ['15.2.3.3', '15.2.3.6', '15.3.5.2'],
+      tests: ['S15.3.3.1_A4']
+    },
+    {
+      description: 'Phantom callee on strict functions',
+      test: test_MISSING_CALLEE_DESCRIPTOR,
+      repair: repair_MISSING_CALLEE_DESCRIPTOR,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=55537'],
+      sections: ['15.2.3.4'],
+      tests: ['S15.2.3.4_A1_T1']
+    },
+    {
+      description: 'Strict delete returned false rather than throwing',
+      test: test_STRICT_DELETE_RETURNS_FALSE,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://connect.microsoft.com/IE/feedback/details/' +
+               '685432/strict-delete-sometimes-returns-false-' +
+               'rather-than-throwing'],
+      sections: ['11.4.1'],
+      tests: ['S11.4.1_A5']
+    },
+    {
+      description: 'Non-deletable RegExp statics are a' +
+        ' global communication channel',
+      test: test_REGEXP_CANT_BE_NEUTERED,
+      repair: repair_REGEXP_CANT_BE_NEUTERED,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685439/non-deletable-regexp-statics-are-a-global-' +
+               'communication-channel'],
+      sections: ['11.4.1'],
+      tests: ['S11.4.1_A5']
+    },
+    {
+      description: 'RegExp.exec leaks match globally',
+      test: test_REGEXP_TEST_EXEC_UNSAFE,
+      repair: repair_REGEXP_TEST_EXEC_UNSAFE,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1393',
+             'http://code.google.com/p/chromium/issues/detail?id=75740',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=635017',
+             'http://code.google.com/p/google-caja/issues/detail?id=528'],
+      sections: ['15.10.6.2'],
+      tests: ['S15.10.6.2_A12']
+    },
+    {
+      description: 'Function.prototype.bind is missing',
+      test: test_MISSING_BIND,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=26382',
+             'https://bugs.webkit.org/show_bug.cgi?id=42371'],
+      sections: ['15.3.4.5'],
+      tests: ['S15.3.4.5_A3']
+    },
+    {
+      description: 'Function.prototype.bind calls .apply rather than [[Call]]',
+      test: test_BIND_CALLS_APPLY,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=892',
+             'http://code.google.com/p/v8/issues/detail?id=828'],
+      sections: ['15.3.4.5.1'],
+      tests: ['S15.3.4.5_A4']
+    },
+    {
+      description: 'Function.prototype.bind does not curry construction',
+      test: test_BIND_CANT_CURRY_NEW,
+      repair: void 0, // JS-based repair essentially impossible
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=26382#c29'],
+      sections: ['15.3.4.5.2'],
+      tests: ['S15.3.4.5_A5']
+    },
+    {
+      description: 'Date.prototype is a global communication channel',
+      test: test_MUTABLE_DATE_PROTO,
+      repair: repair_MUTABLE_DATE_PROTO,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/google-caja/issues/detail?id=1362'],
+      sections: ['15.9.5'],
+      tests: []
+    },
+    {
+      description: 'WeakMap.prototype is a global communication channel',
+      test: test_MUTABLE_WEAKMAP_PROTO,
+      repair: repair_MUTABLE_WEAKMAP_PROTO,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=656828'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Array forEach cannot be frozen while in progress',
+      test: test_NEED_TO_WRAP_FOREACH,
+      repair: repair_NEED_TO_WRAP_FOREACH,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1447'],
+      sections: ['15.4.4.18'],
+      tests: ['S15.4.4.18_A1', 'S15.4.4.18_A2']
+    },
+    {
+      description: 'Workaround undiagnosed need for dummy setter',
+      test: test_NEEDS_DUMMY_SETTER,
+      repair: repair_NEEDS_DUMMY_SETTER,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: [],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Getter on HTMLFormElement disappears',
+      test: test_FORM_GETTERS_DISAPPEAR,
+      repair: repair_NEEDS_DUMMY_SETTER,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/chromium/issues/detail?id=94666',
+             'http://code.google.com/p/v8/issues/detail?id=1651',
+             'http://code.google.com/p/google-caja/issues/detail?id=1401'],
+      sections: ['15.2.3.6'],
+      tests: ['S15.2.3.6_A1']
+    },
+    {
+      description: 'Accessor properties inherit as own properties',
+      test: test_ACCESSORS_INHERIT_AS_OWN,
+      repair: repair_ACCESSORS_INHERIT_AS_OWN,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=637994'],
+      sections: ['8.6.1', '15.2.3.6'],
+      tests: ['S15.2.3.6_A2']
+    },
+    {
+      description: 'Array sort leaks global',
+      test: test_SORT_LEAKS_GLOBAL,
+      repair: repair_SORT_LEAKS_GLOBAL,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1360'],
+      sections: ['15.4.4.11'],
+      tests: ['S15.4.4.11_A8']
+    },
+    {
+      description: 'String replace leaks global',
+      test: test_REPLACE_LEAKS_GLOBAL,
+      repair: repair_REPLACE_LEAKS_GLOBAL,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1360',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685928/bad-this-binding-for-callback-in-string-' +
+               'prototype-replace'],
+      sections: ['15.5.4.11'],
+      tests: ['S15.5.4.11_A12']
+    },
+    {
+      description: 'getOwnPropertyDescriptor on strict "caller" throws',
+      test: test_CANT_GOPD_CALLER,
+      repair: repair_CANT_GOPD_CALLER,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://connect.microsoft.com/IE/feedback/details/' +
+               '685436/getownpropertydescriptor-on-strict-caller-throws'],
+      sections: ['15.2.3.3', '13.2', '13.2.3'],
+      tests: ['S13.2_A6_T1']
+    },
+    {
+      description: 'strict_function.hasOwnProperty("caller") throws',
+      test: test_CANT_HASOWNPROPERTY_CALLER,
+      repair: repair_CANT_HASOWNPROPERTY_CALLER,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398#c3'],
+      sections: ['15.2.4.5', '13.2', '13.2.3'],
+      tests: ['S13.2_A7_T1']
+    },
+    {
+      description: 'Cannot "in" caller on strict function',
+      test: test_CANT_IN_CALLER,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['11.8.7', '13.2', '13.2.3'],
+      tests: ['S13.2_A8_T1']
+    },
+    {
+      description: 'Cannot "in" arguments on strict function',
+      test: test_CANT_IN_ARGUMENTS,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['11.8.7', '13.2', '13.2.3'],
+      tests: ['S13.2_A8_T2']
+    },
+    {
+      description: 'Strict "caller" not poisoned',
+      test: test_STRICT_CALLER_NOT_POISONED,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: [],
+      sections: ['13.2'],
+      tests: ['S13.2.3_A1']
+    },
+    {
+      description: 'Strict "arguments" not poisoned',
+      test: test_STRICT_ARGUMENTS_NOT_POISONED,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: [],
+      sections: ['13.2'],
+      tests: ['S13.2.3_A1']
+    },
+    {
+      description: 'Built in functions leak "caller"',
+      test: test_BUILTIN_LEAKS_CALLER,
+      repair: repair_BUILTIN_LEAKS_CALLER,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1643',
+             'http://code.google.com/p/v8/issues/detail?id=1548',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable'],
+      sections: [],
+      tests: ['Sbp_A10_T1']
+    },
+    {
+      description: 'Built in functions leak "arguments"',
+      test: test_BUILTIN_LEAKS_ARGUMENTS,
+      repair: repair_BUILTIN_LEAKS_ARGUMENTS,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1643',
+             'http://code.google.com/p/v8/issues/detail?id=1548',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable'],
+      sections: [],
+      tests: ['Sbp_A10_T2']
+    },
+    {
+      description: 'Bound functions leak "caller"',
+      test: test_BOUND_FUNCTION_LEAKS_CALLER,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=893',
+             'https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['15.3.4.5'],
+      tests: ['S13.2.3_A1', 'S15.3.4.5_A1']
+    },
+    {
+      description: 'Bound functions leak "arguments"',
+      test: test_BOUND_FUNCTION_LEAKS_ARGUMENTS,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=893',
+             'https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['15.3.4.5'],
+      tests: ['S13.2.3_A1', 'S15.3.4.5_A2']
+    },
+    {
+      description: 'Deleting built-in leaves phantom behind',
+      test: test_DELETED_BUILTINS_IN_OWN_NAMES,
+      repair: repair_DELETED_BUILTINS_IN_OWN_NAMES,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=70207'],
+      sections: ['15.2.3.4'],
+      tests: []
+    },
+    {
+      description: 'getOwnPropertyDescriptor on its own "caller" fails',
+      test: test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,
+      repair: repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1769'],
+      sections: ['13.2', '15.2.3.3'],
+      tests: []
+    },
+    {
+      description: 'JSON.parse confused by "__proto__"',
+      test: test_JSON_PARSE_PROTO_CONFUSION,
+      repair: repair_JSON_PARSE_PROTO_CONFUSION,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=621',
+             'http://code.google.com/p/v8/issues/detail?id=1310'],
+      sections: ['15.12.2'],
+      tests: ['S15.12.2_A1']
+    },
+    {
+      description: 'Prototype still mutable on non-extensible object',
+      test: test_PROTO_NOT_FROZEN,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=65832',
+             'https://bugs.webkit.org/show_bug.cgi?id=78438'],
+      sections: ['8.6.2'],
+      tests: ['S8.6.2_A8']
+    },
+    {
+      description: 'Prototype still redefinable on non-extensible object',
+      test: test_PROTO_REDEFINABLE,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=65832'],
+      sections: ['8.6.2'],
+      tests: ['S8.6.2_A8']
+    },
+    {
+      description: 'Strict eval function leaks variable definitions',
+      test: test_STRICT_EVAL_LEAKS_GLOBALS,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1624'],
+      sections: ['10.4.2.1'],
+      tests: ['S10.4.2.1_A1']
+    },
+    {
+      description: 'parseInt still parsing octal',
+      test: test_PARSEINT_STILL_PARSING_OCTAL,
+      repair: repair_PARSEINT_STILL_PARSING_OCTAL,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1645'],
+      sections: ['15.1.2.2'],
+      tests: ['S15.1.2.2_A5.1_T1']
+    },
+    {
+      description: 'E4X literals allowed in strict code',
+      test: test_STRICT_E4X_LITERALS_ALLOWED,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=695577',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=695579'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Assignment can override frozen inherited property',
+      test: test_ASSIGN_CAN_OVERRIDE_FROZEN,
+      repair: repair_ASSIGN_CAN_OVERRIDE_FROZEN,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1169',
+             'https://mail.mozilla.org/pipermail/es-discuss/' +
+               '2011-November/017997.html'],
+      sections: ['8.12.4'],
+      tests: ['15.2.3.6-4-405']
+    },
+    {
+      description: 'Cannot redefine global NaN to itself',
+      test: test_CANT_REDEFINE_NAN_TO_ITSELF,
+      repair: repair_CANT_REDEFINE_NAN_TO_ITSELF,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: [], // Seen on WebKit Nightly. TODO(erights): report
+      sections: ['8.12.9', '15.1.1.1'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Error instances have unexpected properties',
+      test: test_UNEXPECTED_ERROR_PROPERTIES,
+      repair: void 0,
+      preSeverity: severities.NEW_SYMPTOM,
+      canRepair: false,
+      urls: [],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'getOwnPropertyNames lies, hiding some own properties',
+      test: test_GET_OWN_PROPERTY_NAME_LIES,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=726477'],
+      sections: [],
+      tests: []
+    }
+  ];
+
+  ////////////////////// Testing, Repairing, Reporting ///////////
+
+  var aboutTo = void 0;
+
+  /**
+   * Run a set of tests & repairs, and report results.
+   *
+   * <p>First run all the tests before repairing anything.
+   * Then repair all repairable failed tests.
+   * Some repair might fix multiple problems, but run each repair at most once.
+   * Then run all the tests again, in case some repairs break other tests.
+   * And finally return a list of records of results.
+   */
+  function testRepairReport(kludges) {
+    var beforeFailures = strictMapFn(kludges, function(kludge) {
+      aboutTo = ['pre test: ', kludge.description];
+      return kludge.test();
+    });
+    var repairs = [];
+    strictForEachFn(kludges, function(kludge, i) {
+      if (beforeFailures[i]) {
+        var repair = kludge.repair;
+        if (repair && repairs.lastIndexOf(repair) === -1) {
+          aboutTo = ['repair: ', kludge.description];
+          repair();
+          repairs.push(repair);
+        }
+      }
+    });
+    var afterFailures = strictMapFn(kludges, function(kludge) {
+      aboutTo = ['post test: ', kludge.description];
+      return kludge.test();
+    });
+
+    if (Object.isFrozen && Object.isFrozen(Array.prototype.forEach)) {
+      // Need to do it anyway, to repair the sacrificial freezing we
+      // needed to do to test. Once we can permanently retire this
+      // test, we can also retire the redundant repair.
+      repair_NEED_TO_WRAP_FOREACH();
+    }
+
+    return strictMapFn(kludges, function(kludge, i) {
+      var status = statuses.ALL_FINE;
+      var postSeverity = severities.SAFE;
+      var beforeFailure = beforeFailures[i];
+      var afterFailure = afterFailures[i];
+      if (beforeFailure) { // failed before
+        if (afterFailure) { // failed after
+          if (kludge.repair) {
+            postSeverity = kludge.preSeverity;
+            status = statuses.REPAIR_FAILED;
+          } else {
+            if (!kludge.canRepair) {
+              postSeverity = kludge.preSeverity;
+            } // else no repair + canRepair -> problem isn't safety issue
+            status = statuses.NOT_REPAIRED;
+          }
+        } else { // succeeded after
+          if (kludge.repair) {
+            if (!kludge.canRepair) {
+              // repair for development, not safety
+              postSeverity = kludge.preSeverity;
+              status = statuses.REPAIRED_UNSAFELY;
+            } else {
+              status = statuses.REPAIRED;
+            }
+          } else {
+            status = statuses.ACCIDENTALLY_REPAIRED;
+          }
+        }
+      } else { // succeeded before
+        if (afterFailure) { // failed after
+          if (kludge.repair || !kludge.canRepair) {
+            postSeverity = kludge.preSeverity;
+          } // else no repair + canRepair -> problem isn't safety issue
+          status = statuses.BROKEN_BY_OTHER_ATTEMPTED_REPAIRS;
+        } else { // succeeded after
+          // nothing to see here, move along
+        }
+      }
+
+      if (typeof beforeFailure === 'string' ||
+          typeof afterFailure === 'string') {
+        postSeverity = severities.NEW_SYMPTOM;
+      }
+
+      ses.updateMaxSeverity(postSeverity);
+
+      return {
+        description:   kludge.description,
+        preSeverity:   kludge.preSeverity,
+        canRepair:     kludge.canRepair,
+        urls:          kludge.urls,
+        sections:      kludge.sections,
+        tests:         kludge.tests,
+        status:        status,
+        postSeverity:  postSeverity,
+        beforeFailure: beforeFailure,
+        afterFailure:  afterFailure
+      };
+    });
+  }
+
+  try {
+    var reports = testRepairReport(baseKludges);
+    if (ses.ok()) {
+      reports.push.apply(reports, testRepairReport(supportedKludges));
+    }
+    logger.reportRepairs(reports);
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    var during = aboutTo ? '(' + aboutTo.join('') + ') ' : '';
+    logger.error('ES5 Repair ' + during + 'failed with: ', err);
+  }
+
+  logger.reportMax();
+
+})(this);
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Install a leaky WeakMap emulation on platforms that
+ * don't provide a built-in one.
+ *
+ * <p>Assumes that an ES5 platform where, if {@code WeakMap} is
+ * already present, then it conforms to the anticipated ES6
+ * specification. To run this file on an ES5 or almost ES5
+ * implementation where the {@code WeakMap} specification does not
+ * quite conform, run <code>repairES5.js</code> first.
+ *
+ * @author Mark S. Miller
+ * @requires ses, crypto, ArrayBuffer, Uint8Array
+ * @overrides WeakMap, WeakMapModule
+ */
+
+/**
+ * This {@code WeakMap} emulation is observably equivalent to the
+ * ES-Harmony WeakMap, but with leakier garbage collection properties.
+ *
+ * <p>As with true WeakMaps, in this emulation, a key does not
+ * retain maps indexed by that key and (crucially) a map does not
+ * retain the keys it indexes. A map by itself also does not retain
+ * the values associated with that map.
+ *
+ * <p>However, the values associated with a key in some map are
+ * retained so long as that key is retained and those associations are
+ * not overridden. For example, when used to support membranes, all
+ * values exported from a given membrane will live for the lifetime
+ * they would have had in the absence of an interposed membrane. Even
+ * when the membrane is revoked, all objects that would have been
+ * reachable in the absence of revocation will still be reachable, as
+ * far as the GC can tell, even though they will no longer be relevant
+ * to ongoing computation.
+ *
+ * <p>The API implemented here is approximately the API as implemented
+ * in FF6.0a1 and agreed to by MarkM, Andreas Gal, and Dave Herman,
+ * rather than the offially approved proposal page. TODO(erights):
+ * upgrade the ecmascript WeakMap proposal page to explain this API
+ * change and present to EcmaScript committee for their approval.
+ *
+ * <p>The first difference between the emulation here and that in
+ * FF6.0a1 is the presence of non enumerable {@code get___, has___,
+ * set___, and delete___} methods on WeakMap instances to represent
+ * what would be the hidden internal properties of a primitive
+ * implementation. Whereas the FF6.0a1 WeakMap.prototype methods
+ * require their {@code this} to be a genuine WeakMap instance (i.e.,
+ * an object of {@code [[Class]]} "WeakMap}), since there is nothing
+ * unforgeable about the pseudo-internal method names used here,
+ * nothing prevents these emulated prototype methods from being
+ * applied to non-WeakMaps with pseudo-internal methods of the same
+ * names.
+ *
+ * <p>Another difference is that our emulated {@code
+ * WeakMap.prototype} is not itself a WeakMap. A problem with the
+ * current FF6.0a1 API is that WeakMap.prototype is itself a WeakMap
+ * providing ambient mutability and an ambient communications
+ * channel. Thus, if a WeakMap is already present and has this
+ * problem, repairES5.js wraps it in a safe wrappper in order to
+ * prevent access to this channel. (See
+ * PATCH_MUTABLE_FROZEN_WEAKMAP_PROTO in repairES5.js).
+ */
+var WeakMap;
+
+/**
+ * If this is a full <a href=
+ * "http://code.google.com/p/es-lab/wiki/SecureableES5"
+ * >secureable ES5</a> platform and the ES-Harmony {@code WeakMap} is
+ * absent, install an approximate emulation.
+ *
+ * <p>If this is almost a secureable ES5 platform, then WeakMap.js
+ * should be run after repairES5.js.
+ *
+ * <p>See {@code WeakMap} for documentation of the garbage collection
+ * properties of this WeakMap emulation.
+ */
+(function WeakMapModule() {
+  "use strict";
+
+  if (typeof ses !== 'undefined' && ses.ok && !ses.ok()) {
+    // already too broken, so give up
+    return;
+  }
+
+  if (typeof WeakMap === 'function') {
+    // assumed fine, so we're done.
+    return;
+  }
+
+  var hop = Object.prototype.hasOwnProperty;
+  var gopn = Object.getOwnPropertyNames;
+  var defProp = Object.defineProperty;
+
+  /**
+   * Holds the orginal static properties of the Object constructor,
+   * after repairES5 fixes these if necessary to be a more complete
+   * secureable ES5 environment, but before installing the following
+   * WeakMap emulation overrides and before any untrusted code runs.
+   */
+  var originalProps = {};
+  gopn(Object).forEach(function(name) {
+    originalProps[name] = Object[name];
+  });
+
+  /**
+   * Security depends on HIDDEN_NAME being both <i>unguessable</i> and
+   * <i>undiscoverable</i> by untrusted code.
+   *
+   * <p>Given the known weaknesses of Math.random() on existing
+   * browsers, it does not generate unguessability we can be confident
+   * of.
+   *
+   * <p>It is the monkey patching logic in this file that is intended
+   * to ensure undiscoverability. The basic idea is that there are
+   * three fundamental means of discovering properties of an object:
+   * The for/in loop, Object.keys(), and Object.getOwnPropertyNames(),
+   * as well as some proposed ES6 extensions that appear on our
+   * whitelist. The first two only discover enumerable properties, and
+   * we only use HIDDEN_NAME to name a non-enumerable property, so the
+   * only remaining threat should be getOwnPropertyNames and some
+   * proposed ES6 extensions that appear on our whitelist. We monkey
+   * patch them to remove HIDDEN_NAME from the list of properties they
+   * returns.
+   *
+   * <p>TODO(erights): On a platform with built-in Proxies, proxies
+   * could be used to trap and thereby discover the HIDDEN_NAME, so we
+   * need to monkey patch Proxy.create, Proxy.createFunction, etc, in
+   * order to wrap the provided handler with the real handler which
+   * filters out all traps using HIDDEN_NAME.
+   *
+   * <p>TODO(erights): Revisit Mike Stay's suggestion that we use an
+   * encapsulated function at a not-necessarily-secret name, which
+   * uses the Stiegler shared-state rights amplification pattern to
+   * reveal the associated value only to the WeakMap in which this key
+   * is associated with that value. Since only the key retains the
+   * function, the function can also remember the key without causing
+   * leakage of the key, so this doesn't violate our general gc
+   * goals. In addition, because the name need not be a guarded
+   * secret, we could efficiently handle cross-frame frozen keys.
+   */
+  var HIDDEN_NAME = 'ident:' + Math.random() + '___';
+
+  if (typeof crypto !== 'undefined' &&
+      typeof crypto.getRandomValues === 'function' &&
+      typeof ArrayBuffer === 'function' &&
+      typeof Uint8Array === 'function') {
+    var ab = new ArrayBuffer(25);
+    var u8s = new Uint8Array(ab);
+    crypto.getRandomValues(u8s);
+    HIDDEN_NAME = 'rand:' +
+      Array.prototype.map.call(u8s, function(u8) {
+        return (u8 % 36).toString(36);
+      }).join('') + '___';
+  }
+
+  /**
+   * Monkey patch getOwnPropertyNames to avoid revealing the
+   * HIDDEN_NAME.
+   *
+   * <p>The ES5.1 spec requires each name to appear only once, but as
+   * of this writing, this requirement is controversial for ES6, so we
+   * made this code robust against this case. If the resulting extra
+   * search turns out to be expensive, we can probably relax this once
+   * ES6 is adequately supported on all major browsers, iff no browser
+   * versions we support at that time have relaxed this constraint
+   * without providing built-in ES6 WeakMaps.
+   */
+  defProp(Object, 'getOwnPropertyNames', {
+    value: function fakeGetOwnPropertyNames(obj) {
+      return gopn(obj).filter(function(name) {
+        return name !== HIDDEN_NAME;
+      });
+    }
+  });
+
+  /**
+   * getPropertyNames is not in ES5 but it is proposed for ES6 and
+   * does appear in our whitelist, so we need to clean it too.
+   */
+  if ('getPropertyNames' in Object) {
+    defProp(Object, 'getPropertyNames', {
+      value: function fakeGetPropertyNames(obj) {
+        return originalProps.getPropertyNames(obj).filter(function(name) {
+          return name !== HIDDEN_NAME;
+        });
+      }
+    });
+  }
+
+  /**
+   * <p>To treat objects as identity-keys with reasonable efficiency
+   * on ES5 by itself (i.e., without any object-keyed collections), we
+   * need to add a hidden property to such key objects when we
+   * can. This raises several issues:
+   * <ul>
+   * <li>Arranging to add this property to objects before we lose the
+   *     chance, and
+   * <li>Hiding the existence of this new property from most
+   *     JavaScript code.
+   * <li>Preventing <i>certification theft</i>, where one object is
+   *     created falsely claiming to be the key of an association
+   *     actually keyed by another object.
+   * <li>Preventing <i>value theft</i>, where untrusted code with
+   *     access to a key object but not a weak map nevertheless
+   *     obtains access to the value associated with that key in that
+   *     weak map.
+   * </ul>
+   * We do so by
+   * <ul>
+   * <li>Making the name of the hidden property unguessable, so "[]"
+   *     indexing, which we cannot intercept, cannot be used to access
+   *     a property without knowing the name.
+   * <li>Making the hidden property non-enumerable, so we need not
+   *     worry about for-in loops or {@code Object.keys},
+   * <li>monkey patching those reflective methods that would
+   *     prevent extensions, to add this hidden property first,
+   * <li>monkey patching those methods that would reveal this
+   *     hidden property.
+   * </ul>
+   * Unfortunately, because of same-origin iframes, we cannot reliably
+   * add this hidden property before an object becomes
+   * non-extensible. Instead, if we encounter a non-extensible object
+   * without a hidden record that we can detect (whether or not it has
+   * a hidden record stored under a name secret to us), then we just
+   * use the key object itself to represent its identity in a brute
+   * force leaky map stored in the weak map, losing all the advantages
+   * of weakness for these.
+   */
+  function getHiddenRecord(key) {
+    if (key !== Object(key)) {
+      throw new TypeError('Not an object: ' + key);
+    }
+    var hiddenRecord = key[HIDDEN_NAME];
+    if (hiddenRecord && hiddenRecord.key === key) { return hiddenRecord; }
+    if (!originalProps.isExtensible(key)) {
+      // Weak map must brute force, as explained in doc-comment above.
+      return void 0;
+    }
+    var gets = [];
+    var vals = [];
+    hiddenRecord = {
+      key: key,   // self pointer for quick own check above.
+      gets: gets, // get___ methods identifying weak maps
+      vals: vals  // values associated with this key in each
+                  // corresponding weak map.
+    };
+    defProp(key, HIDDEN_NAME, {
+      value: hiddenRecord,
+      writable: false,
+      enumerable: false,
+      configurable: false
+    });
+    return hiddenRecord;
+  }
+
+
+  /**
+   * Monkey patch operations that would make their argument
+   * non-extensible.
+   *
+   * <p>The monkey patched versions throw a TypeError if their
+   * argument is not an object, so it should only be done to functions
+   * that should throw a TypeError anyway if their argument is not an
+   * object.
+   */
+  (function(){
+    var oldFreeze = Object.freeze;
+    defProp(Object, 'freeze', {
+      value: function identifyingFreeze(obj) {
+        getHiddenRecord(obj);
+        return oldFreeze(obj);
+      }
+    });
+    var oldSeal = Object.seal;
+    defProp(Object, 'seal', {
+      value: function identifyingSeal(obj) {
+        getHiddenRecord(obj);
+        return oldSeal(obj);
+      }
+    });
+    var oldPreventExtensions = Object.preventExtensions;
+    defProp(Object, 'preventExtensions', {
+      value: function identifyingPreventExtensions(obj) {
+        getHiddenRecord(obj);
+        return oldPreventExtensions(obj);
+      }
+    });
+  })();
+
+
+  function constFunc(func) {
+    func.prototype = null;
+    return Object.freeze(func);
+  }
+
+  // Right now (12/25/2012) the histogram supports the current
+  // representation. We should check this occasionally, as a true
+  // constant time representation is easy.
+  // var histogram = [];
+
+  WeakMap = function() {
+    // We are currently (12/25/2012) never encountering any prematurely
+    // non-extensible keys.
+    var keys = []; // brute force for prematurely non-extensible keys.
+    var vals = []; // brute force for corresponding values.
+
+    function get___(key, opt_default) {
+      var hr = getHiddenRecord(key);
+      var i, vs;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        vs = hr.vals;
+      } else {
+        i = keys.indexOf(key);
+        vs = vals;
+      }
+      return (i >= 0) ? vs[i] : opt_default;
+    }
+
+    function has___(key) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+      } else {
+        i = keys.indexOf(key);
+      }
+      return i >= 0;
+    }
+
+    function set___(key, value) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        if (i >= 0) {
+          hr.vals[i] = value;
+        } else {
+//          i = hr.gets.length;
+//          histogram[i] = (histogram[i] || 0) + 1;
+          hr.gets.push(get___);
+          hr.vals.push(value);
+        }
+      } else {
+        i = keys.indexOf(key);
+        if (i >= 0) {
+          vals[i] = value;
+        } else {
+          keys.push(key);
+          vals.push(value);
+        }
+      }
+    }
+
+    function delete___(key) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        if (i >= 0) {
+          hr.gets.splice(i, 1);
+          hr.vals.splice(i, 1);
+        }
+      } else {
+        i = keys.indexOf(key);
+        if (i >= 0) {
+          keys.splice(i, 1);
+          vals.splice(i, 1);
+        }
+      }
+      return true;
+    }
+
+    return Object.create(WeakMap.prototype, {
+      get___:    { value: constFunc(get___) },
+      has___:    { value: constFunc(has___) },
+      set___:    { value: constFunc(set___) },
+      delete___: { value: constFunc(delete___) }
+    });
+  };
+  WeakMap.prototype = Object.create(Object.prototype, {
+    get: {
+      /**
+       * Return the value most recently associated with key, or
+       * opt_default if none.
+       */
+      value: function get(key, opt_default) {
+        return this.get___(key, opt_default);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    has: {
+      /**
+       * Is there a value associated with key in this WeakMap?
+       */
+      value: function has(key) {
+        return this.has___(key);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    set: {
+      /**
+       * Associate value with key in this WeakMap, overwriting any
+       * previous association if present.
+       */
+      value: function set(key, value) {
+        this.set___(key, value);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    'delete': {
+      /**
+       * Remove any association for key in this WeakMap, returning
+       * whether there was one.
+       *
+       * <p>Note that the boolean return here does not work like the
+       * {@code delete} operator. The {@code delete} operator returns
+       * whether the deletion succeeds at bringing about a state in
+       * which the deleted property is absent. The {@code delete}
+       * operator therefore returns true if the property was already
+       * absent, whereas this {@code delete} method returns false if
+       * the association was already absent.
+       */
+      value: function remove(key) {
+        return this.delete___(key);
+      },
+      writable: true,
+      configurable: true
+    }
+  });
+
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Implements StringMap - a map api for strings.
+ *
+ * @author Mark S. Miller
+ * @author Jasvir Nagra
+ * @overrides StringMap
+ */
+
+var StringMap;
+
+(function() {
+   "use strict";
+
+   var create = Object.create;
+   var freeze = Object.freeze;
+   function constFunc(func) {
+     func.prototype = null;
+     return freeze(func);
+   }
+
+   function assertString(x) {
+     if ('string' !== typeof(x)) {
+       throw new TypeError('Not a string: ' + String(x));
+     }
+     return x;
+   }
+
+   StringMap = function StringMap() {
+
+     var objAsMap = create(null);
+
+     return freeze({
+       get: constFunc(function(key) {
+         return objAsMap[assertString(key) + '$'];
+       }),
+       set: constFunc(function(key, value) {
+         objAsMap[assertString(key) + '$'] = value;
+       }),
+       has: constFunc(function(key) {
+         return (assertString(key) + '$') in objAsMap;
+       }),
+       'delete': constFunc(function(key) {
+         return delete objAsMap[assertString(key) + '$'];
+       })
+     });
+   };
+
+ })();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports {@code ses.whitelist}, a recursively defined
+ * JSON record enumerating all the naming paths in the ES5.1 spec,
+ * those de-facto extensions that we judge to be safe, and SES and
+ * Dr. SES extensions provided by the SES runtime.
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * //provides ses.whitelist
+ * @author Mark S. Miller,
+ * @overrides ses, whitelistModule
+ */
+var ses;
+
+/**
+ * <p>Each JSON record enumerates the disposition of the properties on
+ * some corresponding primordial object, with the root record
+ * representing the global object. For each such record, the values
+ * associated with its property names can be
+ * <ul>
+ * <li>Another record, in which case this property is simply
+ *     whitelisted and that next record represents the disposition of
+ *     the object which is its value. For example, {@code "Object"}
+ *     leads to another record explaining what properties {@code
+ *     "Object"} may have and how each such property, if present,
+ *     and its value should be tamed.
+ * <li>true, in which case this property is simply whitelisted. The
+ *     value associated with that property is still traversed and
+ *     tamed, but only according to the taming of the objects that
+ *     object inherits from. For example, {@code "Object.freeze"} leads
+ *     to true, meaning that the {@code "freeze"} property of {@code
+ *     Object} should be whitelisted and the value of the property (a
+ *     function) should be further tamed only according to the
+ *     markings of the other objects it inherits from, like {@code
+ *     "Function.prototype"} and {@code "Object.prototype").
+ * <li>"*", in which case this property on this object is whitelisted,
+ *     as is this property as inherited by all objects that inherit
+ *     from this object. The values associated with all such properties
+ *     are still traversed and tamed, but only according to the taming
+ *     of the objects that object inherits from. For example, {@code
+ *     "Object.prototype.constructor"} leads to "*", meaning that we
+ *     whitelist the {@code "constructor"} property on {@code
+ *     Object.prototype} and on every object that inherits from {@code
+ *     Object.prototype} that does not have a conflicting mark. Each
+ *     of these is tamed as if with true, so that the value of the
+ *     property is further tamed according to what other objects it
+ *     inherits from.
+ * <li>"skip", in which case this property on this object is simply
+ *     whitelisted, as is this property as inherited by all objects
+ *     that inherit from this object, but we avoid taming the value
+ *     associated with that property. For example, as of this writing
+ *     {@code "Function.prototype.caller"} leads to "skip" because
+ *     some current browser bugs prevent us from removing or even
+ *     traversing this property on some platforms of interest.
+ * </ul>
+ *
+ * The "skip" markings are workarounds for browser bugs or other
+ * temporary problems. For each of these, there should be an
+ * explanatory comment explaining why or a bug citation. Ideally, we
+ * can retire all "skip" entries by the time SES is ready for secure
+ * production use.
+ *
+ * The members of the whitelist are either
+ * <ul>
+ * <li>(uncommented) defined by the ES5.1 normative standard text,
+ * <li>(questionable) provides a source of non-determinism, in
+ *     violation of pure object-capability rules, but allowed anyway
+ *     since we've given up on restricting JavaScript to a
+ *     deterministic subset.
+ * <li>(ES5 Appendix B) common elements of de facto JavaScript
+ *     described by the non-normative Appendix B.
+ * <li>(Harmless whatwg) extensions documented at
+ *     <a href="http://wiki.whatwg.org/wiki/Web_ECMAScript"
+ *     >http://wiki.whatwg.org/wiki/Web_ECMAScript</a> that seem to be
+ *     harmless. Note that the RegExp constructor extensions on that
+ *     page are <b>not harmless</b> and so must not be whitelisted.
+ * <li>(ES-Harmony proposal) accepted as "proposal" status for
+ *     EcmaScript-Harmony.
+ * <li>(Marked as "skip") See above.
+ * </ul>
+ *
+ * <p>With the above encoding, there are some sensible whitelists we
+ * cannot express, such as marking a property both with "*" and a JSON
+ * record. This is an expedient decision based only on not having
+ * encountered such a need. Should we need this extra expressiveness,
+ * we'll need to refactor to enable a different encoding.
+ *
+ * <p>We factor out {@code true} into the variable {@code t} just to
+ * get a bit better compression from simple minifiers.
+ */
+(function whitelistModule() {
+  "use strict";
+
+  if (!ses) { ses = {}; }
+
+  var t = true;
+  ses.whitelist = {
+    cajaVM: {                        // Caja support
+      log: t,
+      tamperProof: t,
+      constFunc: t,
+      def: t,
+      is: t,
+
+      compileExpr: t,
+      compileModule: t,              // experimental
+      compileProgram: t,             // Cannot be implemented in just ES5.1.
+      eval: t,
+      Function: t,
+
+      sharedImports: t,
+      makeImports: t,
+      copyToImports: t,
+
+      callWithEjector: t,
+      eject: t,
+      GuardT: {
+        coerce: t
+      },
+      makeTableGuard: t,
+      Trademark: {
+        stamp: t
+      },
+      guard: t,
+      passesGuard: t,
+      stamp: t,
+      makeSealerUnsealerPair: t,
+
+      makeArrayLike: {}
+    },
+    WeakMap: {       // ES-Harmony proposal as currently implemented by FF6.0a1
+      prototype: {
+        // Note: coordinate this list with maintenance of repairES5.js
+        get: t,
+        set: t,
+        has: t,
+        'delete': t
+      }
+    },
+    StringMap: {  // A specialized approximation of ES-Harmony's Map.
+      prototype: {} // Technically, the methods should be on the prototype,
+                    // but doing so while preserving encapsulation will be
+                    // needlessly expensive for current usage.
+    },
+// As of this writing, the WeakMap emulation in WeakMap.js relies on
+// the unguessability and undiscoverability of HIDDEN_NAME, a
+// secret property name. However, on a platform with built-in
+// Proxies, if whitelisted but not properly monkey patched, proxies
+// could be used to trap and thereby discover HIDDEN_NAME. So until we
+// (TODO(erights)) write the needed monkey patching of proxies, we
+// omit them from our whitelist.
+//    Proxy: {                         // ES-Harmony proposal
+//      create: t,
+//      createFunction: t
+//    },
+    escape: t,                       // ES5 Appendix B
+    unescape: t,                     // ES5 Appendix B
+    Object: {
+      // If any new methods are added here that may reveal the
+      // HIDDEN_NAME within WeakMap.js, such as the proposed
+      // getOwnPropertyDescriptors or getPropertyDescriptors, then
+      // extend WeakMap.js to monkey patch these to avoid revealing
+      // HIDDEN_NAME.
+      getPropertyDescriptor: t,      // ES-Harmony proposal
+      getPropertyNames: t,           // ES-Harmony proposal
+      is: t,                         // ES-Harmony proposal
+      prototype: {
+
+        // Whitelisted only to work around a Chrome debugger
+        // stratification bug (TODO(erights): report). These are
+        // redefined in startSES.js in terms of standard methods, so
+        // that we can be confident they introduce no non-standard
+        // possibilities.
+        __defineGetter__: t,
+        __defineSetter__: t,
+        __lookupGetter__: t,
+        __lookupSetter__: t,
+
+        constructor: '*',
+        toString: '*',
+        toLocaleString: '*',
+        valueOf: t,
+        hasOwnProperty: t,
+        isPrototypeOf: t,
+        propertyIsEnumerable: t
+      },
+      getPrototypeOf: t,
+      getOwnPropertyDescriptor: t,
+      getOwnPropertyNames: t,
+      create: t,
+      defineProperty: t,
+      defineProperties: t,
+      seal: t,
+      freeze: t,
+      preventExtensions: t,
+      isSealed: t,
+      isFrozen: t,
+      isExtensible: t,
+      keys: t
+    },
+    NaN: t,
+    Infinity: t,
+    undefined: t,
+    // eval: t,                      // Whitelisting under separate control
+                                     // by TAME_GLOBAL_EVAL in startSES.js
+    parseInt: t,
+    parseFloat: t,
+    isNaN: t,
+    isFinite: t,
+    decodeURI: t,
+    decodeURIComponent: t,
+    encodeURI: t,
+    encodeURIComponent: t,
+    Function: {
+      prototype: {
+        apply: t,
+        call: t,
+        bind: t,
+        prototype: '*',
+        length: '*',
+        arity: '*',                  // non-std, deprecated in favor of length
+        name: '*'                    // non-std
+      }
+    },
+    Array: {
+      prototype: {
+        concat: t,
+        join: t,
+        pop: t,
+        push: t,
+        reverse: t,
+        shift: t,
+        slice: t,
+        sort: t,
+        splice: t,
+        unshift: t,
+        indexOf: t,
+        lastIndexOf: t,
+        every: t,
+        some: t,
+        forEach: t,
+        map: t,
+        filter: t,
+        reduce: t,
+        reduceRight: t,
+        length: 'skip'               // can't be redefined on Mozilla
+        // See https://bugzilla.mozilla.org/show_bug.cgi?id=591059
+        // and https://bugzilla.mozilla.org/show_bug.cgi?id=598996
+      },
+      isArray: t
+    },
+    String: {
+      prototype: {
+        substr: t,                   // ES5 Appendix B
+        anchor: t,                   // Harmless whatwg
+        big: t,                      // Harmless whatwg
+        blink: t,                    // Harmless whatwg
+        bold: t,                     // Harmless whatwg
+        fixed: t,                    // Harmless whatwg
+        fontcolor: t,                // Harmless whatwg
+        fontsize: t,                 // Harmless whatwg
+        italics: t,                  // Harmless whatwg
+        link: t,                     // Harmless whatwg
+        small: t,                    // Harmless whatwg
+        strike: t,                   // Harmless whatwg
+        sub: t,                      // Harmless whatwg
+        sup: t,                      // Harmless whatwg
+        trimLeft: t,                 // non-standard
+        trimRight: t,                // non-standard
+        valueOf: t,
+        charAt: t,
+        charCodeAt: t,
+        concat: t,
+        indexOf: t,
+        lastIndexOf: t,
+        localeCompare: t,
+        match: t,
+        replace: t,
+        search: t,
+        slice: t,
+        split: t,
+        substring: t,
+        toLowerCase: t,
+        toLocaleLowerCase: t,
+        toUpperCase: t,
+        toLocaleUpperCase: t,
+        trim: t,
+        length: '*'
+      },
+      fromCharCode: t
+    },
+    Boolean: {
+      prototype: {
+        valueOf: t
+      }
+    },
+    Number: {
+      prototype: {
+        valueOf: t,
+        toFixed: t,
+        toExponential: t,
+        toPrecision: t
+      },
+      MAX_VALUE: t,
+      MIN_VALUE: t,
+      NaN: t,
+      NEGATIVE_INFINITY: t,
+      POSITIVE_INFINITY: t
+    },
+    Math: {
+      E: t,
+      LN10: t,
+      LN2: t,
+      LOG2E: t,
+      LOG10E: t,
+      PI: t,
+      SQRT1_2: t,
+      SQRT2: t,
+
+      abs: t,
+      acos: t,
+      asin: t,
+      atan: t,
+      atan2: t,
+      ceil: t,
+      cos: t,
+      exp: t,
+      floor: t,
+      log: t,
+      max: t,
+      min: t,
+      pow: t,
+      random: t,                     // questionable
+      round: t,
+      sin: t,
+      sqrt: t,
+      tan: t
+    },
+    Date: {                          // no-arg Date constructor is questionable
+      prototype: {
+        // Note: coordinate this list with maintanence of repairES5.js
+        getYear: t,                  // ES5 Appendix B
+        setYear: t,                  // ES5 Appendix B
+        toGMTString: t,              // ES5 Appendix B
+        toDateString: t,
+        toTimeString: t,
+        toLocaleString: t,
+        toLocaleDateString: t,
+        toLocaleTimeString: t,
+        getTime: t,
+        getFullYear: t,
+        getUTCFullYear: t,
+        getMonth: t,
+        getUTCMonth: t,
+        getDate: t,
+        getUTCDate: t,
+        getDay: t,
+        getUTCDay: t,
+        getHours: t,
+        getUTCHours: t,
+        getMinutes: t,
+        getUTCMinutes: t,
+        getSeconds: t,
+        getUTCSeconds: t,
+        getMilliseconds: t,
+        getUTCMilliseconds: t,
+        getTimezoneOffset: t,
+        setTime: t,
+        setFullYear: t,
+        setUTCFullYear: t,
+        setMonth: t,
+        setUTCMonth: t,
+        setDate: t,
+        setUTCDate: t,
+        setHours: t,
+        setUTCHours: t,
+        setMinutes: t,
+        setUTCMinutes: t,
+        setSeconds: t,
+        setUTCSeconds: t,
+        setMilliseconds: t,
+        setUTCMilliseconds: t,
+        toUTCString: t,
+        toISOString: t,
+        toJSON: t
+      },
+      parse: t,
+      UTC: t,
+      now: t                         // questionable
+    },
+    RegExp: {
+      prototype: {
+        exec: t,
+        test: t,
+        source: '*',
+        global: '*',
+        ignoreCase: '*',
+        multiline: '*',
+        lastIndex: '*',
+        sticky: '*'                  // non-std
+      }
+    },
+    Error: {
+      prototype: {
+        name: '*',
+        message: '*'
+      }
+    },
+    EvalError: {
+      prototype: t
+    },
+    RangeError: {
+      prototype: t
+    },
+    ReferenceError: {
+      prototype: t
+    },
+    SyntaxError: {
+      prototype: t
+    },
+    TypeError: {
+      prototype: t
+    },
+    URIError: {
+      prototype: t
+    },
+    JSON: {
+      parse: t,
+      stringify: t
+    }
+  };
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Export a {@code ses.atLeastFreeVarNames} function for
+ * internal use by the SES-on-ES5 implementation, which enumerates at
+ * least the identifiers which occur freely in a source text string.
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * // provides ses.atLeastFreeVarNames
+ * @author Mark S. Miller
+ * @requires StringMap
+ * @overrides ses, atLeastFreeVarNamesModule
+ */
+var ses;
+
+/**
+ * Calling {@code ses.atLeastFreeVarNames} on a {@code programSrc}
+ * string argument, the result should include at least all the free
+ * variable names of {@code programSrc} as own properties. It is
+ * harmless to include other strings as well.
+ *
+ * <p>Assuming a programSrc that parses as a strict Program,
+ * atLeastFreeVarNames(programSrc) returns a Record whose enumerable
+ * own property names must include the names of all the free variables
+ * occuring in programSrc. It can include as many other strings as is
+ * convenient so long as it includes these. The value of each of these
+ * properties should be {@code true}.
+ *
+ * <p>TODO(erights): On platforms that support Proxies (currently only
+ * FF4 and later), we should stop using atLeastFreeVarNames, since a
+ * {@code with(aProxy) {...}} should reliably intercept all free
+ * variable accesses without needing any prior scan.
+ */
+(function atLeastFreeVarNamesModule() {
+  "use strict";
+
+   if (!ses) { ses = {}; }
+
+  /////////////// KLUDGE SWITCHES ///////////////
+
+  /**
+   * Currently we use this to limit the input text to ascii only
+   * without backslash-u escapes, in order to simply our identifier
+   * gathering.
+   *
+   * <p>This is only a temporary development hack. TODO(erights): fix.
+   */
+  function LIMIT_SRC(programSrc) {
+    if ((/[^\u0000-\u007f]/).test(programSrc)) {
+      throw new EvalError('Non-ascii text not yet supported');
+    }
+    if ((/\\u/).test(programSrc)) {
+      throw new EvalError('Backslash-u escape encoded text not yet supported');
+    }
+  }
+
+  /**
+   * Return a regexp that can be used repeatedly to scan for the next
+   * identifier.
+   *
+   * <p>The current implementation is safe only because of the above
+   * LIMIT_SRC. To do this right takes quite a lot of unicode
+   * machinery. See the "Identifier" production at
+   * http://es-lab.googlecode.com/svn/trunk/src/parser/es5parser.ojs
+   * which depends on
+   * http://es-lab.googlecode.com/svn/trunk/src/parser/unicode.js
+   *
+   * <p>This is only a temporary development hack. TODO(erights): fix.
+   */
+  function SHOULD_MATCH_IDENTIFIER() { return (/(\w|\$)+/g); }
+
+
+  //////////////// END KLUDGE SWITCHES ///////////
+
+  ses.atLeastFreeVarNames = function atLeastFreeVarNames(programSrc) {
+    programSrc = String(programSrc);
+    LIMIT_SRC(programSrc);
+    // Now that we've temporarily limited our attention to ascii...
+    var regexp = SHOULD_MATCH_IDENTIFIER();
+    // Once we decide this file can depends on ES5, the following line
+    // should say "... = Object.create(null);" rather than "... = {};"
+    var result = [];
+    var found = StringMap();
+    var a;
+    while ((a = regexp.exec(programSrc))) {
+      // Note that we could have avoided the while loop by doing
+      // programSrc.match(regexp), except that then we'd need
+      // temporary storage proportional to the total number of
+      // apparent identifiers, rather than the total number of
+      // apparently unique identifiers.
+      var name = a[0];
+
+      if (!found.has(name)) {
+        result.push(name);
+        found.set(name, true);
+      }
+    }
+    return result;
+  };
+
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Make this frame SES-safe or die trying.
+ *
+ * <p>Assumes ES5 plus a WeakMap that conforms to the anticipated ES6
+ * WeakMap spec. Compatible with ES5-strict or anticipated ES6.
+ *
+ * //provides ses.startSES
+ * @author Mark S. Miller,
+ * @requires WeakMap
+ * @overrides ses, console, eval, Function, cajaVM
+ */
+var ses;
+
+
+/**
+ * The global {@code eval} function available to script code, which
+ * may or not be made safe.
+ *
+ * <p>The original global binding of {@code eval} is not
+ * SES-safe. {@code cajaVM.eval} is a safe wrapper around this
+ * original eval, enforcing SES language restrictions.
+ *
+ * <p>If {@code TAME_GLOBAL_EVAL} is true, both the global {@code
+ * eval} variable and {@code sharedImports.eval} are set to the safe
+ * wrapper. If {@code TAME_GLOBAL_EVAL} is false, in order to work
+ * around a bug in the Chrome debugger, then the global {@code eval}
+ * is unaltered and no {@code "eval"} property is available on {@code
+ * sharedImports}. In either case, SES-evaled-code and SES-script-code
+ * can both access the safe eval wrapper as {@code cajaVM.eval}.
+ *
+ * <p>By making the safe eval available on {@code sharedImports} only
+ * when we also make it be the genuine global eval, we preserve the
+ * property that SES-evaled-code differs from SES-script-code only by
+ * having a subset of the same variables in globalish scope. This is a
+ * nice-to-have that makes explanation easier rather than a hard
+ * requirement. With this property, any SES-evaled-code that does not
+ * fail to access a global variable (or to test whether it could)
+ * should operate the same way when run as SES-script-code.
+ *
+ * <p>See doc-comment on cajaVM for the restriction on this API needed
+ * to operate under Caja translation on old browsers.
+ */
+var eval;
+
+/**
+ * The global {@code Function} constructor is always replaced with a
+ * safe wrapper, which is also made available as
+ * {@code sharedImports.Function}.
+ *
+ * <p>Both the original Function constructor and this safe wrapper
+ * point at the original {@code Function.prototype}, so {@code
+ * instanceof} works fine with the wrapper. {@code
+ * Function.prototype.constructor} is set to point at the safe
+ * wrapper, so that only it, and not the unsafe original, is
+ * accessible.
+ *
+ * <p>See doc-comment on cajaVM for the restriction on this API needed
+ * to operate under Caja translation on old browsers.
+ */
+var Function;
+
+/**
+ * A new global exported by SES, intended to become a mostly
+ * compatible API between server-side Caja translation for older
+ * browsers and client-side SES verification for newer browsers.
+ *
+ * <p>Under server-side Caja translation for old pre-ES5 browsers, the
+ * synchronous interface of the evaluation APIs (currently {@code
+ * eval, Function, cajaVM.{compileExpr, compileModule, eval, Function}})
+ * cannot reasonably be provided. Instead, under translation we expect
+ * <ul>
+ * <li>Not to have a binding for {@code "eval"} on
+ *     {@code sharedImports}, just as we would not if
+ *     {@code TAME_GLOBAL_EVAL} is false.
+ * <li>The global {@code eval} seen by scripts is either unaltered (to
+ *     work around the Chrome debugger bug if {@code TAME_GLOBAL_EVAL}
+ *     is false), or is replaced by a function that throws an
+ *     appropriate EvalError diagnostic (if {@code TAME_GLOBAL_EVAL}
+ *     is true).
+ * <li>The global {@code Function} constructor, both as seen by script
+ *     code and evaled code, to throw an appropriate diagnostic.
+ * <li>The {@code Q} API to always be available, to handle
+ *     asynchronous, promise, and remote requests.
+ * <li>The evaluating methods on {@code cajaVM} -- currently {@code
+ *     compileExpr, compileModule, eval, and Function} -- to be remote
+ *     promises for their normal interfaces, which therefore must be
+ *     invoked with {@code Q.post}.
+ * <li>Since {@code Q.post} can be used for asynchronously invoking
+ *     non-promises, invocations like
+ *     {@code Q.post(cajaVM, 'eval', ['2+3'])}, for example,
+ *     will return a promise for a 5. This should work both under Caja
+ *     translation and (TODO(erights)) under SES verification when
+ *     {@code Q} is also installed, and so is the only portable
+ *     evaluating API that SES code should use during this transition
+ *     period.
+ * <li>TODO(erights): {@code Q.post(cajaVM, 'compileModule',
+ *     [moduleSrc]} should eventually pre-load the transitive
+ *     synchronous dependencies of moduleSrc before resolving the
+ *     promise for its result. It currently would not, instead
+ *     requiring its client to do so manually.
+ * </ul>
+ */
+var cajaVM;
+
+/**
+ * <p>{@code ses.startSES} should be called before any other potentially
+ * dangerous script is executed in this frame.
+ *
+ * <p>If {@code ses.startSES} succeeds, the evaluation operations on
+ * {@code cajaVM}, the global {@code Function} contructor, and perhaps
+ * the {@code eval} function (see doc-comment on {@code eval} and
+ * {@code cajaVM}) will only load code according to the <i>loader
+ * isolation</i> rules of the object-capability model, suitable for
+ * loading untrusted code. If all other (trusted) code executed
+ * directly in this frame (i.e., other than through these safe
+ * evaluation operations) takes care to uphold object-capability
+ * rules, then untrusted code loaded via these safe evaluation
+ * operations will be constrained by those rules. TODO(erights):
+ * explain concretely what the trusted code must do or avoid doing to
+ * uphold object-capability rules.
+ *
+ * <p>On a pre-ES5 platform, this script will fail cleanly, leaving
+ * the frame intact. Otherwise, if this script fails, it may leave
+ * this frame in an unusable state. All following description assumes
+ * this script succeeds and that the browser conforms to the ES5
+ * spec. The ES5 spec allows browsers to implement more than is
+ * specified as long as certain invariants are maintained. We further
+ * assume that these extensions are not maliciously designed to obey
+ * the letter of these invariants while subverting the intent of the
+ * spec. In other words, even on an ES5 conformant browser, we do not
+ * presume to defend ourselves from a browser that is out to get us.
+ *
+ * @param global ::Record(any) Assumed to be the real global object
+ *        for some frame. Since {@code ses.startSES} will allow global
+ *        variable references that appear at the top level of the
+ *        whitelist, our safety depends on these variables being
+ *        frozen as a side effect of freezing the corresponding
+ *        properties of {@code global}. These properties are also
+ *        duplicated onto the virtual global objects which are
+ *        provided as the {@code this} binding for the safe
+ *        evaluation calls -- emulating the safe subset of the normal
+ *        global object.
+ *        TODO(erights): Currently, the code has only been tested when
+ *        {@code global} is the global object of <i>this</i>
+ *        frame. The code should be made to work for cross-frame use.
+ * @param whitelist ::Record(Permit) where Permit = true | "*" |
+ *        "skip" | Record(Permit).  Describes the subset of naming
+ *        paths starting from {@code sharedImports} that should be
+ *        accessible. The <i>accessible primordials</i> are all values
+ *        found by navigating these paths starting from {@code
+ *        sharedImports}. All non-whitelisted properties of accessible
+ *        primordials are deleted, and then {@code sharedImports}
+ *        and all accessible primordials are frozen with the
+ *        whitelisted properties frozen as data properties.
+ *        TODO(erights): fix the code and documentation to also
+ *        support confined-ES5, suitable for confining potentially
+ *        offensive code but not supporting defensive code, where we
+ *        skip this last freezing step. With confined-ES5, each frame
+ *        is considered a separate protection domain rather that each
+ *        individual object.
+ * @param atLeastFreeVarNames ::F([string], Record(true))
+ *        Given the sourceText for a strict Program,
+ *        atLeastFreeVarNames(sourceText) returns a Record whose
+ *        enumerable own property names must include the names of all the
+ *        free variables occuring in sourceText. It can include as
+ *        many other strings as is convenient so long as it includes
+ *        these. The value of each of these properties should be
+ *        {@code true}. TODO(erights): On platforms with Proxies
+ *        (currently only Firefox 4 and after), use {@code
+ *        with(aProxy) {...}} to intercept free variables rather than
+ *        atLeastFreeVarNames.
+ * @param extensions ::F([], Record(any)]) A function returning a
+ *        record whose own properties will be copied onto cajaVM. This
+ *        is used for the optional components which bring SES to
+ *        feature parity with the ES5/3 runtime at the price of larger
+ *        code size. At the time that {@code startSES} calls {@code
+ *        extensions}, {@code cajaVM} exists but should not yet be
+ *        used. In particular, {@code extensions} should not call
+ *        {@code cajaVM.def} during this setup, because def would then
+ *        freeze priordials before startSES cleans them (removes
+ *        non-whitelisted properties). The methods that
+ *        {@code extensions} contributes can, of course, use
+ *        {@code cajaVM}, since those methods will only be called once
+ *        {@code startSES} finishes.
+ */
+ses.startSES = function(global,
+                        whitelist,
+                        atLeastFreeVarNames,
+                        extensions) {
+  "use strict";
+
+  /////////////// KLUDGE SWITCHES ///////////////
+
+  /////////////////////////////////
+  // The following are only the minimal kludges needed for the current
+  // Firefox or the current Chrome Beta. At the time of
+  // this writing, these are Firefox 4.0 and Chrome 12.0.742.5 dev
+  // As these move forward, kludges can be removed until we simply
+  // rely on ES5.
+
+  /**
+   * <p>TODO(erights): isolate and report this.
+   *
+   * <p>Workaround for Chrome debugger's own use of 'eval'
+   *
+   * <p>This kludge is safety preserving but not semantics
+   * preserving. When {@code TAME_GLOBAL_EVAL} is false, no {@code
+   * sharedImports.eval} is available, and the 'eval' available as a
+   * global to trusted (script) code is the original 'eval', and so is
+   * not safe.
+   */
+  //var TAME_GLOBAL_EVAL = true;
+  var TAME_GLOBAL_EVAL = false;
+
+  /**
+   * If this is true, then we redefine these to work around a
+   * stratification bug in the Chrome debugger. To allow this, we have
+   * also whitelisted these four properties in whitelist.js
+   */
+  //var EMULATE_LEGACY_GETTERS_SETTERS = false;
+  var EMULATE_LEGACY_GETTERS_SETTERS = true;
+
+  //////////////// END KLUDGE SWITCHES ///////////
+
+
+  var dirty = true;
+
+  var hop = Object.prototype.hasOwnProperty;
+
+  var getProto = Object.getPrototypeOf;
+  var defProp = Object.defineProperty;
+  var gopd = Object.getOwnPropertyDescriptor;
+  var gopn = Object.getOwnPropertyNames;
+  var keys = Object.keys;
+  var freeze = Object.freeze;
+  var create = Object.create;
+
+  /**
+   * Use to tamper proof a function which is not intended to ever be
+   * used as a constructor, since it nulls out the function's
+   * prototype first.
+   */
+  function constFunc(func) {
+    func.prototype = null;
+    return freeze(func);
+  }
+
+
+  function fail(str) {
+    debugger;
+    throw new EvalError(str);
+  }
+
+  if (typeof WeakMap === 'undefined') {
+    fail('No built-in WeakMaps, so WeakMap.js must be loaded first');
+  }
+
+
+  if (EMULATE_LEGACY_GETTERS_SETTERS) {
+    (function(){
+      function legacyDefineGetter(sprop, getter) {
+        sprop = '' + sprop;
+        if (hop.call(this, sprop)) {
+          defProp(this, sprop, { get: getter });
+        } else {
+          defProp(this, sprop, {
+            get: getter,
+            set: undefined,
+            enumerable: true,
+            configurable: true
+          });
+        }
+      }
+      legacyDefineGetter.prototype = null;
+      defProp(Object.prototype, '__defineGetter__', {
+        value: legacyDefineGetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyDefineSetter(sprop, setter) {
+        sprop = '' + sprop;
+        if (hop.call(this, sprop)) {
+          defProp(this, sprop, { set: setter });
+        } else {
+          defProp(this, sprop, {
+            get: undefined,
+            set: setter,
+            enumerable: true,
+            configurable: true
+          });
+        }
+      }
+      legacyDefineSetter.prototype = null;
+      defProp(Object.prototype, '__defineSetter__', {
+        value: legacyDefineSetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyLookupGetter(sprop) {
+        sprop = '' + sprop;
+        var base = this, desc = void 0;
+        while (base && !(desc = gopd(base, sprop))) { base = getProto(base); }
+        return desc && desc.get;
+      }
+      legacyLookupGetter.prototype = null;
+      defProp(Object.prototype, '__lookupGetter__', {
+        value: legacyLookupGetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyLookupSetter(sprop) {
+        sprop = '' + sprop;
+        var base = this, desc = void 0;
+        while (base && !(desc = gopd(base, sprop))) { base = getProto(base); }
+        return desc && desc.set;
+      }
+      legacyLookupSetter.prototype = null;
+      defProp(Object.prototype, '__lookupSetter__', {
+        value: legacyLookupSetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+    })();
+  } else {
+    delete Object.prototype.__defineGetter__;
+    delete Object.prototype.__defineSetter__;
+    delete Object.prototype.__lookupGetter__;
+    delete Object.prototype.__lookupSetter__;
+  }
+
+
+  /**
+   * By this time, WeakMap has already monkey patched Object.freeze if
+   * necessary, so we can do the tamperProofing delayed from
+   * repairES5.js
+   */
+  var tamperProof = ses.makeDelayedTamperProof();
+
+  /**
+   * Code being eval'ed by {@code cajaVM.eval} sees {@code
+   * sharedImports} as its top-level {@code this}, as if {@code
+   * sharedImports} were the global object.
+   *
+   * <p>{@code sharedImports}'s properties are exactly the whitelisted
+   * global variable references. These properties, both as they appear
+   * on the global object and on this {@code sharedImports} object,
+   * are frozen and so cannot diverge. This preserves the illusion.
+   *
+   * <p>For code being evaluated by {@code cajaVM.compileExpr} and its
+   * ilk, the {@code imports} provided to the compiled function is bound
+   * to the top-level {@code this} of the evaluated code. For sanity,
+   * this {@code imports} should first be initialized with a copy of the
+   * properties of {@code sharedImports}, but nothing enforces this.
+   */
+  var sharedImports = create(null);
+
+  (function startSESPrelude() {
+
+    /**
+     * The unsafe* variables hold precious values that must not escape
+     * to untrusted code. When {@code eval} is invoked via {@code
+     * unsafeEval}, this is a call to the indirect eval function, not
+     * the direct eval operator.
+     */
+    var unsafeEval = eval;
+    var UnsafeFunction = Function;
+
+    /**
+     * Fails if {@code programSrc} does not parse as a strict Program
+     * production, or, almost equivalently, as a FunctionBody
+     * production.
+     *
+     * <p>We use Crock's trick of simply passing {@code programSrc} to
+     * the original {@code Function} constructor, which will throw a
+     * SyntaxError if it does not parse as a FunctionBody. We used to
+     * use Ankur's trick (need link) which is more correct, in that it
+     * will throw if {@code programSrc} does not parse as a Program
+     * production, which is the relevant question. However, the
+     * difference -- whether return statements are accepted -- does
+     * not matter for our purposes. And testing reveals that Crock's
+     * trick executes over 100x faster on V8.
+     */
+    function verifyStrictProgram(programSrc) {
+      try {
+        UnsafeFunction('"use strict";' + programSrc);
+      } catch (err) {
+        // debugger; // Useful for debugging -- to look at programSrc
+        throw err;
+      }
+    }
+
+    /**
+     * Fails if {@code exprSource} does not parse as a strict
+     * Expression production.
+     *
+     * <p>To verify that exprSrc parses as a strict Expression, we
+     * verify that (when followed by ";") it parses as a strict
+     * Program, and that when surrounded with parens it still parses
+     * as a strict Program. We place a newline before the terminal
+     * token so that a "//" comment cannot suppress the close paren.
+     */
+    function verifyStrictExpression(exprSrc) {
+      verifyStrictProgram(exprSrc + ';');
+      verifyStrictProgram('( ' + exprSrc + '\n);');
+    }
+
+    /**
+     * Make a virtual global object whose initial own properties are
+     * a copy of the own properties of {@code sharedImports}.
+     *
+     * <p>Further uses of {@code copyToImports} to copy properties
+     * onto this imports object will overwrite, effectively shadowing
+     * the {@code sharedImports}. You should shadow by overwriting
+     * rather than inheritance so that shadowing makes the original
+     * binding inaccessible.
+     *
+     * <p>The returned imports object is extensible and all its
+     * properties are configurable and non-enumerable. Once fully
+     * initialized, the caller can of course freeze the imports
+     * objects if desired. A reason not to do so it to emulate
+     * traditional JavaScript intermodule linkage by side effects to a
+     * shared (virtual) global object.
+     *
+     * <p>See {@code copyToImports} for the precise semantic of the
+     * property copying.
+     */
+    function makeImports() {
+      var imports = create(null);
+      copyToImports(imports, sharedImports);
+      return imports;
+    }
+
+    /**
+     * For all the own properties of {@code from}, copy their
+     * descriptors to {@code imports}, except that each property
+     * added to {@code imports} is unconditionally configurable
+     * and non-enumerable.
+     *
+     * <p>By copying descriptors rather than values, any accessor
+     * properties of {@code env} become accessors of {@code imports}
+     * with the same getter and setter. If these do not use their
+     * {@code this} value, then the original and any copied properties
+     * are effectively joined. If the getter/setter do use their
+     * {@code this}, when accessed with {@code imports} as the base,
+     * their {@code this} will be bound to the {@code imports} rather
+     * than {@code from}. If {@code from} contains writable value
+     * properties, this will copy the current value of the property,
+     * after which they may diverge.
+     *
+     * <p>We make these configurable so that {@code imports} can
+     * be further configured before being frozen. We make these
+     * non-enumerable in order to emulate the normal behavior of
+     * built-in properties of typical global objects, such as the
+     * browser's {@code window} object.
+     */
+    function copyToImports(imports, from) {
+      gopn(from).forEach(function(name) {
+        var desc = gopd(from, name);
+        desc.enumerable = false;
+        desc.configurable = true;
+        defProp(imports, name, desc);
+      });
+      return imports;
+    }
+
+    /**
+     * Make a frozen scope object which reflects all access onto
+     * {@code imports}, for use by {@code with} to prevent
+     * access to any {@code freeNames} other than those found on the.
+     * {@code imports}.
+     */
+    function makeScopeObject(imports, freeNames) {
+      var scopeObject = create(null);
+      // Note: Although this loop is a bottleneck on some platforms,
+      // it does not help to turn it into a for(;;) loop, since we
+      // still need an enclosing function per accessor property
+      // created, to capture its own unique binding of
+      // "name". (Embarrasing fact: despite having often written about
+      // this very danger, I engaged in this mistake in a misbegotten
+      // optimization attempt here.)
+      freeNames.forEach(function interceptName(name) {
+        var desc = gopd(imports, name);
+        if (!desc || desc.writable !== false || desc.configurable) {
+          // If there is no own property, or it isn't a non-writable
+          // value property, or it is configurable. Note that this
+          // case includes accessor properties. The reason we wrap
+          // rather than copying over getters and setters is so the
+          // this-binding of the original getters and setters will be
+          // the imports rather than the scopeObject.
+          desc = {
+            get: function scopedGet() {
+              if (name in imports) {
+                var result = imports[name];
+                if (typeof result === 'function') {
+                  // If it were possible to know that the getter call
+                  // was on behalf of a simple function call to the
+                  // gotten function, we could instead return that
+                  // function as bound to undefined. Unfortunately,
+                  // without parsing (or possibly proxies?), that isn't
+                  // possible.
+                }
+                return result;
+              }
+              // if it were possible to know that the getter call was on
+              // behalf of a typeof expression, we'd return the string
+              // "undefined" here instead. Unfortunately, without
+              // parsing or proxies, that isn't possible.
+              throw new ReferenceError('"' + name + '" not in scope');
+            },
+            set: function scopedSet(newValue) {
+              if (name in imports) {
+                imports[name] = newValue;
+              }
+              throw new TypeError('Cannot set "' + name + '"');
+            },
+            enumerable: false
+          };
+        }
+        desc.enumerable = false;
+        defProp(scopeObject, name, desc);
+      });
+      return freeze(scopeObject);
+    }
+
+
+    /**
+     * Given SES source text that must not be run directly using any
+     * of the built-in unsafe evaluators on this platform, we instead
+     * surround it with a prelude and postlude.
+     *
+     * <p>Evaluating the resulting expression return a function that
+     * <i>can</i>be called to execute the original expression safely,
+     * in a controlled scope. See "makeCompiledExpr" for precisely the
+     * pattern that must be followed to call the resulting function
+     * safely.
+     *
+     * Notice that the source text placed around {@code exprSrc}
+     * <ul>
+     * <li>brings no variable names into scope, avoiding any
+     *     non-hygienic name capture issues, and
+     * <li>does not introduce any newlines preceding exprSrc, so
+     *     that all line number which a debugger might report are
+     *     accurate wrt the original source text. And except for the
+     *     first line, all the column numbers are accurate too.
+     * </ul>
+     *
+     * <p>TODO(erights): Find out if any platforms have any way to
+     * associate a file name and line number with eval'ed text, so
+     * that we can do something useful with the optional {@code
+     * opt_sourcePosition} to better support debugging.
+     */
+    function securableWrapperSrc(exprSrc, opt_sourcePosition) {
+      verifyStrictExpression(exprSrc);
+
+      return '(function() { ' +
+        // non-strict code, where this === scopeObject
+        '  with (this) { ' +
+        '    return function() { ' +
+        '      "use strict"; ' +
+        '      return ( ' +
+        // strict code, where this === imports
+        '        ' + exprSrc + '\n' +
+        '      );\n' +
+        '    };\n' +
+        '  }\n' +
+        '})';
+    }
+    ses.securableWrapperSrc = securableWrapperSrc;
+
+
+    /**
+     * Given a wrapper function, such as the result of evaluating the
+     * source that securableWrapperSrc returns, and a list of all the
+     * names that we want to intercept to redirect to the imports,
+     * return a corresponding <i>compiled expr</i> function.
+     *
+     * <p>A compiled expr function, when called on an imports
+     * object, evaluates the original expression in a context where
+     * all its free variable references that appear in freeNames are
+     * redirected to the corresponding property of imports.
+     */
+    function makeCompiledExpr(wrapper, freeNames) {
+      if (dirty) { fail('Initial cleaning failed'); }
+
+      function compiledCode(imports) {
+        var scopeObject = makeScopeObject(imports, freeNames);
+        return wrapper.call(scopeObject).call(imports);
+      };
+      compiledCode.prototype = null;
+      return compiledCode;
+    }
+    ses.makeCompiledExpr = makeCompiledExpr;
+
+    /**
+     * Compiles {@code exprSrc} as a strict expression into a function
+     * of an {@code imports}, that when called evaluates {@code
+     * exprSrc} in a virtual global environment whose {@code this} is
+     * bound to that {@code imports}, and whose free variables
+     * refer only to the properties of that {@code imports}.
+     *
+     * <p>When SES is provided primitively, it should provide an
+     * analogous {@code compileProgram} function that accepts a
+     * Program and return a function that evaluates it to the
+     * Program's completion value. Unfortunately, this is not
+     * practical as a library without some non-standard support from
+     * the platform such as a parser API that provides an AST.
+     *
+     * <p>Thanks to Mike Samuel and Ankur Taly for this trick of using
+     * {@code with} together with RegExp matching to intercept free
+     * variable access without parsing.
+     */
+    function compileExpr(exprSrc, opt_sourcePosition) {
+      var wrapperSrc = securableWrapperSrc(exprSrc, opt_sourcePosition);
+      var wrapper = unsafeEval(wrapperSrc);
+      var freeNames = atLeastFreeVarNames(exprSrc);
+      var result = makeCompiledExpr(wrapper, freeNames);
+      return freeze(result);
+    }
+
+
+    var directivePattern = (/^['"](?:\w|\s)*['"]$/m);
+
+    /**
+     * A stereotyped form of the CommonJS require statement.
+     */
+    var requirePattern = (/^(?:\w*\s*(?:\w|\$|\.)*\s*=)?\s*require\s*\(\s*['"]((?:\w|\$|\.|\/)+)['"]\s*\)$/m);
+
+    /**
+     * As an experiment, recognize a stereotyped prelude of the
+     * CommonJS module system.
+     */
+    function getRequirements(modSrc) {
+      var result = [];
+      var stmts = modSrc.split(';');
+      var stmt;
+      var i = 0, ilen = stmts.length;
+      for (; i < ilen; i++) {
+        stmt = stmts[i].trim();
+        if (stmt !== '') {
+          if (!directivePattern.test(stmt)) { break; }
+        }
+      }
+      for (; i < ilen; i++) {
+        stmt = stmts[i].trim();
+        if (stmt !== '') {
+          var m = requirePattern.exec(stmt);
+          if (!m) { break; }
+          result.push(m[1]);
+        }
+      }
+      return freeze(result);
+    }
+
+    /**
+     * A module source is actually any valid FunctionBody, and thus
+     * any valid Program.
+     *
+     * <p>In addition, in case the module source happens to begin with
+     * a streotyped prelude of the CommonJS module system, the
+     * function resulting from module compilation has an additional
+     * {@code "requirements"} property whose value is a list of the
+     * module names being required by that prelude. These requirements
+     * are the module's "immediate synchronous dependencies".
+     *
+     * <p>This {@code "requirements"} property is adequate to
+     * bootstrap support for a CommonJS module system, since a loader
+     * can first load and compile the transitive closure of an initial
+     * module's synchronous depencies before actually executing any of
+     * these module functions.
+     *
+     * <p>With a similarly lightweight RegExp, we should be able to
+     * similarly recognize the {@code "load"} syntax of <a href=
+     * "http://wiki.ecmascript.org/doku.php?id=strawman:simple_modules#syntax"
+     * >Sam and Dave's module proposal for ES-Harmony</a>. However,
+     * since browsers do not currently accept this syntax,
+     * {@code getRequirements} above would also have to extract these
+     * from the text to be compiled.
+     */
+    function compileModule(modSrc, opt_sourcePosition) {
+      var exprSrc = '(function() {' + modSrc + '}).call(this)';
+
+      // Follow the pattern in compileExpr
+      var wrapperSrc = securableWrapperSrc(exprSrc, opt_sourcePosition);
+      var wrapper = unsafeEval(wrapperSrc);
+      var freeNames = atLeastFreeVarNames(exprSrc);
+      var moduleMaker = makeCompiledExpr(wrapper, freeNames);
+
+      moduleMaker.requirements = getRequirements(modSrc);
+      return freeze(moduleMaker);
+    }
+
+    /**
+     * A safe form of the {@code Function} constructor, which
+     * constructs strict functions that can only refer freely to the
+     * {@code sharedImports}.
+     *
+     * <p>The returned function is strict whether or not it declares
+     * itself to be.
+     */
+    function FakeFunction(var_args) {
+      var params = [].slice.call(arguments, 0);
+      var body = params.pop();
+      body = String(body || '');
+      params = params.join(',');
+      var exprSrc = '(function(' + params + '\n){' + body + '})';
+      return compileExpr(exprSrc)(sharedImports);
+    }
+    FakeFunction.prototype = UnsafeFunction.prototype;
+    FakeFunction.prototype.constructor = FakeFunction;
+    global.Function = FakeFunction;
+
+    /**
+     * A safe form of the indirect {@code eval} function, which
+     * evaluates {@code src} as strict code that can only refer freely
+     * to the {@code sharedImports}.
+     *
+     * <p>Given our parserless methods of verifying untrusted sources,
+     * we unfortunately have no practical way to obtain the completion
+     * value of a safely evaluated Program. Instead, we adopt a
+     * compromise based on the following observation. All Expressions
+     * are valid Programs, and all Programs are valid
+     * FunctionBodys. If {@code src} parses as a strict expression,
+     * then we evaluate it as an expression and correctly return its
+     * completion value, since that is simply the value of the
+     * expression.
+     *
+     * <p>Otherwise, we evaluate {@code src} as a FunctionBody and
+     * return what that would return from its implicit enclosing
+     * function. If {@code src} is simply a Program, then it would not
+     * have an explicit {@code return} statement, and so we fail to
+     * return its completion value.
+     *
+     * <p>When SES {@code eval} is provided primitively, it should
+     * accept a Program and evaluate it to the Program's completion
+     * value. Unfortunately, this is not possible on ES5 without
+     * parsing.
+     */
+    function fakeEval(src) {
+      try {
+        verifyStrictExpression(src);
+      } catch (x) {
+        src = '(function() {' + src + '\n}).call(this)';
+      }
+      return compileExpr(src)(sharedImports);
+    }
+
+    if (TAME_GLOBAL_EVAL) {
+      global.eval = fakeEval;
+    }
+
+    var defended = WeakMap();
+    var defending = WeakMap();
+    /**
+     * To define a defended object is to tamperProof it and all objects
+     * transitively reachable from it via transitive reflective
+     * property and prototype traversal.
+     */
+    function def(node) {
+      var defendingList = [];
+      function recur(val) {
+        if (!val) { return; }
+        var t = typeof val;
+        if (t === 'number' || t === 'string' || t === 'boolean') { return; }
+        if (defended.get(val) || defending.get(val)) { return; }
+        defending.set(val, true);
+        defendingList.push(val);
+
+        tamperProof(val);
+
+        recur(getProto(val));
+
+        // How to optimize? This is a performance sensitive loop, but
+        // forEach seems to be faster on Chrome 18 Canary but a
+        // for(;;) loop seems better on FF 12 Nightly.
+        gopn(val).forEach(function(p) {
+          if (typeof val === 'function' &&
+              (p === 'caller' || p === 'arguments')) {
+            return;
+          }
+          var desc = gopd(val, p);
+          recur(desc.value);
+          recur(desc.get);
+          recur(desc.set);
+        });
+      }
+      try {
+        recur(node);
+      } catch (err) {
+        defending = WeakMap();
+        throw err;
+      }
+      defendingList.forEach(function(obj) {
+        defended.set(obj, true);
+      });
+      return node;
+    }
+
+
+    /**
+     * makeArrayLike() produces a constructor for the purpose of
+     * taming things like nodeLists.  The result, ArrayLike, takes an
+     * instance of ArrayLike and two functions, getItem and getLength,
+     * which put it in a position to do taming on demand.
+     *
+     * <p>The constructor returns a new object that inherits from the
+     * {@code proto} passed in.
+     */
+    var makeArrayLike;
+    (function() {
+      var itemMap = WeakMap(), lengthMap = WeakMap();
+      function lengthGetter() {
+        var getter = lengthMap.get(this);
+        return getter ? getter() : void 0;
+      }
+      constFunc(lengthGetter);
+
+      var nativeProxies = global.Proxy && (function () {
+        var obj = {0: 'hi'};
+        var p = global.Proxy.create({
+          get: function () {
+            var P = arguments[0];
+            if (typeof P !== 'string') { P = arguments[1]; }
+            return obj[P];
+          }
+        });
+        return p[0] === 'hi';
+      })();
+      if (nativeProxies) {
+        (function () {
+          function ArrayLike(proto, getItem, getLength) {
+            if (typeof proto !== 'object') {
+              throw new TypeError('Expected proto to be an object.');
+            }
+            if (!(proto instanceof ArrayLike)) {
+              throw new TypeError('Expected proto to be instanceof ArrayLike.');
+            }
+            var obj = create(proto);
+            itemMap.set(obj, getItem);
+            lengthMap.set(obj, getLength);
+            return obj;
+          }
+
+          function ownPropDesc(P) {
+            P = '' + P;
+            if (P === 'length') {
+              return { get: lengthGetter };
+            } else if (typeof P === 'number' || P === '' + (+P)) {
+              return {
+                get: constFunc(function() {
+                  var getter = itemMap.get(this);
+                  return getter ? getter(+P) : void 0;
+                }),
+                enumerable: true,
+                configurable: true
+              };
+            }
+            return void 0;
+          }
+          function propDesc(P) {
+            var opd = ownPropDesc(P);
+            if (opd) {
+              return opd;
+            } else {
+              return gopd(Object.prototype, P);
+            }
+          }
+          function has(P) {
+            P = '' + P;
+            return (P === 'length') ||
+                (typeof P === 'number') ||
+                (P === '' + +P) ||
+                (P in Object.prototype);
+          }
+          function hasOwn(P) {
+            P = '' + P;
+            return (P === 'length') ||
+                (typeof P === 'number') ||
+                (P === '' + +P);
+          }
+          function getPN() {
+            var result = getOwnPN ();
+            var objPropNames = gopn(Object.prototype);
+            result.push.apply(result, objPropNames);
+            return result;
+          }
+          function getOwnPN() {
+            var lenGetter = lengthMap.get(this);
+            if (!lenGetter) { return void 0; }
+            var len = lenGetter();
+            var result = ['length'];
+            for (var i = 0; i < len; ++i) {
+              result.push('' + i);
+            }
+            return result;
+          };
+          function del(P) {
+            P = '' + P;
+            if ((P === 'length') || ('' + +P === P)) { return false; }
+            return true;
+          }
+
+          ArrayLike.prototype = global.Proxy.create({
+            getPropertyDescriptor: propDesc,
+            getOwnPropertyDescriptor: ownPropDesc,
+            has: has,
+            hasOwn: hasOwn,
+            getPropertyNames: getPN,
+            getOwnPropertyNames: getOwnPN,
+            'delete': del,
+            fix: function() { return void 0; }
+          }, Object.prototype);
+          tamperProof(ArrayLike);
+          makeArrayLike = function() { return ArrayLike; };
+        })();
+      } else {
+        (function() {
+          // Make BiggestArrayLike.prototype be an object with a fixed
+          // set of numeric getters.  To tame larger lists, replace
+          // BiggestArrayLike and its prototype using
+          // makeArrayLike(newLength).
+
+          // See
+          // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+          function nextUInt31PowerOf2(v) {
+            v &= 0x7fffffff;
+            v |= v >> 1;
+            v |= v >> 2;
+            v |= v >> 4;
+            v |= v >> 8;
+            v |= v >> 16;
+            return v + 1;
+          }
+
+          // The current function whose prototype has the most numeric getters.
+          var BiggestArrayLike = void 0;
+          var maxLen = 0;
+          makeArrayLike = function(length) {
+            if (!BiggestArrayLike || length > maxLen) {
+              var len = nextUInt31PowerOf2(length);
+              // Create a new ArrayLike constructor to replace the old one.
+              var BAL = function(proto, getItem, getLength) {
+                if (typeof(proto) !== 'object') {
+                  throw new TypeError('Expected proto to be an object.');
+                }
+                if (!(proto instanceof BAL)) {
+                  throw new TypeError(
+                      'Expected proto to be instanceof ArrayLike.');
+                }
+                var obj = create(proto);
+                itemMap.set(obj, getItem);
+                lengthMap.set(obj, getLength);
+                return obj;
+              };
+              // Install native numeric getters.
+              for (var i = 0; i < len; i++) {
+                (function(j) {
+                  function get() {
+                    return itemMap.get(this)(j);
+                  }
+                  defProp(BAL.prototype, j, {
+                    get: constFunc(get),
+                    enumerable: true
+                  });
+                })(i);
+              }
+              // Install native length getter.
+              defProp(BAL.prototype, 'length', { get: lengthGetter });
+              // TamperProof and cache the result
+              tamperProof(BAL);
+              tamperProof(BAL.prototype);
+              BiggestArrayLike = BAL;
+              maxLen = len;
+            }
+            return BiggestArrayLike;
+          };
+        })();
+      }
+    })();
+
+    global.cajaVM = { // don't freeze here
+
+      /**
+       * This is about to be deprecated once we expose ses.logger.
+       *
+       * <p>In the meantime, privileged code should use ses.logger.log
+       * instead of cajaVM.log.
+       */
+      log: constFunc(function log(str) {
+        if (typeof console !== 'undefined' && 'log' in console) {
+          // We no longer test (typeof console.log === 'function') since,
+          // on IE9 and IE10preview, in violation of the ES5 spec, it
+          // is callable but has typeof "object". See
+          // https://connect.microsoft.com/IE/feedback/details/685962/
+          //   console-log-and-others-are-callable-but-arent-typeof-function
+          console.log(str);
+        }
+      }),
+      tamperProof: constFunc(tamperProof),
+      constFunc: constFunc(constFunc),
+      // def: see below
+      is: constFunc(ses.is),
+
+      compileExpr: constFunc(compileExpr),
+      compileModule: constFunc(compileModule),
+      // compileProgram: compileProgram, // Cannot be implemented in ES5.1.
+      eval: fakeEval,               // don't freeze here
+      Function: FakeFunction,       // don't freeze here,
+
+      sharedImports: sharedImports, // don't freeze here
+      makeImports: constFunc(makeImports),
+      copyToImports: constFunc(copyToImports),
+
+      makeArrayLike: constFunc(makeArrayLike)
+    };
+    var extensionsRecord = extensions();
+    gopn(extensionsRecord).forEach(function (p) {
+      defProp(cajaVM, p,
+              gopd(extensionsRecord, p));
+    });
+
+    // Move this down here so it is not available during the call to
+    // extensions().
+    global.cajaVM.def = constFunc(def);
+
+  })();
+
+  var propertyReports = {};
+
+  /**
+   * Report how a property manipulation went.
+   */
+  function reportProperty(severity, status, path) {
+    ses.updateMaxSeverity(severity);
+    var group = propertyReports[status] || (propertyReports[status] = {
+      severity: severity,
+      list: []
+    });
+    group.list.push(path);
+  }
+
+  /**
+   * Initialize accessible global variables and {@code sharedImports}.
+   *
+   * For each of the whitelisted globals, we read its value, freeze
+   * that global property as a data property, and mirror that property
+   * with a frozen data property of the same name and value on {@code
+   * sharedImports}, but always non-enumerable. We make these
+   * non-enumerable since ES5.1 specifies that all these properties
+   * are non-enumerable on the global object.
+   */
+  keys(whitelist).forEach(function(name) {
+    var desc = gopd(global, name);
+    if (desc) {
+      var permit = whitelist[name];
+      if (permit) {
+        var newDesc = {
+          value: global[name],
+          writable: false,
+          configurable: false
+        };
+        try {
+          defProp(global, name, newDesc);
+        } catch (err) {
+          reportProperty(ses.severities.NEW_SYMPTOM,
+                         'Global ' + name + ' cannot be made readonly: ' + err);
+        }
+        defProp(sharedImports, name, newDesc);
+      }
+    }
+  });
+  if (TAME_GLOBAL_EVAL) {
+    defProp(sharedImports, 'eval', {
+      value: cajaVM.eval,
+      writable: false,
+      enumerable: false,
+      configurable: false
+    });
+  }
+
+  /**
+   * The whiteTable should map from each path-accessible primordial
+   * object to the permit object that describes how it should be
+   * cleaned.
+   *
+   * We initialize the whiteTable only so that {@code getPermit} can
+   * process "*" and "skip" inheritance using the whitelist, by
+   * walking actual superclass chains.
+   */
+  var whiteTable = WeakMap();
+  function register(value, permit) {
+    if (value !== Object(value)) { return; }
+    if (typeof permit !== 'object') {
+      return;
+    }
+    var oldPermit = whiteTable.get(value);
+    if (oldPermit) {
+      fail('primordial reachable through multiple paths');
+    }
+    whiteTable.set(value, permit);
+    keys(permit).forEach(function(name) {
+      if (permit[name] !== 'skip') {
+        var sub = value[name];
+        register(sub, permit[name]);
+      }
+    });
+  }
+  register(sharedImports, whitelist);
+
+  /**
+   * Should the property named {@code name} be whitelisted on the
+   * {@code base} object, and if so, with what Permit?
+   *
+   * <p>If it should be permitted, return the Permit (where Permit =
+   * true | "*" | "skip" | Record(Permit)), all of which are
+   * truthy. If it should not be permitted, return false.
+   */
+  function getPermit(base, name) {
+    var permit = whiteTable.get(base);
+    if (permit) {
+      if (hop.call(permit, name)) { return permit[name]; }
+    }
+    while (true) {
+      base = getProto(base);
+      if (base === null) { return false; }
+      permit = whiteTable.get(base);
+      if (permit && hop.call(permit, name)) {
+        var result = permit[name];
+        if (result === '*' || result === 'skip') {
+          return result;
+        } else {
+          return false;
+        }
+      }
+    }
+  }
+
+  var cleaning = WeakMap();
+
+  /**
+   * Delete the property if possible, else try to poison.
+   */
+  function cleanProperty(base, name, path) {
+    function poison() {
+      throw new TypeError('Cannot access property ' + path);
+    }
+    var diagnostic;
+
+    if (typeof base === 'function') {
+      if (name === 'caller') {
+        diagnostic = ses.makeCallerHarmless(base, path);
+        // We can use a severity of SAFE here since if this isn't
+        // safe, it is the responsibility of repairES5.js to tell us
+        // so. All the same, we should inspect the reports on all
+        // platforms we care about to see if there are any surprises.
+        reportProperty(ses.severities.SAFE,
+                       diagnostic, path);
+        return true;
+      }
+      if (name === 'arguments') {
+        diagnostic = ses.makeArgumentsHarmless(base, path);
+        // We can use a severity of SAFE here since if this isn't
+        // safe, it is the responsibility of repairES5.js to tell us
+        // so. All the same, we should inspect the reports on all
+        // platforms we care about to see if there are any surprises.
+        reportProperty(ses.severities.SAFE,
+                       diagnostic, path);
+        return true;
+      }
+    }
+
+    var deleted = void 0;
+    var err = void 0;
+    try {
+      deleted = delete base[name];
+    } catch (er) { err = er; }
+    var exists = hop.call(base, name);
+    if (deleted) {
+      if (!exists) {
+        reportProperty(ses.severities.SAFE,
+                       'Deleted', path);
+        return true;
+      }
+      reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+                     'Bounced back', path);
+    } else if (deleted === false) {
+      reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+                     'Strict delete returned false rather than throwing', path);
+    } else if (err instanceof TypeError) {
+      // This is the normal abnormal case, so leave it to the next
+      // section to emit a diagnostic.
+      //
+      // reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+      //                'Cannot be deleted', path);
+    } else {
+      reportProperty(ses.severities.NEW_SYMPTOM,
+                     'Delete failed with' + err, path);
+    }
+
+    try {
+      defProp(base, name, {
+        get: poison,
+        set: poison,
+        enumerable: false,
+        configurable: false
+      });
+    } catch (cantPoisonErr) {
+      try {
+        // Perhaps it's writable non-configurable, in which case we
+        // should still be able to freeze it in a harmless state.
+        var value = gopd(base, name).value;
+        defProp(base, name, {
+          value: value === null ? null : void 0,
+          writable: false,
+          configurable: false
+        });
+      } catch (cantFreezeHarmless) {
+        reportProperty(ses.severities.NOT_ISOLATED,
+                       'Cannot be poisoned', path);
+        return false;
+      }
+    }
+    var desc2 = gopd(base, name);
+    if (desc2.get === poison &&
+        desc2.set === poison &&
+        !desc2.configurable) {
+      try {
+        var dummy2 = base[name];
+      } catch (expectedErr) {
+        if (expectedErr instanceof TypeError) {
+          reportProperty(ses.severities.SAFE,
+                         'Successfully poisoned', path);
+          return true;
+        }
+      }
+    } else if ((desc2.value === void 0 || desc2.value === null) &&
+               !desc2.writable &&
+               !desc2.configurable) {
+      reportProperty(ses.severities.SAFE,
+                     'Frozen harmless', path);
+      return false;
+    }
+    reportProperty(ses.severities.NEW_SYMTOM,
+                   'Failed to be poisoned', path);
+    return false;
+  }
+
+  /**
+   * Assumes all super objects are otherwise accessible and so will be
+   * independently cleaned.
+   */
+  function clean(value, prefix) {
+    if (value !== Object(value)) { return; }
+    if (cleaning.get(value)) { return; }
+    cleaning.set(value, true);
+    gopn(value).forEach(function(name) {
+      var path = prefix + (prefix ? '.' : '') + name;
+      var p = getPermit(value, name);
+      if (p) {
+        if (p === 'skip') {
+          reportProperty(ses.severities.SAFE,
+                         'Skipped', path);
+        } else {
+          var sub = value[name];
+          clean(sub, path);
+        }
+      } else {
+        cleanProperty(value, name, path);
+      }
+    });
+  }
+  clean(sharedImports, '');
+
+  /**
+   * This protection is now gathered here, so that a future version
+   * can skip it for non-defensive frames that must only be confined.
+   */
+  cajaVM.def(sharedImports);
+
+  keys(propertyReports).sort().forEach(function(status) {
+    var group = propertyReports[status];
+    ses.logger.reportDiagnosis(group.severity, status, group.list);
+  });
+
+  ses.logger.reportMax();
+
+  if (ses.ok()) {
+    // We succeeded. Enable safe Function, eval, and compile* to work.
+    dirty = false;
+    ses.logger.log('initSES succeeded.');
+  } else {
+    ses.logger.error('initSES failed.');
+  }
+};
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Call {@code ses.startSES} to turn this frame into a
+ * SES environment following object-capability rules.
+ *
+ * <p>Assumes ES5 plus WeakMap. Compatible with ES5-strict or
+ * anticipated ES6.
+ *
+ * @author Mark S. Miller
+ * @requires this
+ * @overrides ses, hookupSESModule
+ */
+
+(function hookupSESModule(global) {
+  "use strict";
+
+  if (!ses.ok()) {
+    return;
+  }
+
+  try {
+    ses.startSES(global,
+                 ses.whitelist,
+                 ses.atLeastFreeVarNames,
+                 function () { return {}; });
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    ses.logger.error('hookupSES failed with: ', err);
+  }
+})(this);
diff --git a/initSESPlus-minified.js b/initSESPlus-minified.js
new file mode 100644
index 0000000..3d03bea
--- /dev/null
+++ b/initSESPlus-minified.js
@@ -0,0 +1,369 @@
+{var Error,Function,RegExp,StringMap,WeakMap,cajaVM,eval,ses;ses||(ses={}),(function
+loggerModule(){'use strict';var apply,forward,logger,slice;function logNowhere(str){}slice=[].slice,apply=slice.apply,ses.logger?(logger=ses.logger):typeof
+console!=='undefined'&&'log'in console?(forward=function(level,args){var getStack,i,len,stack;args=slice.call(args,0),apply.call(console[level],console,[''].concat(args)),getStack=ses.getStack;if(getStack)for(i=0,len=args.length;i<len;++i)stack=getStack(args[i]),stack&&console[level]('',stack)},logger={'log':function
+log(var_args){forward('log',arguments)},'info':function info(var_args){forward('info',arguments)},'warn':function
+warn(var_args){forward('warn',arguments)},'error':function error(var_args){forward('error',arguments)}}):(logger={'log':logNowhere,'info':logNowhere,'warn':logNowhere,'error':logNowhere});function
+defaultClassify(postSeverity){var MAX_SES_SAFE=ses.severities.SAFE_SPEC_VIOLATION,consoleLevel='log',note='';return postSeverity.level>ses.severities.SAFE.level&&(consoleLevel='info',note=postSeverity.description+'('+postSeverity.level+')',postSeverity.level>ses.maxAcceptableSeverity.level?(consoleLevel='error',note+=' is not suitable for SES'):postSeverity.level>MAX_SES_SAFE.level&&(consoleLevel='warn',note+=' is not SES-safe'),note+='.'),{'consoleLevel':consoleLevel,'note':note}}logger.classify||(logger.classify=defaultClassify);function
+defaultReportRepairs(reports){}logger.reportRepairs||(logger.reportRepairs=defaultReportRepairs);function
+defaultReportMax(){var maxClassification;ses.maxSeverity.level>ses.severities.SAFE.level&&(maxClassification=ses.logger.classify(ses.maxSeverity),logger[maxClassification.consoleLevel]('Max Severity: '+maxClassification.note))}logger.reportMax||(logger.reportMax=defaultReportMax);function
+defaultReportDiagnosis(severity,status,problemList){var classification=ses.logger.classify(severity);ses.logger[classification.consoleLevel](problemList.length+' '+status)}logger.reportDiagnosis||(logger.reportDiagnosis=defaultReportDiagnosis),ses.logger=logger})(),(function
+repairES5Module(global){'use strict';var NEEDS_DUMMY_SETTER_repaired,aboutTo,apply,baseKludges,builtInForEach,builtInMapMethod,call,concat,during,errorInstanceBlacklist,errorInstanceWhitelist,getPrototypeOf,hop,is,logger,makeTamperProof,maxSev,needToTamperProof,objToString,reports,severities,slice,statuses,strictThis,supportedKludges;ses.severities={'SAFE':{'level':0,'description':'Safe'},'SAFE_SPEC_VIOLATION':{'level':1,'description':'Safe spec violation'},'UNSAFE_SPEC_VIOLATION':{'level':2,'description':'Unsafe spec violation'},'NOT_OCAP_SAFE':{'level':3,'description':'Not ocap safe'},'NOT_ISOLATED':{'level':4,'description':'Not isolated'},'NEW_SYMPTOM':{'level':5,'description':'New symptom'},'NOT_SUPPORTED':{'level':6,'description':'Not supported'}},ses.statuses={'ALL_FINE':'All fine','REPAIR_FAILED':'Repair failed','NOT_REPAIRED':'Not repaired','REPAIRED_UNSAFELY':'Repaired unsafely','REPAIRED':'Repaired','ACCIDENTALLY_REPAIRED':'Accidentally repaired','BROKEN_BY_OTHER_ATTEMPTED_REPAIRS':'Broken by other attempted repairs'},logger=ses.logger,ses.maxSeverity=ses.severities.SAFE;if(ses.maxAcceptableSeverityName){maxSev=ses.severities[ses.maxAcceptableSeverityName];if(maxSev&&typeof
+maxSev.level==='number'&&maxSev.level>=ses.severities.SAFE.level&&maxSev.level<ses.severities.NOT_SUPPORTED.level);else
+logger.error('Ignoring bad maxAcceptableSeverityName: '+ses.maxAcceptableSeverityName+'.'),ses.maxAcceptableSeverityName='SAFE_SPEC_VIOLATION'}else
+ses.maxAcceptableSeverityName='SAFE_SPEC_VIOLATION';ses.maxAcceptableSeverity=ses.severities[ses.maxAcceptableSeverityName],ses.ok=function
+ok(){return ses.maxSeverity.level<=ses.maxAcceptableSeverity.level},ses.updateMaxSeverity=function
+updateMaxSeverity(severity){severity.level>ses.maxSeverity.level&&(ses.maxSeverity=severity)};function
+strictForEachFn(list,callback){var i,len;for(i=0,len=list.length;i<len;++i)callback(list[i],i)}function
+strictMapFn(list,callback){var result=[],i,len;for(i=0,len=list.length;i<len;++i)result.push(callback(list[i],i));return result}objToString=Object.prototype.toString,builtInMapMethod=Array.prototype.map,builtInForEach=Array.prototype.forEach,is=ses.is=Object.is||function(x,y){return x===y?x!==0||1/x===1/y:x!==x&&y!==y},ses.makeCallerHarmless=function
+assumeCallerHarmless(func,path){return'Apparently fine'},ses.makeArgumentsHarmless=function
+assumeArgumentsHarmless(func,path){return'Apparently fine'},makeTamperProof=function
+defaultMakeTamperProof(){var gopd=Object.getOwnPropertyDescriptor,gopn=Object.getOwnPropertyNames,getProtoOf=Object.getPrototypeOf,freeze=Object.freeze,isFrozen=Object.isFrozen,defProp=Object.defineProperty;function
+tamperProof(obj){var func;return obj!==Object(obj)?obj:(typeof obj==='object'&&!!gopd(obj,'constructor')&&typeof(func=obj.constructor)==='function'&&func.prototype===obj&&!isFrozen(obj)&&strictForEachFn(gopn(obj),function(name){var
+desc,value;function getter(){var thisObj;return obj===this?value:this===void 0||this===null?void
+0:(thisObj=Object(this),gopd(thisObj,name)?this[name]:getter.call(getProtoOf(thisObj)))}function
+setter(newValue){if(obj===this)throw new TypeError('Cannot set virtually frozen property: '+name);!gopd(this,name)||(this[name]=newValue),defProp(this,name,{'value':newValue,'writable':true,'enumerable':true,'configurable':true})}desc=gopd(obj,name),desc.configurable&&'value'in
+desc&&(value=desc.value,getter.prototype=null,setter.prototype=null,defProp(obj,name,{'get':getter,'set':setter,'enumerable':desc.enumerable,'configurable':false}))}),freeze(obj))}return tamperProof},needToTamperProof=[];function
+rememberToTamperProof(obj){needToTamperProof.push(obj)}ses.makeDelayedTamperProof=function
+makeDelayedTamperProof(){var tamperProof=makeTamperProof();return strictForEachFn(needToTamperProof,tamperProof),needToTamperProof=void
+0,tamperProof};function testGlobalLeak(desc,that){return that===void 0?false:that===global?true:({}).toString.call(that)==='[object Window]'?true:desc+' leaked as: '+that}function
+test_MISSING_GETOWNPROPNAMES(){return!('getOwnPropertyNames'in Object)}function
+test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS(){var that;return global.___global_test_function___=function(){return this},that=___global_test_function___(),delete
+global.___global_test_function___,testGlobalLeak('Global func \"this\"',that)}function
+test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS(){var that=(function(){return this})();return testGlobalLeak('Anon func \"this\"',that)}strictThis=this;function
+test_GLOBAL_LEAKS_FROM_STRICT_THIS(){return testGlobalLeak('Strict \"this\"',strictThis)}function
+test_GLOBAL_LEAKS_FROM_BUILTINS(){var v=({}).valueOf,that='dummy';try{that=v()}catch(err){return err
+instanceof TypeError?false:'valueOf() threw: '+err}return that===void 0?false:testGlobalLeak('valueOf()',that)}function
+test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS(){var that;global.___global_valueOf_function___=({}).valueOf,that='dummy';try{that=___global_valueOf_function___()}catch(err){return err
+instanceof TypeError?false:'valueOf() threw: '+err}finally{delete global.___global_valueOf_function___}return that===void
+0?false:testGlobalLeak('Global valueOf()',that)}function test_MISSING_FREEZE_ETC(){return!('freeze'in
+Object)}function test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES(){function foo(){}return Object.defineProperty(foo,'prototype',{'value':{}}),foo.prototype!==Object.getOwnPropertyDescriptor(foo,'prototype').value}function
+test_MISSING_CALLEE_DESCRIPTOR(){function foo(){}return Object.getOwnPropertyNames(foo).indexOf('callee')<0?false:foo.hasOwnProperty('callee')?'Empty strict function has own callee':true}function
+test_STRICT_DELETE_RETURNS_FALSE(){var deleted;if(!RegExp.hasOwnProperty('rightContext'))return false;try{deleted=delete
+RegExp.rightContext}catch(err){return err instanceof TypeError?false:'Deletion failed with: '+err}return!deleted}function
+test_REGEXP_CANT_BE_NEUTERED(){var deleted;if(!RegExp.hasOwnProperty('leftContext'))return false;try{deleted=delete
+RegExp.leftContext}catch(err){return err instanceof TypeError?true:'Deletion failed with: '+err}return RegExp.hasOwnProperty('leftContext')?deleted?'Deletion of RegExp.leftContext did not succeed.':true:false}function
+test_REGEXP_TEST_EXEC_UNSAFE(){var match;return/foo/.test('xfoox'),match=(new RegExp('(.|\r|\n)*','').exec())[0],match==='undefined'?false:match==='xfoox'?true:'regExp.exec() does not match against \"undefined\".'}function
+test_MISSING_BIND(){return!('bind'in Function.prototype)}function test_BIND_CALLS_APPLY(){var
+answer,applyCalled,b;if(!('bind'in Function.prototype))return false;applyCalled=false;function
+foo(){return[].slice.call(arguments,0).join(',')}return foo.apply=function fakeApply(self,args){return applyCalled=true,Function.prototype.apply.call(this,self,args)},b=foo.bind(33,44),answer=b(55,66),applyCalled?true:answer==='44,55,66'?false:'Bind test returned \"'+answer+'\" instead of \"44,55,66\".'}function
+test_BIND_CANT_CURRY_NEW(){var d,str;function construct(f,args){var bound=Function.prototype.bind.apply(f,[null].concat(args));return new
+bound}try{d=construct(Date,[1957,4,27])}catch(err){return err instanceof TypeError?true:'Curries construction failed with: '+err}return typeof
+d==='string'?true:(str=objToString.call(d),str==='[object Date]'?false:'Unexpected '+str+': '+d)}function
+test_MUTABLE_DATE_PROTO(){var v;try{Date.prototype.setFullYear(1957)}catch(err){return err
+instanceof TypeError?false:'Mutating Date.prototype failed with: '+err}return v=Date.prototype.getFullYear(),Date.prototype.setFullYear(NaN),v!==v&&typeof
+v==='number'?false:v===1957?true:'Mutating Date.prototype did not throw'}function
+test_MUTABLE_WEAKMAP_PROTO(){var v,x;if(typeof WeakMap!=='function')return false;x={};try{WeakMap.prototype.set(x,86)}catch(err){return err
+instanceof TypeError?false:'Mutating WeakMap.prototype failed with: '+err}return v=WeakMap.prototype.get(x),v===86?true:'Mutating WeakMap.prototype did not throw'}function
+test_NEED_TO_WRAP_FOREACH(){if(!('freeze'in Object))return false;if(Array.prototype.forEach!==builtInForEach)return false;try{return['z'].forEach(function(){Object.freeze(Array.prototype.forEach)}),false}catch(err){return err
+instanceof TypeError?true:'freezing forEach failed with '+err}}function test_NEEDS_DUMMY_SETTER(){var
+ChromeMajorVersionPattern,match,ver;return NEEDS_DUMMY_SETTER_repaired?false:typeof
+navigator==='undefined'?false:(ChromeMajorVersionPattern=/Chrome\/(\d*)\./,match=ChromeMajorVersionPattern.exec(navigator.userAgent),match?(ver=+match[1],ver<=17):false)}NEEDS_DUMMY_SETTER_repaired=false;function
+test_FORM_GETTERS_DISAPPEAR(){var desc,f;function getter(){return'gotten'}if(typeof
+document==='undefined'||typeof document.createElement!=='function')return false;f=document.createElement('form');try{Object.defineProperty(f,'foo',{'get':getter,'set':void
+0})}catch(err){return'defining accessor on form failed with: '+err}return desc=Object.getOwnPropertyDescriptor(f,'foo'),desc.get===getter?false:desc.get===void
+0?true:'Getter became '+desc.get}function test_ACCESSORS_INHERIT_AS_OWN(){var base={},derived=Object.create(base);function
+getter(){return'gotten'}return Object.defineProperty(base,'foo',{'get':getter}),!derived.hasOwnProperty('foo')&&Object.getOwnPropertyDescriptor(derived,'foo')===void
+0&&Object.getOwnPropertyNames(derived).indexOf('foo')<0?false:!derived.hasOwnProperty('foo')||Object.getOwnPropertyDescriptor(derived,'foo').get!==getter||Object.getOwnPropertyNames(derived).indexOf('foo')<0?'Accessor properties partially inherit as own properties.':(Object.defineProperty(base,'bar',{'get':getter,'configurable':true}),!derived.hasOwnProperty('bar')&&Object.getOwnPropertyDescriptor(derived,'bar')===void
+0&&Object.getOwnPropertyNames(derived).indexOf('bar')<0?true:'Accessor properties inherit as own even if configurable.')}function
+test_SORT_LEAKS_GLOBAL(){var that='dummy';return[2,3].sort(function(x,y){return that=this,x-y}),that===void
+0?false:that===global?true:'sort called comparefn with \"this\" === '+that}function
+test_REPLACE_LEAKS_GLOBAL(){var that='dummy';function capture(){return that=this,'y'}return'x'.replace(/x/,capture),that===void
+0?false:that===capture?true:that===global?true:'Replace called replaceValue function with \"this\" === '+that}function
+test_CANT_GOPD_CALLER(){var desc=null;try{desc=Object.getOwnPropertyDescriptor(function(){},'caller')}catch(err){return err
+instanceof TypeError?true:'getOwnPropertyDescriptor failed with: '+err}return desc&&typeof
+desc.get==='function'&&typeof desc.set==='function'&&!desc.configurable?false:desc&&desc.value===null&&!desc.writable&&!desc.configurable?false:'getOwnPropertyDesciptor returned unexpected caller descriptor'}function
+test_CANT_HASOWNPROPERTY_CALLER(){var answer=void 0;try{answer=(function(){}).hasOwnProperty('caller')}catch(err){return err
+instanceof TypeError?true:'hasOwnProperty failed with: '+err}return answer?false:'strict_function.hasOwnProperty(\"caller\") was false'}function
+has(base,name,baseDesc){var result=void 0,finallySkipped=true;try{result=name in
+base}catch(err){return logger.error('New symptom (a): (\''+name+'\' in <'+baseDesc+'>) threw: ',err),result=false,false}finally{finallySkipped=false,result===void
+0&&logger.error('New symptom (b): (\''+name+'\' in <'+baseDesc+'>) failed')}return finallySkipped&&logger.error('New symptom (e): (\''+name+'\' in <'+baseDesc+'>) inner finally skipped'),!!result}function
+has2(base,name,baseDesc){var result=void 0,finallySkipped=true;try{result=has(base,name,baseDesc)}catch(err){return logger.error('New symptom (c): (\''+name+'\' in <'+baseDesc+'>) threw: ',err),result=false,false}finally{finallySkipped=false,result===void
+0&&logger.error('New symptom (d): (\''+name+'\' in <'+baseDesc+'>) failed')}return finallySkipped&&logger.error('New symptom (f): (\''+name+'\' in <'+baseDesc+'>) outer finally skipped'),!!result}function
+test_CANT_IN_CALLER(){var answer=void 0;try{answer=has2(function(){},'caller','strict_function')}catch(err){return err
+instanceof TypeError?true:'(\"caller\" in strict_func) failed with: '+err}finally{}return answer?false:'(\"caller\" in strict_func) was false.'}function
+test_CANT_IN_ARGUMENTS(){var answer=void 0;try{answer=has2(function(){},'arguments','strict_function')}catch(err){return err
+instanceof TypeError?true:'(\"arguments\" in strict_func) failed with: '+err}finally{}return answer?false:'(\"arguments\" in strict_func) was false.'}function
+test_STRICT_CALLER_NOT_POISONED(){var caller,testfn;if(!has2(strictMapFn,'caller','a strict function'))return false;function
+foo(m){return m.caller}testfn=Function('m','f','return m([m], f)[0];');try{caller=testfn(strictMapFn,foo)}catch(err){return err
+instanceof TypeError?false:'Strict \"caller\" failed with: '+err}return testfn===caller?true:'Unexpected \"caller\": '+caller}function
+test_STRICT_ARGUMENTS_NOT_POISONED(){var args,testfn;if(!has2(strictMapFn,'arguments','a strict function'))return false;function
+foo(m){return m.arguments}testfn=Function('m','f','return m([m], f)[0];');try{args=testfn(strictMapFn,foo)}catch(err){return err
+instanceof TypeError?false:'Strict \"arguments\" failed with: '+err}return args[1]===foo?true:'Unexpected arguments: '+arguments}function
+test_BUILTIN_LEAKS_CALLER(){var a,caller,testfn;if(!has2(builtInMapMethod,'caller','a builtin'))return false;function
+foo(m){return m.caller}testfn=Function('a','f','return a.map(f)[0];'),a=[builtInMapMethod],a.map=builtInMapMethod;try{caller=testfn(a,foo)}catch(err){return err
+instanceof TypeError?false:'Built-in \"caller\" failed with: '+err}return null===caller||void
+0===caller?false:testfn===caller?true:'Unexpected \"caller\": '+caller}function
+test_BUILTIN_LEAKS_ARGUMENTS(){var a,args,testfn;if(!has2(builtInMapMethod,'arguments','a builtin'))return false;function
+foo(m){return m.arguments}testfn=Function('a','f','return a.map(f)[0];'),a=[builtInMapMethod],a.map=builtInMapMethod;try{args=testfn(a,foo)}catch(err){return err
+instanceof TypeError?false:'Built-in \"arguments\" failed with: '+err}return!(args===void
+0||args===null)}function test_BOUND_FUNCTION_LEAKS_CALLER(){var bar,caller,testfn;if(!('bind'in
+Function.prototype))return false;function foo(){return bar.caller}bar=foo.bind({});if(!has2(bar,'caller','a bound function'))return false;testfn=Function('b','return b();');try{caller=testfn(bar)}catch(err){return err
+instanceof TypeError?false:'Bound function \"caller\" failed with: '+err}return caller===void
+0||caller===null?false:caller===testfn?true:'Unexpected \"caller\": '+caller}function
+test_BOUND_FUNCTION_LEAKS_ARGUMENTS(){var args,bar,testfn;if(!('bind'in Function.prototype))return false;function
+foo(){return bar.arguments}bar=foo.bind({});if(!has2(bar,'arguments','a bound function'))return false;testfn=Function('b','return b();');try{args=testfn(bar)}catch(err){return err
+instanceof TypeError?false:'Bound function \"arguments\" failed with: '+err}return!(args===void
+0||args===null)}function test_DELETED_BUILTINS_IN_OWN_NAMES(){var desc,names;if(!('__defineSetter__'in
+Object.prototype))return false;desc=Object.getOwnPropertyDescriptor(Object.prototype,'__defineSetter__');try{try{delete
+Object.prototype.__defineSetter__}catch(err1){return false}return names=Object.getOwnPropertyNames(Object.prototype),names.indexOf('__defineSetter__')===-1?false:!('__defineSetter__'in
+Object.prototype)}finally{Object.defineProperty(Object.prototype,'__defineSetter__',desc)}}function
+test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS(){try{Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptor,'caller')}catch(err){return err
+instanceof TypeError?true:'getOwnPropertyDescriptor threw: '+err}return false}function
+test_JSON_PARSE_PROTO_CONFUSION(){var x;try{x=JSON.parse('{\"__proto__\":[]}')}catch(err){return err
+instanceof TypeError?false:'JSON.parse failed with: '+err}return Object.getPrototypeOf(x)!==Object.prototype?true:Array.isArray(x.__proto__)?false:'JSON.parse did not set \"__proto__\" as a regular property'}function
+test_PROTO_NOT_FROZEN(){var x,y;if(!('freeze'in Object))return false;x=Object.preventExtensions({});if(x.__proto__===void
+0&&!('__proto__'in x))return false;y={};try{x.__proto__=y}catch(err){return err
+instanceof TypeError?false:'Mutating __proto__ failed with: '+err}return y.isPrototypeOf(x)?true:'Mutating __proto__ neither failed nor succeeded'}function
+test_PROTO_REDEFINABLE(){var x,y;if(!('freeze'in Object))return false;x=Object.preventExtensions({});if(x.__proto__===void
+0&&!('__proto__'in x))return false;y={};try{Object.defineProperty(x,'__proto__',{'value':y})}catch(err){return err
+instanceof TypeError?false:'Defining __proto__ failed with: '+err}return y.isPrototypeOf(x)?true:'Defining __proto__ neither failed nor succeeded'}function
+test_STRICT_EVAL_LEAKS_GLOBALS(){return eval('\"use strict\"; var ___global_test_variable___ = 88;'),'___global_test_variable___'in
+global?(delete global.___global_test_variable___,true):false}function test_PARSEINT_STILL_PARSING_OCTAL(){var
+n=parseInt('010');return n===10?false:n===8?true:'parseInt(\"010\") returned '+n}function
+test_STRICT_E4X_LITERALS_ALLOWED(){var x;try{x=eval('\"use strict\";(<foo/>);')}catch(err){return err
+instanceof SyntaxError?false:'E4X test failed with: '+err}return x!==void 0?true:'E4X literal expression had no value'}function
+test_ASSIGN_CAN_OVERRIDE_FROZEN(){var x=Object.freeze({'foo':88}),y=Object.create(x);try{y.foo=99}catch(err){return err
+instanceof TypeError?false:'Override failed with: '+err}return y.foo===99?true:y.foo===88?'Override failed silently':'Unexpected override outcome: '+y.foo}function
+test_CANT_REDEFINE_NAN_TO_ITSELF(){var descNaN=Object.getOwnPropertyDescriptor(global,'NaN');try{Object.defineProperty(global,'NaN',descNaN)}catch(err){return err
+instanceof TypeError?true:'defineProperty of NaN failed with: '+err}return false}errorInstanceWhitelist=['arguments','message','stack','type','fileName','lineNumber','message','stack','line','message','sourceId','sourceURL','description','message','number','message','stack','stacktrace'],errorInstanceBlacklist=['category','context','href','lineNo','msgId','source','trace','correctSourcePoint','correctWithStackTrace','getSourceLine','resetSource'];function
+freshErrorInstanceWhiteMap(){var result=Object.create(null);return strictForEachFn(errorInstanceWhitelist,function(name){result[name]=true}),result}function
+freshHiddenPropertyCandidates(){var result=freshErrorInstanceWhiteMap();return strictForEachFn(errorInstanceBlacklist,function(name){result[name]=true}),result}function
+test_UNEXPECTED_ERROR_PROPERTIES(){var errs=[new Error('e1')],approvedNames,result;try{null.foo=3}catch(err){errs.push(err)}return result=false,approvedNames=freshErrorInstanceWhiteMap(),strictForEachFn(errs,function(err){strictForEachFn(Object.getOwnPropertyNames(err),function(name){name
+in approvedNames||(result='Unexpected error instance property: '+name)})}),result}function
+test_GET_OWN_PROPERTY_NAME_LIES(){var gopn=Object.getOwnPropertyNames,gopd=Object.getOwnPropertyDescriptor,suspects=[new
+Error('e1')],unreported,unreportedNames;try{null.foo=3}catch(err){suspects.push(err)}return unreported=Object.create(null),strictForEachFn(suspects,function(suspect){var
+candidates=freshHiddenPropertyCandidates();strictForEachFn(gopn(suspect),function(name){delete
+candidates[name]}),strictForEachFn(gopn(candidates),function(name){gopd(suspect,name)||delete
+candidates[name]}),strictForEachFn(gopn(candidates),function(name){unreported[name]=true})}),unreportedNames=gopn(unreported),unreportedNames.length===0?false:'Error own properties unreported by getOwnPropertyNames: '+unreportedNames.sort().join(',')}call=Function.prototype.call,apply=Function.prototype.apply,hop=Object.prototype.hasOwnProperty,slice=Array.prototype.slice,concat=Array.prototype.concat,getPrototypeOf=Object.getPrototypeOf;function
+patchMissingProp(base,name,missingFunc){name in base||Object.defineProperty(base,name,{'value':missingFunc,'writable':true,'enumerable':false,'configurable':true})}function
+repair_MISSING_FREEZE_ETC(){patchMissingProp(Object,'freeze',function fakeFreeze(obj){return obj}),patchMissingProp(Object,'seal',function
+fakeSeal(obj){return obj}),patchMissingProp(Object,'preventExtensions',function
+fakePreventExtensions(obj){return obj}),patchMissingProp(Object,'isFrozen',function
+fakeIsFrozen(obj){return false}),patchMissingProp(Object,'isSealed',function fakeIsSealed(obj){return false}),patchMissingProp(Object,'isExtensible',function
+fakeIsExtensible(obj){return true})}function repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES(){var
+unsafeDefProp=Object.defineProperty;function repairedDefineProperty(base,name,desc){if(typeof
+base==='function'&&name==='prototype'&&'value'in desc)try{base.prototype=desc.value}catch(err){logger.warn('prototype fixup failed',err)}return unsafeDefProp(base,name,desc)}Object.defineProperty(Object,'defineProperty',{'value':repairedDefineProperty})}function
+repair_MISSING_CALLEE_DESCRIPTOR(){var realGOPN=Object.getOwnPropertyNames;Object.defineProperty(Object,'getOwnPropertyNames',{'value':function
+calleeFix(base){var result=realGOPN(base),i;return typeof base==='function'&&(i=result.indexOf('callee'),i>=0&&!hop.call(base,'callee')&&result.splice(i,1)),result}})}function
+repair_REGEXP_CANT_BE_NEUTERED(){var UnsafeRegExp=RegExp,FakeRegExp=function RegExpWrapper(pattern,flags){switch(arguments.length){case
+0:return UnsafeRegExp();case 1:return UnsafeRegExp(pattern);default:return UnsafeRegExp(pattern,flags)}};Object.defineProperty(FakeRegExp,'prototype',{'value':UnsafeRegExp.prototype}),Object.defineProperty(FakeRegExp.prototype,'constructor',{'value':FakeRegExp}),RegExp=FakeRegExp}function
+repair_REGEXP_TEST_EXEC_UNSAFE(){var unsafeRegExpExec=RegExp.prototype.exec,unsafeRegExpTest=RegExp.prototype.test;Object.defineProperty(RegExp.prototype,'exec',{'value':function
+fakeExec(specimen){return unsafeRegExpExec.call(this,String(specimen))}}),Object.defineProperty(RegExp.prototype,'test',{'value':function
+fakeTest(specimen){return unsafeRegExpTest.call(this,String(specimen))}})}function
+repair_MISSING_BIND(){var BOGUS_BOUND_PROTOTYPE={'toString':function BBPToString(){return'bogus bound prototype'}},defProp;rememberToTamperProof(BOGUS_BOUND_PROTOTYPE),BOGUS_BOUND_PROTOTYPE.toString.prototype=null,rememberToTamperProof(BOGUS_BOUND_PROTOTYPE.toString),defProp=Object.defineProperty,defProp(Function.prototype,'bind',{'value':function
+fakeBind(self,var_args){var thisFunc=this,leftArgs=slice.call(arguments,1);function
+funcBound(var_args){var args;if(this===Object(this)&&getPrototypeOf(this)===BOGUS_BOUND_PROTOTYPE)throw new
+TypeError('Cannot emulate \"new\" on pseudo-bound function.');return args=concat.call(leftArgs,slice.call(arguments,0)),apply.call(thisFunc,self,args)}return defProp(funcBound,'prototype',{'value':BOGUS_BOUND_PROTOTYPE,'writable':false,'configurable':false}),funcBound},'writable':true,'enumerable':false,'configurable':true})}function
+makeMutableProtoPatcher(constr,classString){var proto=constr.prototype,baseToString=objToString.call(proto),grandBaseToString,grandProto;if(baseToString!=='[object '+classString+']')throw new
+TypeError('unexpected: '+baseToString);grandProto=getPrototypeOf(proto),grandBaseToString=objToString.call(grandProto);if(grandBaseToString==='[object '+classString+']')throw new
+TypeError('malformed inheritance: '+classString);grandProto!==Object.prototype&&logger.log('unexpected inheritance: '+classString);function
+mutableProtoPatcher(name){var originalMethod;if(!hop.call(proto,name))return;originalMethod=proto[name];function
+replacement(var_args){var parent=getPrototypeOf(this),thisToString;if(parent!==proto){if(objToString.call(parent)!==baseToString)throw thisToString=objToString.call(this),thisToString===baseToString?new
+TypeError('May not mutate internal state of a '+classString+'.prototype'):new TypeError('Unexpected: '+thisToString)};return originalMethod.apply(this,arguments)}Object.defineProperty(proto,name,{'value':replacement})}return mutableProtoPatcher}function
+repair_MUTABLE_DATE_PROTO(){['setYear','setTime','setFullYear','setUTCFullYear','setMonth','setUTCMonth','setDate','setUTCDate','setHours','setUTCHours','setMinutes','setUTCMinutes','setSeconds','setUTCSeconds','setMilliseconds','setUTCMilliseconds'].forEach(makeMutableProtoPatcher(Date,'Date'))}function
+repair_MUTABLE_WEAKMAP_PROTO(){['set','delete'].forEach(makeMutableProtoPatcher(WeakMap,'WeakMap'))}function
+repair_NEED_TO_WRAP_FOREACH(){var forEach=Array.prototype.forEach;Object.defineProperty(Array.prototype,'forEach',{'value':function
+forEachWrapper(callbackfn,opt_thisArg){return forEach.apply(this,arguments)}})}function
+repair_NEEDS_DUMMY_SETTER(){var defProp=Object.defineProperty,gopd=Object.getOwnPropertyDescriptor;function
+dummySetter(newValue){throw new TypeError('no setter for assigning: '+newValue)}dummySetter.prototype=null,rememberToTamperProof(dummySetter),defProp(Object,'defineProperty',{'value':function
+setSetterDefProp(base,name,desc){var desc2,newDesc,oldDesc,result,testBase;if(typeof
+desc.get==='function'&&desc.set===void 0){oldDesc=gopd(base,name);if(oldDesc)testBase={},defProp(testBase,name,oldDesc),defProp(testBase,name,desc),desc=gopd(testBase,name),desc.set===void
+0&&(desc.set=dummySetter);else{if(objToString.call(base)==='[object HTMLFormElement]'){desc2={'get':desc.get},'enumerable'in
+desc&&(desc2.enumerable=desc.enumerable),'configurable'in desc&&(desc2.configurable=desc.configurable),result=defProp(base,name,desc2),newDesc=gopd(base,name);if(newDesc.get===desc.get)return result}desc.set=dummySetter}}return defProp(base,name,desc)}}),NEEDS_DUMMY_SETTER_repaired=true}function
+repair_ACCESSORS_INHERIT_AS_OWN(){var defProp=Object.defineProperty,freeze=Object.freeze,seal=Object.seal,gopn=Object.getOwnPropertyNames,gopd=Object.getOwnPropertyDescriptor,complaint='Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=637994  prohibits enumerable non-configurable accessor properties.';function
+isBadAccessor(derived,name){var desc=gopd(derived,name),base,superDesc;return!desc||!('get'in
+desc)?false:(base=getPrototypeOf(derived),base?(superDesc=gopd(base,name),!superDesc||!('get'in
+superDesc)?false:desc.get&&!desc.configurable&&!superDesc.configurable&&desc.get===superDesc.get&&desc.set===superDesc.set&&desc.enumerable===superDesc.enumerable):false)}defProp(Object,'defineProperty',{'value':function
+definePropertyWrapper(base,name,desc){var oldDesc=gopd(base,name),testBase={},fullDesc;oldDesc&&!isBadAccessor(base,name)&&defProp(testBase,name,oldDesc),defProp(testBase,name,desc),fullDesc=gopd(testBase,name);if('get'in
+fullDesc&&fullDesc.enumerable&&!fullDesc.configurable)throw logger.warn(complaint),new
+TypeError(complaint+' (Object: '+base+' Property: '+name+')');return defProp(base,name,fullDesc)}});function
+ensureSealable(base){gopn(base).forEach(function(name){var desc=gopd(base,name);if('get'in
+desc&&desc.enumerable)throw desc.configurable||logger.error('New symptom: \"'+name+'\" already non-configurable'),logger.warn(complaint),new
+TypeError(complaint+' (During sealing. Object: '+base+' Property: '+name+')')})}defProp(Object,'freeze',{'value':function
+freezeWrapper(base){return ensureSealable(base),freeze(base)}}),defProp(Object,'seal',{'value':function
+sealWrapper(base){return ensureSealable(base),seal(base)}}),defProp(Object.prototype,'hasOwnProperty',{'value':function
+hasOwnPropertyWrapper(name){return hop.call(this,name)&&!isBadAccessor(this,name)}}),defProp(Object,'getOwnPropertyDescriptor',{'value':function
+getOwnPropertyDescriptorWrapper(base,name){return isBadAccessor(base,name)?void 0:gopd(base,name)}}),defProp(Object,'getOwnPropertyNames',{'value':function
+getOwnPropertyNamesWrapper(base){return gopn(base).filter(function(name){return!isBadAccessor(base,name)})}})}function
+repair_SORT_LEAKS_GLOBAL(){var unsafeSort=Array.prototype.sort;function sortWrapper(opt_comparefn){function
+comparefnWrapper(x,y){return opt_comparefn(x,y)}return arguments.length===0?unsafeSort.call(this):unsafeSort.call(this,comparefnWrapper)}Object.defineProperty(Array.prototype,'sort',{'value':sortWrapper})}function
+repair_REPLACE_LEAKS_GLOBAL(){var unsafeReplace=String.prototype.replace;function
+replaceWrapper(searchValue,replaceValue){var safeReplaceValue=replaceValue;function
+replaceValueWrapper(m1,m2,m3){return replaceValue(m1,m2,m3)}return typeof replaceValue==='function'&&(safeReplaceValue=replaceValueWrapper),unsafeReplace.call(this,searchValue,safeReplaceValue)}Object.defineProperty(String.prototype,'replace',{'value':replaceWrapper})}function
+repair_CANT_GOPD_CALLER(){var unsafeGOPD=Object.getOwnPropertyDescriptor;function
+gopdWrapper(base,name){try{return unsafeGOPD(base,name)}catch(err){if(err instanceof
+TypeError&&typeof base==='function'&&(name==='caller'||name==='arguments'))return(function(message){function
+fakePoison(){throw new TypeError(message)}return fakePoison.prototype=null,{'get':fakePoison,'set':fakePoison,'enumerable':false,'configurable':false}})(err.message);throw err}}Object.defineProperty(Object,'getOwnPropertyDescriptor',{'value':gopdWrapper})}function
+repair_CANT_HASOWNPROPERTY_CALLER(){Object.defineProperty(Object.prototype,'hasOwnProperty',{'value':function
+hopWrapper(name){return!!Object.getOwnPropertyDescriptor(this,name)}})}function
+makeHarmless(magicName,func,path){var desc;function poison(){throw new TypeError('Cannot access property '+path)}poison.prototype=null,desc=Object.getOwnPropertyDescriptor(func,magicName);if(!desc&&Object.isExtensible(func)||desc.configurable){try{Object.defineProperty(func,magicName,{'get':poison,'set':poison,'configurable':false})}catch(cantPoisonErr){return'Poisoning failed with '+cantPoisonErr}return desc=Object.getOwnPropertyDescriptor(func,magicName),desc&&desc.get===poison&&desc.set===poison&&!desc.configurable?'Apparently poisoned':'Not poisoned'}if('get'in
+desc||'set'in desc)return'Apparently safe';try{Object.defineProperty(func,magicName,{'value':desc.value===null?null:void
+0,'writable':false,'configurable':false})}catch(cantFreezeHarmlessErr){return'Freezing harmless failed with '+cantFreezeHarmlessErr}return desc=Object.getOwnPropertyDescriptor(func,magicName),desc&&(desc.value===null||desc.value===void
+0)&&!desc.writable&&!desc.configurable?'Apparently frozen harmless':'Did not freeze harmless'}function
+repair_BUILTIN_LEAKS_CALLER(){ses.makeCallerHarmless=makeHarmless.bind(void 0,'caller')}function
+repair_BUILTIN_LEAKS_ARGUMENTS(){ses.makeArgumentsHarmless=makeHarmless.bind(void
+0,'arguments')}function repair_DELETED_BUILTINS_IN_OWN_NAMES(){var realGOPN=Object.getOwnPropertyNames,repairedHop=Object.prototype.hasOwnProperty;function
+getOnlyRealOwnPropertyNames(base){return realGOPN(base).filter(function(name){return repairedHop.call(base,name)})}Object.defineProperty(Object,'getOwnPropertyNames',{'value':getOnlyRealOwnPropertyNames})}function
+repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS(){var realGOPD=Object.getOwnPropertyDescriptor;function
+GOPDWrapper(base,name){return realGOPD(base,name)}Object.defineProperty(Object,'getOwnPropertyDescriptor',{'value':GOPDWrapper})}function
+repair_JSON_PARSE_PROTO_CONFUSION(){var unsafeParse=JSON.parse;function validate(plainJSON){var
+proto;if(plainJSON!==Object(plainJSON))return;proto=getPrototypeOf(plainJSON);if(proto!==Object.prototype&&proto!==Array.prototype)throw new
+TypeError('Parse resulted in invalid JSON. See http://code.google.com/p/v8/issues/detail?id=621');Object.keys(plainJSON).forEach(function(key){validate(plainJSON[key])})}Object.defineProperty(JSON,'parse',{'value':function
+parseWrapper(text,opt_reviver){var result=unsafeParse(text);return validate(result),opt_reviver?unsafeParse(text,opt_reviver):result},'writable':true,'enumerable':false,'configurable':true})}function
+repair_PARSEINT_STILL_PARSING_OCTAL(){var badParseInt=parseInt;function goodParseInt(n,radix){var
+isHexOrOctal,isOct;return n=''+n,radix=+radix,isHexOrOctal=/^\s*[+-]?\s*0(x?)/.exec(n),isOct=isHexOrOctal?isHexOrOctal[1]!=='x':false,isOct&&(radix!==radix||0===radix)?badParseInt(n,10):badParseInt(n,radix)}parseInt=goodParseInt}function
+repair_ASSIGN_CAN_OVERRIDE_FROZEN(){makeTamperProof=function simpleMakeTamperProof(){return Object.freeze}}function
+repair_CANT_REDEFINE_NAN_TO_ITSELF(){var defProp=Object.defineProperty,attrs=['writable','get','set','enumerable','configurable'];defProp(Object,'defineProperty',{'value':function(base,name,desc){var
+attr,i,len,oldDesc;try{return defProp(base,name,desc)}catch(err){oldDesc=Object.getOwnPropertyDescriptor(base,name);for(i=0,len=attrs.length;i<len;++i){attr=attrs[i];if(attr
+in desc&&desc[attr]!==oldDesc[attr])throw err}if(!('value'in desc)||is(desc.value,oldDesc.value))return base;throw err}}})}severities=ses.severities,statuses=ses.statuses,baseKludges=[{'description':'Missing getOwnPropertyNames','test':test_MISSING_GETOWNPROPNAMES,'repair':void
+0,'preSeverity':severities.NOT_SUPPORTED,'canRepair':false,'urls':[],'sections':['15.2.3.4'],'tests':['15.2.3.4-0-1']}],supportedKludges=[{'description':'Global object leaks from global function calls','test':test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=64250'],'sections':['10.2.1.2','10.2.1.2.6'],'tests':['10.4.3-1-8gs']},{'description':'Global object leaks from anonymous function calls','test':test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':[],'sections':['10.4.3'],'tests':['S10.4.3_A1']},{'description':'Global leaks through strict this','test':test_GLOBAL_LEAKS_FROM_STRICT_THIS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':[],'sections':['10.4.3'],'tests':['10.4.3-1-8gs','10.4.3-1-8-s']},{'description':'Global object leaks from built-in methods','test':test_GLOBAL_LEAKS_FROM_BUILTINS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=51097','https://bugs.webkit.org/show_bug.cgi?id=58338','http://code.google.com/p/v8/issues/detail?id=1437','https://connect.microsoft.com/IE/feedback/details/685430/global-object-leaks-from-built-in-methods'],'sections':['15.2.4.4'],'tests':['S15.2.4.4_A14']},{'description':'Global object leaks from globally called built-in methods','test':test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':[],'sections':['10.2.1.2','10.2.1.2.6','15.2.4.4'],'tests':['S15.2.4.4_A15']},{'description':'Object.freeze is missing','test':test_MISSING_FREEZE_ETC,'repair':repair_MISSING_FREEZE_ETC,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=55736'],'sections':['15.2.3.9'],'tests':['15.2.3.9-0-1']},{'description':'A function.prototype\'s descriptor lies','test':test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,'repair':repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1530','http://code.google.com/p/v8/issues/detail?id=1570'],'sections':['15.2.3.3','15.2.3.6','15.3.5.2'],'tests':['S15.3.3.1_A4']},{'description':'Phantom callee on strict functions','test':test_MISSING_CALLEE_DESCRIPTOR,'repair':repair_MISSING_CALLEE_DESCRIPTOR,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=55537'],'sections':['15.2.3.4'],'tests':['S15.2.3.4_A1_T1']},{'description':'Strict delete returned false rather than throwing','test':test_STRICT_DELETE_RETURNS_FALSE,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://connect.microsoft.com/IE/feedback/details/685432/strict-delete-sometimes-returns-false-rather-than-throwing'],'sections':['11.4.1'],'tests':['S11.4.1_A5']},{'description':'Non-deletable RegExp statics are a global communication channel','test':test_REGEXP_CANT_BE_NEUTERED,'repair':repair_REGEXP_CANT_BE_NEUTERED,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=591846','http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable','https://connect.microsoft.com/IE/feedback/details/685439/non-deletable-regexp-statics-are-a-global-communication-channel'],'sections':['11.4.1'],'tests':['S11.4.1_A5']},{'description':'RegExp.exec leaks match globally','test':test_REGEXP_TEST_EXEC_UNSAFE,'repair':repair_REGEXP_TEST_EXEC_UNSAFE,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1393','http://code.google.com/p/chromium/issues/detail?id=75740','https://bugzilla.mozilla.org/show_bug.cgi?id=635017','http://code.google.com/p/google-caja/issues/detail?id=528'],'sections':['15.10.6.2'],'tests':['S15.10.6.2_A12']},{'description':'Function.prototype.bind is missing','test':test_MISSING_BIND,'repair':repair_MISSING_BIND,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=26382','https://bugs.webkit.org/show_bug.cgi?id=42371'],'sections':['15.3.4.5'],'tests':['S15.3.4.5_A3']},{'description':'Function.prototype.bind calls .apply rather than [[Call]]','test':test_BIND_CALLS_APPLY,'repair':repair_MISSING_BIND,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=892','http://code.google.com/p/v8/issues/detail?id=828'],'sections':['15.3.4.5.1'],'tests':['S15.3.4.5_A4']},{'description':'Function.prototype.bind does not curry construction','test':test_BIND_CANT_CURRY_NEW,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=26382#c29'],'sections':['15.3.4.5.2'],'tests':['S15.3.4.5_A5']},{'description':'Date.prototype is a global communication channel','test':test_MUTABLE_DATE_PROTO,'repair':repair_MUTABLE_DATE_PROTO,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/google-caja/issues/detail?id=1362'],'sections':['15.9.5'],'tests':[]},{'description':'WeakMap.prototype is a global communication channel','test':test_MUTABLE_WEAKMAP_PROTO,'repair':repair_MUTABLE_WEAKMAP_PROTO,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=656828'],'sections':[],'tests':[]},{'description':'Array forEach cannot be frozen while in progress','test':test_NEED_TO_WRAP_FOREACH,'repair':repair_NEED_TO_WRAP_FOREACH,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1447'],'sections':['15.4.4.18'],'tests':['S15.4.4.18_A1','S15.4.4.18_A2']},{'description':'Workaround undiagnosed need for dummy setter','test':test_NEEDS_DUMMY_SETTER,'repair':repair_NEEDS_DUMMY_SETTER,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':[],'sections':[],'tests':[]},{'description':'Getter on HTMLFormElement disappears','test':test_FORM_GETTERS_DISAPPEAR,'repair':repair_NEEDS_DUMMY_SETTER,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/chromium/issues/detail?id=94666','http://code.google.com/p/v8/issues/detail?id=1651','http://code.google.com/p/google-caja/issues/detail?id=1401'],'sections':['15.2.3.6'],'tests':['S15.2.3.6_A1']},{'description':'Accessor properties inherit as own properties','test':test_ACCESSORS_INHERIT_AS_OWN,'repair':repair_ACCESSORS_INHERIT_AS_OWN,'preSeverity':severities.UNSAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=637994'],'sections':['8.6.1','15.2.3.6'],'tests':['S15.2.3.6_A2']},{'description':'Array sort leaks global','test':test_SORT_LEAKS_GLOBAL,'repair':repair_SORT_LEAKS_GLOBAL,'preSeverity':severities.NOT_ISOLATED,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1360'],'sections':['15.4.4.11'],'tests':['S15.4.4.11_A8']},{'description':'String replace leaks global','test':test_REPLACE_LEAKS_GLOBAL,'repair':repair_REPLACE_LEAKS_GLOBAL,'preSeverity':severities.NOT_ISOLATED,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1360','https://connect.microsoft.com/IE/feedback/details/685928/bad-this-binding-for-callback-in-string-prototype-replace'],'sections':['15.5.4.11'],'tests':['S15.5.4.11_A12']},{'description':'getOwnPropertyDescriptor on strict \"caller\" throws','test':test_CANT_GOPD_CALLER,'repair':repair_CANT_GOPD_CALLER,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://connect.microsoft.com/IE/feedback/details/685436/getownpropertydescriptor-on-strict-caller-throws'],'sections':['15.2.3.3','13.2','13.2.3'],'tests':['S13.2_A6_T1']},{'description':'strict_function.hasOwnProperty(\"caller\") throws','test':test_CANT_HASOWNPROPERTY_CALLER,'repair':repair_CANT_HASOWNPROPERTY_CALLER,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=63398#c3'],'sections':['15.2.4.5','13.2','13.2.3'],'tests':['S13.2_A7_T1']},{'description':'Cannot \"in\" caller on strict function','test':test_CANT_IN_CALLER,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['11.8.7','13.2','13.2.3'],'tests':['S13.2_A8_T1']},{'description':'Cannot \"in\" arguments on strict function','test':test_CANT_IN_ARGUMENTS,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['11.8.7','13.2','13.2.3'],'tests':['S13.2_A8_T2']},{'description':'Strict \"caller\" not poisoned','test':test_STRICT_CALLER_NOT_POISONED,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':[],'sections':['13.2'],'tests':['S13.2.3_A1']},{'description':'Strict \"arguments\" not poisoned','test':test_STRICT_ARGUMENTS_NOT_POISONED,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':[],'sections':['13.2'],'tests':['S13.2.3_A1']},{'description':'Built in functions leak \"caller\"','test':test_BUILTIN_LEAKS_CALLER,'repair':repair_BUILTIN_LEAKS_CALLER,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1643','http://code.google.com/p/v8/issues/detail?id=1548','https://bugzilla.mozilla.org/show_bug.cgi?id=591846','http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable'],'sections':[],'tests':['Sbp_A10_T1']},{'description':'Built in functions leak \"arguments\"','test':test_BUILTIN_LEAKS_ARGUMENTS,'repair':repair_BUILTIN_LEAKS_ARGUMENTS,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1643','http://code.google.com/p/v8/issues/detail?id=1548','https://bugzilla.mozilla.org/show_bug.cgi?id=591846','http://wiki.ecmascript.org/doku.php?id=conventions:make_non-standard_properties_configurable'],'sections':[],'tests':['Sbp_A10_T2']},{'description':'Bound functions leak \"caller\"','test':test_BOUND_FUNCTION_LEAKS_CALLER,'repair':repair_MISSING_BIND,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=893','https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['15.3.4.5'],'tests':['S13.2.3_A1','S15.3.4.5_A1']},{'description':'Bound functions leak \"arguments\"','test':test_BOUND_FUNCTION_LEAKS_ARGUMENTS,'repair':repair_MISSING_BIND,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=893','https://bugs.webkit.org/show_bug.cgi?id=63398'],'sections':['15.3.4.5'],'tests':['S13.2.3_A1','S15.3.4.5_A2']},{'description':'Deleting built-in leaves phantom behind','test':test_DELETED_BUILTINS_IN_OWN_NAMES,'repair':repair_DELETED_BUILTINS_IN_OWN_NAMES,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['https://bugs.webkit.org/show_bug.cgi?id=70207'],'sections':['15.2.3.4'],'tests':[]},{'description':'getOwnPropertyDescriptor on its own \"caller\" fails','test':test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,'repair':repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1769'],'sections':['13.2','15.2.3.3'],'tests':[]},{'description':'JSON.parse confused by \"__proto__\"','test':test_JSON_PARSE_PROTO_CONFUSION,'repair':repair_JSON_PARSE_PROTO_CONFUSION,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=621','http://code.google.com/p/v8/issues/detail?id=1310'],'sections':['15.12.2'],'tests':['S15.12.2_A1']},{'description':'Prototype still mutable on non-extensible object','test':test_PROTO_NOT_FROZEN,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=65832','https://bugs.webkit.org/show_bug.cgi?id=78438'],'sections':['8.6.2'],'tests':['S8.6.2_A8']},{'description':'Prototype still redefinable on non-extensible object','test':test_PROTO_REDEFINABLE,'repair':void
+0,'preSeverity':severities.NOT_OCAP_SAFE,'canRepair':false,'urls':['https://bugs.webkit.org/show_bug.cgi?id=65832'],'sections':['8.6.2'],'tests':['S8.6.2_A8']},{'description':'Strict eval function leaks variable definitions','test':test_STRICT_EVAL_LEAKS_GLOBALS,'repair':void
+0,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['http://code.google.com/p/v8/issues/detail?id=1624'],'sections':['10.4.2.1'],'tests':['S10.4.2.1_A1']},{'description':'parseInt still parsing octal','test':test_PARSEINT_STILL_PARSING_OCTAL,'repair':repair_PARSEINT_STILL_PARSING_OCTAL,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':['http://code.google.com/p/v8/issues/detail?id=1645'],'sections':['15.1.2.2'],'tests':['S15.1.2.2_A5.1_T1']},{'description':'E4X literals allowed in strict code','test':test_STRICT_E4X_LITERALS_ALLOWED,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=695577','https://bugzilla.mozilla.org/show_bug.cgi?id=695579'],'sections':[],'tests':[]},{'description':'Assignment can override frozen inherited property','test':test_ASSIGN_CAN_OVERRIDE_FROZEN,'repair':repair_ASSIGN_CAN_OVERRIDE_FROZEN,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':false,'urls':['http://code.google.com/p/v8/issues/detail?id=1169','https://mail.mozilla.org/pipermail/es-discuss/2011-November/017997.html'],'sections':['8.12.4'],'tests':['15.2.3.6-4-405']},{'description':'Cannot redefine global NaN to itself','test':test_CANT_REDEFINE_NAN_TO_ITSELF,'repair':repair_CANT_REDEFINE_NAN_TO_ITSELF,'preSeverity':severities.SAFE_SPEC_VIOLATION,'canRepair':true,'urls':[],'sections':['8.12.9','15.1.1.1'],'tests':[]},{'description':'Error instances have unexpected properties','test':test_UNEXPECTED_ERROR_PROPERTIES,'repair':void
+0,'preSeverity':severities.NEW_SYMPTOM,'canRepair':false,'urls':[],'sections':[],'tests':[]},{'description':'getOwnPropertyNames lies, hiding some own properties','test':test_GET_OWN_PROPERTY_NAME_LIES,'repair':void
+0,'preSeverity':severities.NOT_ISOLATED,'canRepair':false,'urls':['https://bugzilla.mozilla.org/show_bug.cgi?id=726477'],'sections':[],'tests':[]}],aboutTo=void
+0;function testRepairReport(kludges){var beforeFailures=strictMapFn(kludges,function(kludge){return aboutTo=['pre test: ',kludge.description],kludge.test()}),repairs=[],afterFailures;return strictForEachFn(kludges,function(kludge,i){var
+repair;beforeFailures[i]&&(repair=kludge.repair,repair&&repairs.lastIndexOf(repair)===-1&&(aboutTo=['repair: ',kludge.description],repair(),repairs.push(repair)))}),afterFailures=strictMapFn(kludges,function(kludge){return aboutTo=['post test: ',kludge.description],kludge.test()}),Object.isFrozen&&Object.isFrozen(Array.prototype.forEach)&&repair_NEED_TO_WRAP_FOREACH(),strictMapFn(kludges,function(kludge,i){var
+status=statuses.ALL_FINE,postSeverity=severities.SAFE,beforeFailure=beforeFailures[i],afterFailure=afterFailures[i];if(beforeFailure)afterFailure?kludge.repair?(postSeverity=kludge.preSeverity,status=statuses.REPAIR_FAILED):(kludge.canRepair||(postSeverity=kludge.preSeverity),status=statuses.NOT_REPAIRED):kludge.repair?kludge.canRepair?(status=statuses.REPAIRED):(postSeverity=kludge.preSeverity,status=statuses.REPAIRED_UNSAFELY):(status=statuses.ACCIDENTALLY_REPAIRED);else
+if(afterFailure)(kludge.repair||!kludge.canRepair)&&(postSeverity=kludge.preSeverity),status=statuses.BROKEN_BY_OTHER_ATTEMPTED_REPAIRS;return(typeof
+beforeFailure==='string'||typeof afterFailure==='string')&&(postSeverity=severities.NEW_SYMPTOM),ses.updateMaxSeverity(postSeverity),{'description':kludge.description,'preSeverity':kludge.preSeverity,'canRepair':kludge.canRepair,'urls':kludge.urls,'sections':kludge.sections,'tests':kludge.tests,'status':status,'postSeverity':postSeverity,'beforeFailure':beforeFailure,'afterFailure':afterFailure}})}try{reports=testRepairReport(baseKludges),ses.ok()&&reports.push.apply(reports,testRepairReport(supportedKludges)),logger.reportRepairs(reports)}catch(err){ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED),during=aboutTo?'('+aboutTo.join('')+') ':'',logger.error('ES5 Repair '+during+'failed with: ',err)}logger.reportMax()})(this),(function
+WeakMapModule(){'use strict';var HIDDEN_NAME,ab,defProp,gopn,hop,originalProps,u8s;if(typeof
+ses!=='undefined'&&ses.ok&&!ses.ok())return;if(typeof WeakMap==='function')return;hop=Object.prototype.hasOwnProperty,gopn=Object.getOwnPropertyNames,defProp=Object.defineProperty,originalProps={},gopn(Object).forEach(function(name){originalProps[name]=Object[name]}),HIDDEN_NAME='ident:'+Math.random()+'___',typeof
+crypto!=='undefined'&&typeof crypto.getRandomValues==='function'&&typeof ArrayBuffer==='function'&&typeof
+Uint8Array==='function'&&(ab=new ArrayBuffer(25),u8s=new Uint8Array(ab),crypto.getRandomValues(u8s),HIDDEN_NAME='rand:'+Array.prototype.map.call(u8s,function(u8){return(u8%36).toString(36)}).join('')+'___'),defProp(Object,'getOwnPropertyNames',{'value':function
+fakeGetOwnPropertyNames(obj){return gopn(obj).filter(function(name){return name!==HIDDEN_NAME})}}),'getPropertyNames'in
+Object&&defProp(Object,'getPropertyNames',{'value':function fakeGetPropertyNames(obj){return originalProps.getPropertyNames(obj).filter(function(name){return name!==HIDDEN_NAME})}});function
+getHiddenRecord(key){var gets,hiddenRecord,vals;if(key!==Object(key))throw new TypeError('Not an object: '+key);return hiddenRecord=key[HIDDEN_NAME],hiddenRecord&&hiddenRecord.key===key?hiddenRecord:originalProps.isExtensible(key)?(gets=[],vals=[],hiddenRecord={'key':key,'gets':gets,'vals':vals},defProp(key,HIDDEN_NAME,{'value':hiddenRecord,'writable':false,'enumerable':false,'configurable':false}),hiddenRecord):void
+0}(function(){var oldFreeze=Object.freeze,oldPreventExtensions,oldSeal;defProp(Object,'freeze',{'value':function
+identifyingFreeze(obj){return getHiddenRecord(obj),oldFreeze(obj)}}),oldSeal=Object.seal,defProp(Object,'seal',{'value':function
+identifyingSeal(obj){return getHiddenRecord(obj),oldSeal(obj)}}),oldPreventExtensions=Object.preventExtensions,defProp(Object,'preventExtensions',{'value':function
+identifyingPreventExtensions(obj){return getHiddenRecord(obj),oldPreventExtensions(obj)}})})();function
+constFunc(func){return func.prototype=null,Object.freeze(func)}WeakMap=function(){var
+keys=[],vals=[];function get___(key,opt_default){var hr=getHiddenRecord(key),i,vs;return hr?(i=hr.gets.indexOf(get___),vs=hr.vals):(i=keys.indexOf(key),vs=vals),i>=0?vs[i]:opt_default}function
+has___(key){var hr=getHiddenRecord(key),i;return i=hr?hr.gets.indexOf(get___):keys.indexOf(key),i>=0}function
+set___(key,value){var hr=getHiddenRecord(key),i;hr?(i=hr.gets.indexOf(get___),i>=0?(hr.vals[i]=value):(hr.gets.push(get___),hr.vals.push(value))):(i=keys.indexOf(key),i>=0?(vals[i]=value):(keys.push(key),vals.push(value)))}function
+delete___(key){var hr=getHiddenRecord(key),i;return hr?(i=hr.gets.indexOf(get___),i>=0&&(hr.gets.splice(i,1),hr.vals.splice(i,1))):(i=keys.indexOf(key),i>=0&&(keys.splice(i,1),vals.splice(i,1))),true}return Object.create(WeakMap.prototype,{'get___':{'value':constFunc(get___)},'has___':{'value':constFunc(has___)},'set___':{'value':constFunc(set___)},'delete___':{'value':constFunc(delete___)}})},WeakMap.prototype=Object.create(Object.prototype,{'get':{'value':function
+get(key,opt_default){return this.get___(key,opt_default)},'writable':true,'configurable':true},'has':{'value':function
+has(key){return this.has___(key)},'writable':true,'configurable':true},'set':{'value':function
+set(key,value){this.set___(key,value)},'writable':true,'configurable':true},'delete':{'value':function
+remove(key){return this.delete___(key)},'writable':true,'configurable':true}})})(),(function
+debugModule(global){'use strict';var UnsafeError;UnsafeError=Error,ses.UnsafeError=Error;function
+FakeError(message){return UnsafeError(message)}FakeError.prototype=UnsafeError.prototype,FakeError.prototype.constructor=FakeError,Error=FakeError,ses.getCWStack=function
+uselessGetCWStack(err){return};if('captureStackTrace'in UnsafeError)(function(){var
+ssts,unsafeCaptureStackTrace;UnsafeError.prepareStackTrace=function(err,sst){return ssts.set(err,sst),void
+0},unsafeCaptureStackTrace=UnsafeError.captureStackTrace,UnsafeError.captureStackTrace=function(obj,opt_MyError){var
+wasFrozen=Object.isFrozen(obj),stackDesc=Object.getOwnPropertyDescriptor(obj,'stack'),ignore,result;try{return result=unsafeCaptureStackTrace(obj,opt_MyError),ignore=obj.stack,result}finally{wasFrozen&&!Object.isFrozen(obj)&&(stackDesc?Object.defineProperty(obj,'stack',stackDesc):delete
+obj.stack,Object.freeze(obj))}},ssts=WeakMap();function getCWStack(err){var sst=ssts.get(err),ignore;return sst===void
+0&&err instanceof Error&&(ignore=err.stack,sst=ssts.get(err)),sst===void 0?void 0:{'calls':sst.map(function(frame){return{'name':''+(frame.getFunctionName()||frame.getMethodName()||'?'),'source':''+(frame.getFileName()||'?'),'span':[[frame.getLineNumber(),frame.getColumnNumber()]]}})}}ses.getCWStack=getCWStack})();else
+if(global.opera);else if((new Error).stack)(function(){var FFFramePattern=/^([^@]*)@(.*?):?(\d*)$/;function
+getCWStack(err){var stack=err.stack,frames,lines;return stack?(lines=stack.split('\n'),frames=lines.map(function(line){var
+match=FFFramePattern.exec(line);return match?{'name':match[1].trim()||'?','source':match[2].trim()||'?','span':[[+match[3]]]}:{'name':line.trim()||'?','source':'?','span':[]}}),{'calls':frames}):void
+0}ses.getCWStack=getCWStack})();function stackString(cwStack){var calls,result;return cwStack?(calls=cwStack.calls,result=calls.map(function(call){var
+spanString=call.span.map(function(subSpan){return subSpan.join(':')}).join('::');return spanString&&(spanString=':'+spanString),'  at '+call.name+' ('+call.source+spanString+')'}),result.join('\n')):void
+0}ses.stackString=stackString;function getStack(err){var cwStack,result;return err!==Object(err)?void
+0:(cwStack=ses.getCWStack(err),cwStack?(result=ses.stackString(cwStack),err instanceof
+Error&&(result=err+'\n'+result),result):void 0)}ses.getStack=getStack})(this),(function(){'use strict';var
+create,freeze;create=Object.create,freeze=Object.freeze;function constFunc(func){return func.prototype=null,freeze(func)}function
+assertString(x){if('string'!==typeof x)throw new TypeError('Not a string: '+String(x));return x}StringMap=function
+StringMap(){var objAsMap=create(null);return freeze({'get':constFunc(function(key){return objAsMap[assertString(key)+'$']}),'set':constFunc(function(key,value){objAsMap[assertString(key)+'$']=value}),'has':constFunc(function(key){return assertString(key)+'$'in
+objAsMap}),'delete':constFunc(function(key){return delete objAsMap[assertString(key)+'$']})})}})(),(function
+whitelistModule(){'use strict';var t;ses||(ses={}),t=true,ses.whitelist={'cajaVM':{'log':t,'tamperProof':t,'constFunc':t,'def':t,'is':t,'compileExpr':t,'compileModule':t,'compileProgram':t,'eval':t,'Function':t,'sharedImports':t,'makeImports':t,'copyToImports':t,'callWithEjector':t,'eject':t,'GuardT':{'coerce':t},'makeTableGuard':t,'Trademark':{'stamp':t},'guard':t,'passesGuard':t,'stamp':t,'makeSealerUnsealerPair':t,'makeArrayLike':{}},'WeakMap':{'prototype':{'get':t,'set':t,'has':t,'delete':t}},'StringMap':{'prototype':{}},'escape':t,'unescape':t,'Object':{'getPropertyDescriptor':t,'getPropertyNames':t,'is':t,'prototype':{'__defineGetter__':t,'__defineSetter__':t,'__lookupGetter__':t,'__lookupSetter__':t,'constructor':'*','toString':'*','toLocaleString':'*','valueOf':t,'hasOwnProperty':t,'isPrototypeOf':t,'propertyIsEnumerable':t},'getPrototypeOf':t,'getOwnPropertyDescriptor':t,'getOwnPropertyNames':t,'create':t,'defineProperty':t,'defineProperties':t,'seal':t,'freeze':t,'preventExtensions':t,'isSealed':t,'isFrozen':t,'isExtensible':t,'keys':t},'NaN':t,'Infinity':t,'undefined':t,'parseInt':t,'parseFloat':t,'isNaN':t,'isFinite':t,'decodeURI':t,'decodeURIComponent':t,'encodeURI':t,'encodeURIComponent':t,'Function':{'prototype':{'apply':t,'call':t,'bind':t,'prototype':'*','length':'*','arity':'*','name':'*'}},'Array':{'prototype':{'concat':t,'join':t,'pop':t,'push':t,'reverse':t,'shift':t,'slice':t,'sort':t,'splice':t,'unshift':t,'indexOf':t,'lastIndexOf':t,'every':t,'some':t,'forEach':t,'map':t,'filter':t,'reduce':t,'reduceRight':t,'length':'skip'},'isArray':t},'String':{'prototype':{'substr':t,'anchor':t,'big':t,'blink':t,'bold':t,'fixed':t,'fontcolor':t,'fontsize':t,'italics':t,'link':t,'small':t,'strike':t,'sub':t,'sup':t,'trimLeft':t,'trimRight':t,'valueOf':t,'charAt':t,'charCodeAt':t,'concat':t,'indexOf':t,'lastIndexOf':t,'localeCompare':t,'match':t,'replace':t,'search':t,'slice':t,'split':t,'substring':t,'toLowerCase':t,'toLocaleLowerCase':t,'toUpperCase':t,'toLocaleUpperCase':t,'trim':t,'length':'*'},'fromCharCode':t},'Boolean':{'prototype':{'valueOf':t}},'Number':{'prototype':{'valueOf':t,'toFixed':t,'toExponential':t,'toPrecision':t},'MAX_VALUE':t,'MIN_VALUE':t,'NaN':t,'NEGATIVE_INFINITY':t,'POSITIVE_INFINITY':t},'Math':{'E':t,'LN10':t,'LN2':t,'LOG2E':t,'LOG10E':t,'PI':t,'SQRT1_2':t,'SQRT2':t,'abs':t,'acos':t,'asin':t,'atan':t,'atan2':t,'ceil':t,'cos':t,'exp':t,'floor':t,'log':t,'max':t,'min':t,'pow':t,'random':t,'round':t,'sin':t,'sqrt':t,'tan':t},'Date':{'prototype':{'getYear':t,'setYear':t,'toGMTString':t,'toDateString':t,'toTimeString':t,'toLocaleString':t,'toLocaleDateString':t,'toLocaleTimeString':t,'getTime':t,'getFullYear':t,'getUTCFullYear':t,'getMonth':t,'getUTCMonth':t,'getDate':t,'getUTCDate':t,'getDay':t,'getUTCDay':t,'getHours':t,'getUTCHours':t,'getMinutes':t,'getUTCMinutes':t,'getSeconds':t,'getUTCSeconds':t,'getMilliseconds':t,'getUTCMilliseconds':t,'getTimezoneOffset':t,'setTime':t,'setFullYear':t,'setUTCFullYear':t,'setMonth':t,'setUTCMonth':t,'setDate':t,'setUTCDate':t,'setHours':t,'setUTCHours':t,'setMinutes':t,'setUTCMinutes':t,'setSeconds':t,'setUTCSeconds':t,'setMilliseconds':t,'setUTCMilliseconds':t,'toUTCString':t,'toISOString':t,'toJSON':t},'parse':t,'UTC':t,'now':t},'RegExp':{'prototype':{'exec':t,'test':t,'source':'*','global':'*','ignoreCase':'*','multiline':'*','lastIndex':'*','sticky':'*'}},'Error':{'prototype':{'name':'*','message':'*'}},'EvalError':{'prototype':t},'RangeError':{'prototype':t},'ReferenceError':{'prototype':t},'SyntaxError':{'prototype':t},'TypeError':{'prototype':t},'URIError':{'prototype':t},'JSON':{'parse':t,'stringify':t}}})(),(function
+atLeastFreeVarNamesModule(){'use strict';ses||(ses={});function LIMIT_SRC(programSrc){if(/[^\u0000-\u007f]/.test(programSrc))throw new
+EvalError('Non-ascii text not yet supported');if(/\\u/.test(programSrc))throw new
+EvalError('Backslash-u escape encoded text not yet supported')}function SHOULD_MATCH_IDENTIFIER(){return/(\w|\$)+/g}ses.atLeastFreeVarNames=function
+atLeastFreeVarNames(programSrc){var a,found,name,regexp,result;programSrc=String(programSrc),LIMIT_SRC(programSrc),regexp=SHOULD_MATCH_IDENTIFIER(),result=[],found=StringMap();while(a=regexp.exec(programSrc))name=a[0],found.has(name)||(result.push(name),found.set(name,true));return result}})(),ses.startSES=function(global,whitelist,atLeastFreeVarNames,extensions){'use strict';var
+EMULATE_LEGACY_GETTERS_SETTERS,TAME_GLOBAL_EVAL,cleaning,create,defProp,dirty,freeze,getProto,gopd,gopn,hop,keys,propertyReports,sharedImports,tamperProof,whiteTable;TAME_GLOBAL_EVAL=false,EMULATE_LEGACY_GETTERS_SETTERS=true,dirty=true,hop=Object.prototype.hasOwnProperty,getProto=Object.getPrototypeOf,defProp=Object.defineProperty,gopd=Object.getOwnPropertyDescriptor,gopn=Object.getOwnPropertyNames,keys=Object.keys,freeze=Object.freeze,create=Object.create;function
+constFunc(func){return func.prototype=null,freeze(func)}function fail(str){debugger;throw new
+EvalError(str)}typeof WeakMap==='undefined'&&fail('No built-in WeakMaps, so WeakMap.js must be loaded first'),EMULATE_LEGACY_GETTERS_SETTERS?(function(){function
+legacyDefineGetter(sprop,getter){sprop=''+sprop,hop.call(this,sprop)?defProp(this,sprop,{'get':getter}):defProp(this,sprop,{'get':getter,'set':undefined,'enumerable':true,'configurable':true})}legacyDefineGetter.prototype=null,defProp(Object.prototype,'__defineGetter__',{'value':legacyDefineGetter,'writable':false,'enumerable':false,'configurable':false});function
+legacyDefineSetter(sprop,setter){sprop=''+sprop,hop.call(this,sprop)?defProp(this,sprop,{'set':setter}):defProp(this,sprop,{'get':undefined,'set':setter,'enumerable':true,'configurable':true})}legacyDefineSetter.prototype=null,defProp(Object.prototype,'__defineSetter__',{'value':legacyDefineSetter,'writable':false,'enumerable':false,'configurable':false});function
+legacyLookupGetter(sprop){var base,desc;sprop=''+sprop,base=this,desc=void 0;while(base&&!(desc=gopd(base,sprop)))base=getProto(base);return desc&&desc.get}legacyLookupGetter.prototype=null,defProp(Object.prototype,'__lookupGetter__',{'value':legacyLookupGetter,'writable':false,'enumerable':false,'configurable':false});function
+legacyLookupSetter(sprop){var base,desc;sprop=''+sprop,base=this,desc=void 0;while(base&&!(desc=gopd(base,sprop)))base=getProto(base);return desc&&desc.set}legacyLookupSetter.prototype=null,defProp(Object.prototype,'__lookupSetter__',{'value':legacyLookupSetter,'writable':false,'enumerable':false,'configurable':false})})():(delete
+Object.prototype.__defineGetter__,delete Object.prototype.__defineSetter__,delete
+Object.prototype.__lookupGetter__,delete Object.prototype.__lookupSetter__),tamperProof=ses.makeDelayedTamperProof(),sharedImports=create(null),(function
+startSESPrelude(){var unsafeEval=eval,UnsafeFunction=Function,defended,defending,directivePattern,extensionsRecord,makeArrayLike,requirePattern;function
+verifyStrictProgram(programSrc){try{UnsafeFunction('\"use strict\";'+programSrc)}catch(err){throw err}}function
+verifyStrictExpression(exprSrc){verifyStrictProgram(exprSrc+';'),verifyStrictProgram('( '+exprSrc+'\n);')}function
+makeImports(){var imports=create(null);return copyToImports(imports,sharedImports),imports}function
+copyToImports(imports,from){return gopn(from).forEach(function(name){var desc=gopd(from,name);desc.enumerable=false,desc.configurable=true,defProp(imports,name,desc)}),imports}function
+makeScopeObject(imports,freeNames){var scopeObject=create(null);return freeNames.forEach(function
+interceptName(name){var desc=gopd(imports,name);(!desc||desc.writable!==false||desc.configurable)&&(desc={'get':function
+scopedGet(){var result;if(name in imports){result=imports[name];if(typeof result==='function');return result}throw new
+ReferenceError('\"'+name+'\" not in scope')},'set':function scopedSet(newValue){throw name
+in imports&&(imports[name]=newValue),new TypeError('Cannot set \"'+name+'\"')},'enumerable':false}),desc.enumerable=false,defProp(scopeObject,name,desc)}),freeze(scopeObject)}function
+securableWrapperSrc(exprSrc,opt_sourcePosition){return verifyStrictExpression(exprSrc),'(function() {   with (this) {     return function() {       \"use strict\";       return (         '+exprSrc+'\n'+'      );\n'+'    };\n'+'  }\n'+'})'}ses.securableWrapperSrc=securableWrapperSrc;function
+makeCompiledExpr(wrapper,freeNames){dirty&&fail('Initial cleaning failed');function
+compiledCode(imports){var scopeObject=makeScopeObject(imports,freeNames);return wrapper.call(scopeObject).call(imports)}return compiledCode.prototype=null,compiledCode}ses.makeCompiledExpr=makeCompiledExpr;function
+compileExpr(exprSrc,opt_sourcePosition){var wrapperSrc=securableWrapperSrc(exprSrc,opt_sourcePosition),wrapper=unsafeEval(wrapperSrc),freeNames=atLeastFreeVarNames(exprSrc),result=makeCompiledExpr(wrapper,freeNames);return freeze(result)}directivePattern=/^['"](?:\w|\s)*['"]$/m,requirePattern=/^(?:\w*\s*(?:\w|\$|\.)*\s*=)?\s*require\s*\(\s*['"]((?:\w|\$|\.|\/)+)['"]\s*\)$/m;function
+getRequirements(modSrc){var result=[],stmts=modSrc.split(';'),i=0,ilen=stmts.length,m,stmt;for(;i<ilen;++i){stmt=stmts[i].trim();if(stmt!==''){if(!directivePattern.test(stmt))break}}for(;i<ilen;++i){stmt=stmts[i].trim();if(stmt!==''){m=requirePattern.exec(stmt);if(!m)break;result.push(m[1])}}return freeze(result)}function
+compileModule(modSrc,opt_sourcePosition){var exprSrc='(function() {'+modSrc+'}).call(this)',wrapperSrc=securableWrapperSrc(exprSrc,opt_sourcePosition),wrapper=unsafeEval(wrapperSrc),freeNames=atLeastFreeVarNames(exprSrc),moduleMaker=makeCompiledExpr(wrapper,freeNames);return moduleMaker.requirements=getRequirements(modSrc),freeze(moduleMaker)}function
+FakeFunction(var_args){var params=[].slice.call(arguments,0),body=params.pop(),exprSrc;return body=String(body||''),params=params.join(','),exprSrc='(function('+params+'\n){'+body+'})',compileExpr(exprSrc)(sharedImports)}FakeFunction.prototype=UnsafeFunction.prototype,FakeFunction.prototype.constructor=FakeFunction,global.Function=FakeFunction;function
+fakeEval(src){try{verifyStrictExpression(src)}catch(x){src='(function() {'+src+'\n}).call(this)'}return compileExpr(src)(sharedImports)}TAME_GLOBAL_EVAL&&(global.eval=fakeEval),defended=WeakMap(),defending=WeakMap();function
+def(node){var defendingList=[];function recur(val){var t;if(!val)return;t=typeof
+val;if(t==='number'||t==='string'||t==='boolean')return;if(defended.get(val)||defending.get(val))return;defending.set(val,true),defendingList.push(val),tamperProof(val),recur(getProto(val)),gopn(val).forEach(function(p){var
+desc;if(typeof val==='function'&&(p==='caller'||p==='arguments'))return;desc=gopd(val,p),recur(desc.value),recur(desc.get),recur(desc.set)})}try{recur(node)}catch(err){throw defending=WeakMap(),err}return defendingList.forEach(function(obj){defended.set(obj,true)}),node}(function(){var
+itemMap=WeakMap(),lengthMap=WeakMap(),nativeProxies;function lengthGetter(){var getter=lengthMap.get(this);return getter?getter():void
+0}constFunc(lengthGetter),nativeProxies=global.Proxy&&(function(){var obj={'0':'hi'},p=global.Proxy.create({'get':function(){var
+P=arguments[0];return typeof P!=='string'&&(P=arguments[1]),obj[P]}});return p[0]==='hi'})(),nativeProxies?(function(){function
+ArrayLike(proto,getItem,getLength){var obj;if(typeof proto!=='object')throw new TypeError('Expected proto to be an object.');if(!(proto
+instanceof ArrayLike))throw new TypeError('Expected proto to be instanceof ArrayLike.');return obj=create(proto),itemMap.set(obj,getItem),lengthMap.set(obj,getLength),obj}function
+ownPropDesc(P){return P=''+P,P==='length'?{'get':lengthGetter}:typeof P==='number'||P===''+
++P?{'get':constFunc(function(){var getter=itemMap.get(this);return getter?getter(+P):void
+0}),'enumerable':true,'configurable':true}:void 0}function propDesc(P){var opd=ownPropDesc(P);return opd||gopd(Object.prototype,P)}function
+has(P){return P=''+P,P==='length'||typeof P==='number'||P===''+ +P||P in Object.prototype}function
+hasOwn(P){return P=''+P,P==='length'||typeof P==='number'||P===''+ +P}function getPN(){var
+result=getOwnPN(),objPropNames=gopn(Object.prototype);return result.push.apply(result,objPropNames),result}function
+getOwnPN(){var lenGetter=lengthMap.get(this),i,len,result;if(!lenGetter)return;len=lenGetter(),result=['length'];for(i=0;i<len;++i)result.push(''+i);return result}function
+del(P){return P=''+P,!(P==='length'||''+ +P===P)}ArrayLike.prototype=global.Proxy.create({'getPropertyDescriptor':propDesc,'getOwnPropertyDescriptor':ownPropDesc,'has':has,'hasOwn':hasOwn,'getPropertyNames':getPN,'getOwnPropertyNames':getOwnPN,'delete':del,'fix':function(){return}},Object.prototype),tamperProof(ArrayLike),makeArrayLike=function(){return ArrayLike}})():(function(){var
+BiggestArrayLike,maxLen;function nextUInt31PowerOf2(v){return v&=2147483647,v|=v>>1,v|=v>>2,v|=v>>4,v|=v>>8,v|=v>>16,v+1}BiggestArrayLike=void
+0,maxLen=0,makeArrayLike=function(length){var BAL,i,len;if(!BiggestArrayLike||length>maxLen){len=nextUInt31PowerOf2(length),BAL=function(proto,getItem,getLength){var
+obj;if(typeof proto!=='object')throw new TypeError('Expected proto to be an object.');if(!(proto
+instanceof BAL))throw new TypeError('Expected proto to be instanceof ArrayLike.');return obj=create(proto),itemMap.set(obj,getItem),lengthMap.set(obj,getLength),obj};for(i=0;i<len;++i)(function(j){function
+get(){return itemMap.get(this)(j)}defProp(BAL.prototype,j,{'get':constFunc(get),'enumerable':true})})(i);defProp(BAL.prototype,'length',{'get':lengthGetter}),tamperProof(BAL),tamperProof(BAL.prototype),BiggestArrayLike=BAL,maxLen=len}return BiggestArrayLike}})()})(),global.cajaVM={'log':constFunc(function
+log(str){typeof console!=='undefined'&&'log'in console&&console.log(str)}),'tamperProof':constFunc(tamperProof),'constFunc':constFunc(constFunc),'is':constFunc(ses.is),'compileExpr':constFunc(compileExpr),'compileModule':constFunc(compileModule),'eval':fakeEval,'Function':FakeFunction,'sharedImports':sharedImports,'makeImports':constFunc(makeImports),'copyToImports':constFunc(copyToImports),'makeArrayLike':constFunc(makeArrayLike)},extensionsRecord=extensions(),gopn(extensionsRecord).forEach(function(p){defProp(cajaVM,p,gopd(extensionsRecord,p))}),global.cajaVM.def=constFunc(def)})(),propertyReports={};function
+reportProperty(severity,status,path){var group;ses.updateMaxSeverity(severity),group=propertyReports[status]||(propertyReports[status]={'severity':severity,'list':[]}),group.list.push(path)}keys(whitelist).forEach(function(name){var
+desc=gopd(global,name),newDesc,permit;if(desc){permit=whitelist[name];if(permit){newDesc={'value':global[name],'writable':false,'configurable':false};try{defProp(global,name,newDesc)}catch(err){reportProperty(ses.severities.NEW_SYMPTOM,'Global '+name+' cannot be made readonly: '+err)}defProp(sharedImports,name,newDesc)}}}),TAME_GLOBAL_EVAL&&defProp(sharedImports,'eval',{'value':cajaVM.eval,'writable':false,'enumerable':false,'configurable':false}),whiteTable=WeakMap();function
+register(value,permit){var oldPermit;if(value!==Object(value))return;if(typeof permit!=='object')return;oldPermit=whiteTable.get(value),oldPermit&&fail('primordial reachable through multiple paths'),whiteTable.set(value,permit),keys(permit).forEach(function(name){var
+sub;permit[name]!=='skip'&&(sub=value[name],register(sub,permit[name]))})}register(sharedImports,whitelist);function
+getPermit(base,name){var permit=whiteTable.get(base),result;if(permit){if(hop.call(permit,name))return permit[name]};while(true){base=getProto(base);if(base===null)return false;permit=whiteTable.get(base);if(permit&&hop.call(permit,name))return result=permit[name],result==='*'||result==='skip'?result:false}}cleaning=WeakMap();function
+cleanProperty(base,name,path){var deleted,desc2,diagnostic,dummy2,err,exists,value;function
+poison(){throw new TypeError('Cannot access property '+path)}if(typeof base==='function'){if(name==='caller')return diagnostic=ses.makeCallerHarmless(base,path),reportProperty(ses.severities.SAFE,diagnostic,path),true;if(name==='arguments')return diagnostic=ses.makeArgumentsHarmless(base,path),reportProperty(ses.severities.SAFE,diagnostic,path),true}deleted=void
+0,err=void 0;try{deleted=delete base[name]}catch(er){err=er}exists=hop.call(base,name);if(deleted){if(!exists)return reportProperty(ses.severities.SAFE,'Deleted',path),true;reportProperty(ses.severities.SAFE_SPEC_VIOLATION,'Bounced back',path)}else
+if(deleted===false)reportProperty(ses.severities.SAFE_SPEC_VIOLATION,'Strict delete returned false rather than throwing',path);else
+if(err instanceof TypeError);else reportProperty(ses.severities.NEW_SYMPTOM,'Delete failed with'+err,path);try{defProp(base,name,{'get':poison,'set':poison,'enumerable':false,'configurable':false})}catch(cantPoisonErr){try{value=gopd(base,name).value,defProp(base,name,{'value':value===null?null:void
+0,'writable':false,'configurable':false})}catch(cantFreezeHarmless){return reportProperty(ses.severities.NOT_ISOLATED,'Cannot be poisoned',path),false}}desc2=gopd(base,name);if(desc2.get===poison&&desc2.set===poison&&!desc2.configurable)try{dummy2=base[name]}catch(expectedErr){if(expectedErr
+instanceof TypeError)return reportProperty(ses.severities.SAFE,'Successfully poisoned',path),true}else
+if((desc2.value===void 0||desc2.value===null)&&!desc2.writable&&!desc2.configurable)return reportProperty(ses.severities.SAFE,'Frozen harmless',path),false;return reportProperty(ses.severities.NEW_SYMTOM,'Failed to be poisoned',path),false}function
+clean(value,prefix){if(value!==Object(value))return;if(cleaning.get(value))return;cleaning.set(value,true),gopn(value).forEach(function(name){var
+path=prefix+(prefix?'.':'')+name,p=getPermit(value,name),sub;p?p==='skip'?reportProperty(ses.severities.SAFE,'Skipped',path):(sub=value[name],clean(sub,path)):cleanProperty(value,name,path)})}clean(sharedImports,''),cajaVM.def(sharedImports),keys(propertyReports).sort().forEach(function(status){var
+group=propertyReports[status];ses.logger.reportDiagnosis(group.severity,status,group.list)}),ses.logger.reportMax(),ses.ok()?(dirty=false,ses.logger.log('initSES succeeded.')):ses.logger.error('initSES failed.')},(function
+ejectorsGuardsTrademarksModule(){'use strict';ses.ejectorsGuardsTrademarks=function
+ejectorsGuardsTrademarks(){var freeze=Object.freeze,constFunc=cajaVM.constFunc,GuardMark,GuardStamp,GuardT,stampers;function
+Token(name){return name=''+name,freeze({'toString':constFunc(function tokenToString(){return name})})}function
+callWithEjector(attemptFunc,opt_failFunc){var failFunc=opt_failFunc||function(x){return x},disabled=false,token=new
+Token('ejection'),stash=void 0;function ejector(result){throw disabled?new Error('ejector disabled'):(stash=result,token)}constFunc(ejector);try{try{return attemptFunc(ejector)}finally{disabled=true}}catch(e){if(e===token)return failFunc(stash);throw e}}function
+eject(opt_ejector,result){throw opt_ejector?(opt_ejector(result),new Error('Ejector did not exit: ',opt_ejector)):new
+Error(result)}function makeSealerUnsealerPair(){var boxValues=new WeakMap(true);function
+seal(value){var box=freeze({});return boxValues.set(box,value),box}function optUnseal(box){return boxValues.has(box)?[boxValues.get(box)]:null}function
+unseal(box){var result=optUnseal(box);if(result===null)throw new Error('That wasn\'t one of my sealed boxes!');return result[0]}return freeze({'seal':constFunc(seal),'unseal':constFunc(unseal),'optUnseal':constFunc(optUnseal)})}stampers=new
+WeakMap(true);function makeTrademark(typename,table){var stamp;return typename=''+typename,stamp=freeze({'toString':constFunc(function(){return typename+'Stamp'})}),stampers.set(stamp,function(obj){return table.set(obj,true),obj}),freeze({'toString':constFunc(function(){return typename+'Mark'}),'stamp':stamp,'guard':freeze({'toString':constFunc(function(){return typename+'T'}),'coerce':constFunc(function(specimen,opt_ejector){return table.get(specimen)||eject(opt_ejector,'Specimen does not have the \"'+typename+'\" trademark'),specimen})})})}GuardMark=makeTrademark('Guard',new
+WeakMap),GuardT=GuardMark.guard,GuardStamp=GuardMark.stamp,stampers.get(GuardStamp)(GuardT);function
+Trademark(typename){var result=makeTrademark(typename,new WeakMap);return stampers.get(GuardStamp)(result.guard),result}function
+stamp(stamps,record){var i,numStamps;if(Object.isFrozen(record))throw new TypeError('Can\'t stamp frozen objects: '+record);stamps=Array.prototype.slice.call(stamps,0),numStamps=stamps.length;for(i=0;i<numStamps;++i)if(!stampers.has(stamps[i]))throw new
+TypeError('Can\'t stamp with a non-stamp: '+stamps[i]);for(i=0;i<numStamps;++i)stampers.get(stamps[i])(record);return freeze(record)}function
+guard(g,specimen,opt_ejector){return g=GuardT.coerce(g),g.coerce(specimen,opt_ejector)}function
+passesGuard(g,specimen){return g=GuardT.coerce(g),callWithEjector(constFunc(function(opt_ejector){return g.coerce(specimen,opt_ejector),true}),constFunc(function(ignored){return false}))}function
+makeTableGuard(table,typename,errorMessage){var g={'toString':constFunc(function(){return typename+'T'}),'coerce':constFunc(function(specimen,opt_ejector){return table.get(specimen)||eject(opt_ejector,errorMessage),specimen})};return stamp([GuardStamp],g),freeze(g)}return freeze({'callWithEjector':constFunc(callWithEjector),'eject':constFunc(eject),'makeSealerUnsealerPair':constFunc(makeSealerUnsealerPair),'GuardT':GuardT,'makeTableGuard':constFunc(makeTableGuard),'Trademark':constFunc(Trademark),'guard':constFunc(guard),'passesGuard':constFunc(passesGuard),'stamp':constFunc(stamp)})}})(),(function
+hookupSESPlusModule(global){'use strict';if(!ses.ok())return;try{ses.startSES(global,ses.whitelist,ses.atLeastFreeVarNames,ses.ejectorsGuardsTrademarks)}catch(err){ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED),ses.logger.error('hookupSESPlus failed with: ',err)}})(this)}
\ No newline at end of file
diff --git a/initSESPlus.js b/initSESPlus.js
new file mode 100644
index 0000000..66c15ca
--- /dev/null
+++ b/initSESPlus.js
@@ -0,0 +1,6339 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports a {@code ses.logger} which logs to the
+ * console if one exists.
+ *
+ * <p>This <code>logger.js</code> file both defines the logger API and
+ * provides default implementations for its methods. Because
+ * <code>logger.js</code> is normally packaged in
+ * <code>initSES.js</code>, it is built to support being overridden by
+ * a script run <i>earlier</i>. For example, for better diagnostics,
+ * consider loading and initializing <code>useHTMLLogger.js</code> first.
+ *
+ * <p>The {@code ses.logger} API consists of
+ * <dl>
+ *   <dt>log, info, warn, and error methods</dt>
+ *     <dd>each of which take a list of arguments which should be
+ *         stringified and appended together. The logger should
+ *         display this string associated with that severity level. If
+ *         any of the arguments has an associated stack trace
+ *         (presumably Error objects), then the logger <i>may</i> also
+ *         show this stack trace. If no {@code ses.logger} already
+ *         exists, the default provided here forwards to the
+ *         pre-existing global {@code console} if one
+ *         exists. Otherwise, all four of these do nothing. If we
+ *         default to forwarding to the pre-existing {@code console} ,
+ *         we prepend an empty string as first argument since we do
+ *         not want to obligate all loggers to implement the console's
+ *         "%" formatting. </dd>
+ *   <dt>classify(postSeverity)</dt>
+ *     <dd>where postSeverity is a severity
+ *         record as defined by {@code ses.severities} in
+ *         <code>repairES5.js</code>, and returns a helpful record
+ *         consisting of a
+ *         <dl>
+ *           <dt>consoleLevel:</dt>
+ *             <dd>which is one of 'log', 'info', 'warn', or
+ *                 'error', which can be used to select one of the above
+ *                 methods.</dd>
+ *           <dt>note:</dt>
+ *             <dd>containing some helpful text to display
+ *                 explaining the impact of this severity on SES.</dd>
+ *         </dl>
+ *   <dt>reportRepairs(reports)</dt>
+ *     <dd>where {@code reports} is the list of repair reports, each
+ *         of which contains
+ *       <dl>
+ *         <dt>description:</dt>
+ *           <dd>a string describing the problem</dd>
+ *         <dt>preSeverity:</dt>
+ *           <dd>a severity record (as defined by {@code
+ *               ses.severities} in <code>repairES5.js</code>)
+ *               indicating the level of severity of this problem if
+ *               unrepaired. Or, if !canRepair, then the severity
+ *               whether or not repaired.</dd>
+ *         <dt>canRepair:</dt>
+ *           <dd>a boolean indicating "if the repair exists and the test
+ *               subsequently does not detect a problem, are we now ok?"</dd>
+ *         <dt>urls:</dt>
+ *           <dd>a list of URL strings, each of which points at a page
+ *               relevant for documenting or tracking the bug in
+ *               question. These are typically into bug-threads in issue
+ *               trackers for the various browsers.</dd>
+ *         <dt>sections:</dt>
+ *           <dd>a list of strings, each of which is a relevant ES5.1
+ *               section number.</dd>
+ *         <dt>tests:</dt>
+ *           <dd>a list of strings, each of which is the name of a
+ *               relevant test262 or sputnik test case.</dd>
+ *         <dt>postSeverity:</dt>
+ *           <dd>a severity record (as defined by {@code
+ *               ses.severities} in <code>repairES5.js</code>)
+ *               indicating the level of severity of this problem
+ *               after all repairs have been attempted.</dd>
+ *         <dt>beforeFailure:</dt>
+ *           <dd>The outcome of the test associated with this record
+ *               as run before any attempted repairs. If {@code
+ *               false}, it means there was no failure. If {@code
+ *               true}, it means that the test fails in some way that
+ *               the authors of <code>repairES5.js</code>
+ *               expected. Otherwise it returns a string describing
+ *               the symptoms of an unexpected form of failure. This
+ *               is typically considered a more severe form of failure
+ *               than {@code true}, since the authors have not
+ *               anticipated the consequences and safety
+ *               implications.</dd>
+ *         <dt>afterFailure:</dt>
+ *           <dd>The outcome of the test associated with this record
+ *               as run after all attempted repairs.</dd>
+ *       </dl>
+ *       The default behavior here is to be silent.</dd>
+ *   <dt>reportMax()</dt>
+ *     <dd>Displays only a summary of the worst case
+ *         severity seen so far, according to {@code ses.maxSeverity} as
+ *         interpreted by {@code ses.logger.classify}.</dd>
+ *   <dt>reportDiagnosis(severity, status, problemList)</dt>
+ *     <dd>where {@code severity} is a severity record, {@code status}
+ *         is a brief string description of a list of problems, and
+ *         {@code problemList} is a list of strings, each of which is
+ *         one occurrence of the described problem.
+ *         The default behavior here should only the number of
+ *         problems, not the individual problems.</dd>
+ * </dl>
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * //provides ses.logger
+ * @author Mark S. Miller
+ * @requires console
+ * @overrides ses, loggerModule
+ */
+var ses;
+if (!ses) { ses = {}; }
+
+(function loggerModule() {
+  "use strict";
+
+  var logger;
+  function logNowhere(str) {}
+
+  var slice = [].slice;
+  var apply = slice.apply;
+
+
+
+  if (ses.logger) {
+    logger = ses.logger;
+
+  } else if (typeof console !== 'undefined' && 'log' in console) {
+    // We no longer test (typeof console.log === 'function') since,
+    // on IE9 and IE10preview, in violation of the ES5 spec, it
+    // is callable but has typeof "object".
+    // See https://connect.microsoft.com/IE/feedback/details/685962/
+    //   console-log-and-others-are-callable-but-arent-typeof-function
+
+    // We manually wrap each call to a console method because <ul>
+    // <li>On some platforms, these methods depend on their
+    //     this-binding being the console.
+    // <li>All this has to work on platforms that might not have their
+    //     own {@code Function.prototype.bind}, and has to work before
+    //     we install an emulated bind.
+    // </ul>
+
+    var forward = function(level, args) {
+      args = slice.call(args, 0);
+      // We don't do "console.apply" because "console" is not a function
+      // on IE 10 preview 2 and it has no apply method. But it is a
+      // callable that Function.prototype.apply can successfully apply.
+      // This code most work on ES3 where there's no bind. When we
+      // decide support defensiveness in contexts (frames) with mutable
+      // primordials, we will need to revisit the "call" below.
+      apply.call(console[level], console, [''].concat(args));
+
+      // See debug.js
+      var getStack = ses.getStack;
+      if (getStack) {
+        for (var i = 0, len = args.length; i < len; i++) {
+          var stack = getStack(args[i]);
+          if (stack) {
+            console[level]('', stack);
+          }
+        }
+      }
+    };
+
+    logger = {
+      log:   function log(var_args)   { forward('log', arguments); },
+      info:  function info(var_args)  { forward('info', arguments); },
+      warn:  function warn(var_args)  { forward('warn', arguments); },
+      error: function error(var_args) { forward('error', arguments); }
+    };
+  } else {
+    logger = {
+      log:   logNowhere,
+      info:  logNowhere,
+      warn:  logNowhere,
+      error: logNowhere
+    };
+  }
+
+  /**
+   * Returns a record that's helpful for displaying a severity.
+   *
+   * <p>The record contains {@code consoleLevel} and {@code note}
+   * properties whose values are strings. The {@code consoleLevel} is
+   * {@code "log", "info", "warn", or "error"}, which can be used as
+   * method names for {@code logger}, or, in an html context, as a css
+   * class name. The {@code note} is a string stating the severity
+   * level and its consequences for SES.
+   */
+  function defaultClassify(postSeverity) {
+    var MAX_SES_SAFE = ses.severities.SAFE_SPEC_VIOLATION;
+
+    var consoleLevel = 'log';
+    var note = '';
+    if (postSeverity.level > ses.severities.SAFE.level) {
+      consoleLevel = 'info';
+      note = postSeverity.description + '(' + postSeverity.level + ')';
+      if (postSeverity.level > ses.maxAcceptableSeverity.level) {
+        consoleLevel = 'error';
+        note += ' is not suitable for SES';
+      } else if (postSeverity.level > MAX_SES_SAFE.level) {
+        consoleLevel = 'warn';
+        note += ' is not SES-safe';
+      }
+      note += '.';
+    }
+    return {
+      consoleLevel: consoleLevel,
+      note: note
+    };
+  }
+
+  if (!logger.classify) {
+    logger.classify = defaultClassify;
+  }
+
+  /**
+   * By default is silent
+   */
+  function defaultReportRepairs(reports) {}
+
+  if (!logger.reportRepairs) {
+    logger.reportRepairs = defaultReportRepairs;
+  }
+
+  /**
+   * By default, logs a report suitable for display on the console.
+   */
+  function defaultReportMax() {
+    if (ses.maxSeverity.level > ses.severities.SAFE.level) {
+      var maxClassification = ses.logger.classify(ses.maxSeverity);
+      logger[maxClassification.consoleLevel](
+        'Max Severity: ' + maxClassification.note);
+    }
+  }
+
+  if (!logger.reportMax) {
+    logger.reportMax = defaultReportMax;
+  }
+
+  function defaultReportDiagnosis(severity, status, problemList) {
+    var classification = ses.logger.classify(severity);
+    ses.logger[classification.consoleLevel](
+      problemList.length + ' ' + status);
+  }
+
+  if (!logger.reportDiagnosis) {
+    logger.reportDiagnosis = defaultReportDiagnosis;
+  }
+
+  ses.logger = logger;
+
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Monkey patch almost ES5 platforms into a closer
+ * emulation of full <a href=
+ * "http://code.google.com/p/es-lab/wiki/SecureableES5">Secureable
+ * ES5</a>.
+ *
+ * <p>Assumes only ES3, but only proceeds to do useful repairs when
+ * the platform is close enough to ES5 to be worth attempting
+ * repairs. Compatible with almost-ES5, ES5, ES5-strict, and
+ * anticipated ES6.
+ *
+ * <p>Ignore the "...requires ___global_test_function___" below. We
+ * create it, use it, and delete it all within this module. But we
+ * need to lie to the linter since it can't tell.
+ *
+ * //provides ses.statuses, ses.ok, ses.is, ses.makeDelayedTamperProof
+ * //provides ses.makeCallerHarmless, ses.makeArgumentsHarmless
+ * //provides ses.severities, ses.maxSeverity, ses.updateMaxSeverity
+ * //provides ses.maxAcceptableSeverityName, ses.maxAcceptableSeverity
+ *
+ * @author Mark S. Miller
+ * @requires ___global_test_function___, ___global_valueOf_function___
+ * @requires JSON, navigator, this, eval, document
+ * @overrides ses, RegExp, WeakMap, Object, parseInt, repairES5Module
+ */
+var RegExp;
+var ses;
+
+/**
+ * <p>Qualifying platforms generally include all JavaScript platforms
+ * shown on <a href="http://kangax.github.com/es5-compat-table/"
+ * >ECMAScript 5 compatibility table</a> that implement {@code
+ * Object.getOwnPropertyNames}. At the time of this writing,
+ * qualifying browsers already include the latest released versions of
+ * Internet Explorer (9), Firefox (4), Chrome (11), and Safari
+ * (5.0.5), their corresponding standalone (e.g., server-side) JavaScript
+ * engines, Rhino 1.73, and BESEN.
+ *
+ * <p>On such not-quite-ES5 platforms, some elements of these
+ * emulations may lose SES safety, as enumerated in the comment on
+ * each kludge record in the {@code kludges} array below. The platform
+ * must at least provide {@code Object.getOwnPropertyNames}, because
+ * it cannot reasonably be emulated.
+ *
+ * <p>This file is useful by itself, as it has no dependencies on the
+ * rest of SES. It creates no new global bindings, but merely repairs
+ * standard globals or standard elements reachable from standard
+ * globals. If the future-standard {@code WeakMap} global is present,
+ * as it is currently on FF7.0a1, then it will repair it in place. The
+ * one non-standard element that this file uses is {@code console} if
+ * present, in order to report the repairs it found necessary, in
+ * which case we use its {@code log, info, warn}, and {@code error}
+ * methods. If {@code console.log} is absent, then this file performs
+ * its repairs silently.
+ *
+ * <p>Generally, this file should be run as the first script in a
+ * JavaScript context (i.e. a browser frame), as it relies on other
+ * primordial objects and methods not yet being perturbed.
+ *
+ * <p>TODO(erights): This file tries to protect itself from some
+ * post-initialization perturbation by stashing some of the
+ * primordials it needs for later use, but this attempt is currently
+ * incomplete. We need to revisit this when we support Confined-ES5,
+ * as a variant of SES in which the primordials are not frozen. See
+ * previous failed attempt at <a
+ * href="http://codereview.appspot.com/5278046/" >Speeds up
+ * WeakMap. Preparing to support unfrozen primordials.</a>. From
+ * analysis of this failed attempt, it seems that the only practical
+ * way to support CES is by use of two frames, where most of initSES
+ * runs in a SES frame, and so can avoid worrying about most of these
+ * perturbations.
+ */
+(function repairES5Module(global) {
+  "use strict";
+
+  /**
+   * The severity levels.
+   *
+   * <dl>
+   *   <dt>SAFE</dt><dd>no problem.
+   *   <dt>SAFE_SPEC_VIOLATION</dt>
+   *     <dd>safe (in an integrity sense) even if unrepaired. May
+   *         still lead to inappropriate failures.</dd>
+   *   <dt>UNSAFE_SPEC_VIOLATION</dt>
+   *     <dd>a safety issue only indirectly, in that this spec
+   *         violation may lead to the corruption of assumptions made
+   *         by other security critical or defensive code.</dd>
+   *   <dt>NOT_OCAP_SAFE</dt>
+   *     <dd>a violation of object-capability rules among objects
+   *         within a coarse-grained unit of isolation.</dd>
+   *   <dt>NOT_ISOLATED</dt>
+   *     <dd>an inability to reliably sandbox even coarse-grain units
+   *         of isolation.</dd>
+   *   <dt>NEW_SYMPTOM</dt>
+   *     <dd>some test failed in a way we did not expect.</dd>
+   *   <dt>NOT_SUPPORTED</dt>
+   *     <dd>this platform cannot even support SES development in an
+   *         unsafe manner.</dd>
+   * </dl>
+   */
+  ses.severities = {
+    SAFE:                  { level: 0, description: 'Safe' },
+    SAFE_SPEC_VIOLATION:   { level: 1, description: 'Safe spec violation' },
+    UNSAFE_SPEC_VIOLATION: { level: 2, description: 'Unsafe spec violation' },
+    NOT_OCAP_SAFE:         { level: 3, description: 'Not ocap safe' },
+    NOT_ISOLATED:          { level: 4, description: 'Not isolated' },
+    NEW_SYMPTOM:           { level: 5, description: 'New symptom' },
+    NOT_SUPPORTED:         { level: 6, description: 'Not supported' }
+  };
+
+  /**
+   * Statuses.
+   *
+   * <dl>
+   *   <dt>ALL_FINE</dt>
+   *     <dd>test passed before and after.</dd>
+   *   <dt>REPAIR_FAILED</dt>
+   *     <dd>test failed before and after repair attempt.</dd>
+   *   <dt>NOT_REPAIRED</dt>
+   *     <dd>test failed before and after, with no repair to attempt.</dd>
+   *   <dt>REPAIRED_UNSAFELY</dt>
+   *     <dd>test failed before and passed after repair attempt, but
+   *         the repair is known to be inadequate for security, so the
+   *         real problem remains.</dd>
+   *   <dt>REPAIRED</dt>
+   *     <dd>test failed before and passed after repair attempt,
+   *         repairing the problem (canRepair was true).</dd>
+   *   <dt>ACCIDENTALLY_REPAIRED</dt>
+   *      <dd>test failed before and passed after, despite no repair
+   *          to attempt. (Must have been fixed by some other
+   *          attempted repair.)</dd>
+   *   <dt>BROKEN_BY_OTHER_ATTEMPTED_REPAIRS</dt>
+   *      <dd>test passed before and failed after, indicating that
+   *          some other attempted repair created the problem.</dd>
+   * </dl>
+   */
+  ses.statuses = {
+    ALL_FINE:                          'All fine',
+    REPAIR_FAILED:                     'Repair failed',
+    NOT_REPAIRED:                      'Not repaired',
+    REPAIRED_UNSAFELY:                 'Repaired unsafely',
+    REPAIRED:                          'Repaired',
+    ACCIDENTALLY_REPAIRED:             'Accidentally repaired',
+    BROKEN_BY_OTHER_ATTEMPTED_REPAIRS: 'Broken by other attempted repairs'
+  };
+
+
+  var logger = ses.logger;
+
+  /**
+   * As we start to repair, this will track the worst post-repair
+   * severity seen so far.
+   */
+  ses.maxSeverity = ses.severities.SAFE;
+
+  /**
+   * {@code ses.maxAcceptableSeverity} is the max post-repair severity
+   * that is considered acceptable for proceeding with the SES
+   * verification-only strategy.
+   *
+   * <p>Although <code>repairES5.js</code> can be used standalone for
+   * partial ES5 repairs, its primary purpose is to repair as a first
+   * stage of <code>initSES.js</code> for purposes of supporting SES
+   * security. In support of that purpose, we initialize
+   * {@code ses.maxAcceptableSeverity} to the post-repair severity
+   * level at which we should report that we are unable to adequately
+   * support SES security. By default, this is set to
+   * {@code ses.severities.SAFE_SPEC_VIOLATION}, which is the maximum
+   * severity that we believe results in no loss of SES security.
+   *
+   * <p>If {@code ses.maxAcceptableSeverityName} is already set (to a
+   * severity property name of a severity below {@code
+   * ses.NOT_SUPPORTED}), then we use that setting to initialize
+   * {@code ses.maxAcceptableSeverity} instead. For example, if we are
+   * using SES only for isolation, then we could set it to
+   * 'NOT_OCAP_SAFE', in which case repairs that are inadequate for
+   * object-capability (ocap) safety would still be judged safe for
+   * our purposes.
+   *
+   * <p>As repairs proceed, they update {@code ses.maxSeverity} to
+   * track the worst case post-repair severity seen so far. When
+   * {@code ses.ok()} is called, it return whether {@code
+   * ses.maxSeverity} is still less than or equal to
+   * {@code ses.maxAcceptableSeverity}, indicating that this platform
+   * still seems adequate for supporting SES. In the Caja context, we
+   * have the choice of using SES on those platforms which we judge to
+   * be adequately repairable, or otherwise falling back to Caja's
+   * ES5/3 translator.
+   */
+  if (ses.maxAcceptableSeverityName) {
+    var maxSev = ses.severities[ses.maxAcceptableSeverityName];
+    if (maxSev && typeof maxSev.level === 'number' &&
+        maxSev.level >= ses.severities.SAFE.level &&
+        maxSev.level < ses.severities.NOT_SUPPORTED.level) {
+      // do nothing
+    } else {
+      logger.error('Ignoring bad maxAcceptableSeverityName: ' +
+                   ses.maxAcceptableSeverityName + '.') ;
+      ses.maxAcceptableSeverityName = 'SAFE_SPEC_VIOLATION';
+    }
+  } else {
+    ses.maxAcceptableSeverityName = 'SAFE_SPEC_VIOLATION';
+  }
+  ses.maxAcceptableSeverity = ses.severities[ses.maxAcceptableSeverityName];
+
+  /**
+   * Once this returns false, we can give up on the SES
+   * verification-only strategy and fall back to ES5/3 translation.
+   */
+  ses.ok = function ok() {
+    return ses.maxSeverity.level <= ses.maxAcceptableSeverity.level;
+  };
+
+  /**
+   * Update the max based on the provided severity.
+   *
+   * <p>If the provided severity exceeds the max so far, update the
+   * max to match.
+   */
+  ses.updateMaxSeverity = function updateMaxSeverity(severity) {
+    if (severity.level > ses.maxSeverity.level) {
+      ses.maxSeverity = severity;
+    }
+  };
+
+  //////// Prepare for "caller" and "argument" testing and repair /////////
+
+  /**
+   * Needs to work on ES3, since repairES5.js may be run on an ES3
+   * platform.
+   */
+  function strictForEachFn(list, callback) {
+    for (var i = 0, len = list.length; i < len; i++) {
+      callback(list[i], i);
+    }
+  }
+
+  /**
+   * Needs to work on ES3, since repairES5.js may be run on an ES3
+   * platform.
+   *
+   * <p>Also serves as our representative strict function, by contrast
+   * to builtInMapMethod below, for testing what the "caller" and
+   * "arguments" properties of a strict function reveals.
+   */
+  function strictMapFn(list, callback) {
+    var result = [];
+    for (var i = 0, len = list.length; i < len; i++) {
+      result.push(callback(list[i], i));
+    }
+    return result;
+  }
+
+  var objToString = Object.prototype.toString;
+
+  /**
+   * Sample map early, to obtain a representative built-in for testing.
+   *
+   * <p>There is no reliable test for whether a function is a
+   * built-in, and it is possible some of the tests below might
+   * replace the built-in Array.prototype.map, though currently none
+   * do. Since we <i>assume</i> (but with no reliable way to check)
+   * that repairES5.js runs in its JavaScript context before anything
+   * which might have replaced map, we sample it now. The map method
+   * is a particularly nice one to sample, since it can easily be used
+   * to test what the "caller" and "arguments" properties on a
+   * in-progress built-in method reveals.
+   */
+  var builtInMapMethod = Array.prototype.map;
+
+  var builtInForEach = Array.prototype.forEach;
+
+  /**
+   * http://wiki.ecmascript.org/doku.php?id=harmony:egal
+   */
+  var is = ses.is = Object.is || function(x, y) {
+    if (x === y) {
+      // 0 === -0, but they are not identical
+      return x !== 0 || 1 / x === 1 / y;
+    }
+
+    // NaN !== NaN, but they are identical.
+    // NaNs are the only non-reflexive value, i.e., if x !== x,
+    // then x is a NaN.
+    // isNaN is broken: it converts its argument to number, so
+    // isNaN("foo") => true
+    return x !== x && y !== y;
+  };
+
+
+  /**
+   * By the time this module exits, either this is repaired to be a
+   * function that is adequate to make the "caller" property of a
+   * strict or built-in function harmess, or this module has reported
+   * a failure to repair.
+   *
+   * <p>Start off with the optimistic assumption that nothing is
+   * needed to make the "caller" property of a strict or built-in
+   * function harmless. We are not concerned with the "caller"
+   * property of non-strict functions. It is not the responsibility of
+   * this module to actually make these "caller" properties
+   * harmless. Rather, this module only provides this function so
+   * clients such as startSES.js can use it to do so on the functions
+   * they whitelist.
+   *
+   * <p>If the "caller" property of strict functions are not already
+   * harmless, then this platform cannot be repaired to be
+   * SES-safe. The only reason why {@code makeCallerHarmless} must
+   * work on strict functions in addition to built-in is that some of
+   * the other repairs below will replace some of the built-ins with
+   * strict functions, so startSES.js will apply {@code
+   * makeCallerHarmless} blindly to both strict and built-in
+   * functions. {@code makeCallerHarmless} simply need not to complete
+   * without breaking anything when given a strict function argument.
+   */
+  ses.makeCallerHarmless = function assumeCallerHarmless(func, path) {
+    return 'Apparently fine';
+  };
+
+  /**
+   * By the time this module exits, either this is repaired to be a
+   * function that is adequate to make the "arguments" property of a
+   * strict or built-in function harmess, or this module has reported
+   * a failure to repair.
+   *
+   * Exactly analogous to {@code makeCallerHarmless}, but for
+   * "arguments" rather than "caller".
+   */
+  ses.makeArgumentsHarmless = function assumeArgumentsHarmless(func, path) {
+    return 'Apparently fine';
+  };
+
+  /**
+   * "makeTamperProof()" returns a "tamperProof(obj)" function that
+   * acts like "Object.freeze(obj)", except that, if obj is a
+   * <i>prototypical</i> object (defined below), it ensures that the
+   * effect of freezing properties of obj does not suppress the
+   * ability to override these properties on derived objects by simple
+   * assignment.
+   *
+   * <p>Because of lack of sufficient foresight at the time, ES5
+   * unifortunately specified that a simple assignment to a
+   * non-existent property must fail if it would override a
+   * non-writable data property of the same name. (In retrospect, this
+   * was a mistake, but it is now too late and we must live with the
+   * consequences.) As a result, simply freezing an object to make it
+   * tamper proof has the unfortunate side effect of breaking
+   * previously correct code that is considered to have followed JS
+   * best practices, of this previous code used assignment to
+   * override.
+   *
+   * <p>To work around this mistake, tamperProof(obj) detects if obj
+   * is <i>prototypical</i>, i.e., is an object whose own
+   * "constructor" is a function whose "prototype" is this obj. If so,
+   * then when tamper proofing it, prior to freezing, replace all its
+   * configurable own data properties with accessor properties which
+   * simulate what we should have specified -- that assignments to
+   * derived objects succeed if otherwise possible.
+   *
+   * <p>Some platforms (Chrome and Safari as of this writing)
+   * implement the assignment semantics ES5 should have specified
+   * rather than what it did specify.
+   * "test_ASSIGN_CAN_OVERRIDE_FROZEN()" below tests whether we are on
+   * such a platform. If so, "repair_ASSIGN_CAN_OVERRIDE_FROZEN()"
+   * replaces "makeTamperProof" with a function that simply returns
+   * "Object.freeze", since the complex workaround here is not needed
+   * on those platforms.
+   *
+   * <p>"makeTamperProof" should only be called after the trusted
+   * initialization has done all the monkey patching that it is going
+   * to do on the Object.* methods, but before any untrusted code runs
+   * in this context.
+   */
+  var makeTamperProof = function defaultMakeTamperProof() {
+
+    // Sample these after all trusted monkey patching initialization
+    // but before any untrusted code runs in this frame.
+    var gopd = Object.getOwnPropertyDescriptor;
+    var gopn = Object.getOwnPropertyNames;
+    var getProtoOf = Object.getPrototypeOf;
+    var freeze = Object.freeze;
+    var isFrozen = Object.isFrozen;
+    var defProp = Object.defineProperty;
+
+    function tamperProof(obj) {
+      if (obj !== Object(obj)) { return obj; }
+      var func;
+      if (typeof obj === 'object' &&
+          !!gopd(obj, 'constructor') &&
+          typeof (func = obj.constructor) === 'function' &&
+          func.prototype === obj &&
+          !isFrozen(obj)) {
+        strictForEachFn(gopn(obj), function(name) {
+          var value;
+          function getter() {
+            if (obj === this) { return value; }
+            if (this === void 0 || this === null) { return void 0; }
+            var thisObj = Object(this);
+            if (!!gopd(thisObj, name)) { return this[name]; }
+            // TODO(erights): If we can reliably uncurryThis() in
+            // repairES5.js, the next line should be:
+            //   return callFn(getter, getProtoOf(thisObj));
+            return getter.call(getProtoOf(thisObj));
+          }
+          function setter(newValue) {
+            if (obj === this) {
+              throw new TypeError('Cannot set virtually frozen property: ' +
+                                  name);
+            }
+            if (!!gopd(this, name)) {
+              this[name] = newValue;
+            }
+            // TODO(erights): Do all the inherited property checks
+            defProp(this, name, {
+              value: newValue,
+              writable: true,
+              enumerable: true,
+              configurable: true
+            });
+          }
+          var desc = gopd(obj, name);
+          if (desc.configurable && 'value' in desc) {
+            value = desc.value;
+            getter.prototype = null;
+            setter.prototype = null;
+            defProp(obj, name, {
+              get: getter,
+              set: setter,
+              // We should be able to omit the enumerable line, since it
+              // should default to its existing setting.
+              enumerable: desc.enumerable,
+              configurable: false
+            });
+          }
+        });
+      }
+      return freeze(obj);
+    }
+    return tamperProof;
+  };
+
+
+  var needToTamperProof = [];
+  /**
+   * Various repairs may expose non-standard objects that are not
+   * reachable from startSES's root, and therefore not freezable by
+   * startSES's normal whitelist traversal. However, freezing these
+   * during repairES5.js may be too early, as it is before WeakMap.js
+   * has had a chance to monkey patch Object.freeze if necessary, in
+   * order to install hidden properties for its own use before the
+   * object becomes non-extensible.
+   */
+  function rememberToTamperProof(obj) {
+    needToTamperProof.push(obj);
+  }
+
+  /**
+   * Makes and returns a tamperProof(obj) function, and uses it to
+   * tamper proof all objects whose tamper proofing had been delayed.
+   *
+   * <p>"makeDelayedTamperProof()" must only be called once.
+   */
+  ses.makeDelayedTamperProof = function makeDelayedTamperProof() {
+    var tamperProof = makeTamperProof();
+    strictForEachFn(needToTamperProof, tamperProof);
+    needToTamperProof = void 0;
+    return tamperProof;
+  };
+
+  /**
+   * Where the "that" parameter represents a "this" that should have
+   * been bound to "undefined" but may be bound to a global or
+   * globaloid object.
+   *
+   * <p>The "desc" parameter is a string to describe the "that" if it
+   * is something unexpected.
+   */
+  function testGlobalLeak(desc, that) {
+    if (that === void 0) { return false; }
+    if (that === global) { return true; }
+    if ({}.toString.call(that) === '[object Window]') { return true; }
+    return desc + ' leaked as: ' + that;
+  }
+
+  ////////////////////// Tests /////////////////////
+  //
+  // Each test is a function of no arguments that should not leave any
+  // significant side effects, which tests for the presence of a
+  // problem. It returns either
+  // <ul>
+  // <li>false, meaning that the problem does not seem to be present.
+  // <li>true, meaning that the problem is present in a form that we expect.
+  // <li>a non-empty string, meaning that there seems to be a related
+  //     problem, but we're seeing a symptom different than what we
+  //     expect. The string should describe the new symptom. It must
+  //     be non-empty so that it is truthy.
+  // </ul>
+  // All the tests are run first to determine which corresponding
+  // repairs to attempt. Then these repairs are run. Then all the
+  // tests are rerun to see how they were effected by these repair
+  // attempts. Finally, we report what happened.
+
+  /**
+   * If {@code Object.getOwnPropertyNames} is missing, we consider
+   * this to be an ES3 browser which is unsuitable for attempting to
+   * run SES.
+   *
+   * <p>If {@code Object.getOwnPropertyNames} is missing, there is no
+   * way to emulate it.
+   */
+  function test_MISSING_GETOWNPROPNAMES() {
+    return !('getOwnPropertyNames' in Object);
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=64250
+   *
+   * <p>No workaround attempted. Just reporting that this platform is
+   * not SES-safe.
+   */
+  function test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS() {
+    global.___global_test_function___ = function() { return this; };
+    var that = ___global_test_function___();
+    delete global.___global_test_function___;
+    return testGlobalLeak('Global func "this"', that);
+  }
+
+  /**
+   * Detects whether the most painful ES3 leak is still with us.
+   */
+  function test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS() {
+    var that = (function(){ return this; })();
+    return testGlobalLeak('Anon func "this"', that);
+  }
+
+  var strictThis = this;
+
+  /**
+   *
+   */
+  function test_GLOBAL_LEAKS_FROM_STRICT_THIS() {
+    return testGlobalLeak('Strict "this"', strictThis);
+  }
+
+  /**
+   * Detects
+   * https://bugs.webkit.org/show_bug.cgi?id=51097
+   * https://bugs.webkit.org/show_bug.cgi?id=58338
+   * http://code.google.com/p/v8/issues/detail?id=1437
+   *
+   * <p>No workaround attempted. Just reporting that this platform is
+   * not SES-safe.
+   */
+  function test_GLOBAL_LEAKS_FROM_BUILTINS() {
+    var v = {}.valueOf;
+    var that = 'dummy';
+    try {
+      that = v();
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'valueOf() threw: ' + err;
+    }
+    if (that === void 0) {
+      // Should report as a safe spec violation
+      return false;
+    }
+    return testGlobalLeak('valueOf()', that);
+  }
+
+  /**
+   *
+   */
+  function test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS() {
+    global.___global_valueOf_function___ = {}.valueOf;
+    var that = 'dummy';
+    try {
+      that = ___global_valueOf_function___();
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'valueOf() threw: ' + err;
+    } finally {
+      delete global.___global_valueOf_function___;
+    }
+    if (that === void 0) {
+      // Should report as a safe spec violation
+      return false;
+    }
+    return testGlobalLeak('Global valueOf()', that);
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=55736
+   *
+   * <p>As of this writing, the only major browser that does implement
+   * Object.getOwnPropertyNames but not Object.freeze etc is the
+   * released Safari 5 (JavaScriptCore). The Safari beta 5.0.4
+   * (5533.20.27, r84622) already does implement freeze, which is why
+   * this WebKit bug is listed as closed. When the released Safari has
+   * this fix, we can retire this kludge.
+   *
+   * <p>This kludge is <b>not</b> safety preserving. The emulations it
+   * installs if needed do not actually provide the safety that the
+   * rest of SES relies on.
+   */
+  function test_MISSING_FREEZE_ETC() {
+    return !('freeze' in Object);
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1530
+   *
+   * <p>Detects whether the value of a function's "prototype" property
+   * as seen by normal object operations might deviate from the value
+   * as seem by the reflective {@code Object.getOwnPropertyDescriptor}
+   */
+  function test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES() {
+    function foo() {}
+    Object.defineProperty(foo, 'prototype', { value: {} });
+    return foo.prototype !==
+      Object.getOwnPropertyDescriptor(foo, 'prototype').value;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=55537
+   *
+   * This bug is fixed on the latest Safari beta 5.0.5 (5533.21.1,
+   * r88603). When the released Safari has this fix, we can retire
+   * this kludge.
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_MISSING_CALLEE_DESCRIPTOR() {
+    function foo(){}
+    if (Object.getOwnPropertyNames(foo).indexOf('callee') < 0) { return false; }
+    if (foo.hasOwnProperty('callee')) {
+      return 'Empty strict function has own callee';
+    }
+    return true;
+  }
+
+  /**
+   * A strict delete should either succeed, returning true, or it
+   * should fail by throwing a TypeError. Under no circumstances
+   * should a strict delete return false.
+   *
+   * <p>This case occurs on IE10preview2.
+   */
+  function test_STRICT_DELETE_RETURNS_FALSE() {
+    if (!RegExp.hasOwnProperty('rightContext')) { return false; }
+    var deleted;
+    try {
+      deleted = delete RegExp.rightContext;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Deletion failed with: ' + err;
+    }
+    if (deleted) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846
+   * as applied to the RegExp constructor.
+   *
+   * <p>Note that Mozilla lists this bug as closed. But reading that
+   * bug thread clarifies that is partially because the code in {@code
+   * repair_REGEXP_CANT_BE_NEUTERED} enables us to work around the
+   * non-configurability of the RegExp statics.
+   */
+  function test_REGEXP_CANT_BE_NEUTERED() {
+    if (!RegExp.hasOwnProperty('leftContext')) { return false; }
+    var deleted;
+    try {
+      deleted = delete RegExp.leftContext;
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'Deletion failed with: ' + err;
+    }
+    if (!RegExp.hasOwnProperty('leftContext')) { return false; }
+    if (deleted) {
+      return 'Deletion of RegExp.leftContext did not succeed.';
+    } else {
+      // This case happens on IE10preview2, as demonstrated by
+      // test_STRICT_DELETE_RETURNS_FALSE.
+      return true;
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1393
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_REGEXP_TEST_EXEC_UNSAFE() {
+    (/foo/).test('xfoox');
+    var match = new RegExp('(.|\r|\n)*','').exec()[0];
+    if (match === 'undefined') { return false; }
+    if (match === 'xfoox') { return true; }
+    return 'regExp.exec() does not match against "undefined".';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=26382
+   *
+   * <p>As of this writing, the only major browser that does implement
+   * Object.getOwnPropertyNames but not Function.prototype.bind is
+   * Safari 5 (JavaScriptCore), including the current Safari beta
+   * 5.0.4 (5533.20.27, r84622).
+   *
+   * <p>This kludge is safety preserving. But see
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c25 for why this
+   * kludge cannot faithfully implement the specified semantics.
+   *
+   * <p>See also https://bugs.webkit.org/show_bug.cgi?id=42371
+   */
+  function test_MISSING_BIND() {
+    return !('bind' in Function.prototype);
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=892
+   *
+   * <p>This tests whether the built-in bind method violates the spec
+   * by calling the original using its current .apply method rather
+   * than the internal [[Call]] method. The workaround is the same as
+   * for test_MISSING_BIND -- to replace the built-in bind with one
+   * written in JavaScript. This introduces a different bug though: As
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c29 explains, a
+   * bind written in JavaScript cannot emulate the specified currying
+   * over the construct behavior, and so fails to enable a var-args
+   * {@code new} operation.
+   */
+  function test_BIND_CALLS_APPLY() {
+    if (!('bind' in Function.prototype)) { return false; }
+    var applyCalled = false;
+    function foo() { return [].slice.call(arguments,0).join(','); }
+    foo.apply = function fakeApply(self, args) {
+      applyCalled = true;
+      return Function.prototype.apply.call(this, self, args);
+    };
+    var b = foo.bind(33,44);
+    var answer = b(55,66);
+    if (applyCalled) { return true; }
+    if (answer === '44,55,66') { return false; }
+    return 'Bind test returned "' + answer + '" instead of "44,55,66".';
+  }
+
+  /**
+   * Demonstrates the point made by comment 29
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c29
+   *
+   * <p>Tests whether Function.prototype.bind curries over
+   * construction ({@code new}) behavior. A built-in bind should. A
+   * bind emulation written in ES5 can't.
+   */
+  function test_BIND_CANT_CURRY_NEW() {
+    function construct(f, args) {
+      var bound = Function.prototype.bind.apply(f, [null].concat(args));
+      return new bound();
+    }
+    var d;
+    try {
+      d = construct(Date, [1957, 4, 27]);
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'Curries construction failed with: ' + err;
+    }
+    if (typeof d === 'string') { return true; } // Opera
+    var str = objToString.call(d);
+    if (str === '[object Date]') { return false; }
+    return 'Unexpected ' + str + ': ' + d;
+  }
+
+  /**
+   * Detects http://code.google.com/p/google-caja/issues/detail?id=1362
+   *
+   * <p>This is an unfortunate oversight in the ES5 spec: Even if
+   * Date.prototype is frozen, it is still defined to be a Date, and
+   * so has mutable state in internal properties that can be mutated
+   * by the primordial mutation methods on Date.prototype, such as
+   * {@code Date.prototype.setFullYear}.
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_MUTABLE_DATE_PROTO() {
+    try {
+      Date.prototype.setFullYear(1957);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating Date.prototype failed with: ' + err;
+    }
+    var v = Date.prototype.getFullYear();
+    Date.prototype.setFullYear(NaN); // hopefully undoes the damage
+    if (v !== v && typeof v === 'number') {
+      // NaN indicates we're probably ok.
+      // TODO(erights) Should we report this as a symptom anyway, so
+      // that we get the repair which gives us a reliable TypeError?
+      return false;
+    }
+    if (v === 1957) { return true; }
+    return 'Mutating Date.prototype did not throw';
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=656828
+   *
+   * <p>A bug in the current FF6.0a1 implementation: Even if
+   * WeakMap.prototype is frozen, it is still defined to be a WeakMap,
+   * and so has mutable state in internal properties that can be
+   * mutated by the primordial mutation methods on WeakMap.prototype,
+   * such as {@code WeakMap.prototype.set}.
+   *
+   * <p>This kludge is safety preserving.
+   *
+   * <p>TODO(erights): Update the ES spec page to reflect the current
+   * agreement with Mozilla.
+   */
+  function test_MUTABLE_WEAKMAP_PROTO() {
+    if (typeof WeakMap !== 'function') { return false; }
+    var x = {};
+    try {
+      WeakMap.prototype.set(x, 86);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating WeakMap.prototype failed with: ' + err;
+    }
+    var v = WeakMap.prototype.get(x);
+    // Since x cannot escape, there's no observable damage to undo.
+    if (v === 86) { return true; }
+    return 'Mutating WeakMap.prototype did not throw';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1447
+   *
+   * <p>This bug is fixed as of V8 r8258 bleeding-edge, but is not yet
+   * available in the latest dev-channel Chrome (13.0.782.15 dev).
+   *
+   * <p>Unfortunately, an ES5 strict method wrapper cannot emulate
+   * absence of a [[Construct]] behavior, as specified for the Chapter
+   * 15 built-in methods. The installed wrapper relies on {@code
+   * Function.prototype.apply}, as inherited by original, obeying its
+   * contract.
+   *
+   * <p>This kludge is safety preserving but non-transparent, in that
+   * the real forEach is frozen even in the success case, since we
+   * have to freeze it in order to test for this failure. We could
+   * repair this non-transparency by replacing it with a transparent
+   * wrapper (as http://codereview.appspot.com/5278046/ does), but
+   * since the SES use of this will freeze it anyway and the
+   * indirection is costly, we choose not to for now.
+   */
+  function test_NEED_TO_WRAP_FOREACH() {
+    if (!('freeze' in Object)) {
+      // Object.freeze is still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    if (Array.prototype.forEach !== builtInForEach) {
+      // If it is already wrapped, we are confident the problem does
+      // not occur, and we need to skip the test to avoid freezing the
+      // wrapper.
+      return false;
+    }
+    try {
+      ['z'].forEach(function(){ Object.freeze(Array.prototype.forEach); });
+      return false;
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'freezing forEach failed with ' + err;
+    }
+  }
+
+  /**
+   * <p>Sometimes, when trying to freeze an object containing an
+   * accessor property with a getter but no setter, Chrome <= 17 fails
+   * with <blockquote>Uncaught TypeError: Cannot set property ident___
+   * of #<Object> which has only a getter</blockquote>. So if
+   * necessary, this kludge overrides {@code Object.defineProperty} to
+   * always install a dummy setter in lieu of the absent one.
+   *
+   * <p>Since this problem seems to have gone away as of Chrome 18, it
+   * is no longer as important to isolate and report it.
+   *
+   * <p>TODO(erights): We should also override {@code
+   * Object.getOwnPropertyDescriptor} to hide the presence of the
+   * dummy setter, and instead report an absent setter.
+   */
+  function test_NEEDS_DUMMY_SETTER() {
+    if (NEEDS_DUMMY_SETTER_repaired) { return false; }
+    if (typeof navigator === 'undefined') { return false; }
+    var ChromeMajorVersionPattern = (/Chrome\/(\d*)\./);
+    var match = ChromeMajorVersionPattern.exec(navigator.userAgent);
+    if (!match) { return false; }
+    var ver = +match[1];
+    return ver <= 17;
+  }
+  /** we use this variable only because we haven't yet isolated a test
+   * for the problem. */
+  var NEEDS_DUMMY_SETTER_repaired = false;
+
+  /**
+   * Detects http://code.google.com/p/chromium/issues/detail?id=94666
+   */
+  function test_FORM_GETTERS_DISAPPEAR() {
+    function getter() { return 'gotten'; }
+
+    if (typeof document === 'undefined' ||
+       typeof document.createElement !== 'function') {
+      // likely not a browser environment
+      return false;
+    }
+    var f = document.createElement("form");
+    try {
+      Object.defineProperty(f, 'foo', {
+        get: getter,
+        set: void 0
+      });
+    } catch (err) {
+      // Happens on Safari 5.0.2 on IPad2.
+      return 'defining accessor on form failed with: ' + err;
+    }
+    var desc = Object.getOwnPropertyDescriptor(f, 'foo');
+    if (desc.get === getter) { return false; }
+    if (desc.get === void 0) { return true; }
+    return 'Getter became ' + desc.get;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=637994
+   *
+   * <p>On Firefox 4 an inherited non-configurable accessor property
+   * appears to be an own property of all objects which inherit this
+   * accessor property. This is fixed as of Forefox Nightly 7.0a1
+   * (2011-06-21).
+   *
+   * <p>Our workaround wraps hasOwnProperty, getOwnPropertyNames, and
+   * getOwnPropertyDescriptor to heuristically decide when an accessor
+   * property looks like it is apparently own because of this bug, and
+   * suppress reporting its existence.
+   *
+   * <p>However, it is not feasible to likewise wrap JSON.stringify,
+   * and this bug will cause JSON.stringify to be misled by inherited
+   * enumerable non-configurable accessor properties. To prevent this,
+   * we wrap defineProperty, freeze, and seal to prevent the creation
+   * of <i>enumerable</i> non-configurable accessor properties on
+   * those platforms with this bug.
+   *
+   * <p>A little known fact about JavaScript is that {@code
+   * Object.prototype.propertyIsEnumerable} actually tests whether a
+   * property is both own and enumerable. Assuming that our wrapping
+   * of defineProperty, freeze, and seal prevents the occurrence of an
+   * enumerable non-configurable accessor property, it should also
+   * prevent the occurrence of this bug for any enumerable property,
+   * and so we do not need to wrap propertyIsEnumerable.
+   *
+   * <p>This kludge seems to be safety preserving, but the issues are
+   * delicate and not well understood.
+   */
+  function test_ACCESSORS_INHERIT_AS_OWN() {
+    var base = {};
+    var derived = Object.create(base);
+    function getter() { return 'gotten'; }
+    Object.defineProperty(base, 'foo', { get: getter });
+    if (!derived.hasOwnProperty('foo') &&
+        Object.getOwnPropertyDescriptor(derived, 'foo') === void 0 &&
+        Object.getOwnPropertyNames(derived).indexOf('foo') < 0) {
+      return false;
+    }
+    if (!derived.hasOwnProperty('foo') ||
+        Object.getOwnPropertyDescriptor(derived, 'foo').get !== getter ||
+        Object.getOwnPropertyNames(derived).indexOf('foo') < 0) {
+      return 'Accessor properties partially inherit as own properties.';
+    }
+    Object.defineProperty(base, 'bar', { get: getter, configurable: true });
+    if (!derived.hasOwnProperty('bar') &&
+        Object.getOwnPropertyDescriptor(derived, 'bar') === void 0 &&
+        Object.getOwnPropertyNames(derived).indexOf('bar') < 0) {
+      return true;
+    }
+    return 'Accessor properties inherit as own even if configurable.';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1360
+   *
+   * Our workaround wraps {@code sort} to wrap the comparefn.
+   */
+  function test_SORT_LEAKS_GLOBAL() {
+    var that = 'dummy';
+    [2,3].sort(function(x,y) { that = this; return x - y; });
+    if (that === void 0) { return false; }
+    if (that === global) { return true; }
+    return 'sort called comparefn with "this" === ' + that;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1360
+   *
+   * <p>Our workaround wraps {@code replace} to wrap the replaceValue
+   * if it's a function.
+   */
+  function test_REPLACE_LEAKS_GLOBAL() {
+    var that = 'dummy';
+    function capture() { that = this; return 'y';}
+    'x'.replace(/x/, capture);
+    if (that === void 0) { return false; }
+    if (that === capture) {
+      // This case happens on IE10preview2. See
+      // https://connect.microsoft.com/IE/feedback/details/685928/
+      //   bad-this-binding-for-callback-in-string-prototype-replace
+      // TODO(erights): When this happens, the kludge.description is
+      // wrong.
+      return true;
+    }
+    if (that === global) { return true; }
+    return 'Replace called replaceValue function with "this" === ' + that;
+  }
+
+  /**
+   * Detects
+   * https://connect.microsoft.com/IE/feedback/details/
+   *   685436/getownpropertydescriptor-on-strict-caller-throws
+   *
+   * <p>Object.getOwnPropertyDescriptor must work even on poisoned
+   * "caller" properties.
+   */
+  function test_CANT_GOPD_CALLER() {
+    var desc = null;
+    try {
+      desc = Object.getOwnPropertyDescriptor(function(){}, 'caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'getOwnPropertyDescriptor failed with: ' + err;
+    }
+    if (desc &&
+        typeof desc.get === 'function' &&
+        typeof desc.set === 'function' &&
+        !desc.configurable) {
+      return false;
+    }
+    if (desc &&
+        desc.value === null &&
+        !desc.writable &&
+        !desc.configurable) {
+      // Seen in IE9. Harmless by itself
+      return false;
+    }
+    return 'getOwnPropertyDesciptor returned unexpected caller descriptor';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>A strict function's caller should be poisoned only in a way
+   * equivalent to an accessor property with a throwing getter and
+   * setter.
+   *
+   * <p>Seen on Safari 5.0.6 through WebKit Nightly r93670
+   */
+  function test_CANT_HASOWNPROPERTY_CALLER() {
+    var answer = void 0;
+    try {
+      answer = function(){}.hasOwnProperty('caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'hasOwnProperty failed with: ' + err;
+    }
+    if (answer) { return false; }
+    return 'strict_function.hasOwnProperty("caller") was false';
+  }
+
+  /**
+   * Protect an 'in' with a try/catch to workaround a bug in Safari
+   * WebKit Nightly Version 5.0.5 (5533.21.1, r89741).
+   *
+   * <p>See https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>Notes: We're seeing exactly
+   * <blockquote>
+   *   New symptom (c): ('caller' in &lt;a bound function&gt;) threw:
+   *   TypeError: Cannot access caller property of a strict mode
+   *   function<br>
+   *   New symptom (c): ('arguments' in &lt;a bound function&gt;)
+   *   threw: TypeError: Can't access arguments object of a strict
+   *   mode function
+   * </blockquote>
+   * which means we're skipping both the catch and the finally in
+   * {@code has} while hitting the catch in {@code has2}. Further, if
+   * we remove one of these finally clauses (forget which) and rerun
+   * the example, if we're under the debugger the browser crashes. If
+   * we're not, then the TypeError escapes both catches.
+   */
+  function has(base, name, baseDesc) {
+    var result = void 0;
+    var finallySkipped = true;
+    try {
+      result = name in base;
+    } catch (err) {
+      logger.error('New symptom (a): (\'' +
+                   name + '\' in <' + baseDesc + '>) threw: ', err);
+      // treat this as a safe absence
+      result = false;
+      return false;
+    } finally {
+      finallySkipped = false;
+      if (result === void 0) {
+        logger.error('New symptom (b): (\'' +
+                     name + '\' in <' + baseDesc + '>) failed');
+      }
+    }
+    if (finallySkipped) {
+      logger.error('New symptom (e): (\'' +
+                   name + '\' in <' + baseDesc +
+                   '>) inner finally skipped');
+    }
+    return !!result;
+  }
+
+  function has2(base, name, baseDesc) {
+    var result = void 0;
+    var finallySkipped = true;
+    try {
+      result = has(base, name, baseDesc);
+    } catch (err) {
+      logger.error('New symptom (c): (\'' +
+                   name + '\' in <' + baseDesc + '>) threw: ', err);
+      // treat this as a safe absence
+      result = false;
+      return false;
+    } finally {
+      finallySkipped = false;
+      if (result === void 0) {
+        logger.error('New symptom (d): (\'' +
+                     name + '\' in <' + baseDesc + '>) failed');
+      }
+    }
+    if (finallySkipped) {
+      logger.error('New symptom (f): (\'' +
+                   name + '\' in <' + baseDesc +
+                   '>) outer finally skipped');
+    }
+    return !!result;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>If this reports a problem in the absence of "New symptom (a)",
+   * it means the error thrown by the "in" in {@code has} is skipping
+   * past the first layer of "catch" surrounding that "in". This is in
+   * fact what we're currently seeing on Safari WebKit Nightly Version
+   * 5.0.5 (5533.21.1, r91108).
+   */
+  function test_CANT_IN_CALLER() {
+    var answer = void 0;
+    try {
+      answer = has2(function(){}, 'caller', 'strict_function');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return '("caller" in strict_func) failed with: ' + err;
+    } finally {}
+    if (answer) { return false; }
+    return '("caller" in strict_func) was false.';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>If this reports a problem in the absence of "New symptom (a)",
+   * it means the error thrown by the "in" in {@code has} is skipping
+   * past the first layer of "catch" surrounding that "in". This is in
+   * fact what we're currently seeing on Safari WebKit Nightly Version
+   * 5.0.5 (5533.21.1, r91108).
+   */
+  function test_CANT_IN_ARGUMENTS() {
+    var answer = void 0;
+    try {
+      answer = has2(function(){}, 'arguments', 'strict_function');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return '("arguments" in strict_func) failed with: ' + err;
+    } finally {}
+    if (answer) { return false; }
+    return '("arguments" in strict_func) was false.';
+  }
+
+  /**
+   * Detects whether strict function violate caller anonymity.
+   */
+  function test_STRICT_CALLER_NOT_POISONED() {
+    if (!has2(strictMapFn, 'caller', 'a strict function')) { return false; }
+    function foo(m) { return m.caller; }
+    // using Function so it'll be non-strict
+    var testfn = Function('m', 'f', 'return m([m], f)[0];');
+    var caller;
+    try {
+      caller = testfn(strictMapFn, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Strict "caller" failed with: ' + err;
+    }
+    if (testfn === caller) {
+      // Seen on IE 9
+      return true;
+    }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects whether strict functions are encapsulated.
+   */
+  function test_STRICT_ARGUMENTS_NOT_POISONED() {
+    if (!has2(strictMapFn, 'arguments', 'a strict function')) { return false; }
+    function foo(m) { return m.arguments; }
+    // using Function so it'll be non-strict
+    var testfn = Function('m', 'f', 'return m([m], f)[0];');
+    var args;
+    try {
+      args = testfn(strictMapFn, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Strict "arguments" failed with: ' + err;
+    }
+    if (args[1] === foo) {
+      // Seen on IE 9
+      return true;
+    }
+    return 'Unexpected arguments: ' + arguments;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846 as
+   * applied to "caller"
+   */
+  function test_BUILTIN_LEAKS_CALLER() {
+    if (!has2(builtInMapMethod, 'caller', 'a builtin')) { return false; }
+    function foo(m) { return m.caller; }
+    // using Function so it'll be non-strict
+    var testfn = Function('a', 'f', 'return a.map(f)[0];');
+    var a = [builtInMapMethod];
+    a.map = builtInMapMethod;
+    var caller;
+    try {
+      caller = testfn(a, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Built-in "caller" failed with: ' + err;
+    }
+    if (null === caller || void 0 === caller) { return false; }
+    if (testfn === caller) { return true; }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846 as
+   * applied to "arguments"
+   */
+  function test_BUILTIN_LEAKS_ARGUMENTS() {
+    if (!has2(builtInMapMethod, 'arguments', 'a builtin')) { return false; }
+    function foo(m) { return m.arguments; }
+    // using Function so it'll be non-strict
+    var testfn = Function('a', 'f', 'return a.map(f)[0];');
+    var a = [builtInMapMethod];
+    a.map = builtInMapMethod;
+    var args;
+    try {
+      args = testfn(a, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Built-in "arguments" failed with: ' + err;
+    }
+    if (args === void 0 || args === null) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=893
+   */
+  function test_BOUND_FUNCTION_LEAKS_CALLER() {
+    if (!('bind' in Function.prototype)) { return false; }
+    function foo() { return bar.caller; }
+    var bar = foo.bind({});
+    if (!has2(bar, 'caller', 'a bound function')) { return false; }
+    // using Function so it'll be non-strict
+    var testfn = Function('b', 'return b();');
+    var caller;
+    try {
+      caller = testfn(bar);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Bound function "caller" failed with: ' + err;
+    }
+    if (caller === void 0 || caller === null) { return false; }
+    if (caller === testfn) { return true; }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=893
+   */
+  function test_BOUND_FUNCTION_LEAKS_ARGUMENTS() {
+    if (!('bind' in Function.prototype)) { return false; }
+    function foo() { return bar.arguments; }
+    var bar = foo.bind({});
+    if (!has2(bar, 'arguments', 'a bound function')) { return false; }
+    // using Function so it'll be non-strict
+    var testfn = Function('b', 'return b();');
+    var args;
+    try {
+      args = testfn(bar);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Bound function "arguments" failed with: ' + err;
+    }
+    if (args === void 0 || args === null) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=70207
+   *
+   * <p>After deleting a built-in, the problem is that
+   * getOwnPropertyNames still lists the name as present, but it seems
+   * absent in all other ways.
+   */
+  function test_DELETED_BUILTINS_IN_OWN_NAMES() {
+    if (!('__defineSetter__' in Object.prototype)) { return false; }
+    var desc = Object.getOwnPropertyDescriptor(Object.prototype,
+                                               '__defineSetter__');
+    try {
+      try {
+        delete Object.prototype.__defineSetter__;
+      } catch (err1) {
+        return false;
+      }
+      var names = Object.getOwnPropertyNames(Object.prototype);
+      if (names.indexOf('__defineSetter__') === -1) { return false; }
+      if ('__defineSetter__' in Object.prototype) {
+        // If it's still there, it bounced back. Which is still a
+        // problem, but not the problem we're testing for here.
+        return false;
+      }
+      return true;
+    } finally {
+      Object.defineProperty(Object.prototype, '__defineSetter__', desc);
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1769
+   */
+  function test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS() {
+    try {
+      Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptor,
+                                      'caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'getOwnPropertyDescriptor threw: ' + err;
+    }
+    return false;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=621
+   *
+   */
+  function test_JSON_PARSE_PROTO_CONFUSION() {
+    var x;
+    try {
+      x = JSON.parse('{"__proto__":[]}');
+    } catch (err) {
+      if (err instanceof TypeError) {
+        // We consider it acceptable to fail this case with a
+        // TypeError, as our repair below will cause it to do.
+        return false;
+      }
+      return 'JSON.parse failed with: ' + err;
+    }
+    if (Object.getPrototypeOf(x) !== Object.prototype) { return true; }
+    if (Array.isArray(x.__proto__)) { return false; }
+    return 'JSON.parse did not set "__proto__" as a regular property';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=65832
+   *
+   * <p>On a non-extensible object, it must not be possible to change
+   * its internal [[Prototype]] property, i.e., which object it
+   * inherits from.
+   *
+   * TODO(erights): investigate the following:
+   * At http://goo.gl/ycCmo Mike Stay says
+   * <blockquote>
+   * Kevin notes in domado.js that on some versions of FF, event
+   * objects switch prototypes when moving between frames. You should
+   * probably check out their behavior around freezing and sealing.
+   * </blockquote>
+   * But I couldn't find it.
+   */
+  function test_PROTO_NOT_FROZEN() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      x.__proto__ = y;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating __proto__ failed with: ' + err;
+    }
+    if (y.isPrototypeOf(x)) { return true; }
+    return 'Mutating __proto__ neither failed nor succeeded';
+  }
+
+  /**
+   * Like test_PROTO_NOT_FROZEN but using defineProperty rather than
+   * assignment.
+   */
+  function test_PROTO_REDEFINABLE() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      Object.defineProperty(x, '__proto__', { value: y });
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Defining __proto__ failed with: ' + err;
+    }
+    if (y.isPrototypeOf(x)) { return true; }
+    return 'Defining __proto__ neither failed nor succeeded';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1624
+   *
+   * <p>Both a direct strict eval operator and an indirect strict eval
+   * function must not leak top level declarations in the string being
+   * evaluated into their containing context.
+   */
+  function test_STRICT_EVAL_LEAKS_GLOBALS() {
+    (1,eval)('"use strict"; var ___global_test_variable___ = 88;');
+    if ('___global_test_variable___' in global) {
+      delete global.___global_test_variable___;
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1645
+   */
+  function test_PARSEINT_STILL_PARSING_OCTAL() {
+    var n = parseInt('010');
+    if (n === 10) { return false; }
+    if (n === 8)  { return true; }
+    return 'parseInt("010") returned ' + n;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=695577
+   *
+   * <p>When E4X syntax is accepted in strict code, then without
+   * parsing, we cannot prevent untrusted code from expressing E4X
+   * literals and so obtaining access to shared E4X prototypes,
+   * despite the absence of these prototypes from our whitelist. While
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=695579 is also
+   * open, we cannot even repair the situation, leading to unpluggable
+   * capability leaks. However, we do not test for this additional
+   * problem, since E4X is such a can of worms that 695577 is adequate
+   * by itself for us to judge this platform to be insecurable without
+   * parsing.
+   */
+  function test_STRICT_E4X_LITERALS_ALLOWED() {
+    var x;
+    try {
+      x = eval('"use strict";(<foo/>);');
+    } catch (err) {
+      if (err instanceof SyntaxError) { return false; }
+      return 'E4X test failed with: ' + err;
+    }
+    if (x !== void 0) { return true; }
+    return 'E4X literal expression had no value';
+  }
+
+  /**
+   * Detects whether assignment can override an inherited
+   * non-writable, non-configurable data property.
+   *
+   * <p>According to ES5.1, assignment should not be able to do so,
+   * which is unfortunate for SES, as the tamperProof function must
+   * kludge expensively to ensure that legacy assignments that don't
+   * violate best practices continue to work. Ironically, on platforms
+   * in which this bug is present, tamperProof can just be cheaply
+   * equivalent to Object.freeze.
+   */
+  function test_ASSIGN_CAN_OVERRIDE_FROZEN() {
+    var x = Object.freeze({foo: 88});
+    var y = Object.create(x);
+    try {
+      y.foo = 99;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Override failed with: ' + err;
+    }
+    if (y.foo === 99) { return true; }
+    if (y.foo === 88) { return 'Override failed silently'; }
+    return 'Unexpected override outcome: ' + y.foo;
+  }
+
+  /**
+   *
+   */
+  function test_CANT_REDEFINE_NAN_TO_ITSELF() {
+    var descNaN = Object.getOwnPropertyDescriptor(global, 'NaN');
+    try {
+      Object.defineProperty(global, 'NaN', descNaN);
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'defineProperty of NaN failed with: ' + err;
+    }
+    return false;
+  }
+
+  /**
+   * These are all the own properties that appear on Error instances
+   * on various ES5 platforms as of this writing.
+   *
+   * <p>Due to browser bugs, some of these are absent from
+   * getOwnPropertyNames (gopn). TODO(erights): File bugs with various
+   * browser makers for any own properties that we know to be present
+   * but not reported by gopn.
+   *
+   * <p>TODO(erights): do intelligence with the various browser
+   * implementors to find out what other properties are provided by
+   * their implementation but absent from gopn, whether on Errors or
+   * anything else. Every one of these are potentially fatal to our
+   * security until we can examine these.
+   *
+   * <p>The source form is a list rather than a map so that we can list a
+   * name like "message" for each browser section we think it goes in.
+   *
+   * <p>We thank the following people, projects, and websites for
+   * providing some useful intelligence of what property names we
+   * should suspect:<ul>
+   * <li><a href="http://stacktracejs.org">stacktracejs.org</a>
+   * <li>TODO(erights): find message on es-discuss list re
+   * "   stack". credit author.
+   * </ul>
+   */
+  var errorInstanceWhitelist = [
+    // at least Chrome 16
+    'arguments',
+    'message',
+    'stack',
+    'type',
+
+    // at least FF 9
+    'fileName',
+    'lineNumber',
+    'message',
+    'stack',
+
+    // at least Safari, WebKit 5.1
+    'line',
+    'message',
+    'sourceId',
+    'sourceURL',
+
+    // at least IE 10 preview 2
+    'description',
+    'message',
+    'number',
+
+    // at least Opera 11.60
+    'message',
+    'stack',
+    'stacktrace'
+  ];
+
+  var errorInstanceBlacklist = [
+    // seen in a Firebug on FF
+    'category',
+    'context',
+    'href',
+    'lineNo',
+    'msgId',
+    'source',
+    'trace',
+    'correctSourcePoint',
+    'correctWithStackTrace',
+    'getSourceLine',
+    'resetSource'
+  ];
+
+  /** Return a fresh one so client can mutate freely */
+  function freshErrorInstanceWhiteMap() {
+    var result = Object.create(null);
+    strictForEachFn(errorInstanceWhitelist, function(name) {
+      // We cannot yet use StringMap so do it manually
+      // We do this naively here assuming we don't need to worry about
+      // __proto__
+      result[name] = true;
+    });
+    return result;
+  }
+
+  function freshHiddenPropertyCandidates() {
+    var result = freshErrorInstanceWhiteMap();
+    strictForEachFn(errorInstanceBlacklist, function(name) {
+      result[name] = true;
+    });
+    return result;
+  }
+
+  /**
+   * Do Error instances on thos platform carry own properties that we
+   * haven't yet examined and determined to be SES-safe?
+   *
+   * <p>A new property should only be added to the
+   * errorInstanceWhitelist after inspecting the consequences of that
+   * property to determine that it does not compromise SES safety. If
+   * some platform maker does add an Error own property that does
+   * compromise SES safety, that might be a severe problem, if we
+   * can't find a way to deny untrusted code access to that property.
+   */
+  function test_UNEXPECTED_ERROR_PROPERTIES() {
+    var errs = [new Error('e1')];
+    try { null.foo = 3; } catch (err) { errs.push(err); }
+    var result = false;
+
+    var approvedNames = freshErrorInstanceWhiteMap();
+
+    strictForEachFn(errs, function(err) {
+      strictForEachFn(Object.getOwnPropertyNames(err), function(name) {
+         if (!(name in approvedNames)) {
+           result = 'Unexpected error instance property: ' + name;
+           // would be good to terminate early
+         }
+      });
+    });
+    return result;
+  }
+
+  /**
+   *
+   */
+  function test_GET_OWN_PROPERTY_NAME_LIES() {
+    var gopn = Object.getOwnPropertyNames;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    var suspects = [new Error('e1')];
+    try { null.foo = 3; } catch (err) { suspects.push(err); }
+
+    var unreported = Object.create(null);
+
+    strictForEachFn(suspects, function(suspect) {
+      var candidates = freshHiddenPropertyCandidates();
+      strictForEachFn(gopn(suspect), function(name) {
+        // Delete the candidates that are reported
+        delete candidates[name];
+      });
+      strictForEachFn(gopn(candidates), function(name) {
+        if (!gopd(suspect, name)) {
+          // Delete the candidates that are not own properties
+          delete candidates[name];
+        }
+      });
+      strictForEachFn(gopn(candidates), function(name) {
+        unreported[name] = true;
+      });
+    });
+
+    var unreportedNames = gopn(unreported);
+    if (unreportedNames.length === 0) { return false; }
+    return 'Error own properties unreported by getOwnPropertyNames: ' +
+      unreportedNames.sort().join(',');
+  }
+
+
+  ////////////////////// Repairs /////////////////////
+  //
+  // Each repair_NAME function exists primarily to repair the problem
+  // indicated by the corresponding test_NAME function. But other test
+  // failures can still trigger a given repair.
+
+
+  var call = Function.prototype.call;
+  var apply = Function.prototype.apply;
+
+  var hop = Object.prototype.hasOwnProperty;
+  var slice = Array.prototype.slice;
+  var concat = Array.prototype.concat;
+  var getPrototypeOf = Object.getPrototypeOf;
+
+  function patchMissingProp(base, name, missingFunc) {
+    if (!(name in base)) {
+      Object.defineProperty(base, name, {
+        value: missingFunc,
+        writable: true,
+        enumerable: false,
+        configurable: true
+      });
+    }
+  }
+
+  function repair_MISSING_FREEZE_ETC() {
+    patchMissingProp(Object, 'freeze',
+                     function fakeFreeze(obj) { return obj; });
+    patchMissingProp(Object, 'seal',
+                     function fakeSeal(obj) { return obj; });
+    patchMissingProp(Object, 'preventExtensions',
+                     function fakePreventExtensions(obj) { return obj; });
+    patchMissingProp(Object, 'isFrozen',
+                     function fakeIsFrozen(obj) { return false; });
+    patchMissingProp(Object, 'isSealed',
+                     function fakeIsSealed(obj) { return false; });
+    patchMissingProp(Object, 'isExtensible',
+                     function fakeIsExtensible(obj) { return true; });
+  }
+
+  function repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES() {
+    var unsafeDefProp = Object.defineProperty;
+    function repairedDefineProperty(base, name, desc) {
+      if (typeof base === 'function' &&
+          name === 'prototype' &&
+          'value' in desc) {
+        try {
+          base.prototype = desc.value;
+        } catch (err) {
+          logger.warn('prototype fixup failed', err);
+        }
+      }
+      return unsafeDefProp(base, name, desc);
+    }
+    Object.defineProperty(Object, 'defineProperty', {
+      value: repairedDefineProperty
+    });
+  }
+
+  function repair_MISSING_CALLEE_DESCRIPTOR() {
+    var realGOPN = Object.getOwnPropertyNames;
+    Object.defineProperty(Object, 'getOwnPropertyNames', {
+      value: function calleeFix(base) {
+        var result = realGOPN(base);
+        if (typeof base === 'function') {
+          var i = result.indexOf('callee');
+          if (i >= 0 && !hop.call(base, 'callee')) {
+            result.splice(i, 1);
+          }
+        }
+        return result;
+      }
+    });
+  }
+
+  function repair_REGEXP_CANT_BE_NEUTERED() {
+    var UnsafeRegExp = RegExp;
+    var FakeRegExp = function RegExpWrapper(pattern, flags) {
+      switch (arguments.length) {
+        case 0: {
+          return UnsafeRegExp();
+        }
+        case 1: {
+          return UnsafeRegExp(pattern);
+        }
+        default: {
+          return UnsafeRegExp(pattern, flags);
+        }
+      }
+    };
+    Object.defineProperty(FakeRegExp, 'prototype', {
+      value: UnsafeRegExp.prototype
+    });
+    Object.defineProperty(FakeRegExp.prototype, 'constructor', {
+      value: FakeRegExp
+    });
+    RegExp = FakeRegExp;
+  }
+
+  function repair_REGEXP_TEST_EXEC_UNSAFE() {
+    var unsafeRegExpExec = RegExp.prototype.exec;
+    var unsafeRegExpTest = RegExp.prototype.test;
+
+    Object.defineProperty(RegExp.prototype, 'exec', {
+      value: function fakeExec(specimen) {
+        return unsafeRegExpExec.call(this, String(specimen));
+      }
+    });
+    Object.defineProperty(RegExp.prototype, 'test', {
+      value: function fakeTest(specimen) {
+        return unsafeRegExpTest.call(this, String(specimen));
+      }
+    });
+  }
+
+  function repair_MISSING_BIND() {
+
+    /**
+     * Actual bound functions are not supposed to have a prototype, and
+     * are supposed to curry over both the [[Call]] and [[Construct]]
+     * behavior of their original function. However, in ES5,
+     * functions written in JavaScript cannot avoid having a 'prototype'
+     * property, and cannot reliably distinguish between being called as
+     * a function vs as a constructor, i.e., by {@code new}.
+     *
+     * <p>Since the repair_MISSING_BIND emulation produces a bound
+     * function written in JavaScript, it cannot faithfully emulate
+     * either the lack of a 'prototype' property nor the currying of the
+     * [[Construct]] behavior. So instead, we use BOGUS_BOUND_PROTOTYPE
+     * to reliably give an error for attempts to {@code new} a bound
+     * function. Since we cannot avoid exposing BOGUS_BOUND_PROTOTYPE
+     * itself, it is possible to pass in a this-binding which inherits
+     * from it without using {@code new}, which will also trigger our
+     * error case. Whether this latter error is appropriate or not, it
+     * still fails safe.
+     *
+     * <p>By making the 'prototype' of the bound function be the same as
+     * the current {@code thisFunc.prototype}, we could have emulated
+     * the [[HasInstance]] property of bound functions. But even this
+     * would have been inaccurate, since we would be unable to track
+     * changes to the original {@code thisFunc.prototype}. (We cannot
+     * make 'prototype' into an accessor to do this tracking, since
+     * 'prototype' on a function written in JavaScript is
+     * non-configurable.) And this one partially faithful emulation
+     * would have come at the cost of no longer being able to reasonably
+     * detect construction, in order to safely reject it.
+     */
+    var BOGUS_BOUND_PROTOTYPE = {
+      toString: function BBPToString() { return 'bogus bound prototype'; }
+    };
+    rememberToTamperProof(BOGUS_BOUND_PROTOTYPE);
+    BOGUS_BOUND_PROTOTYPE.toString.prototype = null;
+    rememberToTamperProof(BOGUS_BOUND_PROTOTYPE.toString);
+
+    var defProp = Object.defineProperty;
+    defProp(Function.prototype, 'bind', {
+      value: function fakeBind(self, var_args) {
+        var thisFunc = this;
+        var leftArgs = slice.call(arguments, 1);
+        function funcBound(var_args) {
+          if (this === Object(this) &&
+              getPrototypeOf(this) === BOGUS_BOUND_PROTOTYPE) {
+            throw new TypeError(
+              'Cannot emulate "new" on pseudo-bound function.');
+          }
+          var args = concat.call(leftArgs, slice.call(arguments, 0));
+          return apply.call(thisFunc, self, args);
+        }
+        defProp(funcBound, 'prototype', {
+          value: BOGUS_BOUND_PROTOTYPE,
+          writable: false,
+          configurable: false
+        });
+        return funcBound;
+      },
+      writable: true,
+      enumerable: false,
+      configurable: true
+    });
+  }
+
+  /**
+   * Return a function suitable for using as a forEach argument on a
+   * list of method names, where that function will monkey patch each
+   * of these names methods on {@code constr.prototype} so that they
+   * can't be called on a {@code constr.prototype} itself even across
+   * frames.
+   *
+   * <p>This only works when {@code constr} corresponds to an internal
+   * [[Class]] property whose value is {@code classString}. To test
+   * for {@code constr.prototype} cross-frame, we observe that for all
+   * objects of this [[Class]], only the prototypes directly inherit
+   * from an object that does not have this [[Class]].
+   */
+  function makeMutableProtoPatcher(constr, classString) {
+    var proto = constr.prototype;
+    var baseToString = objToString.call(proto);
+    if (baseToString !== '[object ' + classString + ']') {
+      throw new TypeError('unexpected: ' + baseToString);
+    }
+    var grandProto = getPrototypeOf(proto);
+    var grandBaseToString = objToString.call(grandProto);
+    if (grandBaseToString === '[object ' + classString + ']') {
+      throw new TypeError('malformed inheritance: ' + classString);
+    }
+    if (grandProto !== Object.prototype) {
+      logger.log('unexpected inheritance: ' + classString);
+    }
+    function mutableProtoPatcher(name) {
+      if (!hop.call(proto, name)) { return; }
+      var originalMethod = proto[name];
+      function replacement(var_args) {
+        var parent = getPrototypeOf(this);
+        if (parent !== proto) {
+          // In the typical case, parent === proto, so the above test
+          // lets the typical case succeed quickly.
+          // Note that, even if parent === proto, that does not
+          // necessarily mean that the method application will
+          // succeed, since, for example, a non-Date can still inherit
+          // from Date.prototype. However, in such cases, the built-in
+          // method application will fail on its own without our help.
+          if (objToString.call(parent) !== baseToString) {
+            // As above, === baseToString does not necessarily mean
+            // success, but the built-in failure again would not need
+            // our help.
+            var thisToString = objToString.call(this);
+            if (thisToString === baseToString) {
+              throw new TypeError('May not mutate internal state of a ' +
+                                  classString + '.prototype');
+            } else {
+              throw new TypeError('Unexpected: ' + thisToString);
+            }
+          }
+        }
+        return originalMethod.apply(this, arguments);
+      }
+      Object.defineProperty(proto, name, { value: replacement });
+    }
+    return mutableProtoPatcher;
+  }
+
+
+  function repair_MUTABLE_DATE_PROTO() {
+    // Note: coordinate this list with maintenance of whitelist.js
+    ['setYear',
+     'setTime',
+     'setFullYear',
+     'setUTCFullYear',
+     'setMonth',
+     'setUTCMonth',
+     'setDate',
+     'setUTCDate',
+     'setHours',
+     'setUTCHours',
+     'setMinutes',
+     'setUTCMinutes',
+     'setSeconds',
+     'setUTCSeconds',
+     'setMilliseconds',
+     'setUTCMilliseconds'].forEach(makeMutableProtoPatcher(Date, 'Date'));
+  }
+
+  function repair_MUTABLE_WEAKMAP_PROTO() {
+    // Note: coordinate this list with maintanence of whitelist.js
+    ['set',
+     'delete'].forEach(makeMutableProtoPatcher(WeakMap, 'WeakMap'));
+  }
+
+  function repair_NEED_TO_WRAP_FOREACH() {
+    var forEach = Array.prototype.forEach;
+    Object.defineProperty(Array.prototype, 'forEach', {
+      value: function forEachWrapper(callbackfn, opt_thisArg) {
+        return forEach.apply(this, arguments);
+      }
+    });
+  }
+
+
+  function repair_NEEDS_DUMMY_SETTER() {
+    var defProp = Object.defineProperty;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    function dummySetter(newValue) {
+      throw new TypeError('no setter for assigning: ' + newValue);
+    }
+    dummySetter.prototype = null;
+    rememberToTamperProof(dummySetter);
+
+    defProp(Object, 'defineProperty', {
+      value: function setSetterDefProp(base, name, desc) {
+        if (typeof desc.get === 'function' && desc.set === void 0) {
+          var oldDesc = gopd(base, name);
+          if (oldDesc) {
+            var testBase = {};
+            defProp(testBase, name, oldDesc);
+            defProp(testBase, name, desc);
+            desc = gopd(testBase, name);
+            if (desc.set === void 0) { desc.set = dummySetter; }
+          } else {
+            if (objToString.call(base) === '[object HTMLFormElement]') {
+              // This repair was triggering bug
+              // http://code.google.com/p/chromium/issues/detail?id=94666
+              // on Chrome, causing
+              // http://code.google.com/p/google-caja/issues/detail?id=1401
+              // so if base is an HTMLFormElement we skip this
+              // fix. Since this repair and this situation are both
+              // Chrome only, it is ok that we're conditioning this on
+              // the unspecified [[Class]] value of base.
+              //
+              // To avoid the further bug identified at Comment 2
+              // http://code.google.com/p/chromium/issues/detail?id=94666#c2
+              // We also have to reconstruct the requested desc so that
+              // the setter is absent. This is why we additionally
+              // condition this special case on the absence of an own
+              // name property on base.
+              var desc2 = { get: desc.get };
+              if ('enumerable' in desc) {
+                desc2.enumerable = desc.enumerable;
+              }
+              if ('configurable' in desc) {
+                desc2.configurable = desc.configurable;
+              }
+              var result = defProp(base, name, desc2);
+              var newDesc = gopd(base, name);
+              if (newDesc.get === desc.get) {
+                return result;
+              }
+            }
+            desc.set = dummySetter;
+          }
+        }
+        return defProp(base, name, desc);
+      }
+    });
+    NEEDS_DUMMY_SETTER_repaired = true;
+  }
+
+
+  function repair_ACCESSORS_INHERIT_AS_OWN() {
+    // restrict these
+    var defProp = Object.defineProperty;
+    var freeze = Object.freeze;
+    var seal = Object.seal;
+
+    // preserve illusion
+    var gopn = Object.getOwnPropertyNames;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    var complaint = 'Workaround for ' +
+      'https://bugzilla.mozilla.org/show_bug.cgi?id=637994 ' +
+      ' prohibits enumerable non-configurable accessor properties.';
+
+    function isBadAccessor(derived, name) {
+      var desc = gopd(derived, name);
+      if (!desc || !('get' in desc)) { return false; }
+      var base = getPrototypeOf(derived);
+      if (!base) { return false; }
+      var superDesc = gopd(base, name);
+      if (!superDesc || !('get' in superDesc)) { return false; }
+      return (desc.get &&
+              !desc.configurable && !superDesc.configurable &&
+              desc.get === superDesc.get &&
+              desc.set === superDesc.set &&
+              desc.enumerable === superDesc.enumerable);
+    }
+
+    defProp(Object, 'defineProperty', {
+      value: function definePropertyWrapper(base, name, desc) {
+        var oldDesc = gopd(base, name);
+        var testBase = {};
+        if (oldDesc && !isBadAccessor(base, name)) {
+          defProp(testBase, name, oldDesc);
+        }
+        defProp(testBase, name, desc);
+        var fullDesc = gopd(testBase, name);
+         if ('get' in fullDesc &&
+            fullDesc.enumerable &&
+            !fullDesc.configurable) {
+          logger.warn(complaint);
+          throw new TypeError(complaint
+              + " (Object: " + base + " Property: " + name + ")");
+        }
+        return defProp(base, name, fullDesc);
+      }
+    });
+
+    function ensureSealable(base) {
+      gopn(base).forEach(function(name) {
+        var desc = gopd(base, name);
+        if ('get' in desc && desc.enumerable) {
+          if (!desc.configurable) {
+            logger.error('New symptom: ' +
+                         '"' + name + '" already non-configurable');
+          }
+          logger.warn(complaint);
+          throw new TypeError(complaint + " (During sealing. Object: "
+              + base + " Property: " + name + ")");
+        }
+      });
+    }
+
+    defProp(Object, 'freeze', {
+      value: function freezeWrapper(base) {
+        ensureSealable(base);
+        return freeze(base);
+      }
+    });
+
+    defProp(Object, 'seal', {
+      value: function sealWrapper(base) {
+        ensureSealable(base);
+        return seal(base);
+      }
+    });
+
+    defProp(Object.prototype, 'hasOwnProperty', {
+      value: function hasOwnPropertyWrapper(name) {
+        return hop.call(this, name) && !isBadAccessor(this, name);
+      }
+    });
+
+    defProp(Object, 'getOwnPropertyDescriptor', {
+      value: function getOwnPropertyDescriptorWrapper(base, name) {
+        if (isBadAccessor(base, name)) { return void 0; }
+        return gopd(base, name);
+      }
+    });
+
+    defProp(Object, 'getOwnPropertyNames', {
+      value: function getOwnPropertyNamesWrapper(base) {
+        return gopn(base).filter(function(name) {
+          return !isBadAccessor(base, name);
+        });
+      }
+    });
+  }
+
+  function repair_SORT_LEAKS_GLOBAL() {
+    var unsafeSort = Array.prototype.sort;
+    function sortWrapper(opt_comparefn) {
+      function comparefnWrapper(x, y) {
+        return opt_comparefn(x, y);
+      }
+      if (arguments.length === 0) {
+        return unsafeSort.call(this);
+      } else {
+        return unsafeSort.call(this, comparefnWrapper);
+      }
+    }
+    Object.defineProperty(Array.prototype, 'sort', {
+      value: sortWrapper
+    });
+  }
+
+  function repair_REPLACE_LEAKS_GLOBAL() {
+    var unsafeReplace = String.prototype.replace;
+    function replaceWrapper(searchValue, replaceValue) {
+      var safeReplaceValue = replaceValue;
+      function replaceValueWrapper(m1, m2, m3) {
+        return replaceValue(m1, m2, m3);
+      }
+      if (typeof replaceValue === 'function') {
+        safeReplaceValue = replaceValueWrapper;
+      }
+      return unsafeReplace.call(this, searchValue, safeReplaceValue);
+    }
+    Object.defineProperty(String.prototype, 'replace', {
+      value: replaceWrapper
+    });
+  }
+
+  function repair_CANT_GOPD_CALLER() {
+    var unsafeGOPD = Object.getOwnPropertyDescriptor;
+    function gopdWrapper(base, name) {
+      try {
+        return unsafeGOPD(base, name);
+      } catch (err) {
+        if (err instanceof TypeError &&
+            typeof base === 'function' &&
+            (name === 'caller' || name === 'arguments')) {
+          return (function(message) {
+             function fakePoison() { throw new TypeError(message); }
+             fakePoison.prototype = null;
+             return {
+               get: fakePoison,
+               set: fakePoison,
+               enumerable: false,
+               configurable: false
+             };
+           })(err.message);
+        }
+        throw err;
+      }
+    }
+    Object.defineProperty(Object, 'getOwnPropertyDescriptor', {
+      value: gopdWrapper
+    });
+  }
+
+  function repair_CANT_HASOWNPROPERTY_CALLER() {
+    Object.defineProperty(Object.prototype, 'hasOwnProperty', {
+      value: function hopWrapper(name) {
+        return !!Object.getOwnPropertyDescriptor(this, name);
+      }
+    });
+  }
+
+  function makeHarmless(magicName, func, path) {
+    function poison() {
+      throw new TypeError('Cannot access property ' + path);
+    }
+    poison.prototype = null;
+    var desc = Object.getOwnPropertyDescriptor(func, magicName);
+    if ((!desc && Object.isExtensible(func)) || desc.configurable) {
+      try {
+        Object.defineProperty(func, magicName, {
+          get: poison,
+          set: poison,
+          configurable: false
+        });
+      } catch (cantPoisonErr) {
+        return 'Poisoning failed with ' + cantPoisonErr;
+      }
+      desc = Object.getOwnPropertyDescriptor(func, magicName);
+      if (desc &&
+          desc.get === poison &&
+          desc.set === poison &&
+          !desc.configurable) {
+        return 'Apparently poisoned';
+      }
+      return 'Not poisoned';
+    }
+    if ('get' in desc || 'set' in desc) {
+      return 'Apparently safe';
+    }
+    try {
+      Object.defineProperty(func, magicName, {
+        value: desc.value === null ? null : void 0,
+        writable: false,
+        configurable: false
+      });
+    } catch (cantFreezeHarmlessErr) {
+      return 'Freezing harmless failed with ' + cantFreezeHarmlessErr;
+    }
+    desc = Object.getOwnPropertyDescriptor(func, magicName);
+    if (desc &&
+        (desc.value === null || desc.value === void 0) &&
+        !desc.writable &&
+        !desc.configurable) {
+      return 'Apparently frozen harmless';
+    }
+    return 'Did not freeze harmless';
+  }
+
+  function repair_BUILTIN_LEAKS_CALLER() {
+    // The call to .bind as a method here is fine since it happens
+    // after all repairs which might fix .bind and before any
+    // untrusted code runs.
+    ses.makeCallerHarmless = makeHarmless.bind(void 0, 'caller');
+    //logger.info(ses.makeCallerHarmless(builtInMapMethod));
+  }
+
+  function repair_BUILTIN_LEAKS_ARGUMENTS() {
+    // The call to .bind as a method here is fine since it happens
+    // after all repairs which might fix .bind and before any
+    // untrusted code runs.
+    ses.makeArgumentsHarmless = makeHarmless.bind(void 0, 'arguments');
+    //logger.info(ses.makeArgumentsHarmless(builtInMapMethod));
+  }
+
+  function repair_DELETED_BUILTINS_IN_OWN_NAMES() {
+    var realGOPN = Object.getOwnPropertyNames;
+    var repairedHop = Object.prototype.hasOwnProperty;
+    function getOnlyRealOwnPropertyNames(base) {
+      return realGOPN(base).filter(function(name) {
+        return repairedHop.call(base, name);
+      });
+    }
+    Object.defineProperty(Object, 'getOwnPropertyNames', {
+      value: getOnlyRealOwnPropertyNames
+    });
+  }
+
+  function repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS() {
+    var realGOPD = Object.getOwnPropertyDescriptor;
+    function GOPDWrapper(base, name) {
+      return realGOPD(base, name);
+    }
+    Object.defineProperty(Object, 'getOwnPropertyDescriptor', {
+      value: GOPDWrapper
+    });
+  }
+
+  function repair_JSON_PARSE_PROTO_CONFUSION() {
+    var unsafeParse = JSON.parse;
+    function validate(plainJSON) {
+      if (plainJSON !== Object(plainJSON)) {
+        // If we were trying to do a full validation, we would
+        // validate that it is not NaN, Infinity, -Infinity, or
+        // (if nested) undefined. However, we are currently only
+        // trying to repair
+        // http://code.google.com/p/v8/issues/detail?id=621
+        // That's why this special case validate function is private
+        // to this repair.
+        return;
+      }
+      var proto = getPrototypeOf(plainJSON);
+      if (proto !== Object.prototype && proto !== Array.prototype) {
+        throw new TypeError(
+          'Parse resulted in invalid JSON. ' +
+            'See http://code.google.com/p/v8/issues/detail?id=621');
+      }
+      Object.keys(plainJSON).forEach(function(key) {
+        validate(plainJSON[key]);
+      });
+    }
+    Object.defineProperty(JSON, 'parse', {
+      value: function parseWrapper(text, opt_reviver) {
+        var result = unsafeParse(text);
+        validate(result);
+        if (opt_reviver) {
+          return unsafeParse(text, opt_reviver);
+        } else {
+          return result;
+        }
+      },
+      writable: true,
+      enumerable: false,
+      configurable: true
+    });
+  }
+
+  function repair_PARSEINT_STILL_PARSING_OCTAL() {
+    var badParseInt = parseInt;
+    function goodParseInt(n, radix) {
+      n = '' + n;
+      // This turns an undefined radix into a NaN but is ok since NaN
+      // is treated as undefined by badParseInt
+      radix = +radix;
+      var isHexOrOctal = /^\s*[+-]?\s*0(x?)/.exec(n);
+      var isOct = isHexOrOctal ? isHexOrOctal[1] !== 'x' : false;
+
+      if (isOct && (radix !== radix || 0 === radix)) {
+        return badParseInt(n, 10);
+      }
+      return badParseInt(n, radix);
+    }
+    parseInt = goodParseInt;
+  }
+
+  function repair_ASSIGN_CAN_OVERRIDE_FROZEN() {
+    makeTamperProof = function simpleMakeTamperProof() {
+      return Object.freeze;
+    };
+  }
+
+  function repair_CANT_REDEFINE_NAN_TO_ITSELF() {
+    var defProp = Object.defineProperty;
+    // 'value' handled separately
+    var attrs = ['writable', 'get', 'set', 'enumerable', 'configurable'];
+
+    defProp(Object, 'defineProperty', {
+      value: function(base, name, desc) {
+        try {
+          return defProp(base, name, desc);
+        } catch (err) {
+          var oldDesc = Object.getOwnPropertyDescriptor(base, name);
+          for (var i = 0, len = attrs.length; i < len; i++) {
+            var attr = attrs[i];
+            if (attr in desc && desc[attr] !== oldDesc[attr]) { throw err; }
+          }
+          if (!('value' in desc) || is(desc.value, oldDesc.value)) {
+            return base;
+          }
+          throw err;
+        }
+      }
+    });
+  }
+
+
+  ////////////////////// Kludge Records /////////////////////
+  //
+  // Each kludge record has a <dl>
+  //   <dt>description:</dt>
+  //     <dd>a string describing the problem</dd>
+  //   <dt>test:</dt>
+  //     <dd>a predicate testing for the presence of the problem</dd>
+  //   <dt>repair:</dt>
+  //     <dd>a function which attempts repair, or undefined if no
+  //         repair is attempted for this problem</dd>
+  //   <dt>preSeverity:</dt>
+  //     <dd>an enum (see below) indicating the level of severity of
+  //         this problem if unrepaired. Or, if !canRepair, then
+  //         the severity whether or not repaired.</dd>
+  //   <dt>canRepair:</dt>
+  //     <dd>a boolean indicating "if the repair exists and the test
+  //         subsequently does not detect a problem, are we now ok?"</dd>
+  //   <dt>urls:</dt>
+  //     <dd>a list of URL strings, each of which points at a page
+  //         relevant for documenting or tracking the bug in
+  //         question. These are typically into bug-threads in issue
+  //         trackers for the various browsers.</dd>
+  //   <dt>sections:</dt>
+  //     <dd>a list of strings, each of which is a relevant ES5.1
+  //         section number.</dd>
+  //   <dt>tests:</dt>
+  //     <dd>a list of strings, each of which is the name of a
+  //         relevant test262 or sputnik test case.</dd>
+  // </dl>
+  // These kludge records are the meta-data driving the testing and
+  // repairing.
+
+  var severities = ses.severities;
+  var statuses = ses.statuses;
+
+  /**
+   * First test whether the platform can even support our repair
+   * attempts.
+   */
+  var baseKludges = [
+    {
+      description: 'Missing getOwnPropertyNames',
+      test: test_MISSING_GETOWNPROPNAMES,
+      repair: void 0,
+      preSeverity: severities.NOT_SUPPORTED,
+      canRepair: false,
+      urls: [],
+      sections: ['15.2.3.4'],
+      tests: ['15.2.3.4-0-1']
+    }
+  ];
+
+  /**
+   * Run these only if baseKludges report success.
+   */
+  var supportedKludges = [
+    {
+      description: 'Global object leaks from global function calls',
+      test: test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=64250'],
+      sections: ['10.2.1.2', '10.2.1.2.6'],
+      tests: ['10.4.3-1-8gs']
+    },
+    {
+      description: 'Global object leaks from anonymous function calls',
+      test: test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.4.3'],
+      tests: ['S10.4.3_A1']
+    },
+    {
+      description: 'Global leaks through strict this',
+      test: test_GLOBAL_LEAKS_FROM_STRICT_THIS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.4.3'],
+      tests: ['10.4.3-1-8gs', '10.4.3-1-8-s']
+    },
+    {
+      description: 'Global object leaks from built-in methods',
+      test: test_GLOBAL_LEAKS_FROM_BUILTINS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=51097',
+             'https://bugs.webkit.org/show_bug.cgi?id=58338',
+             'http://code.google.com/p/v8/issues/detail?id=1437',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685430/global-object-leaks-from-built-in-methods'],
+      sections: ['15.2.4.4'],
+      tests: ['S15.2.4.4_A14']
+    },
+    {
+      description: 'Global object leaks from globally called built-in methods',
+      test: test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.2.1.2', '10.2.1.2.6', '15.2.4.4'],
+      tests: ['S15.2.4.4_A15']
+    },
+    {
+      description: 'Object.freeze is missing',
+      test: test_MISSING_FREEZE_ETC,
+      repair: repair_MISSING_FREEZE_ETC,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,           // repair for development, not safety
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=55736'],
+      sections: ['15.2.3.9'],
+      tests: ['15.2.3.9-0-1']
+    },
+    {
+      description: 'A function.prototype\'s descriptor lies',
+      test: test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,
+      repair: repair_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1530',
+             'http://code.google.com/p/v8/issues/detail?id=1570'],
+      sections: ['15.2.3.3', '15.2.3.6', '15.3.5.2'],
+      tests: ['S15.3.3.1_A4']
+    },
+    {
+      description: 'Phantom callee on strict functions',
+      test: test_MISSING_CALLEE_DESCRIPTOR,
+      repair: repair_MISSING_CALLEE_DESCRIPTOR,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=55537'],
+      sections: ['15.2.3.4'],
+      tests: ['S15.2.3.4_A1_T1']
+    },
+    {
+      description: 'Strict delete returned false rather than throwing',
+      test: test_STRICT_DELETE_RETURNS_FALSE,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://connect.microsoft.com/IE/feedback/details/' +
+               '685432/strict-delete-sometimes-returns-false-' +
+               'rather-than-throwing'],
+      sections: ['11.4.1'],
+      tests: ['S11.4.1_A5']
+    },
+    {
+      description: 'Non-deletable RegExp statics are a' +
+        ' global communication channel',
+      test: test_REGEXP_CANT_BE_NEUTERED,
+      repair: repair_REGEXP_CANT_BE_NEUTERED,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685439/non-deletable-regexp-statics-are-a-global-' +
+               'communication-channel'],
+      sections: ['11.4.1'],
+      tests: ['S11.4.1_A5']
+    },
+    {
+      description: 'RegExp.exec leaks match globally',
+      test: test_REGEXP_TEST_EXEC_UNSAFE,
+      repair: repair_REGEXP_TEST_EXEC_UNSAFE,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1393',
+             'http://code.google.com/p/chromium/issues/detail?id=75740',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=635017',
+             'http://code.google.com/p/google-caja/issues/detail?id=528'],
+      sections: ['15.10.6.2'],
+      tests: ['S15.10.6.2_A12']
+    },
+    {
+      description: 'Function.prototype.bind is missing',
+      test: test_MISSING_BIND,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=26382',
+             'https://bugs.webkit.org/show_bug.cgi?id=42371'],
+      sections: ['15.3.4.5'],
+      tests: ['S15.3.4.5_A3']
+    },
+    {
+      description: 'Function.prototype.bind calls .apply rather than [[Call]]',
+      test: test_BIND_CALLS_APPLY,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=892',
+             'http://code.google.com/p/v8/issues/detail?id=828'],
+      sections: ['15.3.4.5.1'],
+      tests: ['S15.3.4.5_A4']
+    },
+    {
+      description: 'Function.prototype.bind does not curry construction',
+      test: test_BIND_CANT_CURRY_NEW,
+      repair: void 0, // JS-based repair essentially impossible
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=26382#c29'],
+      sections: ['15.3.4.5.2'],
+      tests: ['S15.3.4.5_A5']
+    },
+    {
+      description: 'Date.prototype is a global communication channel',
+      test: test_MUTABLE_DATE_PROTO,
+      repair: repair_MUTABLE_DATE_PROTO,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/google-caja/issues/detail?id=1362'],
+      sections: ['15.9.5'],
+      tests: []
+    },
+    {
+      description: 'WeakMap.prototype is a global communication channel',
+      test: test_MUTABLE_WEAKMAP_PROTO,
+      repair: repair_MUTABLE_WEAKMAP_PROTO,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=656828'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Array forEach cannot be frozen while in progress',
+      test: test_NEED_TO_WRAP_FOREACH,
+      repair: repair_NEED_TO_WRAP_FOREACH,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1447'],
+      sections: ['15.4.4.18'],
+      tests: ['S15.4.4.18_A1', 'S15.4.4.18_A2']
+    },
+    {
+      description: 'Workaround undiagnosed need for dummy setter',
+      test: test_NEEDS_DUMMY_SETTER,
+      repair: repair_NEEDS_DUMMY_SETTER,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: [],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Getter on HTMLFormElement disappears',
+      test: test_FORM_GETTERS_DISAPPEAR,
+      repair: repair_NEEDS_DUMMY_SETTER,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/chromium/issues/detail?id=94666',
+             'http://code.google.com/p/v8/issues/detail?id=1651',
+             'http://code.google.com/p/google-caja/issues/detail?id=1401'],
+      sections: ['15.2.3.6'],
+      tests: ['S15.2.3.6_A1']
+    },
+    {
+      description: 'Accessor properties inherit as own properties',
+      test: test_ACCESSORS_INHERIT_AS_OWN,
+      repair: repair_ACCESSORS_INHERIT_AS_OWN,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=637994'],
+      sections: ['8.6.1', '15.2.3.6'],
+      tests: ['S15.2.3.6_A2']
+    },
+    {
+      description: 'Array sort leaks global',
+      test: test_SORT_LEAKS_GLOBAL,
+      repair: repair_SORT_LEAKS_GLOBAL,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1360'],
+      sections: ['15.4.4.11'],
+      tests: ['S15.4.4.11_A8']
+    },
+    {
+      description: 'String replace leaks global',
+      test: test_REPLACE_LEAKS_GLOBAL,
+      repair: repair_REPLACE_LEAKS_GLOBAL,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1360',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685928/bad-this-binding-for-callback-in-string-' +
+               'prototype-replace'],
+      sections: ['15.5.4.11'],
+      tests: ['S15.5.4.11_A12']
+    },
+    {
+      description: 'getOwnPropertyDescriptor on strict "caller" throws',
+      test: test_CANT_GOPD_CALLER,
+      repair: repair_CANT_GOPD_CALLER,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://connect.microsoft.com/IE/feedback/details/' +
+               '685436/getownpropertydescriptor-on-strict-caller-throws'],
+      sections: ['15.2.3.3', '13.2', '13.2.3'],
+      tests: ['S13.2_A6_T1']
+    },
+    {
+      description: 'strict_function.hasOwnProperty("caller") throws',
+      test: test_CANT_HASOWNPROPERTY_CALLER,
+      repair: repair_CANT_HASOWNPROPERTY_CALLER,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398#c3'],
+      sections: ['15.2.4.5', '13.2', '13.2.3'],
+      tests: ['S13.2_A7_T1']
+    },
+    {
+      description: 'Cannot "in" caller on strict function',
+      test: test_CANT_IN_CALLER,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['11.8.7', '13.2', '13.2.3'],
+      tests: ['S13.2_A8_T1']
+    },
+    {
+      description: 'Cannot "in" arguments on strict function',
+      test: test_CANT_IN_ARGUMENTS,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['11.8.7', '13.2', '13.2.3'],
+      tests: ['S13.2_A8_T2']
+    },
+    {
+      description: 'Strict "caller" not poisoned',
+      test: test_STRICT_CALLER_NOT_POISONED,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: [],
+      sections: ['13.2'],
+      tests: ['S13.2.3_A1']
+    },
+    {
+      description: 'Strict "arguments" not poisoned',
+      test: test_STRICT_ARGUMENTS_NOT_POISONED,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: [],
+      sections: ['13.2'],
+      tests: ['S13.2.3_A1']
+    },
+    {
+      description: 'Built in functions leak "caller"',
+      test: test_BUILTIN_LEAKS_CALLER,
+      repair: repair_BUILTIN_LEAKS_CALLER,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1643',
+             'http://code.google.com/p/v8/issues/detail?id=1548',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable'],
+      sections: [],
+      tests: ['Sbp_A10_T1']
+    },
+    {
+      description: 'Built in functions leak "arguments"',
+      test: test_BUILTIN_LEAKS_ARGUMENTS,
+      repair: repair_BUILTIN_LEAKS_ARGUMENTS,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1643',
+             'http://code.google.com/p/v8/issues/detail?id=1548',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable'],
+      sections: [],
+      tests: ['Sbp_A10_T2']
+    },
+    {
+      description: 'Bound functions leak "caller"',
+      test: test_BOUND_FUNCTION_LEAKS_CALLER,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=893',
+             'https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['15.3.4.5'],
+      tests: ['S13.2.3_A1', 'S15.3.4.5_A1']
+    },
+    {
+      description: 'Bound functions leak "arguments"',
+      test: test_BOUND_FUNCTION_LEAKS_ARGUMENTS,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=893',
+             'https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['15.3.4.5'],
+      tests: ['S13.2.3_A1', 'S15.3.4.5_A2']
+    },
+    {
+      description: 'Deleting built-in leaves phantom behind',
+      test: test_DELETED_BUILTINS_IN_OWN_NAMES,
+      repair: repair_DELETED_BUILTINS_IN_OWN_NAMES,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=70207'],
+      sections: ['15.2.3.4'],
+      tests: []
+    },
+    {
+      description: 'getOwnPropertyDescriptor on its own "caller" fails',
+      test: test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,
+      repair: repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1769'],
+      sections: ['13.2', '15.2.3.3'],
+      tests: []
+    },
+    {
+      description: 'JSON.parse confused by "__proto__"',
+      test: test_JSON_PARSE_PROTO_CONFUSION,
+      repair: repair_JSON_PARSE_PROTO_CONFUSION,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=621',
+             'http://code.google.com/p/v8/issues/detail?id=1310'],
+      sections: ['15.12.2'],
+      tests: ['S15.12.2_A1']
+    },
+    {
+      description: 'Prototype still mutable on non-extensible object',
+      test: test_PROTO_NOT_FROZEN,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=65832',
+             'https://bugs.webkit.org/show_bug.cgi?id=78438'],
+      sections: ['8.6.2'],
+      tests: ['S8.6.2_A8']
+    },
+    {
+      description: 'Prototype still redefinable on non-extensible object',
+      test: test_PROTO_REDEFINABLE,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=65832'],
+      sections: ['8.6.2'],
+      tests: ['S8.6.2_A8']
+    },
+    {
+      description: 'Strict eval function leaks variable definitions',
+      test: test_STRICT_EVAL_LEAKS_GLOBALS,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1624'],
+      sections: ['10.4.2.1'],
+      tests: ['S10.4.2.1_A1']
+    },
+    {
+      description: 'parseInt still parsing octal',
+      test: test_PARSEINT_STILL_PARSING_OCTAL,
+      repair: repair_PARSEINT_STILL_PARSING_OCTAL,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1645'],
+      sections: ['15.1.2.2'],
+      tests: ['S15.1.2.2_A5.1_T1']
+    },
+    {
+      description: 'E4X literals allowed in strict code',
+      test: test_STRICT_E4X_LITERALS_ALLOWED,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=695577',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=695579'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Assignment can override frozen inherited property',
+      test: test_ASSIGN_CAN_OVERRIDE_FROZEN,
+      repair: repair_ASSIGN_CAN_OVERRIDE_FROZEN,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1169',
+             'https://mail.mozilla.org/pipermail/es-discuss/' +
+               '2011-November/017997.html'],
+      sections: ['8.12.4'],
+      tests: ['15.2.3.6-4-405']
+    },
+    {
+      description: 'Cannot redefine global NaN to itself',
+      test: test_CANT_REDEFINE_NAN_TO_ITSELF,
+      repair: repair_CANT_REDEFINE_NAN_TO_ITSELF,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: [], // Seen on WebKit Nightly. TODO(erights): report
+      sections: ['8.12.9', '15.1.1.1'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Error instances have unexpected properties',
+      test: test_UNEXPECTED_ERROR_PROPERTIES,
+      repair: void 0,
+      preSeverity: severities.NEW_SYMPTOM,
+      canRepair: false,
+      urls: [],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'getOwnPropertyNames lies, hiding some own properties',
+      test: test_GET_OWN_PROPERTY_NAME_LIES,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=726477'],
+      sections: [],
+      tests: []
+    }
+  ];
+
+  ////////////////////// Testing, Repairing, Reporting ///////////
+
+  var aboutTo = void 0;
+
+  /**
+   * Run a set of tests & repairs, and report results.
+   *
+   * <p>First run all the tests before repairing anything.
+   * Then repair all repairable failed tests.
+   * Some repair might fix multiple problems, but run each repair at most once.
+   * Then run all the tests again, in case some repairs break other tests.
+   * And finally return a list of records of results.
+   */
+  function testRepairReport(kludges) {
+    var beforeFailures = strictMapFn(kludges, function(kludge) {
+      aboutTo = ['pre test: ', kludge.description];
+      return kludge.test();
+    });
+    var repairs = [];
+    strictForEachFn(kludges, function(kludge, i) {
+      if (beforeFailures[i]) {
+        var repair = kludge.repair;
+        if (repair && repairs.lastIndexOf(repair) === -1) {
+          aboutTo = ['repair: ', kludge.description];
+          repair();
+          repairs.push(repair);
+        }
+      }
+    });
+    var afterFailures = strictMapFn(kludges, function(kludge) {
+      aboutTo = ['post test: ', kludge.description];
+      return kludge.test();
+    });
+
+    if (Object.isFrozen && Object.isFrozen(Array.prototype.forEach)) {
+      // Need to do it anyway, to repair the sacrificial freezing we
+      // needed to do to test. Once we can permanently retire this
+      // test, we can also retire the redundant repair.
+      repair_NEED_TO_WRAP_FOREACH();
+    }
+
+    return strictMapFn(kludges, function(kludge, i) {
+      var status = statuses.ALL_FINE;
+      var postSeverity = severities.SAFE;
+      var beforeFailure = beforeFailures[i];
+      var afterFailure = afterFailures[i];
+      if (beforeFailure) { // failed before
+        if (afterFailure) { // failed after
+          if (kludge.repair) {
+            postSeverity = kludge.preSeverity;
+            status = statuses.REPAIR_FAILED;
+          } else {
+            if (!kludge.canRepair) {
+              postSeverity = kludge.preSeverity;
+            } // else no repair + canRepair -> problem isn't safety issue
+            status = statuses.NOT_REPAIRED;
+          }
+        } else { // succeeded after
+          if (kludge.repair) {
+            if (!kludge.canRepair) {
+              // repair for development, not safety
+              postSeverity = kludge.preSeverity;
+              status = statuses.REPAIRED_UNSAFELY;
+            } else {
+              status = statuses.REPAIRED;
+            }
+          } else {
+            status = statuses.ACCIDENTALLY_REPAIRED;
+          }
+        }
+      } else { // succeeded before
+        if (afterFailure) { // failed after
+          if (kludge.repair || !kludge.canRepair) {
+            postSeverity = kludge.preSeverity;
+          } // else no repair + canRepair -> problem isn't safety issue
+          status = statuses.BROKEN_BY_OTHER_ATTEMPTED_REPAIRS;
+        } else { // succeeded after
+          // nothing to see here, move along
+        }
+      }
+
+      if (typeof beforeFailure === 'string' ||
+          typeof afterFailure === 'string') {
+        postSeverity = severities.NEW_SYMPTOM;
+      }
+
+      ses.updateMaxSeverity(postSeverity);
+
+      return {
+        description:   kludge.description,
+        preSeverity:   kludge.preSeverity,
+        canRepair:     kludge.canRepair,
+        urls:          kludge.urls,
+        sections:      kludge.sections,
+        tests:         kludge.tests,
+        status:        status,
+        postSeverity:  postSeverity,
+        beforeFailure: beforeFailure,
+        afterFailure:  afterFailure
+      };
+    });
+  }
+
+  try {
+    var reports = testRepairReport(baseKludges);
+    if (ses.ok()) {
+      reports.push.apply(reports, testRepairReport(supportedKludges));
+    }
+    logger.reportRepairs(reports);
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    var during = aboutTo ? '(' + aboutTo.join('') + ') ' : '';
+    logger.error('ES5 Repair ' + during + 'failed with: ', err);
+  }
+
+  logger.reportMax();
+
+})(this);
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Install a leaky WeakMap emulation on platforms that
+ * don't provide a built-in one.
+ *
+ * <p>Assumes that an ES5 platform where, if {@code WeakMap} is
+ * already present, then it conforms to the anticipated ES6
+ * specification. To run this file on an ES5 or almost ES5
+ * implementation where the {@code WeakMap} specification does not
+ * quite conform, run <code>repairES5.js</code> first.
+ *
+ * @author Mark S. Miller
+ * @requires ses, crypto, ArrayBuffer, Uint8Array
+ * @overrides WeakMap, WeakMapModule
+ */
+
+/**
+ * This {@code WeakMap} emulation is observably equivalent to the
+ * ES-Harmony WeakMap, but with leakier garbage collection properties.
+ *
+ * <p>As with true WeakMaps, in this emulation, a key does not
+ * retain maps indexed by that key and (crucially) a map does not
+ * retain the keys it indexes. A map by itself also does not retain
+ * the values associated with that map.
+ *
+ * <p>However, the values associated with a key in some map are
+ * retained so long as that key is retained and those associations are
+ * not overridden. For example, when used to support membranes, all
+ * values exported from a given membrane will live for the lifetime
+ * they would have had in the absence of an interposed membrane. Even
+ * when the membrane is revoked, all objects that would have been
+ * reachable in the absence of revocation will still be reachable, as
+ * far as the GC can tell, even though they will no longer be relevant
+ * to ongoing computation.
+ *
+ * <p>The API implemented here is approximately the API as implemented
+ * in FF6.0a1 and agreed to by MarkM, Andreas Gal, and Dave Herman,
+ * rather than the offially approved proposal page. TODO(erights):
+ * upgrade the ecmascript WeakMap proposal page to explain this API
+ * change and present to EcmaScript committee for their approval.
+ *
+ * <p>The first difference between the emulation here and that in
+ * FF6.0a1 is the presence of non enumerable {@code get___, has___,
+ * set___, and delete___} methods on WeakMap instances to represent
+ * what would be the hidden internal properties of a primitive
+ * implementation. Whereas the FF6.0a1 WeakMap.prototype methods
+ * require their {@code this} to be a genuine WeakMap instance (i.e.,
+ * an object of {@code [[Class]]} "WeakMap}), since there is nothing
+ * unforgeable about the pseudo-internal method names used here,
+ * nothing prevents these emulated prototype methods from being
+ * applied to non-WeakMaps with pseudo-internal methods of the same
+ * names.
+ *
+ * <p>Another difference is that our emulated {@code
+ * WeakMap.prototype} is not itself a WeakMap. A problem with the
+ * current FF6.0a1 API is that WeakMap.prototype is itself a WeakMap
+ * providing ambient mutability and an ambient communications
+ * channel. Thus, if a WeakMap is already present and has this
+ * problem, repairES5.js wraps it in a safe wrappper in order to
+ * prevent access to this channel. (See
+ * PATCH_MUTABLE_FROZEN_WEAKMAP_PROTO in repairES5.js).
+ */
+var WeakMap;
+
+/**
+ * If this is a full <a href=
+ * "http://code.google.com/p/es-lab/wiki/SecureableES5"
+ * >secureable ES5</a> platform and the ES-Harmony {@code WeakMap} is
+ * absent, install an approximate emulation.
+ *
+ * <p>If this is almost a secureable ES5 platform, then WeakMap.js
+ * should be run after repairES5.js.
+ *
+ * <p>See {@code WeakMap} for documentation of the garbage collection
+ * properties of this WeakMap emulation.
+ */
+(function WeakMapModule() {
+  "use strict";
+
+  if (typeof ses !== 'undefined' && ses.ok && !ses.ok()) {
+    // already too broken, so give up
+    return;
+  }
+
+  if (typeof WeakMap === 'function') {
+    // assumed fine, so we're done.
+    return;
+  }
+
+  var hop = Object.prototype.hasOwnProperty;
+  var gopn = Object.getOwnPropertyNames;
+  var defProp = Object.defineProperty;
+
+  /**
+   * Holds the orginal static properties of the Object constructor,
+   * after repairES5 fixes these if necessary to be a more complete
+   * secureable ES5 environment, but before installing the following
+   * WeakMap emulation overrides and before any untrusted code runs.
+   */
+  var originalProps = {};
+  gopn(Object).forEach(function(name) {
+    originalProps[name] = Object[name];
+  });
+
+  /**
+   * Security depends on HIDDEN_NAME being both <i>unguessable</i> and
+   * <i>undiscoverable</i> by untrusted code.
+   *
+   * <p>Given the known weaknesses of Math.random() on existing
+   * browsers, it does not generate unguessability we can be confident
+   * of.
+   *
+   * <p>It is the monkey patching logic in this file that is intended
+   * to ensure undiscoverability. The basic idea is that there are
+   * three fundamental means of discovering properties of an object:
+   * The for/in loop, Object.keys(), and Object.getOwnPropertyNames(),
+   * as well as some proposed ES6 extensions that appear on our
+   * whitelist. The first two only discover enumerable properties, and
+   * we only use HIDDEN_NAME to name a non-enumerable property, so the
+   * only remaining threat should be getOwnPropertyNames and some
+   * proposed ES6 extensions that appear on our whitelist. We monkey
+   * patch them to remove HIDDEN_NAME from the list of properties they
+   * returns.
+   *
+   * <p>TODO(erights): On a platform with built-in Proxies, proxies
+   * could be used to trap and thereby discover the HIDDEN_NAME, so we
+   * need to monkey patch Proxy.create, Proxy.createFunction, etc, in
+   * order to wrap the provided handler with the real handler which
+   * filters out all traps using HIDDEN_NAME.
+   *
+   * <p>TODO(erights): Revisit Mike Stay's suggestion that we use an
+   * encapsulated function at a not-necessarily-secret name, which
+   * uses the Stiegler shared-state rights amplification pattern to
+   * reveal the associated value only to the WeakMap in which this key
+   * is associated with that value. Since only the key retains the
+   * function, the function can also remember the key without causing
+   * leakage of the key, so this doesn't violate our general gc
+   * goals. In addition, because the name need not be a guarded
+   * secret, we could efficiently handle cross-frame frozen keys.
+   */
+  var HIDDEN_NAME = 'ident:' + Math.random() + '___';
+
+  if (typeof crypto !== 'undefined' &&
+      typeof crypto.getRandomValues === 'function' &&
+      typeof ArrayBuffer === 'function' &&
+      typeof Uint8Array === 'function') {
+    var ab = new ArrayBuffer(25);
+    var u8s = new Uint8Array(ab);
+    crypto.getRandomValues(u8s);
+    HIDDEN_NAME = 'rand:' +
+      Array.prototype.map.call(u8s, function(u8) {
+        return (u8 % 36).toString(36);
+      }).join('') + '___';
+  }
+
+  /**
+   * Monkey patch getOwnPropertyNames to avoid revealing the
+   * HIDDEN_NAME.
+   *
+   * <p>The ES5.1 spec requires each name to appear only once, but as
+   * of this writing, this requirement is controversial for ES6, so we
+   * made this code robust against this case. If the resulting extra
+   * search turns out to be expensive, we can probably relax this once
+   * ES6 is adequately supported on all major browsers, iff no browser
+   * versions we support at that time have relaxed this constraint
+   * without providing built-in ES6 WeakMaps.
+   */
+  defProp(Object, 'getOwnPropertyNames', {
+    value: function fakeGetOwnPropertyNames(obj) {
+      return gopn(obj).filter(function(name) {
+        return name !== HIDDEN_NAME;
+      });
+    }
+  });
+
+  /**
+   * getPropertyNames is not in ES5 but it is proposed for ES6 and
+   * does appear in our whitelist, so we need to clean it too.
+   */
+  if ('getPropertyNames' in Object) {
+    defProp(Object, 'getPropertyNames', {
+      value: function fakeGetPropertyNames(obj) {
+        return originalProps.getPropertyNames(obj).filter(function(name) {
+          return name !== HIDDEN_NAME;
+        });
+      }
+    });
+  }
+
+  /**
+   * <p>To treat objects as identity-keys with reasonable efficiency
+   * on ES5 by itself (i.e., without any object-keyed collections), we
+   * need to add a hidden property to such key objects when we
+   * can. This raises several issues:
+   * <ul>
+   * <li>Arranging to add this property to objects before we lose the
+   *     chance, and
+   * <li>Hiding the existence of this new property from most
+   *     JavaScript code.
+   * <li>Preventing <i>certification theft</i>, where one object is
+   *     created falsely claiming to be the key of an association
+   *     actually keyed by another object.
+   * <li>Preventing <i>value theft</i>, where untrusted code with
+   *     access to a key object but not a weak map nevertheless
+   *     obtains access to the value associated with that key in that
+   *     weak map.
+   * </ul>
+   * We do so by
+   * <ul>
+   * <li>Making the name of the hidden property unguessable, so "[]"
+   *     indexing, which we cannot intercept, cannot be used to access
+   *     a property without knowing the name.
+   * <li>Making the hidden property non-enumerable, so we need not
+   *     worry about for-in loops or {@code Object.keys},
+   * <li>monkey patching those reflective methods that would
+   *     prevent extensions, to add this hidden property first,
+   * <li>monkey patching those methods that would reveal this
+   *     hidden property.
+   * </ul>
+   * Unfortunately, because of same-origin iframes, we cannot reliably
+   * add this hidden property before an object becomes
+   * non-extensible. Instead, if we encounter a non-extensible object
+   * without a hidden record that we can detect (whether or not it has
+   * a hidden record stored under a name secret to us), then we just
+   * use the key object itself to represent its identity in a brute
+   * force leaky map stored in the weak map, losing all the advantages
+   * of weakness for these.
+   */
+  function getHiddenRecord(key) {
+    if (key !== Object(key)) {
+      throw new TypeError('Not an object: ' + key);
+    }
+    var hiddenRecord = key[HIDDEN_NAME];
+    if (hiddenRecord && hiddenRecord.key === key) { return hiddenRecord; }
+    if (!originalProps.isExtensible(key)) {
+      // Weak map must brute force, as explained in doc-comment above.
+      return void 0;
+    }
+    var gets = [];
+    var vals = [];
+    hiddenRecord = {
+      key: key,   // self pointer for quick own check above.
+      gets: gets, // get___ methods identifying weak maps
+      vals: vals  // values associated with this key in each
+                  // corresponding weak map.
+    };
+    defProp(key, HIDDEN_NAME, {
+      value: hiddenRecord,
+      writable: false,
+      enumerable: false,
+      configurable: false
+    });
+    return hiddenRecord;
+  }
+
+
+  /**
+   * Monkey patch operations that would make their argument
+   * non-extensible.
+   *
+   * <p>The monkey patched versions throw a TypeError if their
+   * argument is not an object, so it should only be done to functions
+   * that should throw a TypeError anyway if their argument is not an
+   * object.
+   */
+  (function(){
+    var oldFreeze = Object.freeze;
+    defProp(Object, 'freeze', {
+      value: function identifyingFreeze(obj) {
+        getHiddenRecord(obj);
+        return oldFreeze(obj);
+      }
+    });
+    var oldSeal = Object.seal;
+    defProp(Object, 'seal', {
+      value: function identifyingSeal(obj) {
+        getHiddenRecord(obj);
+        return oldSeal(obj);
+      }
+    });
+    var oldPreventExtensions = Object.preventExtensions;
+    defProp(Object, 'preventExtensions', {
+      value: function identifyingPreventExtensions(obj) {
+        getHiddenRecord(obj);
+        return oldPreventExtensions(obj);
+      }
+    });
+  })();
+
+
+  function constFunc(func) {
+    func.prototype = null;
+    return Object.freeze(func);
+  }
+
+  // Right now (12/25/2012) the histogram supports the current
+  // representation. We should check this occasionally, as a true
+  // constant time representation is easy.
+  // var histogram = [];
+
+  WeakMap = function() {
+    // We are currently (12/25/2012) never encountering any prematurely
+    // non-extensible keys.
+    var keys = []; // brute force for prematurely non-extensible keys.
+    var vals = []; // brute force for corresponding values.
+
+    function get___(key, opt_default) {
+      var hr = getHiddenRecord(key);
+      var i, vs;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        vs = hr.vals;
+      } else {
+        i = keys.indexOf(key);
+        vs = vals;
+      }
+      return (i >= 0) ? vs[i] : opt_default;
+    }
+
+    function has___(key) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+      } else {
+        i = keys.indexOf(key);
+      }
+      return i >= 0;
+    }
+
+    function set___(key, value) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        if (i >= 0) {
+          hr.vals[i] = value;
+        } else {
+//          i = hr.gets.length;
+//          histogram[i] = (histogram[i] || 0) + 1;
+          hr.gets.push(get___);
+          hr.vals.push(value);
+        }
+      } else {
+        i = keys.indexOf(key);
+        if (i >= 0) {
+          vals[i] = value;
+        } else {
+          keys.push(key);
+          vals.push(value);
+        }
+      }
+    }
+
+    function delete___(key) {
+      var hr = getHiddenRecord(key);
+      var i;
+      if (hr) {
+        i = hr.gets.indexOf(get___);
+        if (i >= 0) {
+          hr.gets.splice(i, 1);
+          hr.vals.splice(i, 1);
+        }
+      } else {
+        i = keys.indexOf(key);
+        if (i >= 0) {
+          keys.splice(i, 1);
+          vals.splice(i, 1);
+        }
+      }
+      return true;
+    }
+
+    return Object.create(WeakMap.prototype, {
+      get___:    { value: constFunc(get___) },
+      has___:    { value: constFunc(has___) },
+      set___:    { value: constFunc(set___) },
+      delete___: { value: constFunc(delete___) }
+    });
+  };
+  WeakMap.prototype = Object.create(Object.prototype, {
+    get: {
+      /**
+       * Return the value most recently associated with key, or
+       * opt_default if none.
+       */
+      value: function get(key, opt_default) {
+        return this.get___(key, opt_default);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    has: {
+      /**
+       * Is there a value associated with key in this WeakMap?
+       */
+      value: function has(key) {
+        return this.has___(key);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    set: {
+      /**
+       * Associate value with key in this WeakMap, overwriting any
+       * previous association if present.
+       */
+      value: function set(key, value) {
+        this.set___(key, value);
+      },
+      writable: true,
+      configurable: true
+    },
+
+    'delete': {
+      /**
+       * Remove any association for key in this WeakMap, returning
+       * whether there was one.
+       *
+       * <p>Note that the boolean return here does not work like the
+       * {@code delete} operator. The {@code delete} operator returns
+       * whether the deletion succeeds at bringing about a state in
+       * which the deleted property is absent. The {@code delete}
+       * operator therefore returns true if the property was already
+       * absent, whereas this {@code delete} method returns false if
+       * the association was already absent.
+       */
+      value: function remove(key) {
+        return this.delete___(key);
+      },
+      writable: true,
+      configurable: true
+    }
+  });
+
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview An optional part of the SES initialization process
+ * that saves potentially valuable debugging aids on the side before
+ * startSES.js would remove these, and adds a debugging API which uses
+ * these without compromising SES security.
+ *
+ * <p>NOTE: The currently exposed debugging API is far from
+ * settled. This module is currently in an exploratory phase.
+ *
+ * <p>Meant to be run sometime after repairs are done and a working
+ * WeakMap is available, but before startSES.js. initSES.js includes
+ * this. initSESPlus.js does not.
+ *
+ * //provides ses.UnsafeError,
+ * //provides ses.getCWStack ses.stackString ses.getStack
+ * @author Mark S. Miller
+ * @requires WeakMap, this
+ * @overrides Error, ses, debugModule
+ */
+
+var Error;
+var ses;
+
+(function debugModule(global) {
+   "use strict";
+
+
+   /**
+    * Save away the original Error constructor as ses.UnsafeError and
+    * make it otheriwse unreachable. Replace it with a reachable
+    * wrapping constructor with the same standard behavior.
+    *
+    * <p>When followed by the rest of SES initialization, the
+    * UnsafeError we save off here is exempt from whitelist-based
+    * extra property removal and primordial freezing. Thus, we can
+    * use any platform specific APIs defined on Error for privileged
+    * debugging operations, unless explicitly turned off below.
+    */
+   var UnsafeError = Error;
+   ses.UnsafeError = Error;
+   function FakeError(message) {
+     return UnsafeError(message);
+   }
+   FakeError.prototype = UnsafeError.prototype;
+   FakeError.prototype.constructor = FakeError;
+
+   Error = FakeError;
+
+   /**
+    * Should be a function of an argument object (normally an error
+    * instance) that returns the stack trace associated with argument
+    * in Causeway format.
+    *
+    * <p>See http://wiki.erights.org/wiki/Causeway_Platform_Developer
+    *
+    * <p>Currently, there is no one portable technique for doing
+    * this. So instead, each platform specific branch of the if below
+    * should assign something useful to getCWStack.
+    */
+   ses.getCWStack = function uselessGetCWStack(err) { return void 0; };
+
+   if ('captureStackTrace' in UnsafeError) {
+     (function() {
+       // Assuming http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+       // So this section is v8 specific.
+
+       UnsafeError.prepareStackTrace = function(err, sst) {
+         ssts.set(err, sst);
+         return void 0;
+       };
+
+       var unsafeCaptureStackTrace = UnsafeError.captureStackTrace;
+
+       // TODO(erights): This seems to be write only. Can this be made
+       // safe enough to expose to untrusted code?
+       UnsafeError.captureStackTrace = function(obj, opt_MyError) {
+         var wasFrozen = Object.isFrozen(obj);
+         var stackDesc = Object.getOwnPropertyDescriptor(obj, 'stack');
+         try {
+           var result = unsafeCaptureStackTrace(obj, opt_MyError);
+           var ignore = obj.stack;
+           return result;
+         } finally {
+           if (wasFrozen && !Object.isFrozen(obj)) {
+             if (stackDesc) {
+               Object.defineProperty(obj, 'stack', stackDesc);
+             } else {
+               delete obj.stack;
+             }
+             Object.freeze(obj);
+           }
+         }
+       };
+
+       var ssts = WeakMap(); // error -> sst
+
+       /**
+        * Returns a stack in Causeway format.
+        *
+        * <p>Based on
+        * http://code.google.com/p/causeway/source/browse/trunk/src/js/com/teleometry/causeway/purchase_example/workers/makeCausewayLogger.js
+        */
+       function getCWStack(err) {
+         var sst = ssts.get(err);
+         if (sst === void 0 && err instanceof Error) {
+           // We hope it triggers prepareStackTrace
+           var ignore = err.stack;
+           sst = ssts.get(err);
+         }
+         if (sst === void 0) { return void 0; }
+
+         return { calls: sst.map(function(frame) {
+           return {
+             name: '' + (frame.getFunctionName() ||
+                         frame.getMethodName() || '?'),
+             source: '' + (frame.getFileName() || '?'),
+             span: [ [ frame.getLineNumber(), frame.getColumnNumber() ] ]
+           };
+         })};
+       };
+       ses.getCWStack = getCWStack;
+     })();
+
+   } else if (global.opera) {
+     (function() {
+       // Since pre-ES5 browsers are disqualified, we can assume a
+       // minimum of Opera 11.60.
+     })();
+
+
+   } else if (new Error().stack) {
+     (function() {
+       var FFFramePattern = (/^([^@]*)@(.*?):?(\d*)$/);
+
+       // stacktracejs.org suggests that this indicates FF. Really?
+       function getCWStack(err) {
+         var stack = err.stack;
+         if (!stack) { return void 0; }
+         var lines = stack.split('\n');
+         var frames = lines.map(function(line) {
+           var match = FFFramePattern.exec(line);
+           if (match) {
+             return {
+               name: match[1].trim() || '?',
+               source: match[2].trim() || '?',
+               span: [[+match[3]]]
+             };
+           } else {
+             return {
+               name: line.trim() || '?',
+               source: '?',
+               span: []
+             };
+           }
+         });
+         return { calls: frames };
+       }
+
+       ses.getCWStack = getCWStack;
+     })();
+
+   } else {
+     (function() {
+       // Including Safari and IE10.
+     })();
+
+   }
+
+   /**
+    * Turn a Causeway stack into a v8-like stack traceback string.
+    */
+   function stackString(cwStack) {
+     if (!cwStack) { return void 0; }
+     var calls = cwStack.calls;
+
+     var result = calls.map(function(call) {
+
+       var spanString = call.span.map(function(subSpan) {
+         return subSpan.join(':');
+       }).join('::');
+       if (spanString) { spanString = ':' + spanString; }
+
+       return '  at ' + call.name + ' (' + call.source + spanString + ')';
+
+     });
+     return result.join('\n');
+   };
+   ses.stackString = stackString;
+
+   /**
+    * Return the v8-like stack traceback string associated with err.
+    */
+   function getStack(err) {
+     if (err !== Object(err)) { return void 0; }
+     var cwStack = ses.getCWStack(err);
+     if (!cwStack) { return void 0; }
+     var result = ses.stackString(cwStack);
+     if (err instanceof Error) { result = err + '\n' + result; }
+     return result;
+   };
+   ses.getStack = getStack;
+
+ })(this);;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Implements StringMap - a map api for strings.
+ *
+ * @author Mark S. Miller
+ * @author Jasvir Nagra
+ * @overrides StringMap
+ */
+
+var StringMap;
+
+(function() {
+   "use strict";
+
+   var create = Object.create;
+   var freeze = Object.freeze;
+   function constFunc(func) {
+     func.prototype = null;
+     return freeze(func);
+   }
+
+   function assertString(x) {
+     if ('string' !== typeof(x)) {
+       throw new TypeError('Not a string: ' + String(x));
+     }
+     return x;
+   }
+
+   StringMap = function StringMap() {
+
+     var objAsMap = create(null);
+
+     return freeze({
+       get: constFunc(function(key) {
+         return objAsMap[assertString(key) + '$'];
+       }),
+       set: constFunc(function(key, value) {
+         objAsMap[assertString(key) + '$'] = value;
+       }),
+       has: constFunc(function(key) {
+         return (assertString(key) + '$') in objAsMap;
+       }),
+       'delete': constFunc(function(key) {
+         return delete objAsMap[assertString(key) + '$'];
+       })
+     });
+   };
+
+ })();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports {@code ses.whitelist}, a recursively defined
+ * JSON record enumerating all the naming paths in the ES5.1 spec,
+ * those de-facto extensions that we judge to be safe, and SES and
+ * Dr. SES extensions provided by the SES runtime.
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * //provides ses.whitelist
+ * @author Mark S. Miller,
+ * @overrides ses, whitelistModule
+ */
+var ses;
+
+/**
+ * <p>Each JSON record enumerates the disposition of the properties on
+ * some corresponding primordial object, with the root record
+ * representing the global object. For each such record, the values
+ * associated with its property names can be
+ * <ul>
+ * <li>Another record, in which case this property is simply
+ *     whitelisted and that next record represents the disposition of
+ *     the object which is its value. For example, {@code "Object"}
+ *     leads to another record explaining what properties {@code
+ *     "Object"} may have and how each such property, if present,
+ *     and its value should be tamed.
+ * <li>true, in which case this property is simply whitelisted. The
+ *     value associated with that property is still traversed and
+ *     tamed, but only according to the taming of the objects that
+ *     object inherits from. For example, {@code "Object.freeze"} leads
+ *     to true, meaning that the {@code "freeze"} property of {@code
+ *     Object} should be whitelisted and the value of the property (a
+ *     function) should be further tamed only according to the
+ *     markings of the other objects it inherits from, like {@code
+ *     "Function.prototype"} and {@code "Object.prototype").
+ * <li>"*", in which case this property on this object is whitelisted,
+ *     as is this property as inherited by all objects that inherit
+ *     from this object. The values associated with all such properties
+ *     are still traversed and tamed, but only according to the taming
+ *     of the objects that object inherits from. For example, {@code
+ *     "Object.prototype.constructor"} leads to "*", meaning that we
+ *     whitelist the {@code "constructor"} property on {@code
+ *     Object.prototype} and on every object that inherits from {@code
+ *     Object.prototype} that does not have a conflicting mark. Each
+ *     of these is tamed as if with true, so that the value of the
+ *     property is further tamed according to what other objects it
+ *     inherits from.
+ * <li>"skip", in which case this property on this object is simply
+ *     whitelisted, as is this property as inherited by all objects
+ *     that inherit from this object, but we avoid taming the value
+ *     associated with that property. For example, as of this writing
+ *     {@code "Function.prototype.caller"} leads to "skip" because
+ *     some current browser bugs prevent us from removing or even
+ *     traversing this property on some platforms of interest.
+ * </ul>
+ *
+ * The "skip" markings are workarounds for browser bugs or other
+ * temporary problems. For each of these, there should be an
+ * explanatory comment explaining why or a bug citation. Ideally, we
+ * can retire all "skip" entries by the time SES is ready for secure
+ * production use.
+ *
+ * The members of the whitelist are either
+ * <ul>
+ * <li>(uncommented) defined by the ES5.1 normative standard text,
+ * <li>(questionable) provides a source of non-determinism, in
+ *     violation of pure object-capability rules, but allowed anyway
+ *     since we've given up on restricting JavaScript to a
+ *     deterministic subset.
+ * <li>(ES5 Appendix B) common elements of de facto JavaScript
+ *     described by the non-normative Appendix B.
+ * <li>(Harmless whatwg) extensions documented at
+ *     <a href="http://wiki.whatwg.org/wiki/Web_ECMAScript"
+ *     >http://wiki.whatwg.org/wiki/Web_ECMAScript</a> that seem to be
+ *     harmless. Note that the RegExp constructor extensions on that
+ *     page are <b>not harmless</b> and so must not be whitelisted.
+ * <li>(ES-Harmony proposal) accepted as "proposal" status for
+ *     EcmaScript-Harmony.
+ * <li>(Marked as "skip") See above.
+ * </ul>
+ *
+ * <p>With the above encoding, there are some sensible whitelists we
+ * cannot express, such as marking a property both with "*" and a JSON
+ * record. This is an expedient decision based only on not having
+ * encountered such a need. Should we need this extra expressiveness,
+ * we'll need to refactor to enable a different encoding.
+ *
+ * <p>We factor out {@code true} into the variable {@code t} just to
+ * get a bit better compression from simple minifiers.
+ */
+(function whitelistModule() {
+  "use strict";
+
+  if (!ses) { ses = {}; }
+
+  var t = true;
+  ses.whitelist = {
+    cajaVM: {                        // Caja support
+      log: t,
+      tamperProof: t,
+      constFunc: t,
+      def: t,
+      is: t,
+
+      compileExpr: t,
+      compileModule: t,              // experimental
+      compileProgram: t,             // Cannot be implemented in just ES5.1.
+      eval: t,
+      Function: t,
+
+      sharedImports: t,
+      makeImports: t,
+      copyToImports: t,
+
+      callWithEjector: t,
+      eject: t,
+      GuardT: {
+        coerce: t
+      },
+      makeTableGuard: t,
+      Trademark: {
+        stamp: t
+      },
+      guard: t,
+      passesGuard: t,
+      stamp: t,
+      makeSealerUnsealerPair: t,
+
+      makeArrayLike: {}
+    },
+    WeakMap: {       // ES-Harmony proposal as currently implemented by FF6.0a1
+      prototype: {
+        // Note: coordinate this list with maintenance of repairES5.js
+        get: t,
+        set: t,
+        has: t,
+        'delete': t
+      }
+    },
+    StringMap: {  // A specialized approximation of ES-Harmony's Map.
+      prototype: {} // Technically, the methods should be on the prototype,
+                    // but doing so while preserving encapsulation will be
+                    // needlessly expensive for current usage.
+    },
+// As of this writing, the WeakMap emulation in WeakMap.js relies on
+// the unguessability and undiscoverability of HIDDEN_NAME, a
+// secret property name. However, on a platform with built-in
+// Proxies, if whitelisted but not properly monkey patched, proxies
+// could be used to trap and thereby discover HIDDEN_NAME. So until we
+// (TODO(erights)) write the needed monkey patching of proxies, we
+// omit them from our whitelist.
+//    Proxy: {                         // ES-Harmony proposal
+//      create: t,
+//      createFunction: t
+//    },
+    escape: t,                       // ES5 Appendix B
+    unescape: t,                     // ES5 Appendix B
+    Object: {
+      // If any new methods are added here that may reveal the
+      // HIDDEN_NAME within WeakMap.js, such as the proposed
+      // getOwnPropertyDescriptors or getPropertyDescriptors, then
+      // extend WeakMap.js to monkey patch these to avoid revealing
+      // HIDDEN_NAME.
+      getPropertyDescriptor: t,      // ES-Harmony proposal
+      getPropertyNames: t,           // ES-Harmony proposal
+      is: t,                         // ES-Harmony proposal
+      prototype: {
+
+        // Whitelisted only to work around a Chrome debugger
+        // stratification bug (TODO(erights): report). These are
+        // redefined in startSES.js in terms of standard methods, so
+        // that we can be confident they introduce no non-standard
+        // possibilities.
+        __defineGetter__: t,
+        __defineSetter__: t,
+        __lookupGetter__: t,
+        __lookupSetter__: t,
+
+        constructor: '*',
+        toString: '*',
+        toLocaleString: '*',
+        valueOf: t,
+        hasOwnProperty: t,
+        isPrototypeOf: t,
+        propertyIsEnumerable: t
+      },
+      getPrototypeOf: t,
+      getOwnPropertyDescriptor: t,
+      getOwnPropertyNames: t,
+      create: t,
+      defineProperty: t,
+      defineProperties: t,
+      seal: t,
+      freeze: t,
+      preventExtensions: t,
+      isSealed: t,
+      isFrozen: t,
+      isExtensible: t,
+      keys: t
+    },
+    NaN: t,
+    Infinity: t,
+    undefined: t,
+    // eval: t,                      // Whitelisting under separate control
+                                     // by TAME_GLOBAL_EVAL in startSES.js
+    parseInt: t,
+    parseFloat: t,
+    isNaN: t,
+    isFinite: t,
+    decodeURI: t,
+    decodeURIComponent: t,
+    encodeURI: t,
+    encodeURIComponent: t,
+    Function: {
+      prototype: {
+        apply: t,
+        call: t,
+        bind: t,
+        prototype: '*',
+        length: '*',
+        arity: '*',                  // non-std, deprecated in favor of length
+        name: '*'                    // non-std
+      }
+    },
+    Array: {
+      prototype: {
+        concat: t,
+        join: t,
+        pop: t,
+        push: t,
+        reverse: t,
+        shift: t,
+        slice: t,
+        sort: t,
+        splice: t,
+        unshift: t,
+        indexOf: t,
+        lastIndexOf: t,
+        every: t,
+        some: t,
+        forEach: t,
+        map: t,
+        filter: t,
+        reduce: t,
+        reduceRight: t,
+        length: 'skip'               // can't be redefined on Mozilla
+        // See https://bugzilla.mozilla.org/show_bug.cgi?id=591059
+        // and https://bugzilla.mozilla.org/show_bug.cgi?id=598996
+      },
+      isArray: t
+    },
+    String: {
+      prototype: {
+        substr: t,                   // ES5 Appendix B
+        anchor: t,                   // Harmless whatwg
+        big: t,                      // Harmless whatwg
+        blink: t,                    // Harmless whatwg
+        bold: t,                     // Harmless whatwg
+        fixed: t,                    // Harmless whatwg
+        fontcolor: t,                // Harmless whatwg
+        fontsize: t,                 // Harmless whatwg
+        italics: t,                  // Harmless whatwg
+        link: t,                     // Harmless whatwg
+        small: t,                    // Harmless whatwg
+        strike: t,                   // Harmless whatwg
+        sub: t,                      // Harmless whatwg
+        sup: t,                      // Harmless whatwg
+        trimLeft: t,                 // non-standard
+        trimRight: t,                // non-standard
+        valueOf: t,
+        charAt: t,
+        charCodeAt: t,
+        concat: t,
+        indexOf: t,
+        lastIndexOf: t,
+        localeCompare: t,
+        match: t,
+        replace: t,
+        search: t,
+        slice: t,
+        split: t,
+        substring: t,
+        toLowerCase: t,
+        toLocaleLowerCase: t,
+        toUpperCase: t,
+        toLocaleUpperCase: t,
+        trim: t,
+        length: '*'
+      },
+      fromCharCode: t
+    },
+    Boolean: {
+      prototype: {
+        valueOf: t
+      }
+    },
+    Number: {
+      prototype: {
+        valueOf: t,
+        toFixed: t,
+        toExponential: t,
+        toPrecision: t
+      },
+      MAX_VALUE: t,
+      MIN_VALUE: t,
+      NaN: t,
+      NEGATIVE_INFINITY: t,
+      POSITIVE_INFINITY: t
+    },
+    Math: {
+      E: t,
+      LN10: t,
+      LN2: t,
+      LOG2E: t,
+      LOG10E: t,
+      PI: t,
+      SQRT1_2: t,
+      SQRT2: t,
+
+      abs: t,
+      acos: t,
+      asin: t,
+      atan: t,
+      atan2: t,
+      ceil: t,
+      cos: t,
+      exp: t,
+      floor: t,
+      log: t,
+      max: t,
+      min: t,
+      pow: t,
+      random: t,                     // questionable
+      round: t,
+      sin: t,
+      sqrt: t,
+      tan: t
+    },
+    Date: {                          // no-arg Date constructor is questionable
+      prototype: {
+        // Note: coordinate this list with maintanence of repairES5.js
+        getYear: t,                  // ES5 Appendix B
+        setYear: t,                  // ES5 Appendix B
+        toGMTString: t,              // ES5 Appendix B
+        toDateString: t,
+        toTimeString: t,
+        toLocaleString: t,
+        toLocaleDateString: t,
+        toLocaleTimeString: t,
+        getTime: t,
+        getFullYear: t,
+        getUTCFullYear: t,
+        getMonth: t,
+        getUTCMonth: t,
+        getDate: t,
+        getUTCDate: t,
+        getDay: t,
+        getUTCDay: t,
+        getHours: t,
+        getUTCHours: t,
+        getMinutes: t,
+        getUTCMinutes: t,
+        getSeconds: t,
+        getUTCSeconds: t,
+        getMilliseconds: t,
+        getUTCMilliseconds: t,
+        getTimezoneOffset: t,
+        setTime: t,
+        setFullYear: t,
+        setUTCFullYear: t,
+        setMonth: t,
+        setUTCMonth: t,
+        setDate: t,
+        setUTCDate: t,
+        setHours: t,
+        setUTCHours: t,
+        setMinutes: t,
+        setUTCMinutes: t,
+        setSeconds: t,
+        setUTCSeconds: t,
+        setMilliseconds: t,
+        setUTCMilliseconds: t,
+        toUTCString: t,
+        toISOString: t,
+        toJSON: t
+      },
+      parse: t,
+      UTC: t,
+      now: t                         // questionable
+    },
+    RegExp: {
+      prototype: {
+        exec: t,
+        test: t,
+        source: '*',
+        global: '*',
+        ignoreCase: '*',
+        multiline: '*',
+        lastIndex: '*',
+        sticky: '*'                  // non-std
+      }
+    },
+    Error: {
+      prototype: {
+        name: '*',
+        message: '*'
+      }
+    },
+    EvalError: {
+      prototype: t
+    },
+    RangeError: {
+      prototype: t
+    },
+    ReferenceError: {
+      prototype: t
+    },
+    SyntaxError: {
+      prototype: t
+    },
+    TypeError: {
+      prototype: t
+    },
+    URIError: {
+      prototype: t
+    },
+    JSON: {
+      parse: t,
+      stringify: t
+    }
+  };
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Export a {@code ses.atLeastFreeVarNames} function for
+ * internal use by the SES-on-ES5 implementation, which enumerates at
+ * least the identifiers which occur freely in a source text string.
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * // provides ses.atLeastFreeVarNames
+ * @author Mark S. Miller
+ * @requires StringMap
+ * @overrides ses, atLeastFreeVarNamesModule
+ */
+var ses;
+
+/**
+ * Calling {@code ses.atLeastFreeVarNames} on a {@code programSrc}
+ * string argument, the result should include at least all the free
+ * variable names of {@code programSrc} as own properties. It is
+ * harmless to include other strings as well.
+ *
+ * <p>Assuming a programSrc that parses as a strict Program,
+ * atLeastFreeVarNames(programSrc) returns a Record whose enumerable
+ * own property names must include the names of all the free variables
+ * occuring in programSrc. It can include as many other strings as is
+ * convenient so long as it includes these. The value of each of these
+ * properties should be {@code true}.
+ *
+ * <p>TODO(erights): On platforms that support Proxies (currently only
+ * FF4 and later), we should stop using atLeastFreeVarNames, since a
+ * {@code with(aProxy) {...}} should reliably intercept all free
+ * variable accesses without needing any prior scan.
+ */
+(function atLeastFreeVarNamesModule() {
+  "use strict";
+
+   if (!ses) { ses = {}; }
+
+  /////////////// KLUDGE SWITCHES ///////////////
+
+  /**
+   * Currently we use this to limit the input text to ascii only
+   * without backslash-u escapes, in order to simply our identifier
+   * gathering.
+   *
+   * <p>This is only a temporary development hack. TODO(erights): fix.
+   */
+  function LIMIT_SRC(programSrc) {
+    if ((/[^\u0000-\u007f]/).test(programSrc)) {
+      throw new EvalError('Non-ascii text not yet supported');
+    }
+    if ((/\\u/).test(programSrc)) {
+      throw new EvalError('Backslash-u escape encoded text not yet supported');
+    }
+  }
+
+  /**
+   * Return a regexp that can be used repeatedly to scan for the next
+   * identifier.
+   *
+   * <p>The current implementation is safe only because of the above
+   * LIMIT_SRC. To do this right takes quite a lot of unicode
+   * machinery. See the "Identifier" production at
+   * http://es-lab.googlecode.com/svn/trunk/src/parser/es5parser.ojs
+   * which depends on
+   * http://es-lab.googlecode.com/svn/trunk/src/parser/unicode.js
+   *
+   * <p>This is only a temporary development hack. TODO(erights): fix.
+   */
+  function SHOULD_MATCH_IDENTIFIER() { return (/(\w|\$)+/g); }
+
+
+  //////////////// END KLUDGE SWITCHES ///////////
+
+  ses.atLeastFreeVarNames = function atLeastFreeVarNames(programSrc) {
+    programSrc = String(programSrc);
+    LIMIT_SRC(programSrc);
+    // Now that we've temporarily limited our attention to ascii...
+    var regexp = SHOULD_MATCH_IDENTIFIER();
+    // Once we decide this file can depends on ES5, the following line
+    // should say "... = Object.create(null);" rather than "... = {};"
+    var result = [];
+    var found = StringMap();
+    var a;
+    while ((a = regexp.exec(programSrc))) {
+      // Note that we could have avoided the while loop by doing
+      // programSrc.match(regexp), except that then we'd need
+      // temporary storage proportional to the total number of
+      // apparent identifiers, rather than the total number of
+      // apparently unique identifiers.
+      var name = a[0];
+
+      if (!found.has(name)) {
+        result.push(name);
+        found.set(name, true);
+      }
+    }
+    return result;
+  };
+
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Make this frame SES-safe or die trying.
+ *
+ * <p>Assumes ES5 plus a WeakMap that conforms to the anticipated ES6
+ * WeakMap spec. Compatible with ES5-strict or anticipated ES6.
+ *
+ * //provides ses.startSES
+ * @author Mark S. Miller,
+ * @requires WeakMap
+ * @overrides ses, console, eval, Function, cajaVM
+ */
+var ses;
+
+
+/**
+ * The global {@code eval} function available to script code, which
+ * may or not be made safe.
+ *
+ * <p>The original global binding of {@code eval} is not
+ * SES-safe. {@code cajaVM.eval} is a safe wrapper around this
+ * original eval, enforcing SES language restrictions.
+ *
+ * <p>If {@code TAME_GLOBAL_EVAL} is true, both the global {@code
+ * eval} variable and {@code sharedImports.eval} are set to the safe
+ * wrapper. If {@code TAME_GLOBAL_EVAL} is false, in order to work
+ * around a bug in the Chrome debugger, then the global {@code eval}
+ * is unaltered and no {@code "eval"} property is available on {@code
+ * sharedImports}. In either case, SES-evaled-code and SES-script-code
+ * can both access the safe eval wrapper as {@code cajaVM.eval}.
+ *
+ * <p>By making the safe eval available on {@code sharedImports} only
+ * when we also make it be the genuine global eval, we preserve the
+ * property that SES-evaled-code differs from SES-script-code only by
+ * having a subset of the same variables in globalish scope. This is a
+ * nice-to-have that makes explanation easier rather than a hard
+ * requirement. With this property, any SES-evaled-code that does not
+ * fail to access a global variable (or to test whether it could)
+ * should operate the same way when run as SES-script-code.
+ *
+ * <p>See doc-comment on cajaVM for the restriction on this API needed
+ * to operate under Caja translation on old browsers.
+ */
+var eval;
+
+/**
+ * The global {@code Function} constructor is always replaced with a
+ * safe wrapper, which is also made available as
+ * {@code sharedImports.Function}.
+ *
+ * <p>Both the original Function constructor and this safe wrapper
+ * point at the original {@code Function.prototype}, so {@code
+ * instanceof} works fine with the wrapper. {@code
+ * Function.prototype.constructor} is set to point at the safe
+ * wrapper, so that only it, and not the unsafe original, is
+ * accessible.
+ *
+ * <p>See doc-comment on cajaVM for the restriction on this API needed
+ * to operate under Caja translation on old browsers.
+ */
+var Function;
+
+/**
+ * A new global exported by SES, intended to become a mostly
+ * compatible API between server-side Caja translation for older
+ * browsers and client-side SES verification for newer browsers.
+ *
+ * <p>Under server-side Caja translation for old pre-ES5 browsers, the
+ * synchronous interface of the evaluation APIs (currently {@code
+ * eval, Function, cajaVM.{compileExpr, compileModule, eval, Function}})
+ * cannot reasonably be provided. Instead, under translation we expect
+ * <ul>
+ * <li>Not to have a binding for {@code "eval"} on
+ *     {@code sharedImports}, just as we would not if
+ *     {@code TAME_GLOBAL_EVAL} is false.
+ * <li>The global {@code eval} seen by scripts is either unaltered (to
+ *     work around the Chrome debugger bug if {@code TAME_GLOBAL_EVAL}
+ *     is false), or is replaced by a function that throws an
+ *     appropriate EvalError diagnostic (if {@code TAME_GLOBAL_EVAL}
+ *     is true).
+ * <li>The global {@code Function} constructor, both as seen by script
+ *     code and evaled code, to throw an appropriate diagnostic.
+ * <li>The {@code Q} API to always be available, to handle
+ *     asynchronous, promise, and remote requests.
+ * <li>The evaluating methods on {@code cajaVM} -- currently {@code
+ *     compileExpr, compileModule, eval, and Function} -- to be remote
+ *     promises for their normal interfaces, which therefore must be
+ *     invoked with {@code Q.post}.
+ * <li>Since {@code Q.post} can be used for asynchronously invoking
+ *     non-promises, invocations like
+ *     {@code Q.post(cajaVM, 'eval', ['2+3'])}, for example,
+ *     will return a promise for a 5. This should work both under Caja
+ *     translation and (TODO(erights)) under SES verification when
+ *     {@code Q} is also installed, and so is the only portable
+ *     evaluating API that SES code should use during this transition
+ *     period.
+ * <li>TODO(erights): {@code Q.post(cajaVM, 'compileModule',
+ *     [moduleSrc]} should eventually pre-load the transitive
+ *     synchronous dependencies of moduleSrc before resolving the
+ *     promise for its result. It currently would not, instead
+ *     requiring its client to do so manually.
+ * </ul>
+ */
+var cajaVM;
+
+/**
+ * <p>{@code ses.startSES} should be called before any other potentially
+ * dangerous script is executed in this frame.
+ *
+ * <p>If {@code ses.startSES} succeeds, the evaluation operations on
+ * {@code cajaVM}, the global {@code Function} contructor, and perhaps
+ * the {@code eval} function (see doc-comment on {@code eval} and
+ * {@code cajaVM}) will only load code according to the <i>loader
+ * isolation</i> rules of the object-capability model, suitable for
+ * loading untrusted code. If all other (trusted) code executed
+ * directly in this frame (i.e., other than through these safe
+ * evaluation operations) takes care to uphold object-capability
+ * rules, then untrusted code loaded via these safe evaluation
+ * operations will be constrained by those rules. TODO(erights):
+ * explain concretely what the trusted code must do or avoid doing to
+ * uphold object-capability rules.
+ *
+ * <p>On a pre-ES5 platform, this script will fail cleanly, leaving
+ * the frame intact. Otherwise, if this script fails, it may leave
+ * this frame in an unusable state. All following description assumes
+ * this script succeeds and that the browser conforms to the ES5
+ * spec. The ES5 spec allows browsers to implement more than is
+ * specified as long as certain invariants are maintained. We further
+ * assume that these extensions are not maliciously designed to obey
+ * the letter of these invariants while subverting the intent of the
+ * spec. In other words, even on an ES5 conformant browser, we do not
+ * presume to defend ourselves from a browser that is out to get us.
+ *
+ * @param global ::Record(any) Assumed to be the real global object
+ *        for some frame. Since {@code ses.startSES} will allow global
+ *        variable references that appear at the top level of the
+ *        whitelist, our safety depends on these variables being
+ *        frozen as a side effect of freezing the corresponding
+ *        properties of {@code global}. These properties are also
+ *        duplicated onto the virtual global objects which are
+ *        provided as the {@code this} binding for the safe
+ *        evaluation calls -- emulating the safe subset of the normal
+ *        global object.
+ *        TODO(erights): Currently, the code has only been tested when
+ *        {@code global} is the global object of <i>this</i>
+ *        frame. The code should be made to work for cross-frame use.
+ * @param whitelist ::Record(Permit) where Permit = true | "*" |
+ *        "skip" | Record(Permit).  Describes the subset of naming
+ *        paths starting from {@code sharedImports} that should be
+ *        accessible. The <i>accessible primordials</i> are all values
+ *        found by navigating these paths starting from {@code
+ *        sharedImports}. All non-whitelisted properties of accessible
+ *        primordials are deleted, and then {@code sharedImports}
+ *        and all accessible primordials are frozen with the
+ *        whitelisted properties frozen as data properties.
+ *        TODO(erights): fix the code and documentation to also
+ *        support confined-ES5, suitable for confining potentially
+ *        offensive code but not supporting defensive code, where we
+ *        skip this last freezing step. With confined-ES5, each frame
+ *        is considered a separate protection domain rather that each
+ *        individual object.
+ * @param atLeastFreeVarNames ::F([string], Record(true))
+ *        Given the sourceText for a strict Program,
+ *        atLeastFreeVarNames(sourceText) returns a Record whose
+ *        enumerable own property names must include the names of all the
+ *        free variables occuring in sourceText. It can include as
+ *        many other strings as is convenient so long as it includes
+ *        these. The value of each of these properties should be
+ *        {@code true}. TODO(erights): On platforms with Proxies
+ *        (currently only Firefox 4 and after), use {@code
+ *        with(aProxy) {...}} to intercept free variables rather than
+ *        atLeastFreeVarNames.
+ * @param extensions ::F([], Record(any)]) A function returning a
+ *        record whose own properties will be copied onto cajaVM. This
+ *        is used for the optional components which bring SES to
+ *        feature parity with the ES5/3 runtime at the price of larger
+ *        code size. At the time that {@code startSES} calls {@code
+ *        extensions}, {@code cajaVM} exists but should not yet be
+ *        used. In particular, {@code extensions} should not call
+ *        {@code cajaVM.def} during this setup, because def would then
+ *        freeze priordials before startSES cleans them (removes
+ *        non-whitelisted properties). The methods that
+ *        {@code extensions} contributes can, of course, use
+ *        {@code cajaVM}, since those methods will only be called once
+ *        {@code startSES} finishes.
+ */
+ses.startSES = function(global,
+                        whitelist,
+                        atLeastFreeVarNames,
+                        extensions) {
+  "use strict";
+
+  /////////////// KLUDGE SWITCHES ///////////////
+
+  /////////////////////////////////
+  // The following are only the minimal kludges needed for the current
+  // Firefox or the current Chrome Beta. At the time of
+  // this writing, these are Firefox 4.0 and Chrome 12.0.742.5 dev
+  // As these move forward, kludges can be removed until we simply
+  // rely on ES5.
+
+  /**
+   * <p>TODO(erights): isolate and report this.
+   *
+   * <p>Workaround for Chrome debugger's own use of 'eval'
+   *
+   * <p>This kludge is safety preserving but not semantics
+   * preserving. When {@code TAME_GLOBAL_EVAL} is false, no {@code
+   * sharedImports.eval} is available, and the 'eval' available as a
+   * global to trusted (script) code is the original 'eval', and so is
+   * not safe.
+   */
+  //var TAME_GLOBAL_EVAL = true;
+  var TAME_GLOBAL_EVAL = false;
+
+  /**
+   * If this is true, then we redefine these to work around a
+   * stratification bug in the Chrome debugger. To allow this, we have
+   * also whitelisted these four properties in whitelist.js
+   */
+  //var EMULATE_LEGACY_GETTERS_SETTERS = false;
+  var EMULATE_LEGACY_GETTERS_SETTERS = true;
+
+  //////////////// END KLUDGE SWITCHES ///////////
+
+
+  var dirty = true;
+
+  var hop = Object.prototype.hasOwnProperty;
+
+  var getProto = Object.getPrototypeOf;
+  var defProp = Object.defineProperty;
+  var gopd = Object.getOwnPropertyDescriptor;
+  var gopn = Object.getOwnPropertyNames;
+  var keys = Object.keys;
+  var freeze = Object.freeze;
+  var create = Object.create;
+
+  /**
+   * Use to tamper proof a function which is not intended to ever be
+   * used as a constructor, since it nulls out the function's
+   * prototype first.
+   */
+  function constFunc(func) {
+    func.prototype = null;
+    return freeze(func);
+  }
+
+
+  function fail(str) {
+    debugger;
+    throw new EvalError(str);
+  }
+
+  if (typeof WeakMap === 'undefined') {
+    fail('No built-in WeakMaps, so WeakMap.js must be loaded first');
+  }
+
+
+  if (EMULATE_LEGACY_GETTERS_SETTERS) {
+    (function(){
+      function legacyDefineGetter(sprop, getter) {
+        sprop = '' + sprop;
+        if (hop.call(this, sprop)) {
+          defProp(this, sprop, { get: getter });
+        } else {
+          defProp(this, sprop, {
+            get: getter,
+            set: undefined,
+            enumerable: true,
+            configurable: true
+          });
+        }
+      }
+      legacyDefineGetter.prototype = null;
+      defProp(Object.prototype, '__defineGetter__', {
+        value: legacyDefineGetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyDefineSetter(sprop, setter) {
+        sprop = '' + sprop;
+        if (hop.call(this, sprop)) {
+          defProp(this, sprop, { set: setter });
+        } else {
+          defProp(this, sprop, {
+            get: undefined,
+            set: setter,
+            enumerable: true,
+            configurable: true
+          });
+        }
+      }
+      legacyDefineSetter.prototype = null;
+      defProp(Object.prototype, '__defineSetter__', {
+        value: legacyDefineSetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyLookupGetter(sprop) {
+        sprop = '' + sprop;
+        var base = this, desc = void 0;
+        while (base && !(desc = gopd(base, sprop))) { base = getProto(base); }
+        return desc && desc.get;
+      }
+      legacyLookupGetter.prototype = null;
+      defProp(Object.prototype, '__lookupGetter__', {
+        value: legacyLookupGetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyLookupSetter(sprop) {
+        sprop = '' + sprop;
+        var base = this, desc = void 0;
+        while (base && !(desc = gopd(base, sprop))) { base = getProto(base); }
+        return desc && desc.set;
+      }
+      legacyLookupSetter.prototype = null;
+      defProp(Object.prototype, '__lookupSetter__', {
+        value: legacyLookupSetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+    })();
+  } else {
+    delete Object.prototype.__defineGetter__;
+    delete Object.prototype.__defineSetter__;
+    delete Object.prototype.__lookupGetter__;
+    delete Object.prototype.__lookupSetter__;
+  }
+
+
+  /**
+   * By this time, WeakMap has already monkey patched Object.freeze if
+   * necessary, so we can do the tamperProofing delayed from
+   * repairES5.js
+   */
+  var tamperProof = ses.makeDelayedTamperProof();
+
+  /**
+   * Code being eval'ed by {@code cajaVM.eval} sees {@code
+   * sharedImports} as its top-level {@code this}, as if {@code
+   * sharedImports} were the global object.
+   *
+   * <p>{@code sharedImports}'s properties are exactly the whitelisted
+   * global variable references. These properties, both as they appear
+   * on the global object and on this {@code sharedImports} object,
+   * are frozen and so cannot diverge. This preserves the illusion.
+   *
+   * <p>For code being evaluated by {@code cajaVM.compileExpr} and its
+   * ilk, the {@code imports} provided to the compiled function is bound
+   * to the top-level {@code this} of the evaluated code. For sanity,
+   * this {@code imports} should first be initialized with a copy of the
+   * properties of {@code sharedImports}, but nothing enforces this.
+   */
+  var sharedImports = create(null);
+
+  (function startSESPrelude() {
+
+    /**
+     * The unsafe* variables hold precious values that must not escape
+     * to untrusted code. When {@code eval} is invoked via {@code
+     * unsafeEval}, this is a call to the indirect eval function, not
+     * the direct eval operator.
+     */
+    var unsafeEval = eval;
+    var UnsafeFunction = Function;
+
+    /**
+     * Fails if {@code programSrc} does not parse as a strict Program
+     * production, or, almost equivalently, as a FunctionBody
+     * production.
+     *
+     * <p>We use Crock's trick of simply passing {@code programSrc} to
+     * the original {@code Function} constructor, which will throw a
+     * SyntaxError if it does not parse as a FunctionBody. We used to
+     * use Ankur's trick (need link) which is more correct, in that it
+     * will throw if {@code programSrc} does not parse as a Program
+     * production, which is the relevant question. However, the
+     * difference -- whether return statements are accepted -- does
+     * not matter for our purposes. And testing reveals that Crock's
+     * trick executes over 100x faster on V8.
+     */
+    function verifyStrictProgram(programSrc) {
+      try {
+        UnsafeFunction('"use strict";' + programSrc);
+      } catch (err) {
+        // debugger; // Useful for debugging -- to look at programSrc
+        throw err;
+      }
+    }
+
+    /**
+     * Fails if {@code exprSource} does not parse as a strict
+     * Expression production.
+     *
+     * <p>To verify that exprSrc parses as a strict Expression, we
+     * verify that (when followed by ";") it parses as a strict
+     * Program, and that when surrounded with parens it still parses
+     * as a strict Program. We place a newline before the terminal
+     * token so that a "//" comment cannot suppress the close paren.
+     */
+    function verifyStrictExpression(exprSrc) {
+      verifyStrictProgram(exprSrc + ';');
+      verifyStrictProgram('( ' + exprSrc + '\n);');
+    }
+
+    /**
+     * Make a virtual global object whose initial own properties are
+     * a copy of the own properties of {@code sharedImports}.
+     *
+     * <p>Further uses of {@code copyToImports} to copy properties
+     * onto this imports object will overwrite, effectively shadowing
+     * the {@code sharedImports}. You should shadow by overwriting
+     * rather than inheritance so that shadowing makes the original
+     * binding inaccessible.
+     *
+     * <p>The returned imports object is extensible and all its
+     * properties are configurable and non-enumerable. Once fully
+     * initialized, the caller can of course freeze the imports
+     * objects if desired. A reason not to do so it to emulate
+     * traditional JavaScript intermodule linkage by side effects to a
+     * shared (virtual) global object.
+     *
+     * <p>See {@code copyToImports} for the precise semantic of the
+     * property copying.
+     */
+    function makeImports() {
+      var imports = create(null);
+      copyToImports(imports, sharedImports);
+      return imports;
+    }
+
+    /**
+     * For all the own properties of {@code from}, copy their
+     * descriptors to {@code imports}, except that each property
+     * added to {@code imports} is unconditionally configurable
+     * and non-enumerable.
+     *
+     * <p>By copying descriptors rather than values, any accessor
+     * properties of {@code env} become accessors of {@code imports}
+     * with the same getter and setter. If these do not use their
+     * {@code this} value, then the original and any copied properties
+     * are effectively joined. If the getter/setter do use their
+     * {@code this}, when accessed with {@code imports} as the base,
+     * their {@code this} will be bound to the {@code imports} rather
+     * than {@code from}. If {@code from} contains writable value
+     * properties, this will copy the current value of the property,
+     * after which they may diverge.
+     *
+     * <p>We make these configurable so that {@code imports} can
+     * be further configured before being frozen. We make these
+     * non-enumerable in order to emulate the normal behavior of
+     * built-in properties of typical global objects, such as the
+     * browser's {@code window} object.
+     */
+    function copyToImports(imports, from) {
+      gopn(from).forEach(function(name) {
+        var desc = gopd(from, name);
+        desc.enumerable = false;
+        desc.configurable = true;
+        defProp(imports, name, desc);
+      });
+      return imports;
+    }
+
+    /**
+     * Make a frozen scope object which reflects all access onto
+     * {@code imports}, for use by {@code with} to prevent
+     * access to any {@code freeNames} other than those found on the.
+     * {@code imports}.
+     */
+    function makeScopeObject(imports, freeNames) {
+      var scopeObject = create(null);
+      // Note: Although this loop is a bottleneck on some platforms,
+      // it does not help to turn it into a for(;;) loop, since we
+      // still need an enclosing function per accessor property
+      // created, to capture its own unique binding of
+      // "name". (Embarrasing fact: despite having often written about
+      // this very danger, I engaged in this mistake in a misbegotten
+      // optimization attempt here.)
+      freeNames.forEach(function interceptName(name) {
+        var desc = gopd(imports, name);
+        if (!desc || desc.writable !== false || desc.configurable) {
+          // If there is no own property, or it isn't a non-writable
+          // value property, or it is configurable. Note that this
+          // case includes accessor properties. The reason we wrap
+          // rather than copying over getters and setters is so the
+          // this-binding of the original getters and setters will be
+          // the imports rather than the scopeObject.
+          desc = {
+            get: function scopedGet() {
+              if (name in imports) {
+                var result = imports[name];
+                if (typeof result === 'function') {
+                  // If it were possible to know that the getter call
+                  // was on behalf of a simple function call to the
+                  // gotten function, we could instead return that
+                  // function as bound to undefined. Unfortunately,
+                  // without parsing (or possibly proxies?), that isn't
+                  // possible.
+                }
+                return result;
+              }
+              // if it were possible to know that the getter call was on
+              // behalf of a typeof expression, we'd return the string
+              // "undefined" here instead. Unfortunately, without
+              // parsing or proxies, that isn't possible.
+              throw new ReferenceError('"' + name + '" not in scope');
+            },
+            set: function scopedSet(newValue) {
+              if (name in imports) {
+                imports[name] = newValue;
+              }
+              throw new TypeError('Cannot set "' + name + '"');
+            },
+            enumerable: false
+          };
+        }
+        desc.enumerable = false;
+        defProp(scopeObject, name, desc);
+      });
+      return freeze(scopeObject);
+    }
+
+
+    /**
+     * Given SES source text that must not be run directly using any
+     * of the built-in unsafe evaluators on this platform, we instead
+     * surround it with a prelude and postlude.
+     *
+     * <p>Evaluating the resulting expression return a function that
+     * <i>can</i>be called to execute the original expression safely,
+     * in a controlled scope. See "makeCompiledExpr" for precisely the
+     * pattern that must be followed to call the resulting function
+     * safely.
+     *
+     * Notice that the source text placed around {@code exprSrc}
+     * <ul>
+     * <li>brings no variable names into scope, avoiding any
+     *     non-hygienic name capture issues, and
+     * <li>does not introduce any newlines preceding exprSrc, so
+     *     that all line number which a debugger might report are
+     *     accurate wrt the original source text. And except for the
+     *     first line, all the column numbers are accurate too.
+     * </ul>
+     *
+     * <p>TODO(erights): Find out if any platforms have any way to
+     * associate a file name and line number with eval'ed text, so
+     * that we can do something useful with the optional {@code
+     * opt_sourcePosition} to better support debugging.
+     */
+    function securableWrapperSrc(exprSrc, opt_sourcePosition) {
+      verifyStrictExpression(exprSrc);
+
+      return '(function() { ' +
+        // non-strict code, where this === scopeObject
+        '  with (this) { ' +
+        '    return function() { ' +
+        '      "use strict"; ' +
+        '      return ( ' +
+        // strict code, where this === imports
+        '        ' + exprSrc + '\n' +
+        '      );\n' +
+        '    };\n' +
+        '  }\n' +
+        '})';
+    }
+    ses.securableWrapperSrc = securableWrapperSrc;
+
+
+    /**
+     * Given a wrapper function, such as the result of evaluating the
+     * source that securableWrapperSrc returns, and a list of all the
+     * names that we want to intercept to redirect to the imports,
+     * return a corresponding <i>compiled expr</i> function.
+     *
+     * <p>A compiled expr function, when called on an imports
+     * object, evaluates the original expression in a context where
+     * all its free variable references that appear in freeNames are
+     * redirected to the corresponding property of imports.
+     */
+    function makeCompiledExpr(wrapper, freeNames) {
+      if (dirty) { fail('Initial cleaning failed'); }
+
+      function compiledCode(imports) {
+        var scopeObject = makeScopeObject(imports, freeNames);
+        return wrapper.call(scopeObject).call(imports);
+      };
+      compiledCode.prototype = null;
+      return compiledCode;
+    }
+    ses.makeCompiledExpr = makeCompiledExpr;
+
+    /**
+     * Compiles {@code exprSrc} as a strict expression into a function
+     * of an {@code imports}, that when called evaluates {@code
+     * exprSrc} in a virtual global environment whose {@code this} is
+     * bound to that {@code imports}, and whose free variables
+     * refer only to the properties of that {@code imports}.
+     *
+     * <p>When SES is provided primitively, it should provide an
+     * analogous {@code compileProgram} function that accepts a
+     * Program and return a function that evaluates it to the
+     * Program's completion value. Unfortunately, this is not
+     * practical as a library without some non-standard support from
+     * the platform such as a parser API that provides an AST.
+     *
+     * <p>Thanks to Mike Samuel and Ankur Taly for this trick of using
+     * {@code with} together with RegExp matching to intercept free
+     * variable access without parsing.
+     */
+    function compileExpr(exprSrc, opt_sourcePosition) {
+      var wrapperSrc = securableWrapperSrc(exprSrc, opt_sourcePosition);
+      var wrapper = unsafeEval(wrapperSrc);
+      var freeNames = atLeastFreeVarNames(exprSrc);
+      var result = makeCompiledExpr(wrapper, freeNames);
+      return freeze(result);
+    }
+
+
+    var directivePattern = (/^['"](?:\w|\s)*['"]$/m);
+
+    /**
+     * A stereotyped form of the CommonJS require statement.
+     */
+    var requirePattern = (/^(?:\w*\s*(?:\w|\$|\.)*\s*=)?\s*require\s*\(\s*['"]((?:\w|\$|\.|\/)+)['"]\s*\)$/m);
+
+    /**
+     * As an experiment, recognize a stereotyped prelude of the
+     * CommonJS module system.
+     */
+    function getRequirements(modSrc) {
+      var result = [];
+      var stmts = modSrc.split(';');
+      var stmt;
+      var i = 0, ilen = stmts.length;
+      for (; i < ilen; i++) {
+        stmt = stmts[i].trim();
+        if (stmt !== '') {
+          if (!directivePattern.test(stmt)) { break; }
+        }
+      }
+      for (; i < ilen; i++) {
+        stmt = stmts[i].trim();
+        if (stmt !== '') {
+          var m = requirePattern.exec(stmt);
+          if (!m) { break; }
+          result.push(m[1]);
+        }
+      }
+      return freeze(result);
+    }
+
+    /**
+     * A module source is actually any valid FunctionBody, and thus
+     * any valid Program.
+     *
+     * <p>In addition, in case the module source happens to begin with
+     * a streotyped prelude of the CommonJS module system, the
+     * function resulting from module compilation has an additional
+     * {@code "requirements"} property whose value is a list of the
+     * module names being required by that prelude. These requirements
+     * are the module's "immediate synchronous dependencies".
+     *
+     * <p>This {@code "requirements"} property is adequate to
+     * bootstrap support for a CommonJS module system, since a loader
+     * can first load and compile the transitive closure of an initial
+     * module's synchronous depencies before actually executing any of
+     * these module functions.
+     *
+     * <p>With a similarly lightweight RegExp, we should be able to
+     * similarly recognize the {@code "load"} syntax of <a href=
+     * "http://wiki.ecmascript.org/doku.php?id=strawman:simple_modules#syntax"
+     * >Sam and Dave's module proposal for ES-Harmony</a>. However,
+     * since browsers do not currently accept this syntax,
+     * {@code getRequirements} above would also have to extract these
+     * from the text to be compiled.
+     */
+    function compileModule(modSrc, opt_sourcePosition) {
+      var exprSrc = '(function() {' + modSrc + '}).call(this)';
+
+      // Follow the pattern in compileExpr
+      var wrapperSrc = securableWrapperSrc(exprSrc, opt_sourcePosition);
+      var wrapper = unsafeEval(wrapperSrc);
+      var freeNames = atLeastFreeVarNames(exprSrc);
+      var moduleMaker = makeCompiledExpr(wrapper, freeNames);
+
+      moduleMaker.requirements = getRequirements(modSrc);
+      return freeze(moduleMaker);
+    }
+
+    /**
+     * A safe form of the {@code Function} constructor, which
+     * constructs strict functions that can only refer freely to the
+     * {@code sharedImports}.
+     *
+     * <p>The returned function is strict whether or not it declares
+     * itself to be.
+     */
+    function FakeFunction(var_args) {
+      var params = [].slice.call(arguments, 0);
+      var body = params.pop();
+      body = String(body || '');
+      params = params.join(',');
+      var exprSrc = '(function(' + params + '\n){' + body + '})';
+      return compileExpr(exprSrc)(sharedImports);
+    }
+    FakeFunction.prototype = UnsafeFunction.prototype;
+    FakeFunction.prototype.constructor = FakeFunction;
+    global.Function = FakeFunction;
+
+    /**
+     * A safe form of the indirect {@code eval} function, which
+     * evaluates {@code src} as strict code that can only refer freely
+     * to the {@code sharedImports}.
+     *
+     * <p>Given our parserless methods of verifying untrusted sources,
+     * we unfortunately have no practical way to obtain the completion
+     * value of a safely evaluated Program. Instead, we adopt a
+     * compromise based on the following observation. All Expressions
+     * are valid Programs, and all Programs are valid
+     * FunctionBodys. If {@code src} parses as a strict expression,
+     * then we evaluate it as an expression and correctly return its
+     * completion value, since that is simply the value of the
+     * expression.
+     *
+     * <p>Otherwise, we evaluate {@code src} as a FunctionBody and
+     * return what that would return from its implicit enclosing
+     * function. If {@code src} is simply a Program, then it would not
+     * have an explicit {@code return} statement, and so we fail to
+     * return its completion value.
+     *
+     * <p>When SES {@code eval} is provided primitively, it should
+     * accept a Program and evaluate it to the Program's completion
+     * value. Unfortunately, this is not possible on ES5 without
+     * parsing.
+     */
+    function fakeEval(src) {
+      try {
+        verifyStrictExpression(src);
+      } catch (x) {
+        src = '(function() {' + src + '\n}).call(this)';
+      }
+      return compileExpr(src)(sharedImports);
+    }
+
+    if (TAME_GLOBAL_EVAL) {
+      global.eval = fakeEval;
+    }
+
+    var defended = WeakMap();
+    var defending = WeakMap();
+    /**
+     * To define a defended object is to tamperProof it and all objects
+     * transitively reachable from it via transitive reflective
+     * property and prototype traversal.
+     */
+    function def(node) {
+      var defendingList = [];
+      function recur(val) {
+        if (!val) { return; }
+        var t = typeof val;
+        if (t === 'number' || t === 'string' || t === 'boolean') { return; }
+        if (defended.get(val) || defending.get(val)) { return; }
+        defending.set(val, true);
+        defendingList.push(val);
+
+        tamperProof(val);
+
+        recur(getProto(val));
+
+        // How to optimize? This is a performance sensitive loop, but
+        // forEach seems to be faster on Chrome 18 Canary but a
+        // for(;;) loop seems better on FF 12 Nightly.
+        gopn(val).forEach(function(p) {
+          if (typeof val === 'function' &&
+              (p === 'caller' || p === 'arguments')) {
+            return;
+          }
+          var desc = gopd(val, p);
+          recur(desc.value);
+          recur(desc.get);
+          recur(desc.set);
+        });
+      }
+      try {
+        recur(node);
+      } catch (err) {
+        defending = WeakMap();
+        throw err;
+      }
+      defendingList.forEach(function(obj) {
+        defended.set(obj, true);
+      });
+      return node;
+    }
+
+
+    /**
+     * makeArrayLike() produces a constructor for the purpose of
+     * taming things like nodeLists.  The result, ArrayLike, takes an
+     * instance of ArrayLike and two functions, getItem and getLength,
+     * which put it in a position to do taming on demand.
+     *
+     * <p>The constructor returns a new object that inherits from the
+     * {@code proto} passed in.
+     */
+    var makeArrayLike;
+    (function() {
+      var itemMap = WeakMap(), lengthMap = WeakMap();
+      function lengthGetter() {
+        var getter = lengthMap.get(this);
+        return getter ? getter() : void 0;
+      }
+      constFunc(lengthGetter);
+
+      var nativeProxies = global.Proxy && (function () {
+        var obj = {0: 'hi'};
+        var p = global.Proxy.create({
+          get: function () {
+            var P = arguments[0];
+            if (typeof P !== 'string') { P = arguments[1]; }
+            return obj[P];
+          }
+        });
+        return p[0] === 'hi';
+      })();
+      if (nativeProxies) {
+        (function () {
+          function ArrayLike(proto, getItem, getLength) {
+            if (typeof proto !== 'object') {
+              throw new TypeError('Expected proto to be an object.');
+            }
+            if (!(proto instanceof ArrayLike)) {
+              throw new TypeError('Expected proto to be instanceof ArrayLike.');
+            }
+            var obj = create(proto);
+            itemMap.set(obj, getItem);
+            lengthMap.set(obj, getLength);
+            return obj;
+          }
+
+          function ownPropDesc(P) {
+            P = '' + P;
+            if (P === 'length') {
+              return { get: lengthGetter };
+            } else if (typeof P === 'number' || P === '' + (+P)) {
+              return {
+                get: constFunc(function() {
+                  var getter = itemMap.get(this);
+                  return getter ? getter(+P) : void 0;
+                }),
+                enumerable: true,
+                configurable: true
+              };
+            }
+            return void 0;
+          }
+          function propDesc(P) {
+            var opd = ownPropDesc(P);
+            if (opd) {
+              return opd;
+            } else {
+              return gopd(Object.prototype, P);
+            }
+          }
+          function has(P) {
+            P = '' + P;
+            return (P === 'length') ||
+                (typeof P === 'number') ||
+                (P === '' + +P) ||
+                (P in Object.prototype);
+          }
+          function hasOwn(P) {
+            P = '' + P;
+            return (P === 'length') ||
+                (typeof P === 'number') ||
+                (P === '' + +P);
+          }
+          function getPN() {
+            var result = getOwnPN ();
+            var objPropNames = gopn(Object.prototype);
+            result.push.apply(result, objPropNames);
+            return result;
+          }
+          function getOwnPN() {
+            var lenGetter = lengthMap.get(this);
+            if (!lenGetter) { return void 0; }
+            var len = lenGetter();
+            var result = ['length'];
+            for (var i = 0; i < len; ++i) {
+              result.push('' + i);
+            }
+            return result;
+          };
+          function del(P) {
+            P = '' + P;
+            if ((P === 'length') || ('' + +P === P)) { return false; }
+            return true;
+          }
+
+          ArrayLike.prototype = global.Proxy.create({
+            getPropertyDescriptor: propDesc,
+            getOwnPropertyDescriptor: ownPropDesc,
+            has: has,
+            hasOwn: hasOwn,
+            getPropertyNames: getPN,
+            getOwnPropertyNames: getOwnPN,
+            'delete': del,
+            fix: function() { return void 0; }
+          }, Object.prototype);
+          tamperProof(ArrayLike);
+          makeArrayLike = function() { return ArrayLike; };
+        })();
+      } else {
+        (function() {
+          // Make BiggestArrayLike.prototype be an object with a fixed
+          // set of numeric getters.  To tame larger lists, replace
+          // BiggestArrayLike and its prototype using
+          // makeArrayLike(newLength).
+
+          // See
+          // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+          function nextUInt31PowerOf2(v) {
+            v &= 0x7fffffff;
+            v |= v >> 1;
+            v |= v >> 2;
+            v |= v >> 4;
+            v |= v >> 8;
+            v |= v >> 16;
+            return v + 1;
+          }
+
+          // The current function whose prototype has the most numeric getters.
+          var BiggestArrayLike = void 0;
+          var maxLen = 0;
+          makeArrayLike = function(length) {
+            if (!BiggestArrayLike || length > maxLen) {
+              var len = nextUInt31PowerOf2(length);
+              // Create a new ArrayLike constructor to replace the old one.
+              var BAL = function(proto, getItem, getLength) {
+                if (typeof(proto) !== 'object') {
+                  throw new TypeError('Expected proto to be an object.');
+                }
+                if (!(proto instanceof BAL)) {
+                  throw new TypeError(
+                      'Expected proto to be instanceof ArrayLike.');
+                }
+                var obj = create(proto);
+                itemMap.set(obj, getItem);
+                lengthMap.set(obj, getLength);
+                return obj;
+              };
+              // Install native numeric getters.
+              for (var i = 0; i < len; i++) {
+                (function(j) {
+                  function get() {
+                    return itemMap.get(this)(j);
+                  }
+                  defProp(BAL.prototype, j, {
+                    get: constFunc(get),
+                    enumerable: true
+                  });
+                })(i);
+              }
+              // Install native length getter.
+              defProp(BAL.prototype, 'length', { get: lengthGetter });
+              // TamperProof and cache the result
+              tamperProof(BAL);
+              tamperProof(BAL.prototype);
+              BiggestArrayLike = BAL;
+              maxLen = len;
+            }
+            return BiggestArrayLike;
+          };
+        })();
+      }
+    })();
+
+    global.cajaVM = { // don't freeze here
+
+      /**
+       * This is about to be deprecated once we expose ses.logger.
+       *
+       * <p>In the meantime, privileged code should use ses.logger.log
+       * instead of cajaVM.log.
+       */
+      log: constFunc(function log(str) {
+        if (typeof console !== 'undefined' && 'log' in console) {
+          // We no longer test (typeof console.log === 'function') since,
+          // on IE9 and IE10preview, in violation of the ES5 spec, it
+          // is callable but has typeof "object". See
+          // https://connect.microsoft.com/IE/feedback/details/685962/
+          //   console-log-and-others-are-callable-but-arent-typeof-function
+          console.log(str);
+        }
+      }),
+      tamperProof: constFunc(tamperProof),
+      constFunc: constFunc(constFunc),
+      // def: see below
+      is: constFunc(ses.is),
+
+      compileExpr: constFunc(compileExpr),
+      compileModule: constFunc(compileModule),
+      // compileProgram: compileProgram, // Cannot be implemented in ES5.1.
+      eval: fakeEval,               // don't freeze here
+      Function: FakeFunction,       // don't freeze here,
+
+      sharedImports: sharedImports, // don't freeze here
+      makeImports: constFunc(makeImports),
+      copyToImports: constFunc(copyToImports),
+
+      makeArrayLike: constFunc(makeArrayLike)
+    };
+    var extensionsRecord = extensions();
+    gopn(extensionsRecord).forEach(function (p) {
+      defProp(cajaVM, p,
+              gopd(extensionsRecord, p));
+    });
+
+    // Move this down here so it is not available during the call to
+    // extensions().
+    global.cajaVM.def = constFunc(def);
+
+  })();
+
+  var propertyReports = {};
+
+  /**
+   * Report how a property manipulation went.
+   */
+  function reportProperty(severity, status, path) {
+    ses.updateMaxSeverity(severity);
+    var group = propertyReports[status] || (propertyReports[status] = {
+      severity: severity,
+      list: []
+    });
+    group.list.push(path);
+  }
+
+  /**
+   * Initialize accessible global variables and {@code sharedImports}.
+   *
+   * For each of the whitelisted globals, we read its value, freeze
+   * that global property as a data property, and mirror that property
+   * with a frozen data property of the same name and value on {@code
+   * sharedImports}, but always non-enumerable. We make these
+   * non-enumerable since ES5.1 specifies that all these properties
+   * are non-enumerable on the global object.
+   */
+  keys(whitelist).forEach(function(name) {
+    var desc = gopd(global, name);
+    if (desc) {
+      var permit = whitelist[name];
+      if (permit) {
+        var newDesc = {
+          value: global[name],
+          writable: false,
+          configurable: false
+        };
+        try {
+          defProp(global, name, newDesc);
+        } catch (err) {
+          reportProperty(ses.severities.NEW_SYMPTOM,
+                         'Global ' + name + ' cannot be made readonly: ' + err);
+        }
+        defProp(sharedImports, name, newDesc);
+      }
+    }
+  });
+  if (TAME_GLOBAL_EVAL) {
+    defProp(sharedImports, 'eval', {
+      value: cajaVM.eval,
+      writable: false,
+      enumerable: false,
+      configurable: false
+    });
+  }
+
+  /**
+   * The whiteTable should map from each path-accessible primordial
+   * object to the permit object that describes how it should be
+   * cleaned.
+   *
+   * We initialize the whiteTable only so that {@code getPermit} can
+   * process "*" and "skip" inheritance using the whitelist, by
+   * walking actual superclass chains.
+   */
+  var whiteTable = WeakMap();
+  function register(value, permit) {
+    if (value !== Object(value)) { return; }
+    if (typeof permit !== 'object') {
+      return;
+    }
+    var oldPermit = whiteTable.get(value);
+    if (oldPermit) {
+      fail('primordial reachable through multiple paths');
+    }
+    whiteTable.set(value, permit);
+    keys(permit).forEach(function(name) {
+      if (permit[name] !== 'skip') {
+        var sub = value[name];
+        register(sub, permit[name]);
+      }
+    });
+  }
+  register(sharedImports, whitelist);
+
+  /**
+   * Should the property named {@code name} be whitelisted on the
+   * {@code base} object, and if so, with what Permit?
+   *
+   * <p>If it should be permitted, return the Permit (where Permit =
+   * true | "*" | "skip" | Record(Permit)), all of which are
+   * truthy. If it should not be permitted, return false.
+   */
+  function getPermit(base, name) {
+    var permit = whiteTable.get(base);
+    if (permit) {
+      if (hop.call(permit, name)) { return permit[name]; }
+    }
+    while (true) {
+      base = getProto(base);
+      if (base === null) { return false; }
+      permit = whiteTable.get(base);
+      if (permit && hop.call(permit, name)) {
+        var result = permit[name];
+        if (result === '*' || result === 'skip') {
+          return result;
+        } else {
+          return false;
+        }
+      }
+    }
+  }
+
+  var cleaning = WeakMap();
+
+  /**
+   * Delete the property if possible, else try to poison.
+   */
+  function cleanProperty(base, name, path) {
+    function poison() {
+      throw new TypeError('Cannot access property ' + path);
+    }
+    var diagnostic;
+
+    if (typeof base === 'function') {
+      if (name === 'caller') {
+        diagnostic = ses.makeCallerHarmless(base, path);
+        // We can use a severity of SAFE here since if this isn't
+        // safe, it is the responsibility of repairES5.js to tell us
+        // so. All the same, we should inspect the reports on all
+        // platforms we care about to see if there are any surprises.
+        reportProperty(ses.severities.SAFE,
+                       diagnostic, path);
+        return true;
+      }
+      if (name === 'arguments') {
+        diagnostic = ses.makeArgumentsHarmless(base, path);
+        // We can use a severity of SAFE here since if this isn't
+        // safe, it is the responsibility of repairES5.js to tell us
+        // so. All the same, we should inspect the reports on all
+        // platforms we care about to see if there are any surprises.
+        reportProperty(ses.severities.SAFE,
+                       diagnostic, path);
+        return true;
+      }
+    }
+
+    var deleted = void 0;
+    var err = void 0;
+    try {
+      deleted = delete base[name];
+    } catch (er) { err = er; }
+    var exists = hop.call(base, name);
+    if (deleted) {
+      if (!exists) {
+        reportProperty(ses.severities.SAFE,
+                       'Deleted', path);
+        return true;
+      }
+      reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+                     'Bounced back', path);
+    } else if (deleted === false) {
+      reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+                     'Strict delete returned false rather than throwing', path);
+    } else if (err instanceof TypeError) {
+      // This is the normal abnormal case, so leave it to the next
+      // section to emit a diagnostic.
+      //
+      // reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+      //                'Cannot be deleted', path);
+    } else {
+      reportProperty(ses.severities.NEW_SYMPTOM,
+                     'Delete failed with' + err, path);
+    }
+
+    try {
+      defProp(base, name, {
+        get: poison,
+        set: poison,
+        enumerable: false,
+        configurable: false
+      });
+    } catch (cantPoisonErr) {
+      try {
+        // Perhaps it's writable non-configurable, in which case we
+        // should still be able to freeze it in a harmless state.
+        var value = gopd(base, name).value;
+        defProp(base, name, {
+          value: value === null ? null : void 0,
+          writable: false,
+          configurable: false
+        });
+      } catch (cantFreezeHarmless) {
+        reportProperty(ses.severities.NOT_ISOLATED,
+                       'Cannot be poisoned', path);
+        return false;
+      }
+    }
+    var desc2 = gopd(base, name);
+    if (desc2.get === poison &&
+        desc2.set === poison &&
+        !desc2.configurable) {
+      try {
+        var dummy2 = base[name];
+      } catch (expectedErr) {
+        if (expectedErr instanceof TypeError) {
+          reportProperty(ses.severities.SAFE,
+                         'Successfully poisoned', path);
+          return true;
+        }
+      }
+    } else if ((desc2.value === void 0 || desc2.value === null) &&
+               !desc2.writable &&
+               !desc2.configurable) {
+      reportProperty(ses.severities.SAFE,
+                     'Frozen harmless', path);
+      return false;
+    }
+    reportProperty(ses.severities.NEW_SYMTOM,
+                   'Failed to be poisoned', path);
+    return false;
+  }
+
+  /**
+   * Assumes all super objects are otherwise accessible and so will be
+   * independently cleaned.
+   */
+  function clean(value, prefix) {
+    if (value !== Object(value)) { return; }
+    if (cleaning.get(value)) { return; }
+    cleaning.set(value, true);
+    gopn(value).forEach(function(name) {
+      var path = prefix + (prefix ? '.' : '') + name;
+      var p = getPermit(value, name);
+      if (p) {
+        if (p === 'skip') {
+          reportProperty(ses.severities.SAFE,
+                         'Skipped', path);
+        } else {
+          var sub = value[name];
+          clean(sub, path);
+        }
+      } else {
+        cleanProperty(value, name, path);
+      }
+    });
+  }
+  clean(sharedImports, '');
+
+  /**
+   * This protection is now gathered here, so that a future version
+   * can skip it for non-defensive frames that must only be confined.
+   */
+  cajaVM.def(sharedImports);
+
+  keys(propertyReports).sort().forEach(function(status) {
+    var group = propertyReports[status];
+    ses.logger.reportDiagnosis(group.severity, status, group.list);
+  });
+
+  ses.logger.reportMax();
+
+  if (ses.ok()) {
+    // We succeeded. Enable safe Function, eval, and compile* to work.
+    dirty = false;
+    ses.logger.log('initSES succeeded.');
+  } else {
+    ses.logger.error('initSES failed.');
+  }
+};
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview
+ * This is a pure-ES5 implementation of ejectors, guards, and trademarks as
+ * otherwise provided by ES5/3. It is incorporated into the cajaVM object by
+ * hookupSESPlus.js.
+ *
+ * <p>Assumes ES5. Compatible with ES5-strict.
+ *
+ * // provides ses.ejectorsGuardsTrademarks
+ * @author kpreid@switchb.org
+ * @requires WeakMap, cajaVM
+ * @overrides ses, ejectorsGuardsTrademarksModule
+ */
+var ses;
+
+(function ejectorsGuardsTrademarksModule(){
+  "use strict";
+
+  ses.ejectorsGuardsTrademarks = function ejectorsGuardsTrademarks() {
+
+    /**
+     * During the call to {@code ejectorsGuardsTrademarks}, {@code
+     * ejectorsGuardsTrademarks} must not call {@code cajaVM.def},
+     * since startSES.js has not yet finished cleaning things. See the
+     * doc-comments on the {@code extensions} parameter of
+     * startSES.js.
+     *
+     * <p>Instead, we define here some conveniences for freezing just
+     * enough without prematurely freezing primodial objects
+     * transitively reachable from these.
+     */
+    var freeze = Object.freeze;
+    var constFunc = cajaVM.constFunc;
+
+
+    /**
+     * Returns a new object whose only utility is its identity and (for
+     * diagnostic purposes only) its name.
+     */
+    function Token(name) {
+      name = '' + name;
+      return freeze({
+        toString: constFunc(function tokenToString() {
+          return name;
+        })
+      });
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////
+    // Ejectors
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * One-arg form is known in scheme as "call with escape
+     * continuation" (call/ec).
+     *
+     * <p>In this analogy, a call to {@code callWithEjector} emulates a
+     * labeled statement. The ejector passed to the {@code attemptFunc}
+     * emulates the label part. The {@code attemptFunc} itself emulates
+     * the statement being labeled. And a call to {@code eject} with
+     * this ejector emulates the return-to-label statement.
+     *
+     * <p>We extend the normal notion of call/ec with an
+     * {@code opt_failFunc} in order to give more the sense of a
+     * {@code try/catch} (or similarly, the {@code escape} special
+     * form in E). The {@code attemptFunc} is like the {@code try}
+     * clause and the {@code opt_failFunc} is like the {@code catch}
+     * clause. If omitted, {@code opt_failFunc} defaults to the
+     * {@code identity} function.
+     *
+     * <p>{@code callWithEjector} creates a fresh ejector -- a one
+     * argument function -- for exiting from this attempt. It then calls
+     * {@code attemptFunc} passing that ejector as argument. If
+     * {@code attemptFunc} completes without calling the ejector, then
+     * this call to {@code callWithEjector} completes
+     * likewise. Otherwise, if the ejector is called with an argument,
+     * then {@code opt_failFunc} is called with that argument. The
+     * completion of {@code opt_failFunc} is then the completion of the
+     * {@code callWithEjector} as a whole.
+     *
+     * <p>The ejector stays live until {@code attemptFunc} is exited,
+     * at which point the ejector is disabled. Calling a disabled
+     * ejector throws.
+     *
+     * <p>Historic note: This was first invented by John C. Reynolds in
+     * <a href="http://doi.acm.org/10.1145/800194.805852"
+     * >Definitional interpreters for higher-order programming
+     * languages</a>. Reynold's invention was a special form as in E,
+     * rather than a higher order function as here and in call/ec.
+     */
+    function callWithEjector(attemptFunc, opt_failFunc) {
+      var failFunc = opt_failFunc || function (x) { return x; };
+      var disabled = false;
+      var token = new Token('ejection');
+      var stash = void 0;
+      function ejector(result) {
+        if (disabled) {
+          throw new Error('ejector disabled');
+        } else {
+          // don't disable here.
+          stash = result;
+          throw token;
+        }
+      }
+      constFunc(ejector);
+      try {
+        try {
+          return attemptFunc(ejector);
+        } finally {
+          disabled = true;
+        }
+      } catch (e) {
+        if (e === token) {
+          return failFunc(stash);
+        } else {
+          throw e;
+        }
+      }
+    }
+
+    /**
+     * Safely invokes {@code opt_ejector} with {@code result}.
+     * <p>
+     * If {@code opt_ejector} is falsy, disabled, or returns
+     * normally, then {@code eject} throws. Under no conditions does
+     * {@code eject} return normally.
+     */
+    function eject(opt_ejector, result) {
+      if (opt_ejector) {
+        opt_ejector(result);
+        throw new Error('Ejector did not exit: ', opt_ejector);
+      } else {
+        throw new Error(result);
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Sealing and Unsealing
+    ////////////////////////////////////////////////////////////////////////
+
+    function makeSealerUnsealerPair() {
+      var boxValues = new WeakMap(true); // use key lifetime
+
+      function seal(value) {
+        var box = freeze({});
+        boxValues.set(box, value);
+        return box;
+      }
+      function optUnseal(box) {
+        return boxValues.has(box) ? [boxValues.get(box)] : null;
+      }
+      function unseal(box) {
+        var result = optUnseal(box);
+        if (result === null) {
+          throw new Error("That wasn't one of my sealed boxes!");
+        } else {
+          return result[0];
+        }
+      }
+      return freeze({
+        seal: constFunc(seal),
+        unseal: constFunc(unseal),
+        optUnseal: constFunc(optUnseal)
+      });
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////
+    // Trademarks
+    ////////////////////////////////////////////////////////////////////////
+
+    var stampers = new WeakMap(true);
+
+    /**
+     * Internal routine for making a trademark from a table.
+     *
+     * <p>To untangle a cycle, the guard made by {@code makeTrademark}
+     * is not yet stamped. The caller of {@code makeTrademark} must
+     * stamp it before allowing the guard to escape.
+     *
+     * <p>Note that {@code makeTrademark} is called during the call to
+     * {@code ejectorsGuardsTrademarks}, and so must not call {@code
+     * cajaVM.def}.
+     */
+    function makeTrademark(typename, table) {
+      typename = '' + typename;
+
+      var stamp = freeze({
+        toString: constFunc(function() { return typename + 'Stamp'; })
+      });
+
+      stampers.set(stamp, function(obj) {
+        table.set(obj, true);
+        return obj;
+      });
+
+      return freeze({
+        toString: constFunc(function() { return typename + 'Mark'; }),
+        stamp: stamp,
+        guard: freeze({
+          toString: constFunc(function() { return typename + 'T'; }),
+          coerce: constFunc(function(specimen, opt_ejector) {
+            if (!table.get(specimen)) {
+              eject(opt_ejector,
+                    'Specimen does not have the "' + typename + '" trademark');
+            }
+            return specimen;
+          })
+        })
+      });
+    }
+
+    /**
+     * Objects representing guards should be marked as such, so that
+     * they will pass the {@code GuardT} guard.
+     * <p>
+     * {@code GuardT} is generally accessible as
+     * {@code cajaVM.GuardT}. However, {@code GuardStamp} must not be
+     * made generally accessible, but rather only given to code trusted
+     * to use it to deem as guards things that act in a guard-like
+     * manner: A guard MUST be immutable and SHOULD be idempotent. By
+     * "idempotent", we mean that<pre>
+     *     var x = g(specimen, ej); // may fail
+     *     // if we're still here, then without further failure
+     *     g(x) === x
+     * </pre>
+     */
+    var GuardMark = makeTrademark('Guard', new WeakMap());
+    var GuardT = GuardMark.guard;
+    var GuardStamp = GuardMark.stamp;
+    stampers.get(GuardStamp)(GuardT);
+
+    /**
+     * The {@code Trademark} constructor makes a trademark, which is a
+     * guard/stamp pair, where the stamp marks and freezes unfrozen
+     * records as carrying that trademark and the corresponding guard
+     * cerifies objects as carrying that trademark (and therefore as
+     * having been marked by that stamp).
+     *
+     * <p>By convention, a guard representing the type-like concept
+     * 'Foo' is named 'FooT'. The corresponding stamp is
+     * 'FooStamp'. And the record holding both is 'FooMark'. Many
+     * guards also have {@code of} methods for making guards like
+     * themselves but parameterized by further constraints, which are
+     * usually other guards. For example, {@code T.ListT} is the guard
+     * representing frozen array, whereas {@code
+     * T.ListT.of(cajaVM.GuardT)} represents frozen arrays of guards.
+     */
+    function Trademark(typename) {
+      var result = makeTrademark(typename, new WeakMap());
+      stampers.get(GuardStamp)(result.guard);
+      return result;
+    };
+
+    /**
+     * Given that {@code stamps} is a list of stamps and
+     * {@code record} is a non-frozen object, this marks record with
+     * the trademarks of all of these stamps, and then freezes and
+     * returns the record.
+     * <p>
+     * If any of these conditions do not hold, this throws.
+     */
+    function stamp(stamps, record) {
+      // TODO: Should nonextensible objects be stampable?
+      if (Object.isFrozen(record)) {
+        throw new TypeError("Can't stamp frozen objects: " + record);
+      }
+      stamps = Array.prototype.slice.call(stamps, 0);
+      var numStamps = stamps.length;
+      // First ensure that we will succeed before applying any stamps to
+      // the record.
+      var i;
+      for (i = 0; i < numStamps; i++) {
+        if (!stampers.has(stamps[i])) {
+          throw new TypeError("Can't stamp with a non-stamp: " + stamps[i]);
+        }
+      }
+      for (i = 0; i < numStamps; i++) {
+        // Only works for real stamps, postponing the need for a
+        // user-implementable auditing protocol.
+        stampers.get(stamps[i])(record);
+      }
+      return freeze(record);
+    };
+
+    ////////////////////////////////////////////////////////////////////////
+    // Guards
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * First ensures that g is a guard; then does
+     * {@code g.coerce(specimen, opt_ejector)}.
+     */
+    function guard(g, specimen, opt_ejector) {
+      g = GuardT.coerce(g); // failure throws rather than ejects
+      return g.coerce(specimen, opt_ejector);
+    }
+
+    /**
+     * First ensures that g is a guard; then checks whether the specimen
+     * passes that guard.
+     * <p>
+     * If g is a coercing guard, this only checks that g coerces the
+     * specimen to something rather than failing. Note that trademark
+     * guards are non-coercing, so if specimen passes a trademark guard,
+     * then specimen itself has been marked with that trademark.
+     */
+    function passesGuard(g, specimen) {
+      g = GuardT.coerce(g); // failure throws rather than ejects
+      return callWithEjector(
+        constFunc(function(opt_ejector) {
+          g.coerce(specimen, opt_ejector);
+          return true;
+        }),
+        constFunc(function(ignored) {
+          return false;
+        })
+      );
+    }
+
+
+    /**
+     * Create a guard which passes all objects present in {@code table}.
+     * This may be used to define trademark-like systems which do not require
+     * the object to be frozen.
+     *
+     * {@code typename} is used for toString and {@code errorMessage} is used
+     * when an object does not pass the guard.
+     */
+    function makeTableGuard(table, typename, errorMessage) {
+      var g = {
+        toString: constFunc(function() { return typename + 'T'; }),
+        coerce: constFunc(function(specimen, opt_ejector) {
+          if (!table.get(specimen)) { eject(opt_ejector, errorMessage); }
+          return specimen;
+        })
+      };
+      stamp([GuardStamp], g);
+      return freeze(g);
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Exporting
+    ////////////////////////////////////////////////////////////////////////
+
+    return freeze({
+      callWithEjector: constFunc(callWithEjector),
+      eject: constFunc(eject),
+      makeSealerUnsealerPair: constFunc(makeSealerUnsealerPair),
+      GuardT: GuardT,
+      makeTableGuard: constFunc(makeTableGuard),
+      Trademark: constFunc(Trademark),
+      guard: constFunc(guard),
+      passesGuard: constFunc(passesGuard),
+      stamp: constFunc(stamp)
+    });
+  };
+})();
+;
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Call {@code ses.startSES} to turn this frame into a
+ * SES environment following object-capability rules.
+ *
+ * <p>Assumes ES5 plus WeakMap. Compatible with ES5-strict or
+ * anticipated ES6.
+ *
+ * @author Mark S. Miller
+ * @requires this
+ * @overrides ses, hookupSESPlusModule
+ */
+
+(function hookupSESPlusModule(global) {
+  "use strict";
+
+  if (!ses.ok()) {
+    return;
+  }
+
+  try {
+    ses.startSES(global,
+                 ses.whitelist,
+                 ses.atLeastFreeVarNames,
+                 ses.ejectorsGuardsTrademarks);
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    ses.logger.error('hookupSESPlus failed with: ', err);
+  }
+})(this);
diff --git a/logger.js b/logger.js
new file mode 100644
index 0000000..bf4827a
--- /dev/null
+++ b/logger.js
@@ -0,0 +1,274 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports a {@code ses.logger} which logs to the
+ * console if one exists.
+ *
+ * <p>This <code>logger.js</code> file both defines the logger API and
+ * provides default implementations for its methods. Because
+ * <code>logger.js</code> is normally packaged in
+ * <code>initSES.js</code>, it is built to support being overridden by
+ * a script run <i>earlier</i>. For example, for better diagnostics,
+ * consider loading and initializing <code>useHTMLLogger.js</code> first.
+ *
+ * <p>The {@code ses.logger} API consists of
+ * <dl>
+ *   <dt>log, info, warn, and error methods</dt>
+ *     <dd>each of which take a list of arguments which should be
+ *         stringified and appended together. The logger should
+ *         display this string associated with that severity level. If
+ *         any of the arguments has an associated stack trace
+ *         (presumably Error objects), then the logger <i>may</i> also
+ *         show this stack trace. If no {@code ses.logger} already
+ *         exists, the default provided here forwards to the
+ *         pre-existing global {@code console} if one
+ *         exists. Otherwise, all four of these do nothing. If we
+ *         default to forwarding to the pre-existing {@code console} ,
+ *         we prepend an empty string as first argument since we do
+ *         not want to obligate all loggers to implement the console's
+ *         "%" formatting. </dd>
+ *   <dt>classify(postSeverity)</dt>
+ *     <dd>where postSeverity is a severity
+ *         record as defined by {@code ses.severities} in
+ *         <code>repairES5.js</code>, and returns a helpful record
+ *         consisting of a
+ *         <dl>
+ *           <dt>consoleLevel:</dt>
+ *             <dd>which is one of 'log', 'info', 'warn', or
+ *                 'error', which can be used to select one of the above
+ *                 methods.</dd>
+ *           <dt>note:</dt>
+ *             <dd>containing some helpful text to display
+ *                 explaining the impact of this severity on SES.</dd>
+ *         </dl>
+ *   <dt>reportRepairs(reports)</dt>
+ *     <dd>where {@code reports} is the list of repair reports, each
+ *         of which contains
+ *       <dl>
+ *         <dt>description:</dt>
+ *           <dd>a string describing the problem</dd>
+ *         <dt>preSeverity:</dt>
+ *           <dd>a severity record (as defined by {@code
+ *               ses.severities} in <code>repairES5.js</code>)
+ *               indicating the level of severity of this problem if
+ *               unrepaired. Or, if !canRepair, then the severity
+ *               whether or not repaired.</dd>
+ *         <dt>canRepair:</dt>
+ *           <dd>a boolean indicating "if the repair exists and the test
+ *               subsequently does not detect a problem, are we now ok?"</dd>
+ *         <dt>urls:</dt>
+ *           <dd>a list of URL strings, each of which points at a page
+ *               relevant for documenting or tracking the bug in
+ *               question. These are typically into bug-threads in issue
+ *               trackers for the various browsers.</dd>
+ *         <dt>sections:</dt>
+ *           <dd>a list of strings, each of which is a relevant ES5.1
+ *               section number.</dd>
+ *         <dt>tests:</dt>
+ *           <dd>a list of strings, each of which is the name of a
+ *               relevant test262 or sputnik test case.</dd>
+ *         <dt>postSeverity:</dt>
+ *           <dd>a severity record (as defined by {@code
+ *               ses.severities} in <code>repairES5.js</code>)
+ *               indicating the level of severity of this problem
+ *               after all repairs have been attempted.</dd>
+ *         <dt>beforeFailure:</dt>
+ *           <dd>The outcome of the test associated with this record
+ *               as run before any attempted repairs. If {@code
+ *               false}, it means there was no failure. If {@code
+ *               true}, it means that the test fails in some way that
+ *               the authors of <code>repairES5.js</code>
+ *               expected. Otherwise it returns a string describing
+ *               the symptoms of an unexpected form of failure. This
+ *               is typically considered a more severe form of failure
+ *               than {@code true}, since the authors have not
+ *               anticipated the consequences and safety
+ *               implications.</dd>
+ *         <dt>afterFailure:</dt>
+ *           <dd>The outcome of the test associated with this record
+ *               as run after all attempted repairs.</dd>
+ *       </dl>
+ *       The default behavior here is to be silent.</dd>
+ *   <dt>reportMax()</dt>
+ *     <dd>Displays only a summary of the worst case
+ *         severity seen so far, according to {@code ses.maxSeverity} as
+ *         interpreted by {@code ses.logger.classify}.</dd>
+ *   <dt>reportDiagnosis(severity, status, problemList)</dt>
+ *     <dd>where {@code severity} is a severity record, {@code status}
+ *         is a brief string description of a list of problems, and
+ *         {@code problemList} is a list of strings, each of which is
+ *         one occurrence of the described problem.
+ *         The default behavior here should only the number of
+ *         problems, not the individual problems.</dd>
+ * </dl>
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * //provides ses.logger
+ * @author Mark S. Miller
+ * @requires console
+ * @overrides ses, loggerModule
+ */
+var ses;
+if (!ses) { ses = {}; }
+
+(function loggerModule() {
+  "use strict";
+
+  var logger;
+  function logNowhere(str) {}
+
+  var slice = [].slice;
+  var apply = slice.apply;
+
+
+
+  if (ses.logger) {
+    logger = ses.logger;
+
+  } else if (typeof console !== 'undefined' && 'log' in console) {
+    // We no longer test (typeof console.log === 'function') since,
+    // on IE9 and IE10preview, in violation of the ES5 spec, it
+    // is callable but has typeof "object".
+    // See https://connect.microsoft.com/IE/feedback/details/685962/
+    //   console-log-and-others-are-callable-but-arent-typeof-function
+
+    // We manually wrap each call to a console method because <ul>
+    // <li>On some platforms, these methods depend on their
+    //     this-binding being the console.
+    // <li>All this has to work on platforms that might not have their
+    //     own {@code Function.prototype.bind}, and has to work before
+    //     we install an emulated bind.
+    // </ul>
+
+    var forward = function(level, args) {
+      args = slice.call(args, 0);
+      // We don't do "console.apply" because "console" is not a function
+      // on IE 10 preview 2 and it has no apply method. But it is a
+      // callable that Function.prototype.apply can successfully apply.
+      // This code most work on ES3 where there's no bind. When we
+      // decide support defensiveness in contexts (frames) with mutable
+      // primordials, we will need to revisit the "call" below.
+      apply.call(console[level], console, [''].concat(args));
+
+      // See debug.js
+      var getStack = ses.getStack;
+      if (getStack) {
+        for (var i = 0, len = args.length; i < len; i++) {
+          var stack = getStack(args[i]);
+          if (stack) {
+            console[level]('', stack);
+          }
+        }
+      }
+    };
+
+    logger = {
+      log:   function log(var_args)   { forward('log', arguments); },
+      info:  function info(var_args)  { forward('info', arguments); },
+      warn:  function warn(var_args)  { forward('warn', arguments); },
+      error: function error(var_args) { forward('error', arguments); }
+    };
+  } else {
+    logger = {
+      log:   logNowhere,
+      info:  logNowhere,
+      warn:  logNowhere,
+      error: logNowhere
+    };
+  }
+
+  /**
+   * Returns a record that's helpful for displaying a severity.
+   *
+   * <p>The record contains {@code consoleLevel} and {@code note}
+   * properties whose values are strings. The {@code consoleLevel} is
+   * {@code "log", "info", "warn", or "error"}, which can be used as
+   * method names for {@code logger}, or, in an html context, as a css
+   * class name. The {@code note} is a string stating the severity
+   * level and its consequences for SES.
+   */
+  function defaultClassify(postSeverity) {
+    var MAX_SES_SAFE = ses.severities.SAFE_SPEC_VIOLATION;
+
+    var consoleLevel = 'log';
+    var note = '';
+    if (postSeverity.level > ses.severities.SAFE.level) {
+      consoleLevel = 'info';
+      note = postSeverity.description + '(' + postSeverity.level + ')';
+      if (postSeverity.level > ses.maxAcceptableSeverity.level) {
+        consoleLevel = 'error';
+        note += ' is not suitable for SES';
+      } else if (postSeverity.level > MAX_SES_SAFE.level) {
+        consoleLevel = 'warn';
+        note += ' is not SES-safe';
+      }
+      note += '.';
+    }
+    return {
+      consoleLevel: consoleLevel,
+      note: note
+    };
+  }
+
+  if (!logger.classify) {
+    logger.classify = defaultClassify;
+  }
+
+  /**
+   * By default is chatty
+   */
+  function defaultReportRepairs(reports) {
+    for (var i = 0; i < reports.length; i++) {
+      var report = reports[i];
+      if (report.status !== 'All fine') {
+        logger.warn(report.status + ': ' + report.description);
+      }
+    }
+  }
+
+  if (!logger.reportRepairs) {
+    logger.reportRepairs = defaultReportRepairs;
+  }
+
+  /**
+   * By default, logs a report suitable for display on the console.
+   */
+  function defaultReportMax() {
+    if (ses.maxSeverity.level > ses.severities.SAFE.level) {
+      var maxClassification = ses.logger.classify(ses.maxSeverity);
+      logger[maxClassification.consoleLevel](
+        'Max Severity: ' + maxClassification.note);
+    }
+  }
+
+  if (!logger.reportMax) {
+    logger.reportMax = defaultReportMax;
+  }
+
+  function defaultReportDiagnosis(severity, status, problemList) {
+    var classification = ses.logger.classify(severity);
+    ses.logger[classification.consoleLevel](
+      problemList.length + ' ' + status);
+  }
+
+  if (!logger.reportDiagnosis) {
+    logger.reportDiagnosis = defaultReportDiagnosis;
+  }
+
+  ses.logger = logger;
+
+})();
diff --git a/makeFarResourceMaker.js b/makeFarResourceMaker.js
new file mode 100644
index 0000000..92db94e
--- /dev/null
+++ b/makeFarResourceMaker.js
@@ -0,0 +1,141 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Makes a "makeFarResource" function using a given
+ * serializer/unserializer pair. A makeFarResource function makes a
+ * farPromise for an (assumed remote) resource for a given URL.
+ *
+ * //provides ses.makeFarResourceMaker
+ * @author Mark S. Miller, but interim only until I examine how
+ * ref_send/web_send (Tyler Close), qcomm (Kris Kowal), and BCap (Mark
+ * Lentczner, Arjun Guha, Joe Politz) deal with similar issues.
+ * @overrides ses
+ * @requires Q, cajaVM
+ * @requires UniformRequest, AnonXMLHttpRequest, XMLHttpRequest
+ */
+
+var ses;
+
+(function() {
+   "use strict";
+
+   if (ses && !ses.ok()) { return; }
+
+   var bind = Function.prototype.bind;
+   // See
+   // http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
+   var uncurryThis = bind.bind(bind.call);
+
+   var applyFn = uncurryThis(bind.apply);
+   var mapFn = uncurryThis([].map);
+
+   var freeze = Object.freeze;
+   var constFunc = cajaVM.constFunc;
+
+   var XHR;
+   if (typeof UniformRequest !== 'undefined') {
+     // Prefer UniformRequest
+     XHR = UniformRequest;
+   } else if (typeof AnonXMLHttpRequest !== 'undefined') {
+     // AnonXMLHttpRequest is our next preference
+     XHR = AnonXMLHttpRequest;
+   } else {
+     // If we can find a way to turn off the sending of credentials
+     // for same-origin requests even in this case, we should.
+     XHR = XMLHttpRequest;
+   }
+
+   /**
+    * Makes a makeFarResource function using a given
+    * serializer/unserializer pair. A makeFarResource function makes a
+    * farPromise for an (assumed remote) resource for a given URL.
+    *
+    * <p>The optional serializer, if omitted, defaults to passing
+    * through undefined and simple coercion of to string of everything
+    * else. The optional unserializer defaults to passing back the
+    * undefined or resultText that it is given. If both are omitted,
+    * the resulting maker makes text resources, that provide access to
+    * the text representation of the resource named at that url.
+    */
+   function makeFarResourceMaker(opt_serialize, opt_unserialize) {
+     var serialize = opt_serialize || function(opt_input) {
+       if (opt_input === void 0) { return void 0; }
+       return '' + opt_input;
+     };
+     var unserialize = opt_unserialize || function(opt_resultText) {
+       return opt_resultText;
+     };
+
+     /**
+      * Makes a farPromise for an (assumed remote) resource for a given
+      * URL.
+      */
+     function makeFarResource(url) {
+       url = '' + url;
+
+       var nextSlot = Q.defer();
+
+       function farDispatch(OP, args) {
+         var opt_name = args[0];
+         var opt_entityBody = serialize(args[1]);
+         var xhr = new XHR();
+         if (opt_name !== void 0) {
+           // This should be a safe encoding
+           url = url + '&q=' + encodeURIComponent(opt_name);
+         }
+         xhr.open(OP, url);
+
+         var result = Q.defer();
+         xhr.onreadystatechange = function() {
+           if (this.readyState === 4) {
+             // TODO(erights): On the status codes, do what mzero
+             // suggests. Seek to interoperate not just with ourselves
+             // but at least with ref_send, qcomm, and bcap.
+             if (this.status === 200) {
+               result.resolve(unserialize(this.responseText));
+
+          // } else if... { // What about other success statuses besides 200?
+               // And do we deal with any redirects here, such as a
+               // permanent redirect?
+
+             } else if (this.status === 410) {
+               var broken = Q.reject(new Error('Resource Gone'));
+               nextSlot.resolve(freeze({value: broken}));
+               result.resolve(broken);
+
+             } else {
+               // TODO(erights): better diagnostics. Include
+               // responseText in Error?
+               result.resolve(Q.reject(new Error('xhr ' + OP +
+                                                 ' failed with status: ' +
+                                                 this.status)));
+             }
+           }
+         };
+         if (opt_entityBody === void 0) {
+           xhr.send();
+         } else {
+           xhr.send(opt_entityBody);
+         }
+         return result.promise;
+       }
+
+       return Q.makeFar(farDispatch, nextSlot.promise);
+     }
+     return constFunc(makeFarResource);
+   }
+   ses.makeFarResourceMaker = constFunc(makeFarResourceMaker);
+
+ })();
diff --git a/makeQ.js b/makeQ.js
new file mode 100644
index 0000000..4f8cad9
--- /dev/null
+++ b/makeQ.js
@@ -0,0 +1,690 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Implements the EcmaScript
+ * http://wiki.ecmascript.org/doku.php?id=strawman:concurrency
+ * strawman, securely when run a Caja or SES platform.
+ *
+ * //provides ses.makeQ
+ * @author Mark S. Miller, based on earlier designs by Tyler Close,
+ * Kris Kowal, and Kevin Reid.
+ * @overrides ses
+ * @requires WeakMap, cajaVM
+ */
+
+var ses;
+
+(function() {
+   "use strict";
+
+   if (ses && !ses.ok()) { return; }
+
+   var bind = Function.prototype.bind;
+   // See
+   // http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
+   var uncurryThis = bind.bind(bind.call);
+
+   var bindFn = uncurryThis(bind);
+   var applyFn = uncurryThis(bind.apply);
+   var sliceFn = uncurryThis([].slice);
+   var toStringFn = uncurryThis({}.toString);
+
+   var freeze = Object.freeze;
+   var constFunc = cajaVM.constFunc;
+   var def = cajaVM.def;
+   var is = cajaVM.is;
+
+
+   /**
+    * Tests if the presumably thrown error is simply signaling the end
+    * of a generator's iteration.
+    *
+    * <p>TODO(erights): Find some way to accomodate Firefox's
+    * pre-harmony iterators, at least for pre-harmony testing. Take a
+    * look at how Kris Kowal's q library handles this.
+    *
+    * <p>See
+    * http://wiki.ecmascript.org/doku.php?id=harmony:iterators#stopiteration
+    */
+   function isStopIteration(err) {
+     return toStringFn(err) === '[object StopIteration]';
+   }
+
+
+   /**
+    * Makes a Q object which uses the provided setTimeout function to
+    * postpone events to future turns.
+    */
+   function makeQ(setTimeout) {
+
+     /**
+      * Maps from promises to their handlers.
+      *
+      * <p>All handlers and the "handlers" map must never escape. A
+      * handler holds <i>all</i> the state of its promise, serving as a
+      * private state record, but more flexible in two ways we take
+      * advantage of:
+      * <ul>
+      * <li>A promise can change state and behavior by changing which
+      * handler it is associated with.
+      * <li>More than one promise can share the same handler, making them
+      * essentially identical except for identity.
+      * </ul>
+      */
+     var handlers = WeakMap();
+
+     /**
+      * Among objects, all and only promises have handlers.
+      */
+     function isPromise(value) {
+       if (value !== Object(value)) { return false; }
+       return !!handlers.get(value);
+     }
+
+     /**
+      * Get the "best" handler associated with this promise, shortening
+      * "became" chains in the process.
+      */
+     function handle(promise) {
+       var handler = handlers.get(promise);
+       if (!handler || !handler.became) { return handler; }
+       while (handler.became) {
+         handler = handler.became;
+       }
+       handlers.set(promise, handler);
+       return handler;
+     }
+
+     /**
+      * Run the thunk later in its own turn, but immediately return a
+      * promise for what its outcome will be.
+      */
+     function postpone(thunk) {
+       var result = defer();
+       setTimeout(function() {
+         var value;
+         try {
+           value = thunk();
+         } catch (reason) {
+           value = reject(reason);
+         }
+         result.resolve(value);
+       }, 0);
+       return result.promise;
+     }
+
+     /**
+      * To deliver a messenger to a handler is to eventually ask the handler to
+      * dispatch on the meesage carried by the messenger, and to return the
+      * outcome to the messenger's resolver.
+      *
+      * <p>A messenger is a record with
+      * <ul>
+      * <li>OP - the name of one of the concrete handler methods spelled
+      * in all upper case, which is currently GET, POST, PUT, DELETE, and
+      * WHEN. We might add the other HTTP verbs, HEAD and OPTION. And we
+      * might add the other needed reference bookkeeping operation,
+      * WHEN_BROKEN, so that a farPromise can notify if it later breaks.
+      * <li>args - the array of arguments to use when calling the
+      * handler's OP method.
+      * <li>resolve - a resolver function, for reporting the outcome of
+      * eventually asking the handler to dispatch the messenger's message.
+      * </ul>
+      * The messenger's message consists of its OP and args.
+      *
+      * <p>A handler's dispatch method may deliver the messenger's message
+      * to this handler, buffer the messenger for later, or ask another
+      * handler to dispatch it.
+      */
+     function deliver(handler, messenger) {
+       var value;
+       setTimeout(function() {
+         try {
+           value = handler.dispatch(messenger.OP,
+                                    messenger.args);
+         } catch (reason) {
+           value = reject(reason);
+         }
+         messenger.resolve(value);
+       }, 0);
+     }
+
+
+     /*************************************************************************
+      * A near promise's resolution is a non-promise.
+      *
+      * <p>"promise" must be a near promise whose handler is this
+      * handler. "target" must be a non-promise. The NearHandler
+      * constructor does not actually use its "promise" argument, but it
+      * is there to support the general HandlerConstructor API as assumed
+      * by the Promise constructor.
+      */
+     function NearHandler(promise, target) {
+       this.target = target;
+     }
+     NearHandler.prototype = {
+
+       stateName: 'near',
+
+       nearer: function() { return this.target; },
+
+       dispatch: function(OP, args) {
+         return applyFn(this[OP], this, args);
+       },
+
+       POST: function(opt_name, args) {
+         var target = this.target;
+         if (opt_name === null || opt_name === void 0) {
+           return applyFn(target, void 0, args);
+         } else {
+           return applyFn(target[opt_name], target, args);
+         }
+       },
+
+       GET: function(name)        { return this.target[name]; },
+       PUT: function(name, value) { this.target[name] = value; return void 0; },
+       DELETE: function(name)     { return delete this.target[name]; },
+
+       /** Just invoke sk, the success continuation */
+       WHEN:function(sk, fk)      { return sk(this.target); }
+     };
+
+     /**
+      * Returns the promise form of value.
+      *
+      * <p>If value is already a promise, return it. Otherwise wrap it
+      * in a promise that is already resolved to value.
+      */
+     function Q(value) {
+       if (isPromise(value)) { return value; }
+       return new Promise(NearHandler, value);
+     }
+
+
+     /*************************************************************************
+      * A broken promise will never deliver any operations because of the
+      * stated reason.
+      *
+      * <p>"promise" must be a broken promise whose handler is this handler.
+      * "reason" will typically be a thrown Error. An originally broken
+      * promise's resolution is itself. A broken promise's resolution is
+      * a broken promise just like itself, except possibly for identity.
+      */
+     function BrokenHandler(promise, reason) {
+       this.promise = promise;
+       this.reason = reason;
+
+       this.stateName = 'broken (by ' + reason + ')';
+     }
+     BrokenHandler.prototype = {
+
+       nearer: function() { return this.promise; },
+
+       dispatch: function(OP, args) {
+         if (OP === 'WHEN') { return this.WHEN (args[0], args[1]); }
+         return this.promise;
+       },
+
+       /** Just invoke fk, the failure continuation */
+       WHEN:  function(sk, fk) { return fk(this.reason); }
+     };
+
+     /**
+      * Reject makes a new broken promise which reports "reason" as the
+      * alleged reason why it is broken.
+      *
+      * <p>Does a def(reason), which (transitively under SES) freezes
+      * reason.
+      */
+     function reject(reason) {
+       reason = def(reason);
+       try {
+         return new Promise(BrokenHandler, reason);
+       } catch (err) {
+         // Workaround undiagnosed intermittent FF bug. TODO(erights):
+         // isolate and report.
+         // debugger;
+         reason = 'Failing to report error for mysterious reasons';
+       }
+       return new Promise(BrokenHandler, reason);
+     }
+
+     /**
+      * Resolving a promise to itself breaks all promises in the loop
+      * with the reason being an Error complaining of a vicious promise
+      * cycle.
+      */
+     var theViciousCycle;
+     var theViciousCycleHandler;
+
+
+     /*************************************************************************
+      * The handler for a local unresolved promise, as made by defer().
+      *
+      * <p>"promise" must be a local unresolved promise.
+      */
+     function UnresolvedHandler(promise, queue) {
+       this.promise = promise;
+       this.queue = queue;
+     }
+     UnresolvedHandler.prototype = {
+
+       stateName: 'unresolved',
+
+       nearer: function() { return this.promise; },
+
+       dispatch: function(OP, args) {
+         var result = defer();
+         this.queue({
+           resolve: result.resolve,
+           OP: OP,
+           args: args
+         });
+         return result.promise;
+       }
+     };
+
+     /**
+      * Have all promises which were using oldHandler as their handler
+      * instead use newPromise's handler as their handler.
+      *
+      * <p>oldHandler must be a become-able kind of handler, i.e., an
+      * UnresolvedHandler, FarHandler, or RemoteHandler. It also must
+      * not yet have become anything.
+      */
+     function become(oldHandler, newPromise) {
+       oldHandler.became = theViciousCycleHandler;
+       var newHandler = handle(newPromise);
+       oldHandler.became = newHandler;
+       return newHandler;
+     }
+
+     /**
+      * Returns an unresolved promise and its corresponding resolver
+      * (resolve function).
+      */
+     function defer() {
+       var buffer = [];
+       function queue(messenger) {
+         if (buffer) {
+           buffer.push(messenger);
+         } else {
+           // This case seems to have happened once but I have not yet
+           // been able to reproduce it.
+           debugger;
+         }
+       }
+       var promise = new Promise(UnresolvedHandler, queue);
+       var handler = handle(promise);
+
+       function resolve(value) {
+         if (!buffer) { return; } // silent
+         // assert(handler === handle(promise)) since, the only way this
+         // becomes untrue is by a prior call to resolve, which will
+         // clear buffer, so we would never get here.
+
+         var buf = buffer;
+         buffer = void 0;
+
+         var newHandler = become(handler, Q(value));
+         handle(promise); // just to shorten
+         handler = void 0; // A dead resolver should not retain dead objects
+         promise = void 0;
+
+         var forward;
+         if (newHandler instanceof UnresolvedHandler) {
+           // A nice optimization but not strictly necessary.
+           forward = newHandler.queue;
+         } else {
+           forward = bindFn(deliver, void 0, newHandler);
+         }
+
+         for (var i = 0, len = buf.length; i < len; i++) {
+           forward(buf[i]);
+         }
+       }
+
+       return freeze({
+         promise: promise,
+         resolve: constFunc(resolve)
+       });
+     }
+
+
+     /*************************************************************************
+      * A far promise is a fulfilled promise to a possibly remote
+      * object whose behavior is locally represented by a farDispatch
+      * function.
+      *
+      * <p>The farDispatch function acts like the dispatch method of the
+      * FarHandler, except that it gets only the HTTP verb operations,
+      * not the WHEN operation.
+      *
+      * <p>To support the reporting of partition, for those farDispatches
+      * whose failure model makes partition visible, a far promise may
+      * become broken.
+      */
+     function FarHandler(promise, dispatch) {
+       this.promise = promise;
+       this.dispatch = dispatch;
+     }
+     FarHandler.prototype = {
+       stateName: 'far',
+
+       nearer: function() { return this.promise; },
+
+       /** Just invoke sk, the success continuation */
+       WHEN: function(sk, fk) { return sk(this.promise); }
+     };
+
+     function makeFar(farDispatch, nextSlotP) {
+       var farPromise;
+
+       function dispatch(OP, args) {
+         if (OP === 'WHEN') { return farPromise.WHEN(args[0], args[1]); }
+         return farDispatch(OP, args);
+       }
+       farPromise = new Promise(FarHandler, dispatch);
+
+
+       function breakFar(reason) {
+         // Note that a farPromise is resolved, so its nearer()
+         // identity must be stable, even when it becomes
+         // broken. Thus, we do not become(farHandler, reject(reason))
+         // or become(farHandler, nextSlot.value). Rather, we switch
+         // to a new broken handler whose promise is this same
+         // farPromise.
+         var farHandler = handle(farPromise);
+         var brokenHandler = new BrokenHandler(farPromise, reason);
+         handlers.set(farPromise, brokenHandler);
+         become(farHandler, farPromise);
+       }
+
+       Q(nextSlotP).get('value').when(function(v) {
+         breakFar(new Error('A farPromise can only further resolve to broken'));
+       }, breakFar).end();
+
+       return farPromise;
+     };
+
+
+     /*************************************************************************
+      * A remote promise is an unresolved promise with a possibly remote
+      * resolver, where the behavior of sending a message to a remote
+      * promise may be to send the message to that destination (e.g. for
+      * promise pipelining). The actual behavior is locally represented
+      * by a remoteDispatch function.
+      *
+      * <p>The remoteDispatch function acts like the dispatch method of the
+      * RemoteHandler, except that it gets only the HTTP verb operations,
+      * not the WHEN operation. Instead, the WHEN operations are
+      * forwarded on to the promise for the remote promise's next
+      * resolution.
+      */
+     function RemoteHandler(promise, dispatch) {
+       this.promise = promise;
+       this.dispatch = dispatch;
+     }
+     RemoteHandler.prototype = {
+       stateName: 'unresolved remote',
+
+       nearer: function()       { return this.promise; }
+     };
+
+     function makeRemote(remoteDispatch, nextSlotP) {
+       var remotePromise;
+
+       function dispatch(OP, args) {
+         if (OP === 'WHEN') {
+           // Send "when"s to the remote promise's eventual next
+           // resolution. This has the effect of buffering them locally
+           // until there is such a next resolution.
+           return Q(nextSlotP).get('value').when(args[0], args[1]);
+         }
+         return remoteDispatch(OP, args);
+       }
+       remotePromise = new Promise(RemoteHandler, remoteDispatch);
+
+
+       Q(nextSlotP).when(function(nextSlot) {
+         become(handle(remotePromise, Q(nextSlot.value)));
+       }, function(reason) {
+         become(handle(remotePromise, reject(reason)));
+       }).end();
+
+       return remotePromise;
+     };
+
+
+     /*************************************************************************
+      * <p>A promise is an object which represents a reference to some
+      * other object, where the other object might be elsewhere (e.g., on
+      * a remote machine) or elsewhen (e.g., not yet computed).
+      *
+      * <p>The Promise constructor must not escape. Clients of this module
+      * use the Q function to make promises from non-promises. Since
+      * Promise.prototype does escape, it must not point back at Promise.
+      *
+      * <p>The various methods on a genuine promise never execute "user
+      * code", i.e., possibly untrusted client code, during the immediate
+      * call to the promise method, protecting the caller from plan
+      * interference hazards. Rather, any such execution happens on later
+      * turns scheduled by the promise method. Except for "end", which
+      * returns nothing, all other promise methods return genuine
+      * promises, enabling safe chaining.
+      */
+     function Promise(HandlerMaker, arg) {
+       var handler = new HandlerMaker(this, arg);
+       handlers.set(this, handler);
+       freeze(this);
+     }
+     function DontMakePromise() {
+       throw new Error('Make promises by calling Q()');
+     }
+     DontMakePromise.prototype = Promise.prototype = {
+       constructor: DontMakePromise,
+
+       toString: function() {
+         return '[' + handle(this).stateName + ' promise]';
+       },
+       post: function(opt_name, args) {
+         var that = this;
+         return postpone(function() {
+           return handle(that).dispatch('POST', [opt_name, args]);
+         });
+       },
+       send: function(opt_name, var_args) {
+         return applyFn(this.post, this, [opt_name, sliceFn(arguments, 1)]);
+       },
+       get: function(name) {
+         var that = this;
+         return postpone(function() {
+           return handle(that).dispatch('GET', [name]);
+         });
+       },
+       put: function(name, value) {
+         var that = this;
+         return postpone(function() {
+           return handle(that).dispatch('PUT', [name, value]);
+         });
+       },
+       'delete': function(name) {
+         var that = this;
+         return postpone(function() {
+           return handle(that).dispatch('DELETE', [name]);
+         });
+       },
+       when: function(callback, opt_errback) {
+         var errback = opt_errback || function(reason) { throw reason; };
+         var done = false;
+
+         /** success continuation */
+         function sk(value) {
+           if (done) { throw new Error('This "when" already done.'); }
+           done = true;
+           return postpone(function() { return callback(value); });
+         }
+         /** failure continuation */
+         function fk(reason) {
+           if (done) { throw new Error('This "when" already done.'); }
+           done = true;
+           return postpone(function() { return errback(reason); });
+         }
+
+         var that = this;
+         return postpone(function() {
+           return handle(that).dispatch('WHEN', [sk, fk]);
+         });
+       },
+       end: function() {
+         this.when(function(){},
+                   function(reason) {
+           // So if this setTimeout logs throws that terminate a turn, it
+           // will also log this reason.
+           setTimeout(function() { throw reason; }, 0);
+         });
+       }
+     };
+     def(DontMakePromise);
+
+     function nearer(target1) {
+       var optHandler = handle(target1);
+       if (!optHandler) { return target1; }
+       return optHandler.nearer();
+     }
+
+     //////////////////////////////////////////////////////////////////////////
+
+     Q.reject = reject;
+     Q.defer = defer;
+     Q.isPromise = isPromise;
+
+     Q.makeFar = makeFar;
+
+     Q.makeRemote = makeRemote;
+
+     Q.nearer = nearer;
+
+     theViciousCycle = reject(new Error('vicious promise cycle'));
+     theViciousCycleHandler = handle(theViciousCycle);
+
+     //////////////////////////////////////////////////////////////////////////
+     // Non-fundamental conveniences below.
+
+     Q.delay = function(millis, opt_answer) {
+       var result = Q.defer();
+       setTimeout(function() { result.resolve(opt_answer); }, millis);
+       return result.promise;
+     };
+
+     Q.race = function(answerPs) {
+       var result = Q.defer();
+       answerPs.forEach(function(answerP) {
+         Q(answerP).when(function(answer) {
+           result.resolve(answer);
+         }, function(err) {
+           result.resolve(Q.reject(err));
+         });
+       });
+       return result.promise;
+     };
+
+     Q.all = function(answerPs) {
+       var countDown = answerPs.length;
+       var answers = [];
+       if (countDown === 0) { return Q(answers); }
+       var result = Q.defer();
+       answerPs.forEach(function(answerP, index) {
+         Q(answerP).when(function(answer) {
+           answers[index] = answer;
+           if (--countDown === 0) {
+             // Note: Only a shallow freeze(), not a def().
+             result.resolve(Object.freeze(answers));
+           }
+         }, function(err) {
+           result.resolve(Q.reject(err));
+         });
+       });
+       return result.promise;
+     };
+
+     Q.join = function(var_args) {
+       var args = sliceFn(arguments, 0);
+       var len = args.length;
+       if (len === 0) {
+         return Q.reject(new Error('No references joined'));
+       }
+       return Q.all(args).when(function(fulfilleds) {
+         var first = fulfilleds[0];
+         for (var i = 1; i < len; i++) {
+           if (!is(first, fulfilleds[i])) {
+             throw new Error("not the same");
+           }
+         }
+         // is() guarantees there's no observable difference between
+         // first and any of the others
+         return first;
+       });
+     };
+
+     Q.memoize = function(oneArgFuncP, opt_memoMap) {
+       var memoMap = opt_memoMap || WeakMap();
+
+       function oneArgMemo(arg) {
+         var resultP = memoMap.get(arg);
+         if (!resultP) {
+           resultP = Q(oneArgFuncP).send(void 0, arg);
+           memoMap.set(arg, resultP);
+         }
+         return resultP;
+       }
+       return constFunc(oneArgMemo);
+     };
+
+     /**
+      * On platforms with generators (either ES-Harmony or existing
+      * FF), this can be used with generators to express <a href=
+      * "http://wiki.ecmascript.org/doku.php?id=strawman:async_functions"
+      * >Asynchronous Functions</a>. Please see that page for further
+      * explanation.
+      */
+     Q.async = function(generatorFunc) {
+       function asyncFunc(var_args) {
+         var args = sliceFn(arguments, 0);
+         var generator = generatorFunc.apply(this, args);
+         var callback = continuer.bind(void 0, 'send');
+         var errback = continuer.bind(void 0, 'throw');
+
+         function continuer(verb, valueOrErr) {
+           var promisedValue;
+           try {
+             promisedValue = generator[verb](valueOrErr);
+           } catch (err) {
+             if (isStopIteration(err)) { return Q(err.value); }
+             return Q.reject(err);
+           }
+           return Q(promisedValue).when(callback, errback);
+         }
+
+         return callback(void 0);
+       }
+       return constFunc(asyncFunc);
+     };
+
+     return def(Q);
+   };
+   def(makeQ);
+   ses.makeQ = makeQ;
+ })();
diff --git a/makeSimpleAMDLoader.js b/makeSimpleAMDLoader.js
new file mode 100644
index 0000000..da1cf08
--- /dev/null
+++ b/makeSimpleAMDLoader.js
@@ -0,0 +1,143 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Makes a loader for a simple subset of the
+ * Asynchronous Module Loader (AMD) API
+ * https://github.com/amdjs/amdjs-api/wiki/AMD . Based on
+ * http://wiki.ecmascript.org/doku.php?id=strawman:concurrency#amd_loader_lite
+ *
+ * //provides makeSimpleAMDLoader
+ * @author Mark S. Miller
+ * @requires StringMap, cajaVM
+ * @requires this, compileExprLater, Q
+ */
+
+
+(function(imports){
+   "use strict";
+
+   var bind = Function.prototype.bind;
+   // See
+   // http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
+   var uncurryThis = bind.bind(bind.call);
+
+   var applyFn = uncurryThis(bind.apply);
+   var mapFn = uncurryThis([].map);
+
+   var freeze = Object.freeze;
+   var constFunc = cajaVM.constFunc;
+
+
+   /**
+    * A pumpkin is a unique value that must never escape, and so may
+    * safely be used to test for the absence of any possible
+    * user-provided value.
+    */
+   var defineNotCalledPumpkin = {};
+
+   /**
+    * Makes a loader for a simple subset of the Asynchronous Module
+    * Loader (AMD) API.
+    *
+    * <p>Terminology: When we say a function "reveals" a value X, we
+    * means that it either immediately returns an X or it immediately
+    * returns a promise that it eventually fulfills with an X. Unless
+    * stated otherwise, we implicitly elide the error conditions from
+    * such statements. For the more explicit statement, append: "or it
+    * throws, or it does not terminate, or it breaks the returned
+    * promise, or it never resolves the returned promise."
+    *
+    * <p>The provided "fetch" function should be a function from a
+    * module name string to revealing the source string for that
+    * module. This source string is assumed to be in (our simple
+    * subset of) AMD format. When run under Caja/SES, the module
+    * source is executed in a scope consisting of only the whitelisted
+    * globals and the "define" function from our subset of the AMD
+    * API. Our "define" function always takes at least the following
+    * two arguments: <ul>
+    * <li>"deps" --- a "dependencies" array of module name strings,
+    * <li>and a factory function.
+    * </ul>
+    * The factory function should have one parameter for accepting
+    * each module instance corresponding to each of these module
+    * names. Whatever the factory function reveals is taken to be the
+    * instance of this module.
+    *
+    * <p>Note that in this subset, a module's source does not get to
+    * determine its own module name. Rather, this naming is only
+    * according to the mapping provided by the "fetch"
+    * function. However, in a concession to jQuery, the module can
+    * provide the "define" function's first optional argument, in
+    * which it declares its own module name. The "define" function
+    * will then check whether this agrees with the module name as
+    * determined by the "fetch" function, and if not, break the
+    * promise for the module instance.
+    *
+    * <p>The opt_moduleMap, if provided, should be a mapping from
+    * module names to module instances. To endow a subsystem with the
+    * ability to import connections to the outside world, provide an
+    * opt_moduleMap already initialized with some pre-existing
+    * name-to-instance associations.
+    */
+   function makeSimpleAMDLoader(fetch, opt_moduleMap) {
+     var moduleMap = opt_moduleMap || StringMap();
+
+     var loader;
+
+     function rawLoad(id) {
+       return Q(fetch(id)).when(function(src) {
+
+         var result = defineNotCalledPumpkin;
+         function define(opt_id, deps, factory) {
+           if (typeof opt_id === 'string') {
+             if (opt_id !== id) {
+               result = Q.reject(new Error('module "' + id +
+                                           '" thinks it is "' + opt_id + '"'));
+               return;
+             }
+           } else {
+             factory = deps;
+             deps = opt_id;
+           }
+           var importPs = mapFn(deps, loader);
+           result = Q.all(importPs).when(function(imports) {
+             return applyFn(factory, void 0, imports);
+           });
+         }
+         // TODO(erights): Once we're jQuery compatible, change
+         // jQuery: to true.
+         define.amd = freeze({ lite: true, caja: true, jQuery: false });
+
+         var imports = cajaVM.makeImports();
+         cajaVM.copyToImports(imports, {define: constFunc(define)});
+
+         var compiledExprP = compileExprLater(
+           '(function(){' + src + '})()', id);
+         return Q(compiledExprP).when(function(compiledExpr) {
+
+           compiledExpr(imports);
+           if (result === defineNotCalledPumpkin) {
+             result = Q.reject(new Error('"define" not called by: ' + id));
+           }
+           return result;
+         });
+       });
+     }
+     return loader = Q.memoize(rawLoad, moduleMap);
+   }
+
+   imports.makeSimpleAMDLoader = constFunc(makeSimpleAMDLoader);
+
+ })(this);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..9d39875
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+    "name": "ses",
+    "version": "0.0.0",
+    "dependencies": {
+    }
+}
diff --git a/repairES5.js b/repairES5.js
new file mode 100644
index 0000000..0a13260
--- /dev/null
+++ b/repairES5.js
@@ -0,0 +1,3463 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Monkey patch almost ES5 platforms into a closer
+ * emulation of full <a href=
+ * "http://code.google.com/p/es-lab/wiki/SecureableES5">Secureable
+ * ES5</a>.
+ *
+ * <p>Assumes only ES3, but only proceeds to do useful repairs when
+ * the platform is close enough to ES5 to be worth attempting
+ * repairs. Compatible with almost-ES5, ES5, ES5-strict, and
+ * anticipated ES6.
+ *
+ * <p>Ignore the "...requires ___global_test_function___" below. We
+ * create it, use it, and delete it all within this module. But we
+ * need to lie to the linter since it can't tell.
+ *
+ * //provides ses.statuses, ses.ok, ses.is, ses.makeDelayedTamperProof
+ * //provides ses.makeCallerHarmless, ses.makeArgumentsHarmless
+ * //provides ses.severities, ses.maxSeverity, ses.updateMaxSeverity
+ * //provides ses.maxAcceptableSeverityName, ses.maxAcceptableSeverity
+ *
+ * @author Mark S. Miller
+ * @requires ___global_test_function___, ___global_valueOf_function___
+ * @requires JSON, navigator, this, eval, document
+ * @overrides ses, RegExp, WeakMap, Object, parseInt, repairES5Module
+ */
+var RegExp;
+var ses;
+
+/**
+ * <p>Qualifying platforms generally include all JavaScript platforms
+ * shown on <a href="http://kangax.github.com/es5-compat-table/"
+ * >ECMAScript 5 compatibility table</a> that implement {@code
+ * Object.getOwnPropertyNames}. At the time of this writing,
+ * qualifying browsers already include the latest released versions of
+ * Internet Explorer (9), Firefox (4), Chrome (11), and Safari
+ * (5.0.5), their corresponding standalone (e.g., server-side) JavaScript
+ * engines, Rhino 1.73, and BESEN.
+ *
+ * <p>On such not-quite-ES5 platforms, some elements of these
+ * emulations may lose SES safety, as enumerated in the comment on
+ * each kludge record in the {@code kludges} array below. The platform
+ * must at least provide {@code Object.getOwnPropertyNames}, because
+ * it cannot reasonably be emulated.
+ *
+ * <p>This file is useful by itself, as it has no dependencies on the
+ * rest of SES. It creates no new global bindings, but merely repairs
+ * standard globals or standard elements reachable from standard
+ * globals. If the future-standard {@code WeakMap} global is present,
+ * as it is currently on FF7.0a1, then it will repair it in place. The
+ * one non-standard element that this file uses is {@code console} if
+ * present, in order to report the repairs it found necessary, in
+ * which case we use its {@code log, info, warn}, and {@code error}
+ * methods. If {@code console.log} is absent, then this file performs
+ * its repairs silently.
+ *
+ * <p>Generally, this file should be run as the first script in a
+ * JavaScript context (i.e. a browser frame), as it relies on other
+ * primordial objects and methods not yet being perturbed.
+ *
+ * <p>TODO(erights): This file tries to protect itself from some
+ * post-initialization perturbation by stashing some of the
+ * primordials it needs for later use, but this attempt is currently
+ * incomplete. We need to revisit this when we support Confined-ES5,
+ * as a variant of SES in which the primordials are not frozen. See
+ * previous failed attempt at <a
+ * href="http://codereview.appspot.com/5278046/" >Speeds up
+ * WeakMap. Preparing to support unfrozen primordials.</a>. From
+ * analysis of this failed attempt, it seems that the only practical
+ * way to support CES is by use of two frames, where most of initSES
+ * runs in a SES frame, and so can avoid worrying about most of these
+ * perturbations.
+ */
+(function repairES5Module(global) {
+  "use strict";
+
+  /**
+   * The severity levels.
+   *
+   * <dl>
+   *   <dt>MAGICAL_UNICORN</dt><dd>Unachievable magical mode used for testing.
+   *   <dt>SAFE</dt><dd>no problem.
+   *   <dt>SAFE_SPEC_VIOLATION</dt>
+   *     <dd>safe (in an integrity sense) even if unrepaired. May
+   *         still lead to inappropriate failures.</dd>
+   *   <dt>NO_KNOWN_EXPLOIT_SPEC_VIOLATION</dt>
+   *     <dd>known to introduce an indirect safety issue which,
+   *     however, is not known to be exploitable.</dd>
+   *   <dt>UNSAFE_SPEC_VIOLATION</dt>
+   *     <dd>a safety issue only indirectly, in that this spec
+   *         violation may lead to the corruption of assumptions made
+   *         by other security critical or defensive code.</dd>
+   *   <dt>NOT_OCAP_SAFE</dt>
+   *     <dd>a violation of object-capability rules among objects
+   *         within a coarse-grained unit of isolation.</dd>
+   *   <dt>NOT_ISOLATED</dt>
+   *     <dd>an inability to reliably sandbox even coarse-grain units
+   *         of isolation.</dd>
+   *   <dt>NEW_SYMPTOM</dt>
+   *     <dd>some test failed in a way we did not expect.</dd>
+   *   <dt>NOT_SUPPORTED</dt>
+   *     <dd>this platform cannot even support SES development in an
+   *         unsafe manner.</dd>
+   * </dl>
+   */
+  ses.severities = {
+    MAGICAL_UNICORN:       { level: -1, description: 'Testing only' },
+    SAFE:                  { level: 0, description: 'Safe' },
+    SAFE_SPEC_VIOLATION:   { level: 1, description: 'Safe spec violation' },
+    NO_KNOWN_EXPLOIT_SPEC_VIOLATION: {
+        level: 2, description: 'Unsafe spec violation but no known exploits' },
+    UNSAFE_SPEC_VIOLATION: { level: 3, description: 'Unsafe spec violation' },
+    NOT_OCAP_SAFE:         { level: 4, description: 'Not ocap safe' },
+    NOT_ISOLATED:          { level: 5, description: 'Not isolated' },
+    NEW_SYMPTOM:           { level: 6, description: 'New symptom' },
+    NOT_SUPPORTED:         { level: 7, description: 'Not supported' }
+  };
+
+  /**
+   * Statuses.
+   *
+   * <dl>
+   *   <dt>ALL_FINE</dt>
+   *     <dd>test passed before and after.</dd>
+   *   <dt>REPAIR_FAILED</dt>
+   *     <dd>test failed before and after repair attempt.</dd>
+   *   <dt>NOT_REPAIRED</dt>
+   *     <dd>test failed before and after, with no repair to attempt.</dd>
+   *   <dt>REPAIRED_UNSAFELY</dt>
+   *     <dd>test failed before and passed after repair attempt, but
+   *         the repair is known to be inadequate for security, so the
+   *         real problem remains.</dd>
+   *   <dt>REPAIRED</dt>
+   *     <dd>test failed before and passed after repair attempt,
+   *         repairing the problem (canRepair was true).</dd>
+   *   <dt>ACCIDENTALLY_REPAIRED</dt>
+   *      <dd>test failed before and passed after, despite no repair
+   *          to attempt. (Must have been fixed by some other
+   *          attempted repair.)</dd>
+   *   <dt>BROKEN_BY_OTHER_ATTEMPTED_REPAIRS</dt>
+   *      <dd>test passed before and failed after, indicating that
+   *          some other attempted repair created the problem.</dd>
+   * </dl>
+   */
+  ses.statuses = {
+    ALL_FINE:                          'All fine',
+    REPAIR_FAILED:                     'Repair failed',
+    NOT_REPAIRED:                      'Not repaired',
+    REPAIRED_UNSAFELY:                 'Repaired unsafely',
+    REPAIRED:                          'Repaired',
+    ACCIDENTALLY_REPAIRED:             'Accidentally repaired',
+    BROKEN_BY_OTHER_ATTEMPTED_REPAIRS: 'Broken by other attempted repairs'
+  };
+
+
+  var logger = ses.logger;
+
+  /**
+   * As we start to repair, this will track the worst post-repair
+   * severity seen so far.
+   */
+  ses.maxSeverity = ses.severities.SAFE;
+
+  /**
+   * {@code ses.maxAcceptableSeverity} is the max post-repair severity
+   * that is considered acceptable for proceeding with the SES
+   * verification-only strategy.
+   *
+   * <p>Although <code>repairES5.js</code> can be used standalone for
+   * partial ES5 repairs, its primary purpose is to repair as a first
+   * stage of <code>initSES.js</code> for purposes of supporting SES
+   * security. In support of that purpose, we initialize
+   * {@code ses.maxAcceptableSeverity} to the post-repair severity
+   * level at which we should report that we are unable to adequately
+   * support SES security. By default, this is set to
+   * {@code ses.severities.SAFE_SPEC_VIOLATION}, which is the maximum
+   * severity that we believe results in no loss of SES security.
+   *
+   * <p>If {@code ses.maxAcceptableSeverityName} is already set (to a
+   * severity property name of a severity below {@code
+   * ses.NOT_SUPPORTED}), then we use that setting to initialize
+   * {@code ses.maxAcceptableSeverity} instead. For example, if we are
+   * using SES only for isolation, then we could set it to
+   * 'NOT_OCAP_SAFE', in which case repairs that are inadequate for
+   * object-capability (ocap) safety would still be judged safe for
+   * our purposes.
+   *
+   * <p>As repairs proceed, they update {@code ses.maxSeverity} to
+   * track the worst case post-repair severity seen so far. When
+   * {@code ses.ok()} is called, it return whether {@code
+   * ses.maxSeverity} is still less than or equal to
+   * {@code ses.maxAcceptableSeverity}, indicating that this platform
+   * still seems adequate for supporting SES. In the Caja context, we
+   * have the choice of using SES on those platforms which we judge to
+   * be adequately repairable, or otherwise falling back to Caja's
+   * ES5/3 translator.
+   */
+  ses.maxAcceptableSeverityName = 
+    validateSeverityName(ses.maxAcceptableSeverityName);
+  ses.maxAcceptableSeverity = ses.severities[ses.maxAcceptableSeverityName];
+
+  function validateSeverityName(severityName) {
+    if (severityName) {
+      var sev = ses.severities[severityName];
+      if (sev && typeof sev.level === 'number' &&
+        sev.level >= ses.severities.SAFE.level &&
+        sev.level < ses.severities.NOT_SUPPORTED.level) {
+        // do nothing
+      } else {
+        logger.error('Ignoring bad severityName: ' +
+                   severityName + '.');
+        severityName = 'SAFE_SPEC_VIOLATION';
+      }
+    } else {
+      severityName = 'SAFE_SPEC_VIOLATION';
+    }
+    return severityName;
+  }
+  function severityNameToLevel(severityName) {
+    return ses.severities[validateSeverityName(severityName)];
+  }
+
+  /**
+   * Once this returns false, we can give up on the SES
+   * verification-only strategy and fall back to ES5/3 translation.
+   */
+  ses.ok = function ok(maxSeverity) {
+    if ("string" === typeof maxSeverity) {
+      maxSeverity = ses.severities[maxSeverity];
+    }
+    if (!maxSeverity) {
+      maxSeverity = ses.maxAcceptableSeverity;
+    }
+    return ses.maxSeverity.level <= maxSeverity.level;
+  };
+
+  /**
+   * Update the max based on the provided severity.
+   *
+   * <p>If the provided severity exceeds the max so far, update the
+   * max to match.
+   */
+  ses.updateMaxSeverity = function updateMaxSeverity(severity) {
+    if (severity.level > ses.maxSeverity.level) {
+      ses.maxSeverity = severity;
+    }
+  };
+
+  //////// Prepare for "caller" and "argument" testing and repair /////////
+
+  /**
+   * Needs to work on ES3, since repairES5.js may be run on an ES3
+   * platform.
+   */
+  function strictForEachFn(list, callback) {
+    for (var i = 0, len = list.length; i < len; i++) {
+      callback(list[i], i);
+    }
+  }
+
+  /**
+   * Needs to work on ES3, since repairES5.js may be run on an ES3
+   * platform.
+   *
+   * <p>Also serves as our representative strict function, by contrast
+   * to builtInMapMethod below, for testing what the "caller" and
+   * "arguments" properties of a strict function reveals.
+   */
+  function strictMapFn(list, callback) {
+    var result = [];
+    for (var i = 0, len = list.length; i < len; i++) {
+      result.push(callback(list[i], i));
+    }
+    return result;
+  }
+
+  var objToString = Object.prototype.toString;
+
+  /**
+   * Sample map early, to obtain a representative built-in for testing.
+   *
+   * <p>There is no reliable test for whether a function is a
+   * built-in, and it is possible some of the tests below might
+   * replace the built-in Array.prototype.map, though currently none
+   * do. Since we <i>assume</i> (but with no reliable way to check)
+   * that repairES5.js runs in its JavaScript context before anything
+   * which might have replaced map, we sample it now. The map method
+   * is a particularly nice one to sample, since it can easily be used
+   * to test what the "caller" and "arguments" properties on a
+   * in-progress built-in method reveals.
+   */
+  var builtInMapMethod = Array.prototype.map;
+
+  var builtInForEach = Array.prototype.forEach;
+
+  /**
+   * http://wiki.ecmascript.org/doku.php?id=harmony:egal
+   */
+  var is = ses.is = Object.is || function(x, y) {
+    if (x === y) {
+      // 0 === -0, but they are not identical
+      return x !== 0 || 1 / x === 1 / y;
+    }
+
+    // NaN !== NaN, but they are identical.
+    // NaNs are the only non-reflexive value, i.e., if x !== x,
+    // then x is a NaN.
+    // isNaN is broken: it converts its argument to number, so
+    // isNaN("foo") => true
+    return x !== x && y !== y;
+  };
+
+
+  /**
+   * By the time this module exits, either this is repaired to be a
+   * function that is adequate to make the "caller" property of a
+   * strict or built-in function harmess, or this module has reported
+   * a failure to repair.
+   *
+   * <p>Start off with the optimistic assumption that nothing is
+   * needed to make the "caller" property of a strict or built-in
+   * function harmless. We are not concerned with the "caller"
+   * property of non-strict functions. It is not the responsibility of
+   * this module to actually make these "caller" properties
+   * harmless. Rather, this module only provides this function so
+   * clients such as startSES.js can use it to do so on the functions
+   * they whitelist.
+   *
+   * <p>If the "caller" property of strict functions are not already
+   * harmless, then this platform cannot be repaired to be
+   * SES-safe. The only reason why {@code makeCallerHarmless} must
+   * work on strict functions in addition to built-in is that some of
+   * the other repairs below will replace some of the built-ins with
+   * strict functions, so startSES.js will apply {@code
+   * makeCallerHarmless} blindly to both strict and built-in
+   * functions. {@code makeCallerHarmless} simply need not to complete
+   * without breaking anything when given a strict function argument.
+   */
+  ses.makeCallerHarmless = function assumeCallerHarmless(func, path) {
+    return 'Apparently fine';
+  };
+
+  /**
+   * By the time this module exits, either this is repaired to be a
+   * function that is adequate to make the "arguments" property of a
+   * strict or built-in function harmess, or this module has reported
+   * a failure to repair.
+   *
+   * Exactly analogous to {@code makeCallerHarmless}, but for
+   * "arguments" rather than "caller".
+   */
+  ses.makeArgumentsHarmless = function assumeArgumentsHarmless(func, path) {
+    return 'Apparently fine';
+  };
+
+  /**
+   * "makeTamperProof()" returns a "tamperProof(obj)" function that
+   * acts like "Object.freeze(obj)", except that, if obj is a
+   * <i>prototypical</i> object (defined below), it ensures that the
+   * effect of freezing properties of obj does not suppress the
+   * ability to override these properties on derived objects by simple
+   * assignment.
+   *
+   * <p>Because of lack of sufficient foresight at the time, ES5
+   * unfortunately specified that a simple assignment to a
+   * non-existent property must fail if it would override a
+   * non-writable data property of the same name. (In retrospect, this
+   * was a mistake, but it is now too late and we must live with the
+   * consequences.) As a result, simply freezing an object to make it
+   * tamper proof has the unfortunate side effect of breaking
+   * previously correct code that is considered to have followed JS
+   * best practices, if this previous code used assignment to
+   * override.
+   *
+   * <p>To work around this mistake, tamperProof(obj) detects if obj
+   * is <i>prototypical</i>, i.e., is an object whose own
+   * "constructor" is a function whose "prototype" is this obj. For example,
+   * Object.prototype and Function.prototype are prototypical.  If so,
+   * then when tamper proofing it, prior to freezing, replace all its
+   * configurable own data properties with accessor properties which
+   * simulate what we should have specified -- that assignments to
+   * derived objects succeed if otherwise possible.
+   *
+   * <p>Some platforms (Chrome and Safari as of this writing)
+   * implement the assignment semantics ES5 should have specified
+   * rather than what it did specify.
+   * "test_ASSIGN_CAN_OVERRIDE_FROZEN()" below tests whether we are on
+   * such a platform. If so, "repair_ASSIGN_CAN_OVERRIDE_FROZEN()"
+   * replaces "makeTamperProof" with a function that simply returns
+   * "Object.freeze", since the complex workaround here is not needed
+   * on those platforms.
+   *
+   * <p>"makeTamperProof" should only be called after the trusted
+   * initialization has done all the monkey patching that it is going
+   * to do on the Object.* methods, but before any untrusted code runs
+   * in this context.
+   */
+  var makeTamperProof = function defaultMakeTamperProof() {
+
+    // Sample these after all trusted monkey patching initialization
+    // but before any untrusted code runs in this frame.
+    var gopd = Object.getOwnPropertyDescriptor;
+    var gopn = Object.getOwnPropertyNames;
+    var getProtoOf = Object.getPrototypeOf;
+    var freeze = Object.freeze;
+    var isFrozen = Object.isFrozen;
+    var defProp = Object.defineProperty;
+
+    function tamperProof(obj) {
+      if (obj !== Object(obj)) { return obj; }
+      var func;
+      if (typeof obj === 'object' &&
+          !!gopd(obj, 'constructor') &&
+          typeof (func = obj.constructor) === 'function' &&
+          func.prototype === obj &&
+          !isFrozen(obj)) {
+        strictForEachFn(gopn(obj), function(name) {
+          var value;
+          function getter() {
+            if (obj === this) { return value; }
+            if (this === void 0 || this === null) { return void 0; }
+            var thisObj = Object(this);
+            if (!!gopd(thisObj, name)) { return this[name]; }
+            // TODO(erights): If we can reliably uncurryThis() in
+            // repairES5.js, the next line should be:
+            //   return callFn(getter, getProtoOf(thisObj));
+            return getter.call(getProtoOf(thisObj));
+          }
+          function setter(newValue) {
+            if (obj === this) {
+              throw new TypeError('Cannot set virtually frozen property: ' +
+                                  name);
+            }
+            if (!!gopd(this, name)) {
+              this[name] = newValue;
+            }
+            // TODO(erights): Do all the inherited property checks
+            defProp(this, name, {
+              value: newValue,
+              writable: true,
+              enumerable: true,
+              configurable: true
+            });
+          }
+          var desc = gopd(obj, name);
+          if (desc.configurable && 'value' in desc) {
+            value = desc.value;
+            getter.prototype = null;
+            setter.prototype = null;
+            defProp(obj, name, {
+              get: getter,
+              set: setter,
+              // We should be able to omit the enumerable line, since it
+              // should default to its existing setting.
+              enumerable: desc.enumerable,
+              configurable: false
+            });
+          }
+        });
+      }
+      return freeze(obj);
+    }
+    return tamperProof;
+  };
+
+
+  var needToTamperProof = [];
+  /**
+   * Various repairs may expose non-standard objects that are not
+   * reachable from startSES's root, and therefore not freezable by
+   * startSES's normal whitelist traversal. However, freezing these
+   * during repairES5.js may be too early, as it is before WeakMap.js
+   * has had a chance to monkey patch Object.freeze if necessary, in
+   * order to install hidden properties for its own use before the
+   * object becomes non-extensible.
+   */
+  function rememberToTamperProof(obj) {
+    needToTamperProof.push(obj);
+  }
+
+  /**
+   * Makes and returns a tamperProof(obj) function, and uses it to
+   * tamper proof all objects whose tamper proofing had been delayed.
+   *
+   * <p>"makeDelayedTamperProof()" must only be called once.
+   */
+  var makeDelayedTamperProofCalled = false;
+  ses.makeDelayedTamperProof = function makeDelayedTamperProof() {
+    if (makeDelayedTamperProofCalled) {
+      throw "makeDelayedTamperProof() must only be called once.";
+    }
+    var tamperProof = makeTamperProof();
+    strictForEachFn(needToTamperProof, tamperProof);
+    needToTamperProof = void 0;
+    makeDelayedTamperProofCalled = true;
+    return tamperProof;
+  };
+
+  /**
+   * Where the "that" parameter represents a "this" that should have
+   * been bound to "undefined" but may be bound to a global or
+   * globaloid object.
+   *
+   * <p>The "desc" parameter is a string to describe the "that" if it
+   * is something unexpected.
+   */
+  function testGlobalLeak(desc, that) {
+    if (that === void 0) { return false; }
+    if (that === global) { return true; }
+    if (objToString.call(that) === '[object Window]') { return true; }
+    return desc + ' leaked as: ' + that;
+  }
+
+  ////////////////////// Tests /////////////////////
+  //
+  // Each test is a function of no arguments that should not leave any
+  // significant side effects, which tests for the presence of a
+  // problem. It returns either
+  // <ul>
+  // <li>false, meaning that the problem does not seem to be present.
+  // <li>true, meaning that the problem is present in a form that we expect.
+  // <li>a non-empty string, meaning that there seems to be a related
+  //     problem, but we're seeing a symptom different than what we
+  //     expect. The string should describe the new symptom. It must
+  //     be non-empty so that it is truthy.
+  // </ul>
+  // All the tests are run first to determine which corresponding
+  // repairs to attempt. Then these repairs are run. Then all the
+  // tests are rerun to see how they were effected by these repair
+  // attempts. Finally, we report what happened.
+
+  /**
+   * If {@code Object.getOwnPropertyNames} is missing, we consider
+   * this to be an ES3 browser which is unsuitable for attempting to
+   * run SES.
+   *
+   * <p>If {@code Object.getOwnPropertyNames} is missing, there is no
+   * way to emulate it.
+   */
+  function test_MISSING_GETOWNPROPNAMES() {
+    return !('getOwnPropertyNames' in Object);
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=64250
+   *
+   * <p>No workaround attempted. Just reporting that this platform is
+   * not SES-safe.
+   */
+  function test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS() {
+    global.___global_test_function___ = function() { return this; };
+    var that = ___global_test_function___();
+    delete global.___global_test_function___;
+    return testGlobalLeak('Global func "this"', that);
+  }
+
+  /**
+   * Detects whether the most painful ES3 leak is still with us.
+   */
+  function test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS() {
+    var that = (function(){ return this; })();
+    return testGlobalLeak('Anon func "this"', that);
+  }
+
+  var strictThis = this;
+
+  /**
+   *
+   */
+  function test_GLOBAL_LEAKS_FROM_STRICT_THIS() {
+    return testGlobalLeak('Strict "this"', strictThis);
+  }
+
+  /**
+   * Detects
+   * https://bugs.webkit.org/show_bug.cgi?id=51097
+   * https://bugs.webkit.org/show_bug.cgi?id=58338
+   * http://code.google.com/p/v8/issues/detail?id=1437
+   *
+   * <p>No workaround attempted. Just reporting that this platform is
+   * not SES-safe.
+   */
+  function test_GLOBAL_LEAKS_FROM_BUILTINS() {
+    var v = {}.valueOf;
+    var that = 'dummy';
+    try {
+      that = v();
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'valueOf() threw: ' + err;
+    }
+    if (that === void 0) {
+      // Should report as a safe spec violation
+      return false;
+    }
+    return testGlobalLeak('valueOf()', that);
+  }
+
+  /**
+   *
+   */
+  function test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS() {
+    global.___global_valueOf_function___ = {}.valueOf;
+    var that = 'dummy';
+    try {
+      that = ___global_valueOf_function___();
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'valueOf() threw: ' + err;
+    } finally {
+      delete global.___global_valueOf_function___;
+    }
+    if (that === void 0) {
+      // Should report as a safe spec violation
+      return false;
+    }
+    return testGlobalLeak('Global valueOf()', that);
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=55736
+   *
+   * <p>As of this writing, the only major browser that does implement
+   * Object.getOwnPropertyNames but not Object.freeze etc is the
+   * released Safari 5 (JavaScriptCore). The Safari beta 5.0.4
+   * (5533.20.27, r84622) already does implement freeze, which is why
+   * this WebKit bug is listed as closed. When the released Safari has
+   * this fix, we can retire this kludge.
+   *
+   * <p>This kludge is <b>not</b> safety preserving. The emulations it
+   * installs if needed do not actually provide the safety that the
+   * rest of SES relies on.
+   */
+  function test_MISSING_FREEZE_ETC() {
+    return !('freeze' in Object);
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1530
+   *
+   * <p>Detects whether the value of a function's "prototype" property
+   * as seen by normal object operations might deviate from the value
+   * as seem by the reflective {@code Object.getOwnPropertyDescriptor}
+   */
+  function test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES() {
+    function foo() {}
+    Object.defineProperty(foo, 'prototype', { value: {} });
+    return foo.prototype !==
+      Object.getOwnPropertyDescriptor(foo, 'prototype').value;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=55537
+   *
+   * This bug is fixed on the latest Safari beta 5.0.5 (5533.21.1,
+   * r88603). When the released Safari has this fix, we can retire
+   * this kludge.
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_MISSING_CALLEE_DESCRIPTOR() {
+    function foo(){}
+    if (Object.getOwnPropertyNames(foo).indexOf('callee') < 0) { return false; }
+    if (foo.hasOwnProperty('callee')) {
+      return 'Empty strict function has own callee';
+    }
+    return true;
+  }
+
+  /**
+   * A strict delete should either succeed, returning true, or it
+   * should fail by throwing a TypeError. Under no circumstances
+   * should a strict delete return false.
+   *
+   * <p>This case occurs on IE10preview2.
+   */
+  function test_STRICT_DELETE_RETURNS_FALSE() {
+    if (!RegExp.hasOwnProperty('rightContext')) { return false; }
+    var deleted;
+    try {
+      deleted = delete RegExp.rightContext;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Deletion failed with: ' + err;
+    }
+    if (deleted) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846
+   * as applied to the RegExp constructor.
+   *
+   * <p>Note that Mozilla lists this bug as closed. But reading that
+   * bug thread clarifies that is partially because the code in {@code
+   * repair_REGEXP_CANT_BE_NEUTERED} enables us to work around the
+   * non-configurability of the RegExp statics.
+   */
+  function test_REGEXP_CANT_BE_NEUTERED() {
+    if (!RegExp.hasOwnProperty('leftContext')) { return false; }
+    var deleted;
+    try {
+      deleted = delete RegExp.leftContext;
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'Deletion failed with: ' + err;
+    }
+    if (!RegExp.hasOwnProperty('leftContext')) { return false; }
+    if (deleted) {
+      return 'Deletion of RegExp.leftContext did not succeed.';
+    } else {
+      // This case happens on IE10preview2, as demonstrated by
+      // test_STRICT_DELETE_RETURNS_FALSE.
+      return true;
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1393
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_REGEXP_TEST_EXEC_UNSAFE() {
+    (/foo/).test('xfoox');
+    var match = new RegExp('(.|\r|\n)*','').exec()[0];
+    if (match === 'undefined') { return false; }
+    if (match === 'xfoox') { return true; }
+    return 'regExp.exec() does not match against "undefined".';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=26382
+   *
+   * <p>As of this writing, the only major browser that does implement
+   * Object.getOwnPropertyNames but not Function.prototype.bind is
+   * Safari 5 (JavaScriptCore), including the current Safari beta
+   * 5.0.4 (5533.20.27, r84622).
+   *
+   * <p>This kludge is safety preserving. But see
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c25 for why this
+   * kludge cannot faithfully implement the specified semantics.
+   *
+   * <p>See also https://bugs.webkit.org/show_bug.cgi?id=42371
+   */
+  function test_MISSING_BIND() {
+    return !('bind' in Function.prototype);
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=892
+   *
+   * <p>This tests whether the built-in bind method violates the spec
+   * by calling the original using its current .apply method rather
+   * than the internal [[Call]] method. The workaround is the same as
+   * for test_MISSING_BIND -- to replace the built-in bind with one
+   * written in JavaScript. This introduces a different bug though: As
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c29 explains, a
+   * bind written in JavaScript cannot emulate the specified currying
+   * over the construct behavior, and so fails to enable a var-args
+   * {@code new} operation.
+   */
+  function test_BIND_CALLS_APPLY() {
+    if (!('bind' in Function.prototype)) { return false; }
+    var applyCalled = false;
+    function foo() { return [].slice.call(arguments,0).join(','); }
+    foo.apply = function fakeApply(self, args) {
+      applyCalled = true;
+      return Function.prototype.apply.call(this, self, args);
+    };
+    var b = foo.bind(33,44);
+    var answer = b(55,66);
+    if (applyCalled) { return true; }
+    if (answer === '44,55,66') { return false; }
+    return 'Bind test returned "' + answer + '" instead of "44,55,66".';
+  }
+
+  /**
+   * Demonstrates the point made by comment 29
+   * https://bugs.webkit.org/show_bug.cgi?id=26382#c29
+   *
+   * <p>Tests whether Function.prototype.bind curries over
+   * construction ({@code new}) behavior. A built-in bind should. A
+   * bind emulation written in ES5 can't.
+   */
+  function test_BIND_CANT_CURRY_NEW() {
+    function construct(f, args) {
+      var bound = Function.prototype.bind.apply(f, [null].concat(args));
+      return new bound();
+    }
+    var d;
+    try {
+      d = construct(Date, [1957, 4, 27]);
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'Curries construction failed with: ' + err;
+    }
+    if (typeof d === 'string') { return true; } // Opera
+    var str = objToString.call(d);
+    if (str === '[object Date]') { return false; }
+    return 'Unexpected ' + str + ': ' + d;
+  }
+
+  /**
+   * Detects http://code.google.com/p/google-caja/issues/detail?id=1362
+   *
+   * <p>This is an unfortunate oversight in the ES5 spec: Even if
+   * Date.prototype is frozen, it is still defined to be a Date, and
+   * so has mutable state in internal properties that can be mutated
+   * by the primordial mutation methods on Date.prototype, such as
+   * {@code Date.prototype.setFullYear}.
+   *
+   * <p>This kludge is safety preserving.
+   */
+  function test_MUTABLE_DATE_PROTO() {
+    try {
+      Date.prototype.setFullYear(1957);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating Date.prototype failed with: ' + err;
+    }
+    var v = Date.prototype.getFullYear();
+    Date.prototype.setFullYear(NaN); // hopefully undoes the damage
+    if (v !== v && typeof v === 'number') {
+      // NaN indicates we're probably ok.
+      // TODO(erights) Should we report this as a symptom anyway, so
+      // that we get the repair which gives us a reliable TypeError?
+      return false;
+    }
+    if (v === 1957) { return true; }
+    return 'Mutating Date.prototype did not throw';
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=656828
+   *
+   * <p>A bug in the current FF6.0a1 implementation: Even if
+   * WeakMap.prototype is frozen, it is still defined to be a WeakMap,
+   * and so has mutable state in internal properties that can be
+   * mutated by the primordial mutation methods on WeakMap.prototype,
+   * such as {@code WeakMap.prototype.set}.
+   *
+   * <p>This kludge is safety preserving.
+   *
+   * <p>TODO(erights): Update the ES spec page to reflect the current
+   * agreement with Mozilla.
+   */
+  function test_MUTABLE_WEAKMAP_PROTO() {
+    if (typeof WeakMap !== 'function') { return false; }
+    var x = {};
+    try {
+      WeakMap.prototype.set(x, 86);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating WeakMap.prototype failed with: ' + err;
+    }
+    var v = WeakMap.prototype.get(x);
+    // Since x cannot escape, there's no observable damage to undo.
+    if (v === 86) { return true; }
+    return 'Mutating WeakMap.prototype did not throw';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1447
+   *
+   * <p>This bug is fixed as of V8 r8258 bleeding-edge, but is not yet
+   * available in the latest dev-channel Chrome (13.0.782.15 dev).
+   *
+   * <p>Unfortunately, an ES5 strict method wrapper cannot emulate
+   * absence of a [[Construct]] behavior, as specified for the Chapter
+   * 15 built-in methods. The installed wrapper relies on {@code
+   * Function.prototype.apply}, as inherited by original, obeying its
+   * contract.
+   *
+   * <p>This kludge is safety preserving but non-transparent, in that
+   * the real forEach is frozen even in the success case, since we
+   * have to freeze it in order to test for this failure. We could
+   * repair this non-transparency by replacing it with a transparent
+   * wrapper (as http://codereview.appspot.com/5278046/ does), but
+   * since the SES use of this will freeze it anyway and the
+   * indirection is costly, we choose not to for now.
+   */
+  function test_NEED_TO_WRAP_FOREACH() {
+    if (!('freeze' in Object)) {
+      // Object.freeze is still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    if (Array.prototype.forEach !== builtInForEach) {
+      // If it is already wrapped, we are confident the problem does
+      // not occur, and we need to skip the test to avoid freezing the
+      // wrapper.
+      return false;
+    }
+    try {
+      ['z'].forEach(function(){ Object.freeze(Array.prototype.forEach); });
+      return false;
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'freezing forEach failed with ' + err;
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=2273
+   *
+   * A strict mode function should receive a non-coerced 'this'
+   * value. That is, in strict mode, if 'this' is a primitive, it
+   * should not be boxed
+   */
+  function test_FOREACH_COERCES_THISOBJ() {
+    "use strict";
+    var needsWrapping = true;
+    [1].forEach(function(){ needsWrapping = ("string" != typeof this); }, "f");
+    return needsWrapping;
+  }
+
+  /**
+   * <p>Sometimes, when trying to freeze an object containing an
+   * accessor property with a getter but no setter, Chrome <= 17 fails
+   * with <blockquote>Uncaught TypeError: Cannot set property ident___
+   * of #<Object> which has only a getter</blockquote>. So if
+   * necessary, this kludge overrides {@code Object.defineProperty} to
+   * always install a dummy setter in lieu of the absent one.
+   *
+   * <p>Since this problem seems to have gone away as of Chrome 18, it
+   * is no longer as important to isolate and report it.
+   *
+   * <p>TODO(erights): We should also override {@code
+   * Object.getOwnPropertyDescriptor} to hide the presence of the
+   * dummy setter, and instead report an absent setter.
+   */
+  function test_NEEDS_DUMMY_SETTER() {
+    if (NEEDS_DUMMY_SETTER_repaired) { return false; }
+    if (typeof navigator === 'undefined') { return false; }
+    var ChromeMajorVersionPattern = (/Chrome\/(\d*)\./);
+    var match = ChromeMajorVersionPattern.exec(navigator.userAgent);
+    if (!match) { return false; }
+    var ver = +match[1];
+    return ver <= 17;
+  }
+  /** we use this variable only because we haven't yet isolated a test
+   * for the problem. */
+  var NEEDS_DUMMY_SETTER_repaired = false;
+
+  /**
+   * Detects http://code.google.com/p/chromium/issues/detail?id=94666
+   */
+  function test_FORM_GETTERS_DISAPPEAR() {
+    function getter() { return 'gotten'; }
+
+    if (typeof document === 'undefined' ||
+       typeof document.createElement !== 'function') {
+      // likely not a browser environment
+      return false;
+    }
+    var f = document.createElement("form");
+    try {
+      Object.defineProperty(f, 'foo', {
+        get: getter,
+        set: void 0
+      });
+    } catch (err) {
+      // Happens on Safari 5.0.2 on IPad2.
+      return 'defining accessor on form failed with: ' + err;
+    }
+    var desc = Object.getOwnPropertyDescriptor(f, 'foo');
+    if (desc.get === getter) { return false; }
+    if (desc.get === void 0) { return true; }
+    return 'Getter became ' + desc.get;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=637994
+   *
+   * <p>On Firefox 4 an inherited non-configurable accessor property
+   * appears to be an own property of all objects which inherit this
+   * accessor property. This is fixed as of Forefox Nightly 7.0a1
+   * (2011-06-21).
+   *
+   * <p>Our workaround wraps hasOwnProperty, getOwnPropertyNames, and
+   * getOwnPropertyDescriptor to heuristically decide when an accessor
+   * property looks like it is apparently own because of this bug, and
+   * suppress reporting its existence.
+   *
+   * <p>However, it is not feasible to likewise wrap JSON.stringify,
+   * and this bug will cause JSON.stringify to be misled by inherited
+   * enumerable non-configurable accessor properties. To prevent this,
+   * we wrap defineProperty, freeze, and seal to prevent the creation
+   * of <i>enumerable</i> non-configurable accessor properties on
+   * those platforms with this bug.
+   *
+   * <p>A little known fact about JavaScript is that {@code
+   * Object.prototype.propertyIsEnumerable} actually tests whether a
+   * property is both own and enumerable. Assuming that our wrapping
+   * of defineProperty, freeze, and seal prevents the occurrence of an
+   * enumerable non-configurable accessor property, it should also
+   * prevent the occurrence of this bug for any enumerable property,
+   * and so we do not need to wrap propertyIsEnumerable.
+   *
+   * <p>This kludge seems to be safety preserving, but the issues are
+   * delicate and not well understood.
+   */
+  function test_ACCESSORS_INHERIT_AS_OWN() {
+    var base = {};
+    var derived = Object.create(base);
+    function getter() { return 'gotten'; }
+    Object.defineProperty(base, 'foo', { get: getter });
+    if (!derived.hasOwnProperty('foo') &&
+        Object.getOwnPropertyDescriptor(derived, 'foo') === void 0 &&
+        Object.getOwnPropertyNames(derived).indexOf('foo') < 0) {
+      return false;
+    }
+    if (!derived.hasOwnProperty('foo') ||
+        Object.getOwnPropertyDescriptor(derived, 'foo').get !== getter ||
+        Object.getOwnPropertyNames(derived).indexOf('foo') < 0) {
+      return 'Accessor properties partially inherit as own properties.';
+    }
+    Object.defineProperty(base, 'bar', { get: getter, configurable: true });
+    if (!derived.hasOwnProperty('bar') &&
+        Object.getOwnPropertyDescriptor(derived, 'bar') === void 0 &&
+        Object.getOwnPropertyNames(derived).indexOf('bar') < 0) {
+      return true;
+    }
+    return 'Accessor properties inherit as own even if configurable.';
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1360
+   *
+   * Our workaround wraps {@code sort} to wrap the comparefn.
+   */
+  function test_SORT_LEAKS_GLOBAL() {
+    var that = 'dummy';
+    [2,3].sort(function(x,y) { that = this; return x - y; });
+    if (that === void 0) { return false; }
+    if (that === global) { return true; }
+    return 'sort called comparefn with "this" === ' + that;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1360
+   *
+   * <p>Our workaround wraps {@code replace} to wrap the replaceValue
+   * if it's a function.
+   */
+  function test_REPLACE_LEAKS_GLOBAL() {
+    var that = 'dummy';
+    function capture() { that = this; return 'y';}
+    'x'.replace(/x/, capture);
+    if (that === void 0) { return false; }
+    if (that === capture) {
+      // This case happens on IE10preview2. See
+      // https://connect.microsoft.com/IE/feedback/details/685928/
+      //   bad-this-binding-for-callback-in-string-prototype-replace
+      // TODO(erights): When this happens, the kludge.description is
+      // wrong.
+      return true;
+    }
+    if (that === global) { return true; }
+    return 'Replace called replaceValue function with "this" === ' + that;
+  }
+
+  /**
+   * Detects
+   * https://connect.microsoft.com/IE/feedback/details/
+   *   685436/getownpropertydescriptor-on-strict-caller-throws
+   *
+   * <p>Object.getOwnPropertyDescriptor must work even on poisoned
+   * "caller" properties.
+   */
+  function test_CANT_GOPD_CALLER() {
+    var desc = null;
+    try {
+      desc = Object.getOwnPropertyDescriptor(function(){}, 'caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'getOwnPropertyDescriptor failed with: ' + err;
+    }
+    if (desc &&
+        typeof desc.get === 'function' &&
+        typeof desc.set === 'function' &&
+        !desc.configurable) {
+      return false;
+    }
+    if (desc &&
+        desc.value === null &&
+        !desc.writable &&
+        !desc.configurable) {
+      // Seen in IE9. Harmless by itself
+      return false;
+    }
+    return 'getOwnPropertyDesciptor returned unexpected caller descriptor';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>A strict function's caller should be poisoned only in a way
+   * equivalent to an accessor property with a throwing getter and
+   * setter.
+   *
+   * <p>Seen on Safari 5.0.6 through WebKit Nightly r93670
+   */
+  function test_CANT_HASOWNPROPERTY_CALLER() {
+    var answer = void 0;
+    try {
+      answer = function(){}.hasOwnProperty('caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'hasOwnProperty failed with: ' + err;
+    }
+    if (answer) { return false; }
+    return 'strict_function.hasOwnProperty("caller") was false';
+  }
+
+  /**
+   * Protect an 'in' with a try/catch to workaround a bug in Safari
+   * WebKit Nightly Version 5.0.5 (5533.21.1, r89741).
+   *
+   * <p>See https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>Notes: We're seeing exactly
+   * <blockquote>
+   *   New symptom (c): ('caller' in &lt;a bound function&gt;) threw:
+   *   TypeError: Cannot access caller property of a strict mode
+   *   function<br>
+   *   New symptom (c): ('arguments' in &lt;a bound function&gt;)
+   *   threw: TypeError: Can't access arguments object of a strict
+   *   mode function
+   * </blockquote>
+   * which means we're skipping both the catch and the finally in
+   * {@code has} while hitting the catch in {@code has2}. Further, if
+   * we remove one of these finally clauses (forget which) and rerun
+   * the example, if we're under the debugger the browser crashes. If
+   * we're not, then the TypeError escapes both catches.
+   */
+  function has(base, name, baseDesc) {
+    var result = void 0;
+    var finallySkipped = true;
+    try {
+      result = name in base;
+    } catch (err) {
+      logger.error('New symptom (a): (\'' +
+                   name + '\' in <' + baseDesc + '>) threw: ', err);
+      // treat this as a safe absence
+      result = false;
+      return false;
+    } finally {
+      finallySkipped = false;
+      if (result === void 0) {
+        logger.error('New symptom (b): (\'' +
+                     name + '\' in <' + baseDesc + '>) failed');
+      }
+    }
+    if (finallySkipped) {
+      logger.error('New symptom (e): (\'' +
+                   name + '\' in <' + baseDesc +
+                   '>) inner finally skipped');
+    }
+    return !!result;
+  }
+
+  function has2(base, name, baseDesc) {
+    var result = void 0;
+    var finallySkipped = true;
+    try {
+      result = has(base, name, baseDesc);
+    } catch (err) {
+      logger.error('New symptom (c): (\'' +
+                   name + '\' in <' + baseDesc + '>) threw: ', err);
+      // treat this as a safe absence
+      result = false;
+      return false;
+    } finally {
+      finallySkipped = false;
+      if (result === void 0) {
+        logger.error('New symptom (d): (\'' +
+                     name + '\' in <' + baseDesc + '>) failed');
+      }
+    }
+    if (finallySkipped) {
+      logger.error('New symptom (f): (\'' +
+                   name + '\' in <' + baseDesc +
+                   '>) outer finally skipped');
+    }
+    return !!result;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>If this reports a problem in the absence of "New symptom (a)",
+   * it means the error thrown by the "in" in {@code has} is skipping
+   * past the first layer of "catch" surrounding that "in". This is in
+   * fact what we're currently seeing on Safari WebKit Nightly Version
+   * 5.0.5 (5533.21.1, r91108).
+   */
+  function test_CANT_IN_CALLER() {
+    var answer = void 0;
+    try {
+      answer = has2(function(){}, 'caller', 'strict_function');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return '("caller" in strict_func) failed with: ' + err;
+    } finally {}
+    if (answer) { return false; }
+    return '("caller" in strict_func) was false.';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=63398
+   *
+   * <p>If this reports a problem in the absence of "New symptom (a)",
+   * it means the error thrown by the "in" in {@code has} is skipping
+   * past the first layer of "catch" surrounding that "in". This is in
+   * fact what we're currently seeing on Safari WebKit Nightly Version
+   * 5.0.5 (5533.21.1, r91108).
+   */
+  function test_CANT_IN_ARGUMENTS() {
+    var answer = void 0;
+    try {
+      answer = has2(function(){}, 'arguments', 'strict_function');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return '("arguments" in strict_func) failed with: ' + err;
+    } finally {}
+    if (answer) { return false; }
+    return '("arguments" in strict_func) was false.';
+  }
+
+  /**
+   * Detects whether strict function violate caller anonymity.
+   */
+  function test_STRICT_CALLER_NOT_POISONED() {
+    if (!has2(strictMapFn, 'caller', 'a strict function')) { return false; }
+    function foo(m) { return m.caller; }
+    // using Function so it'll be non-strict
+    var testfn = Function('m', 'f', 'return m([m], f)[0];');
+    var caller;
+    try {
+      caller = testfn(strictMapFn, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Strict "caller" failed with: ' + err;
+    }
+    if (testfn === caller) {
+      // Seen on IE 9
+      return true;
+    }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects whether strict functions are encapsulated.
+   */
+  function test_STRICT_ARGUMENTS_NOT_POISONED() {
+    if (!has2(strictMapFn, 'arguments', 'a strict function')) { return false; }
+    function foo(m) { return m.arguments; }
+    // using Function so it'll be non-strict
+    var testfn = Function('m', 'f', 'return m([m], f)[0];');
+    var args;
+    try {
+      args = testfn(strictMapFn, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Strict "arguments" failed with: ' + err;
+    }
+    if (args[1] === foo) {
+      // Seen on IE 9
+      return true;
+    }
+    return 'Unexpected arguments: ' + arguments;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846 as
+   * applied to "caller"
+   */
+  function test_BUILTIN_LEAKS_CALLER() {
+    if (!has2(builtInMapMethod, 'caller', 'a builtin')) { return false; }
+    function foo(m) { return m.caller; }
+    // using Function so it'll be non-strict
+    var testfn = Function('a', 'f', 'return a.map(f)[0];');
+    var a = [builtInMapMethod];
+    a.map = builtInMapMethod;
+    var caller;
+    try {
+      caller = testfn(a, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Built-in "caller" failed with: ' + err;
+    }
+    if (null === caller || void 0 === caller) { return false; }
+    if (testfn === caller) { return true; }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=591846 as
+   * applied to "arguments"
+   */
+  function test_BUILTIN_LEAKS_ARGUMENTS() {
+    if (!has2(builtInMapMethod, 'arguments', 'a builtin')) { return false; }
+    function foo(m) { return m.arguments; }
+    // using Function so it'll be non-strict
+    var testfn = Function('a', 'f', 'return a.map(f)[0];');
+    var a = [builtInMapMethod];
+    a.map = builtInMapMethod;
+    var args;
+    try {
+      args = testfn(a, foo);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Built-in "arguments" failed with: ' + err;
+    }
+    if (args === void 0 || args === null) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=893
+   */
+  function test_BOUND_FUNCTION_LEAKS_CALLER() {
+    if (!('bind' in Function.prototype)) { return false; }
+    function foo() { return bar.caller; }
+    var bar = foo.bind({});
+    if (!has2(bar, 'caller', 'a bound function')) { return false; }
+    // using Function so it'll be non-strict
+    var testfn = Function('b', 'return b();');
+    var caller;
+    try {
+      caller = testfn(bar);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Bound function "caller" failed with: ' + err;
+    }
+    if (caller === void 0 || caller === null) { return false; }
+    if (caller === testfn) { return true; }
+    return 'Unexpected "caller": ' + caller;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=893
+   */
+  function test_BOUND_FUNCTION_LEAKS_ARGUMENTS() {
+    if (!('bind' in Function.prototype)) { return false; }
+    function foo() { return bar.arguments; }
+    var bar = foo.bind({});
+    if (!has2(bar, 'arguments', 'a bound function')) { return false; }
+    // using Function so it'll be non-strict
+    var testfn = Function('b', 'return b();');
+    var args;
+    try {
+      args = testfn(bar);
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Bound function "arguments" failed with: ' + err;
+    }
+    if (args === void 0 || args === null) { return false; }
+    return true;
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=70207
+   *
+   * <p>After deleting a built-in, the problem is that
+   * getOwnPropertyNames still lists the name as present, but it seems
+   * absent in all other ways.
+   */
+  function test_DELETED_BUILTINS_IN_OWN_NAMES() {
+    if (!('__defineSetter__' in Object.prototype)) { return false; }
+    var desc = Object.getOwnPropertyDescriptor(Object.prototype,
+                                               '__defineSetter__');
+    try {
+      try {
+        delete Object.prototype.__defineSetter__;
+      } catch (err1) {
+        return false;
+      }
+      var names = Object.getOwnPropertyNames(Object.prototype);
+      if (names.indexOf('__defineSetter__') === -1) { return false; }
+      if ('__defineSetter__' in Object.prototype) {
+        // If it's still there, it bounced back. Which is still a
+        // problem, but not the problem we're testing for here.
+        return false;
+      }
+      return true;
+    } finally {
+      Object.defineProperty(Object.prototype, '__defineSetter__', desc);
+    }
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1769
+   */
+  function test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS() {
+    try {
+      Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptor,
+                                      'caller');
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'getOwnPropertyDescriptor threw: ' + err;
+    }
+    return false;
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=621
+   *
+   */
+  function test_JSON_PARSE_PROTO_CONFUSION() {
+    var x;
+    try {
+      x = JSON.parse('{"__proto__":[]}');
+    } catch (err) {
+      if (err instanceof TypeError) {
+        // We consider it acceptable to fail this case with a
+        // TypeError, as our repair below will cause it to do.
+        return false;
+      }
+      return 'JSON.parse failed with: ' + err;
+    }
+    if (Object.getPrototypeOf(x) !== Object.prototype) { return true; }
+    if (Array.isArray(x.__proto__)) { return false; }
+    return 'JSON.parse did not set "__proto__" as a regular property';
+  }
+
+  /**
+   * Detects https://bugs.webkit.org/show_bug.cgi?id=65832
+   *
+   * <p>On a non-extensible object, it must not be possible to change
+   * its internal [[Prototype]] property, i.e., which object it
+   * inherits from.
+   *
+   * TODO(erights): investigate the following:
+   * At http://goo.gl/ycCmo Mike Stay says
+   * <blockquote>
+   * Kevin notes in domado.js that on some versions of FF, event
+   * objects switch prototypes when moving between frames. You should
+   * probably check out their behavior around freezing and sealing.
+   * </blockquote>
+   * But I couldn't find it.
+   */
+  function test_PROTO_NOT_FROZEN() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      x.__proto__ = y;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Mutating __proto__ failed with: ' + err;
+    }
+    if (y.isPrototypeOf(x)) { return true; }
+    return 'Mutating __proto__ neither failed nor succeeded';
+  }
+
+  /**
+   * Like test_PROTO_NOT_FROZEN but using defineProperty rather than
+   * assignment.
+   */
+  function test_PROTO_REDEFINABLE() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      Object.defineProperty(x, '__proto__', { value: y });
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Defining __proto__ failed with: ' + err;
+    }
+    // If x.__proto__ has changed but is not equal to y,
+    // we deal with that in the next test.
+    return (x.__proto__ === y);
+  }
+
+
+  /**
+   * Some versions of v8 fail silently when attempting to assign to __proto__
+   */
+  function test_DEFINING_READ_ONLY_PROTO_FAILS_SILENTLY() {
+    if (!('freeze' in Object)) {
+      // Object.freeze and its ilk (including preventExtensions) are
+      // still absent on released Android and would
+      // cause a bogus bug detection in the following try/catch code.
+      return false;
+    }
+    var x = Object.preventExtensions({});
+    if (x.__proto__ === void 0 && !('__proto__' in x)) { return false; }
+    var y = {};
+    try {
+      Object.defineProperty(x, '__proto__', { value: y });
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Defining __proto__ failed with: ' + err;
+    }
+    if (x.__proto__ === Object.prototype) {
+      return true;
+    }
+    return "Read-only proto was changed in a strange way.";
+  }
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1624
+   *
+   * <p>Both a direct strict eval operator and an indirect strict eval
+   * function must not leak top level declarations in the string being
+   * evaluated into their containing context.
+   */
+  function test_STRICT_EVAL_LEAKS_GLOBALS() {
+    (1,eval)('"use strict"; var ___global_test_variable___ = 88;');
+    if ('___global_test_variable___' in global) {
+      delete global.___global_test_variable___;
+      return true;
+    }
+    return false;
+  }
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=2396
+   * 
+   * <p>Commenting out the eval does the right thing.  Only fails in
+   * non-strict mode.
+   */
+  function test_EVAL_BREAKS_MASKING() {
+    var x;
+    x = (function a() {
+      function a() {}
+      eval("");
+      return a;
+    });
+    // x() should be the internal function a(), not itself
+    return x() === x;
+  }
+
+
+  /**
+   * Detects http://code.google.com/p/v8/issues/detail?id=1645
+   */
+  function test_PARSEINT_STILL_PARSING_OCTAL() {
+    var n = parseInt('010');
+    if (n === 10) { return false; }
+    if (n === 8)  { return true; }
+    return 'parseInt("010") returned ' + n;
+  }
+
+  /**
+   * Detects https://bugzilla.mozilla.org/show_bug.cgi?id=695577
+   *
+   * <p>When E4X syntax is accepted in strict code, then without
+   * parsing, we cannot prevent untrusted code from expressing E4X
+   * literals and so obtaining access to shared E4X prototypes,
+   * despite the absence of these prototypes from our whitelist. While
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=695579 is also
+   * open, we cannot even repair the situation, leading to unpluggable
+   * capability leaks. However, we do not test for this additional
+   * problem, since E4X is such a can of worms that 695577 is adequate
+   * by itself for us to judge this platform to be insecurable without
+   * parsing.
+   */
+  function test_STRICT_E4X_LITERALS_ALLOWED() {
+    var x;
+    try {
+      x = eval('"use strict";(<foo/>);');
+    } catch (err) {
+      if (err instanceof SyntaxError) { return false; }
+      return 'E4X test failed with: ' + err;
+    }
+    if (x !== void 0) { return true; }
+    return 'E4X literal expression had no value';
+  }
+
+  /**
+   * Detects whether assignment can override an inherited
+   * non-writable, non-configurable data property.
+   *
+   * <p>According to ES5.1, assignment should not be able to do so,
+   * which is unfortunate for SES, as the tamperProof function must
+   * kludge expensively to ensure that legacy assignments that don't
+   * violate best practices continue to work. Ironically, on platforms
+   * in which this bug is present, tamperProof can just be cheaply
+   * equivalent to Object.freeze.
+   */
+  function test_ASSIGN_CAN_OVERRIDE_FROZEN() {
+    var x = Object.freeze({foo: 88});
+    var y = Object.create(x);
+    try {
+      y.foo = 99;
+    } catch (err) {
+      if (err instanceof TypeError) { return false; }
+      return 'Override failed with: ' + err;
+    }
+    if (y.foo === 99) { return true; }
+    if (y.foo === 88) { return 'Override failed silently'; }
+    return 'Unexpected override outcome: ' + y.foo;
+  }
+
+  /**
+   * Detects whether calling pop on a frozen array can modify the array.
+   * See https://bugs.webkit.org/show_bug.cgi?id=75788
+   */
+  function test_POP_IGNORES_FROZEN() {
+    var x = [1,2];
+    Object.freeze(x);
+    try {
+      x.pop();
+    } catch (e) {
+      if (x.length !== 2) { return 'Unexpected modification of frozen array'; }
+      if (x[0] === 1 && x[1] === 2) { return false; }
+    }
+    if (x.length !== 2) {
+      return 'Unexpected silent modification of frozen array';
+    }
+    return (x[0] !== 1 || x[1] !== 2);
+  }
+
+
+  /**
+   * Detects whether calling sort on a frozen array can modify the array.
+   * See http://code.google.com/p/v8/issues/detail?id=2419
+   */
+  function test_SORT_IGNORES_FROZEN() {
+    var x = [2,1];
+    Object.freeze(x);
+    try {
+      x.sort();
+    } catch (e) {
+      if (x.length !== 2) { return 'Unexpected modification of frozen array'; }
+      if (x[0] === 2 && x[1] === 1) { return false; }
+    }
+    if (x.length !== 2) {
+      return 'Unexpected silent modification of frozen array';
+    }
+    return (x[0] !== 2 || x[1] !== 1);
+  }
+
+  /**
+   * Detects whether calling push on a sealed array can modify the array.
+   * See http://code.google.com/p/v8/issues/detail?id=2412
+   */
+  function test_PUSH_IGNORES_SEALED() {
+    var x = [1,2];
+    Object.seal(x);
+    try {
+      x.push(3);
+    } catch (e) {
+      if (x.length !== 2) { return 'Unexpected modification of frozen array'; }
+      if (x[0] === 1 && x[1] === 2) { return false; }
+    }
+    return (x.length !== 2 || x[0] !== 1 || x[1] !== 2);
+  }
+
+  /**
+   * In some browsers, assigning to array length can delete
+   * non-configurable properties.
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=590690
+   * TODO(felix8a): file bug for chrome
+   */
+  function test_ARRAYS_DELETE_NONCONFIGURABLE() {
+    var x = [];
+    Object.defineProperty(x, 0, { value: 3, configurable: false });
+    try {
+      x.length = 0;
+    } catch (e) {}
+    return x.length !== 1 || x[0] !== 3;
+  }
+
+  /**
+   * In some versions of Chrome, extending an array can
+   * modify a read-only length property.
+   * http://code.google.com/p/v8/issues/detail?id=2379
+   */
+  function test_ARRAYS_MODIFY_READONLY() {
+    var x = [];
+    try {
+      Object.defineProperty(x, 'length', {value: 0, writable: false});
+      x[0] = 1;
+    } catch(e) {}
+    return x.length !== 0 || x[0] !== void 0;
+  }
+
+  /**
+   *
+   */
+  function test_CANT_REDEFINE_NAN_TO_ITSELF() {
+    var descNaN = Object.getOwnPropertyDescriptor(global, 'NaN');
+    try {
+      Object.defineProperty(global, 'NaN', descNaN);
+    } catch (err) {
+      if (err instanceof TypeError) { return true; }
+      return 'defineProperty of NaN failed with: ' + err;
+    }
+    return false;
+  }
+
+  /**		
+   * In Firefox 15+, Object.freeze and Object.isFrozen only work for		
+   * descendents of that same Object.		
+   */		
+  function test_FIREFOX_15_FREEZE_PROBLEM() {		
+    if (!document || !document.createElement) { return false; }		
+    var iframe = document.createElement('iframe');		
+    var where = document.getElementsByTagName('script')[0];		
+    where.parentNode.insertBefore(iframe, where);		
+    var otherObject = iframe.contentWindow.Object;		
+    where.parentNode.removeChild(iframe);		
+    var obj = {};		
+    otherObject.freeze(obj);		
+    return !Object.isFrozen(obj);		
+  }
+
+  /**
+   * These are all the own properties that appear on Error instances
+   * on various ES5 platforms as of this writing.
+   *
+   * <p>Due to browser bugs, some of these are absent from
+   * getOwnPropertyNames (gopn). TODO(erights): File bugs with various
+   * browser makers for any own properties that we know to be present
+   * but not reported by gopn.
+   *
+   * <p>TODO(erights): do intelligence with the various browser
+   * implementors to find out what other properties are provided by
+   * their implementation but absent from gopn, whether on Errors or
+   * anything else. Every one of these are potentially fatal to our
+   * security until we can examine these.
+   *
+   * <p>The source form is a list rather than a map so that we can list a
+   * name like "message" for each browser section we think it goes in.
+   *
+   * <p>We thank the following people, projects, and websites for
+   * providing some useful intelligence of what property names we
+   * should suspect:<ul>
+   * <li><a href="http://stacktracejs.com">stacktracejs.com</a>
+   * <li>TODO(erights): find message on es-discuss list re
+   * "   stack". credit author.
+   * </ul>
+   */
+  var errorInstanceWhitelist = [
+    // at least Chrome 16
+    'arguments',
+    'message',
+    'stack',
+    'type',
+
+    // at least FF 9
+    'fileName',
+    'lineNumber',
+    'message',
+    'stack',
+
+    // at least Safari, WebKit 5.1
+    'line',
+    'message',
+    'sourceId',
+    'sourceURL',
+
+    // at least IE 10 preview 2
+    'description',
+    'message',
+    'number',
+
+    // at least Opera 11.60
+    'message',
+    'stack',
+    'stacktrace'
+  ];
+
+  var errorInstanceBlacklist = [
+    // seen in a Firebug on FF
+    'category',
+    'context',
+    'href',
+    'lineNo',
+    'msgId',
+    'source',
+    'trace',
+    'correctSourcePoint',
+    'correctWithStackTrace',
+    'getSourceLine',
+    'resetSource'
+  ];
+
+  /** Return a fresh one so client can mutate freely */
+  function freshErrorInstanceWhiteMap() {
+    var result = Object.create(null);
+    strictForEachFn(errorInstanceWhitelist, function(name) {
+      // We cannot yet use StringMap so do it manually
+      // We do this naively here assuming we don't need to worry about
+      // __proto__
+      result[name] = true;
+    });
+    return result;
+  }
+
+  /**
+   * Do Error instances on those platform carry own properties that we
+   * haven't yet examined and determined to be SES-safe?
+   *
+   * <p>A new property should only be added to the
+   * errorInstanceWhitelist after inspecting the consequences of that
+   * property to determine that it does not compromise SES safety. If
+   * some platform maker does add an Error own property that does
+   * compromise SES safety, that might be a severe problem, if we
+   * can't find a way to deny untrusted code access to that property.
+   */
+  function test_UNEXPECTED_ERROR_PROPERTIES() {
+    var errs = [new Error('e1')];
+    try { null.foo = 3; } catch (err) { errs.push(err); }
+    var result = false;
+
+    var approvedNames = freshErrorInstanceWhiteMap();
+
+    strictForEachFn(errs, function(err) {
+      strictForEachFn(Object.getOwnPropertyNames(err), function(name) {
+         if (!(name in approvedNames)) {
+           result = 'Unexpected error instance property: ' + name;
+           // would be good to terminate early
+         }
+      });
+    });
+    return result;
+  }
+
+  /**
+   * On Firefox 14+ (and probably earlier), error instances have magical
+   * properties that do not appear in getOwnPropertyNames until you refer
+   * to the property.  This makes test_UNEXPECTED_ERROR_PROPERTIES
+   * unreliable, so we can't assume that passing that test is safe.
+   */
+  function test_ERRORS_HAVE_INVISIBLE_PROPERTIES() {
+    var gopn = Object.getOwnPropertyNames;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    var errors = [new Error('e1')];
+    try { null.foo = 3; } catch (err) { errors.push(err); }
+    for (var i = 0; i < errors.length; i++) {
+      var err = errors[i];
+      var found = Object.create(null);
+      strictForEachFn(gopn(err), function (prop) {
+        found[prop] = true;
+      });
+      var j, prop;
+      for (j = 0; j < errorInstanceWhitelist.length; j++) {
+        prop = errorInstanceWhitelist[j];
+        if (gopd(err, prop) && !found[prop]) {
+          return true;
+        }
+      }
+      for (j = 0; j < errorInstanceBlacklist.length; j++) {
+        prop = errorInstanceBlacklist[j];
+        if (gopd(err, prop) && !found[prop]) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   *
+   */
+  function test_STRICT_GETTER_BOXES() {
+    Object.defineProperty(Number.prototype, '___test_prop___', {
+      get: function() { return this; },
+      set: void 0,
+      enumerable: false,
+      configurable: true
+    });
+    var v = null;
+    try {
+      v = (3).___test_prop___;
+      if (v === 3) { return false; }
+      if (v instanceof Number) { return true; }
+      return 'unexpected boxing test result: ' + v;
+    } finally {
+      delete Number.prototype.___test_prop___;
+    }
+  }
+
+  /**
+   *
+   */
+  function test_NON_STRICT_GETTER_DOESNT_BOX() {
+    Object.defineProperty(Number.prototype, '___test_prop___', {
+      get: new Function('return this;'),
+      set: void 0,
+      enumerable: false,
+      configurable: true
+    });
+    var v = null;
+    try {
+      v = (3).___test_prop___;
+      if (v instanceof Number) { return false; }
+      if (v === 3) { return true; }
+      return 'unexpected non-boxing test result: ' + v;
+    } finally {
+      delete Number.prototype.___test_prop___;
+    }
+  }
+
+
+  ////////////////////// Repairs /////////////////////
+  //
+  // Each repair_NAME function exists primarily to repair the problem
+  // indicated by the corresponding test_NAME function. But other test
+  // failures can still trigger a given repair.
+
+
+  var call = Function.prototype.call;
+  var apply = Function.prototype.apply;
+
+  var hop = Object.prototype.hasOwnProperty;
+  var slice = Array.prototype.slice;
+  var concat = Array.prototype.concat;
+  var getPrototypeOf = Object.getPrototypeOf;
+  var unsafeDefProp = Object.defineProperty;
+  var isExtensible = Object.isExtensible;
+
+  function patchMissingProp(base, name, missingFunc) {
+    if (!(name in base)) {
+      Object.defineProperty(base, name, {
+        value: missingFunc,
+        writable: true,
+        enumerable: false,
+        configurable: true
+      });
+    }
+  }
+
+  function repair_MISSING_FREEZE_ETC() {
+    patchMissingProp(Object, 'freeze',
+                     function fakeFreeze(obj) { return obj; });
+    patchMissingProp(Object, 'seal',
+                     function fakeSeal(obj) { return obj; });
+    patchMissingProp(Object, 'preventExtensions',
+                     function fakePreventExtensions(obj) { return obj; });
+    patchMissingProp(Object, 'isFrozen',
+                     function fakeIsFrozen(obj) { return false; });
+    patchMissingProp(Object, 'isSealed',
+                     function fakeIsSealed(obj) { return false; });
+    patchMissingProp(Object, 'isExtensible',
+                     function fakeIsExtensible(obj) { return true; });
+  }
+
+  /*
+   * Fixes both FUNCTION_PROTOTYPE_DESCRIPTOR_LIES and
+   * DEFINING_READ_ONLY_PROTO_FAILS_SILENTLY.
+   */
+  function repair_DEFINE_PROPERTY() {
+    function repairedDefineProperty(base, name, desc) {
+      if (typeof base === 'function' &&
+          name === 'prototype' &&
+          'value' in desc) {
+        try {
+          base.prototype = desc.value;
+        } catch (err) {
+          logger.warn('prototype fixup failed', err);
+        }
+      }
+      if (!isExtensible(base) && name === '__proto__') {
+        throw TypeError('Cannot redefine __proto__ on a non-extensible object');
+      }
+      return unsafeDefProp(base, name, desc);
+    }
+    Object.defineProperty(Object, 'defineProperty', {
+      value: repairedDefineProperty
+    });
+  }
+
+  function repair_MISSING_CALLEE_DESCRIPTOR() {
+    var realGOPN = Object.getOwnPropertyNames;
+    Object.defineProperty(Object, 'getOwnPropertyNames', {
+      value: function calleeFix(base) {
+        var result = realGOPN(base);
+        if (typeof base === 'function') {
+          var i = result.indexOf('callee');
+          if (i >= 0 && !hop.call(base, 'callee')) {
+            result.splice(i, 1);
+          }
+        }
+        return result;
+      }
+    });
+  }
+
+  function repair_REGEXP_CANT_BE_NEUTERED() {
+    var UnsafeRegExp = RegExp;
+    var FakeRegExp = function RegExpWrapper(pattern, flags) {
+      switch (arguments.length) {
+        case 0: {
+          return UnsafeRegExp();
+        }
+        case 1: {
+          return UnsafeRegExp(pattern);
+        }
+        default: {
+          return UnsafeRegExp(pattern, flags);
+        }
+      }
+    };
+    Object.defineProperty(FakeRegExp, 'prototype', {
+      value: UnsafeRegExp.prototype
+    });
+    Object.defineProperty(FakeRegExp.prototype, 'constructor', {
+      value: FakeRegExp
+    });
+    RegExp = FakeRegExp;
+  }
+
+  function repair_REGEXP_TEST_EXEC_UNSAFE() {
+    var unsafeRegExpExec = RegExp.prototype.exec;
+    var unsafeRegExpTest = RegExp.prototype.test;
+
+    Object.defineProperty(RegExp.prototype, 'exec', {
+      value: function fakeExec(specimen) {
+        return unsafeRegExpExec.call(this, String(specimen));
+      }
+    });
+    Object.defineProperty(RegExp.prototype, 'test', {
+      value: function fakeTest(specimen) {
+        return unsafeRegExpTest.call(this, String(specimen));
+      }
+    });
+  }
+
+  function repair_MISSING_BIND() {
+
+    /**
+     * Actual bound functions are not supposed to have a prototype, and
+     * are supposed to curry over both the [[Call]] and [[Construct]]
+     * behavior of their original function. However, in ES5,
+     * functions written in JavaScript cannot avoid having a 'prototype'
+     * property, and cannot reliably distinguish between being called as
+     * a function vs as a constructor, i.e., by {@code new}.
+     *
+     * <p>Since the repair_MISSING_BIND emulation produces a bound
+     * function written in JavaScript, it cannot faithfully emulate
+     * either the lack of a 'prototype' property nor the currying of the
+     * [[Construct]] behavior. So instead, we use BOGUS_BOUND_PROTOTYPE
+     * to reliably give an error for attempts to {@code new} a bound
+     * function. Since we cannot avoid exposing BOGUS_BOUND_PROTOTYPE
+     * itself, it is possible to pass in a this-binding which inherits
+     * from it without using {@code new}, which will also trigger our
+     * error case. Whether this latter error is appropriate or not, it
+     * still fails safe.
+     *
+     * <p>By making the 'prototype' of the bound function be the same as
+     * the current {@code thisFunc.prototype}, we could have emulated
+     * the [[HasInstance]] property of bound functions. But even this
+     * would have been inaccurate, since we would be unable to track
+     * changes to the original {@code thisFunc.prototype}. (We cannot
+     * make 'prototype' into an accessor to do this tracking, since
+     * 'prototype' on a function written in JavaScript is
+     * non-configurable.) And this one partially faithful emulation
+     * would have come at the cost of no longer being able to reasonably
+     * detect construction, in order to safely reject it.
+     */
+    var BOGUS_BOUND_PROTOTYPE = {
+      toString: function BBPToString() { return 'bogus bound prototype'; }
+    };
+    rememberToTamperProof(BOGUS_BOUND_PROTOTYPE);
+    BOGUS_BOUND_PROTOTYPE.toString.prototype = null;
+    rememberToTamperProof(BOGUS_BOUND_PROTOTYPE.toString);
+
+    var defProp = Object.defineProperty;
+    defProp(Function.prototype, 'bind', {
+      value: function fakeBind(self, var_args) {
+        var thisFunc = this;
+        var leftArgs = slice.call(arguments, 1);
+        function funcBound(var_args) {
+          if (this === Object(this) &&
+              getPrototypeOf(this) === BOGUS_BOUND_PROTOTYPE) {
+            throw new TypeError(
+              'Cannot emulate "new" on pseudo-bound function.');
+          }
+          var args = concat.call(leftArgs, slice.call(arguments, 0));
+          return apply.call(thisFunc, self, args);
+        }
+        defProp(funcBound, 'prototype', {
+          value: BOGUS_BOUND_PROTOTYPE,
+          writable: false,
+          configurable: false
+        });
+        return funcBound;
+      },
+      writable: true,
+      enumerable: false,
+      configurable: true
+    });
+  }
+
+  /**
+   * Return a function suitable for using as a forEach argument on a
+   * list of method names, where that function will monkey patch each
+   * of these names methods on {@code constr.prototype} so that they
+   * can't be called on a {@code constr.prototype} itself even across
+   * frames.
+   *
+   * <p>This only works when {@code constr} corresponds to an internal
+   * [[Class]] property whose value is {@code classString}. To test
+   * for {@code constr.prototype} cross-frame, we observe that for all
+   * objects of this [[Class]], only the prototypes directly inherit
+   * from an object that does not have this [[Class]].
+   */
+  function makeMutableProtoPatcher(constr, classString) {
+    var proto = constr.prototype;
+    var baseToString = objToString.call(proto);
+    if (baseToString !== '[object ' + classString + ']') {
+      throw new TypeError('unexpected: ' + baseToString);
+    }
+    var grandProto = getPrototypeOf(proto);
+    var grandBaseToString = objToString.call(grandProto);
+    if (grandBaseToString === '[object ' + classString + ']') {
+      throw new TypeError('malformed inheritance: ' + classString);
+    }
+    if (grandProto !== Object.prototype) {
+      logger.log('unexpected inheritance: ' + classString);
+    }
+    function mutableProtoPatcher(name) {
+      if (!hop.call(proto, name)) { return; }
+      var originalMethod = proto[name];
+      function replacement(var_args) {
+        var parent = getPrototypeOf(this);
+        if (parent !== proto) {
+          // In the typical case, parent === proto, so the above test
+          // lets the typical case succeed quickly.
+          // Note that, even if parent === proto, that does not
+          // necessarily mean that the method application will
+          // succeed, since, for example, a non-Date can still inherit
+          // from Date.prototype. However, in such cases, the built-in
+          // method application will fail on its own without our help.
+          if (objToString.call(parent) !== baseToString) {
+            // As above, === baseToString does not necessarily mean
+            // success, but the built-in failure again would not need
+            // our help.
+            var thisToString = objToString.call(this);
+            if (thisToString === baseToString) {
+              throw new TypeError('May not mutate internal state of a ' +
+                                  classString + '.prototype');
+            } else {
+              throw new TypeError('Unexpected: ' + thisToString);
+            }
+          }
+        }
+        return originalMethod.apply(this, arguments);
+      }
+      Object.defineProperty(proto, name, { value: replacement });
+    }
+    return mutableProtoPatcher;
+  }
+
+
+  function repair_MUTABLE_DATE_PROTO() {
+    // Note: coordinate this list with maintenance of whitelist.js
+    ['setYear',
+     'setTime',
+     'setFullYear',
+     'setUTCFullYear',
+     'setMonth',
+     'setUTCMonth',
+     'setDate',
+     'setUTCDate',
+     'setHours',
+     'setUTCHours',
+     'setMinutes',
+     'setUTCMinutes',
+     'setSeconds',
+     'setUTCSeconds',
+     'setMilliseconds',
+     'setUTCMilliseconds'].forEach(makeMutableProtoPatcher(Date, 'Date'));
+  }
+
+  function repair_MUTABLE_WEAKMAP_PROTO() {
+    // Note: coordinate this list with maintanence of whitelist.js
+    ['set',
+     'delete'].forEach(makeMutableProtoPatcher(WeakMap, 'WeakMap'));
+  }
+
+  function repair_NEED_TO_WRAP_FOREACH() {
+    Object.defineProperty(Array.prototype, 'forEach', {
+      // Taken from https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
+      value: function(callback, thisArg) { 
+        var T, k;
+        if (this === null || this === undefined) {
+          throw new TypeError("this is null or not defined");
+        }
+        var O = Object(this);
+        var len = O.length >>> 0;
+        if (objToString.call(callback) !== "[object Function]") {
+          throw new TypeError(callback + " is not a function");
+        }
+        T = thisArg;
+        k = 0;
+        while(k < len) {
+          var kValue;
+          if (k in O) {
+            kValue = O[k];
+            callback.call(T, kValue, k, O);
+          }
+          k++;
+        }
+      }
+    });
+  }
+
+
+  function repair_NEEDS_DUMMY_SETTER() {
+    var defProp = Object.defineProperty;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    function dummySetter(newValue) {
+      throw new TypeError('no setter for assigning: ' + newValue);
+    }
+    dummySetter.prototype = null;
+    rememberToTamperProof(dummySetter);
+
+    defProp(Object, 'defineProperty', {
+      value: function setSetterDefProp(base, name, desc) {
+        if (typeof desc.get === 'function' && desc.set === void 0) {
+          var oldDesc = gopd(base, name);
+          if (oldDesc) {
+            var testBase = {};
+            defProp(testBase, name, oldDesc);
+            defProp(testBase, name, desc);
+            desc = gopd(testBase, name);
+            if (desc.set === void 0) { desc.set = dummySetter; }
+          } else {
+            if (objToString.call(base) === '[object HTMLFormElement]') {
+              // This repair was triggering bug
+              // http://code.google.com/p/chromium/issues/detail?id=94666
+              // on Chrome, causing
+              // http://code.google.com/p/google-caja/issues/detail?id=1401
+              // so if base is an HTMLFormElement we skip this
+              // fix. Since this repair and this situation are both
+              // Chrome only, it is ok that we're conditioning this on
+              // the unspecified [[Class]] value of base.
+              //
+              // To avoid the further bug identified at Comment 2
+              // http://code.google.com/p/chromium/issues/detail?id=94666#c2
+              // We also have to reconstruct the requested desc so that
+              // the setter is absent. This is why we additionally
+              // condition this special case on the absence of an own
+              // name property on base.
+              var desc2 = { get: desc.get };
+              if ('enumerable' in desc) {
+                desc2.enumerable = desc.enumerable;
+              }
+              if ('configurable' in desc) {
+                desc2.configurable = desc.configurable;
+              }
+              var result = defProp(base, name, desc2);
+              var newDesc = gopd(base, name);
+              if (newDesc.get === desc.get) {
+                return result;
+              }
+            }
+            desc.set = dummySetter;
+          }
+        }
+        return defProp(base, name, desc);
+      }
+    });
+    NEEDS_DUMMY_SETTER_repaired = true;
+  }
+
+
+  function repair_ACCESSORS_INHERIT_AS_OWN() {
+    // restrict these
+    var defProp = Object.defineProperty;
+    var freeze = Object.freeze;
+    var seal = Object.seal;
+
+    // preserve illusion
+    var gopn = Object.getOwnPropertyNames;
+    var gopd = Object.getOwnPropertyDescriptor;
+
+    var complaint = 'Workaround for ' +
+      'https://bugzilla.mozilla.org/show_bug.cgi?id=637994 ' +
+      ' prohibits enumerable non-configurable accessor properties.';
+
+    function isBadAccessor(derived, name) {
+      var desc = gopd(derived, name);
+      if (!desc || !('get' in desc)) { return false; }
+      var base = getPrototypeOf(derived);
+      if (!base) { return false; }
+      var superDesc = gopd(base, name);
+      if (!superDesc || !('get' in superDesc)) { return false; }
+      return (desc.get &&
+              !desc.configurable && !superDesc.configurable &&
+              desc.get === superDesc.get &&
+              desc.set === superDesc.set &&
+              desc.enumerable === superDesc.enumerable);
+    }
+
+    defProp(Object, 'defineProperty', {
+      value: function definePropertyWrapper(base, name, desc) {
+        var oldDesc = gopd(base, name);
+        var testBase = {};
+        if (oldDesc && !isBadAccessor(base, name)) {
+          defProp(testBase, name, oldDesc);
+        }
+        defProp(testBase, name, desc);
+        var fullDesc = gopd(testBase, name);
+         if ('get' in fullDesc &&
+            fullDesc.enumerable &&
+            !fullDesc.configurable) {
+          logger.warn(complaint);
+          throw new TypeError(complaint
+              + " (Object: " + base + " Property: " + name + ")");
+        }
+        return defProp(base, name, fullDesc);
+      }
+    });
+
+    function ensureSealable(base) {
+      gopn(base).forEach(function(name) {
+        var desc = gopd(base, name);
+        if ('get' in desc && desc.enumerable) {
+          if (!desc.configurable) {
+            logger.error('New symptom: ' +
+                         '"' + name + '" already non-configurable');
+          }
+          logger.warn(complaint);
+          throw new TypeError(complaint + " (During sealing. Object: "
+              + base + " Property: " + name + ")");
+        }
+      });
+    }
+
+    defProp(Object, 'freeze', {
+      value: function freezeWrapper(base) {
+        ensureSealable(base);
+        return freeze(base);
+      }
+    });
+
+    defProp(Object, 'seal', {
+      value: function sealWrapper(base) {
+        ensureSealable(base);
+        return seal(base);
+      }
+    });
+
+    defProp(Object.prototype, 'hasOwnProperty', {
+      value: function hasOwnPropertyWrapper(name) {
+        return hop.call(this, name) && !isBadAccessor(this, name);
+      }
+    });
+
+    defProp(Object, 'getOwnPropertyDescriptor', {
+      value: function getOwnPropertyDescriptorWrapper(base, name) {
+        if (isBadAccessor(base, name)) { return void 0; }
+        return gopd(base, name);
+      }
+    });
+
+    defProp(Object, 'getOwnPropertyNames', {
+      value: function getOwnPropertyNamesWrapper(base) {
+        return gopn(base).filter(function(name) {
+          return !isBadAccessor(base, name);
+        });
+      }
+    });
+  }
+
+  function repair_SORT_LEAKS_GLOBAL() {
+    var unsafeSort = Array.prototype.sort;
+    function sortWrapper(opt_comparefn) {
+      function comparefnWrapper(x, y) {
+        return opt_comparefn(x, y);
+      }
+      if (arguments.length === 0) {
+        return unsafeSort.call(this);
+      } else {
+        return unsafeSort.call(this, comparefnWrapper);
+      }
+    }
+    Object.defineProperty(Array.prototype, 'sort', {
+      value: sortWrapper
+    });
+  }
+
+  function repair_REPLACE_LEAKS_GLOBAL() {
+    var unsafeReplace = String.prototype.replace;
+    function replaceWrapper(searchValue, replaceValue) {
+      var safeReplaceValue = replaceValue;
+      function replaceValueWrapper(m1, m2, m3) {
+        return replaceValue(m1, m2, m3);
+      }
+      if (typeof replaceValue === 'function') {
+        safeReplaceValue = replaceValueWrapper;
+      }
+      return unsafeReplace.call(this, searchValue, safeReplaceValue);
+    }
+    Object.defineProperty(String.prototype, 'replace', {
+      value: replaceWrapper
+    });
+  }
+
+  function repair_CANT_GOPD_CALLER() {
+    var unsafeGOPD = Object.getOwnPropertyDescriptor;
+    function gopdWrapper(base, name) {
+      try {
+        return unsafeGOPD(base, name);
+      } catch (err) {
+        if (err instanceof TypeError &&
+            typeof base === 'function' &&
+            (name === 'caller' || name === 'arguments')) {
+          return (function(message) {
+             function fakePoison() { throw new TypeError(message); }
+             fakePoison.prototype = null;
+             return {
+               get: fakePoison,
+               set: fakePoison,
+               enumerable: false,
+               configurable: false
+             };
+           })(err.message);
+        }
+        throw err;
+      }
+    }
+    Object.defineProperty(Object, 'getOwnPropertyDescriptor', {
+      value: gopdWrapper
+    });
+  }
+
+  function repair_CANT_HASOWNPROPERTY_CALLER() {
+    Object.defineProperty(Object.prototype, 'hasOwnProperty', {
+      value: function hopWrapper(name) {
+        return !!Object.getOwnPropertyDescriptor(this, name);
+      }
+    });
+  }
+
+  function makeHarmless(magicName, func, path) {
+    function poison() {
+      throw new TypeError('Cannot access property ' + path);
+    }
+    poison.prototype = null;
+    var desc = Object.getOwnPropertyDescriptor(func, magicName);
+    if ((!desc && Object.isExtensible(func)) || desc.configurable) {
+      try {
+        Object.defineProperty(func, magicName, {
+          get: poison,
+          set: poison,
+          configurable: false
+        });
+      } catch (cantPoisonErr) {
+        return 'Poisoning failed with ' + cantPoisonErr;
+      }
+      desc = Object.getOwnPropertyDescriptor(func, magicName);
+      if (desc &&
+          desc.get === poison &&
+          desc.set === poison &&
+          !desc.configurable) {
+        return 'Apparently poisoned';
+      }
+      return 'Not poisoned';
+    }
+    if ('get' in desc || 'set' in desc) {
+      return 'Apparently safe';
+    }
+    try {
+      Object.defineProperty(func, magicName, {
+        value: desc.value === null ? null : void 0,
+        writable: false,
+        configurable: false
+      });
+    } catch (cantFreezeHarmlessErr) {
+      return 'Freezing harmless failed with ' + cantFreezeHarmlessErr;
+    }
+    desc = Object.getOwnPropertyDescriptor(func, magicName);
+    if (desc &&
+        (desc.value === null || desc.value === void 0) &&
+        !desc.writable &&
+        !desc.configurable) {
+      return 'Apparently frozen harmless';
+    }
+    return 'Did not freeze harmless';
+  }
+
+  function repair_BUILTIN_LEAKS_CALLER() {
+    // The call to .bind as a method here is fine since it happens
+    // after all repairs which might fix .bind and before any
+    // untrusted code runs.
+    ses.makeCallerHarmless = makeHarmless.bind(void 0, 'caller');
+    //logger.info(ses.makeCallerHarmless(builtInMapMethod));
+  }
+
+  function repair_BUILTIN_LEAKS_ARGUMENTS() {
+    // The call to .bind as a method here is fine since it happens
+    // after all repairs which might fix .bind and before any
+    // untrusted code runs.
+    ses.makeArgumentsHarmless = makeHarmless.bind(void 0, 'arguments');
+    //logger.info(ses.makeArgumentsHarmless(builtInMapMethod));
+  }
+
+  function repair_DELETED_BUILTINS_IN_OWN_NAMES() {
+    var realGOPN = Object.getOwnPropertyNames;
+    var repairedHop = Object.prototype.hasOwnProperty;
+    function getOnlyRealOwnPropertyNames(base) {
+      return realGOPN(base).filter(function(name) {
+        return repairedHop.call(base, name);
+      });
+    }
+    Object.defineProperty(Object, 'getOwnPropertyNames', {
+      value: getOnlyRealOwnPropertyNames
+    });
+  }
+
+  function repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS() {
+    var realGOPD = Object.getOwnPropertyDescriptor;
+    function GOPDWrapper(base, name) {
+      return realGOPD(base, name);
+    }
+    Object.defineProperty(Object, 'getOwnPropertyDescriptor', {
+      value: GOPDWrapper
+    });
+  }
+
+  function repair_JSON_PARSE_PROTO_CONFUSION() {
+    var unsafeParse = JSON.parse;
+    function validate(plainJSON) {
+      if (plainJSON !== Object(plainJSON)) {
+        // If we were trying to do a full validation, we would
+        // validate that it is not NaN, Infinity, -Infinity, or
+        // (if nested) undefined. However, we are currently only
+        // trying to repair
+        // http://code.google.com/p/v8/issues/detail?id=621
+        // That's why this special case validate function is private
+        // to this repair.
+        return;
+      }
+      var proto = getPrototypeOf(plainJSON);
+      if (proto !== Object.prototype && proto !== Array.prototype) {
+        throw new TypeError(
+          'Parse resulted in invalid JSON. ' +
+            'See http://code.google.com/p/v8/issues/detail?id=621');
+      }
+      Object.keys(plainJSON).forEach(function(key) {
+        validate(plainJSON[key]);
+      });
+    }
+    Object.defineProperty(JSON, 'parse', {
+      value: function parseWrapper(text, opt_reviver) {
+        var result = unsafeParse(text);
+        validate(result);
+        if (opt_reviver) {
+          return unsafeParse(text, opt_reviver);
+        } else {
+          return result;
+        }
+      },
+      writable: true,
+      enumerable: false,
+      configurable: true
+    });
+  }
+
+  function repair_PARSEINT_STILL_PARSING_OCTAL() {
+    var badParseInt = parseInt;
+    function goodParseInt(n, radix) {
+      n = '' + n;
+      // This turns an undefined radix into a NaN but is ok since NaN
+      // is treated as undefined by badParseInt
+      radix = +radix;
+      var isHexOrOctal = /^\s*[+-]?\s*0(x?)/.exec(n);
+      var isOct = isHexOrOctal ? isHexOrOctal[1] !== 'x' : false;
+
+      if (isOct && (radix !== radix || 0 === radix)) {
+        return badParseInt(n, 10);
+      }
+      return badParseInt(n, radix);
+    }
+    parseInt = goodParseInt;
+  }
+
+  function repair_ASSIGN_CAN_OVERRIDE_FROZEN() {
+    makeTamperProof = function simpleMakeTamperProof() {
+      return Object.freeze;
+    };
+  }
+
+  function repair_CANT_REDEFINE_NAN_TO_ITSELF() {
+    var defProp = Object.defineProperty;
+    // 'value' handled separately
+    var attrs = ['writable', 'get', 'set', 'enumerable', 'configurable'];
+
+    defProp(Object, 'defineProperty', {
+      value: function(base, name, desc) {
+        try {
+          return defProp(base, name, desc);
+        } catch (err) {
+          var oldDesc = Object.getOwnPropertyDescriptor(base, name);
+          for (var i = 0, len = attrs.length; i < len; i++) {
+            var attr = attrs[i];
+            if (attr in desc && desc[attr] !== oldDesc[attr]) { throw err; }
+          }
+          if (!('value' in desc) || is(desc.value, oldDesc.value)) {
+            return base;
+          }
+          throw err;
+        }
+      }
+    });
+  }
+
+  function repair_POP_IGNORES_FROZEN() {
+    var pop = Array.prototype.pop;
+    var frozen = Object.isFrozen;
+    Object.defineProperty(Array.prototype, 'pop', {
+      value: function () {
+        if (frozen(this)) {
+          throw new TypeError('Cannot pop a frozen object.');
+        }
+        return pop.call(this);
+      },
+      configurable : true,
+      writable: true
+    });
+  }
+
+  function repair_SORT_IGNORES_FROZEN() {
+    var sort = Array.prototype.sort;
+    var frozen = Object.isFrozen;
+    Object.defineProperty(Array.prototype, 'sort', {
+      value: function (compareFn) {
+        if (frozen(this)) {
+          throw new TypeError('Cannot sort a frozen object.');
+        }
+        if (arguments.length === 0) {
+          return sort.call(this);
+        } else {
+          return sort.call(this, compareFn);
+        }
+      },
+      configurable: true,
+      writable: true
+    });
+  }
+
+  function repair_PUSH_IGNORES_SEALED() {
+    var push = Array.prototype.push;
+    var sealed = Object.isSealed;
+    Object.defineProperty(Array.prototype, 'push', {
+      value: function (compareFn) {
+        if (sealed(this)) {
+          throw new TypeError('Cannot push onto a sealed object.');
+        }
+        return push.apply(this, arguments);
+      },
+      configurable: true,
+      writable: true
+    });
+  }
+
+  ////////////////////// Kludge Records /////////////////////
+  //
+  // Each kludge record has a <dl>
+  //   <dt>description:</dt>
+  //     <dd>a string describing the problem</dd>
+  //   <dt>test:</dt>
+  //     <dd>a predicate testing for the presence of the problem</dd>
+  //   <dt>repair:</dt>
+  //     <dd>a function which attempts repair, or undefined if no
+  //         repair is attempted for this problem</dd>
+  //   <dt>preSeverity:</dt>
+  //     <dd>an enum (see below) indicating the level of severity of
+  //         this problem if unrepaired. Or, if !canRepair, then
+  //         the severity whether or not repaired.</dd>
+  //   <dt>canRepair:</dt>
+  //     <dd>a boolean indicating "if the repair exists and the test
+  //         subsequently does not detect a problem, are we now ok?"</dd>
+  //   <dt>urls:</dt>
+  //     <dd>a list of URL strings, each of which points at a page
+  //         relevant for documenting or tracking the bug in
+  //         question. These are typically into bug-threads in issue
+  //         trackers for the various browsers.</dd>
+  //   <dt>sections:</dt>
+  //     <dd>a list of strings, each of which is a relevant ES5.1
+  //         section number.</dd>
+  //   <dt>tests:</dt>
+  //     <dd>a list of strings, each of which is the name of a
+  //         relevant test262 or sputnik test case.</dd>
+  // </dl>
+  // These kludge records are the meta-data driving the testing and
+  // repairing.
+
+  var severities = ses.severities;
+  var statuses = ses.statuses;
+
+  /**
+   * First test whether the platform can even support our repair
+   * attempts.
+   */
+  var baseKludges = [
+    {
+      description: 'Missing getOwnPropertyNames',
+      test: test_MISSING_GETOWNPROPNAMES,
+      repair: void 0,
+      preSeverity: severities.NOT_SUPPORTED,
+      canRepair: false,
+      urls: [],
+      sections: ['15.2.3.4'],
+      tests: ['15.2.3.4-0-1']
+    }
+  ];
+
+  /**
+   * Run these only if baseKludges report success.
+   */
+  var supportedKludges = [
+    {
+      description: 'Global object leaks from global function calls',
+      test: test_GLOBAL_LEAKS_FROM_GLOBAL_FUNCTION_CALLS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=64250'],
+      sections: ['10.2.1.2', '10.2.1.2.6'],
+      tests: ['10.4.3-1-8gs']
+    },
+    {
+      description: 'Global object leaks from anonymous function calls',
+      test: test_GLOBAL_LEAKS_FROM_ANON_FUNCTION_CALLS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.4.3'],
+      tests: ['S10.4.3_A1']
+    },
+    {
+      description: 'Global leaks through strict this',
+      test: test_GLOBAL_LEAKS_FROM_STRICT_THIS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.4.3'],
+      tests: ['10.4.3-1-8gs', '10.4.3-1-8-s']
+    },
+    {
+      description: 'Global object leaks from built-in methods',
+      test: test_GLOBAL_LEAKS_FROM_BUILTINS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=51097',
+             'https://bugs.webkit.org/show_bug.cgi?id=58338',
+             'http://code.google.com/p/v8/issues/detail?id=1437',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685430/global-object-leaks-from-built-in-methods'],
+      sections: ['15.2.4.4'],
+      tests: ['S15.2.4.4_A14']
+    },
+    {
+      description: 'Global object leaks from globally called built-in methods',
+      test: test_GLOBAL_LEAKS_FROM_GLOBALLY_CALLED_BUILTINS,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: [],
+      sections: ['10.2.1.2', '10.2.1.2.6', '15.2.4.4'],
+      tests: ['S15.2.4.4_A15']
+    },
+    {
+      description: 'Object.freeze is missing',
+      test: test_MISSING_FREEZE_ETC,
+      repair: repair_MISSING_FREEZE_ETC,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,           // repair for development, not safety
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=55736'],
+      sections: ['15.2.3.9'],
+      tests: ['15.2.3.9-0-1']
+    },
+    {
+      description: 'A function.prototype\'s descriptor lies',
+      test: test_FUNCTION_PROTOTYPE_DESCRIPTOR_LIES,
+      repair: repair_DEFINE_PROPERTY,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1530',
+             'http://code.google.com/p/v8/issues/detail?id=1570'],
+      sections: ['15.2.3.3', '15.2.3.6', '15.3.5.2'],
+      tests: ['S15.3.3.1_A4']
+    },
+    {
+      description: 'Phantom callee on strict functions',
+      test: test_MISSING_CALLEE_DESCRIPTOR,
+      repair: repair_MISSING_CALLEE_DESCRIPTOR,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=55537'],
+      sections: ['15.2.3.4'],
+      tests: ['S15.2.3.4_A1_T1']
+    },
+    {
+      description: 'Strict delete returned false rather than throwing',
+      test: test_STRICT_DELETE_RETURNS_FALSE,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://connect.microsoft.com/IE/feedback/details/' +
+               '685432/strict-delete-sometimes-returns-false-' +
+               'rather-than-throwing'],
+      sections: ['11.4.1'],
+      tests: ['S11.4.1_A5']
+    },
+    {
+      description: 'Non-deletable RegExp statics are a' +
+        ' global communication channel',
+      test: test_REGEXP_CANT_BE_NEUTERED,
+      repair: repair_REGEXP_CANT_BE_NEUTERED,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685439/non-deletable-regexp-statics-are-a-global-' +
+               'communication-channel'],
+      sections: ['11.4.1'],
+      tests: ['S11.4.1_A5']
+    },
+    {
+      description: 'RegExp.exec leaks match globally',
+      test: test_REGEXP_TEST_EXEC_UNSAFE,
+      repair: repair_REGEXP_TEST_EXEC_UNSAFE,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1393',
+             'http://code.google.com/p/chromium/issues/detail?id=75740',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=635017',
+             'http://code.google.com/p/google-caja/issues/detail?id=528'],
+      sections: ['15.10.6.2'],
+      tests: ['S15.10.6.2_A12']
+    },
+    {
+      description: 'Function.prototype.bind is missing',
+      test: test_MISSING_BIND,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=26382',
+             'https://bugs.webkit.org/show_bug.cgi?id=42371'],
+      sections: ['15.3.4.5'],
+      tests: ['S15.3.4.5_A3']
+    },
+    {
+      description: 'Function.prototype.bind calls .apply rather than [[Call]]',
+      test: test_BIND_CALLS_APPLY,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=892',
+             'http://code.google.com/p/v8/issues/detail?id=828'],
+      sections: ['15.3.4.5.1'],
+      tests: ['S15.3.4.5_A4']
+    },
+    {
+      description: 'Function.prototype.bind does not curry construction',
+      test: test_BIND_CANT_CURRY_NEW,
+      repair: void 0, // JS-based repair essentially impossible
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=26382#c29'],
+      sections: ['15.3.4.5.2'],
+      tests: ['S15.3.4.5_A5']
+    },
+    {
+      description: 'Date.prototype is a global communication channel',
+      test: test_MUTABLE_DATE_PROTO,
+      repair: repair_MUTABLE_DATE_PROTO,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/google-caja/issues/detail?id=1362'],
+      sections: ['15.9.5'],
+      tests: []
+    },
+    {
+      description: 'WeakMap.prototype is a global communication channel',
+      test: test_MUTABLE_WEAKMAP_PROTO,
+      repair: repair_MUTABLE_WEAKMAP_PROTO,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=656828'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Array forEach cannot be frozen while in progress',
+      test: test_NEED_TO_WRAP_FOREACH,
+      repair: repair_NEED_TO_WRAP_FOREACH,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1447'],
+      sections: ['15.4.4.18'],
+      tests: ['S15.4.4.18_A1', 'S15.4.4.18_A2']
+    },
+    {
+      description: 'Array forEach converts primitive thisObj arg to object',
+      test: test_FOREACH_COERCES_THISOBJ,
+      repair: repair_NEED_TO_WRAP_FOREACH,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=2273',
+          'https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach'],
+      sections: ['15.4.4.18'],
+      tests: []
+    },
+    {
+      description: 'Workaround undiagnosed need for dummy setter',
+      test: test_NEEDS_DUMMY_SETTER,
+      repair: repair_NEEDS_DUMMY_SETTER,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: [],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Getter on HTMLFormElement disappears',
+      test: test_FORM_GETTERS_DISAPPEAR,
+      repair: repair_NEEDS_DUMMY_SETTER,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/chromium/issues/detail?id=94666',
+             'http://code.google.com/p/v8/issues/detail?id=1651',
+             'http://code.google.com/p/google-caja/issues/detail?id=1401'],
+      sections: ['15.2.3.6'],
+      tests: ['S15.2.3.6_A1']
+    },
+    {
+      description: 'Accessor properties inherit as own properties',
+      test: test_ACCESSORS_INHERIT_AS_OWN,
+      repair: repair_ACCESSORS_INHERIT_AS_OWN,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=637994'],
+      sections: ['8.6.1', '15.2.3.6'],
+      tests: ['S15.2.3.6_A2']
+    },
+    {
+      description: 'Array sort leaks global',
+      test: test_SORT_LEAKS_GLOBAL,
+      repair: repair_SORT_LEAKS_GLOBAL,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1360'],
+      sections: ['15.4.4.11'],
+      tests: ['S15.4.4.11_A8']
+    },
+    {
+      description: 'String replace leaks global',
+      test: test_REPLACE_LEAKS_GLOBAL,
+      repair: repair_REPLACE_LEAKS_GLOBAL,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1360',
+             'https://connect.microsoft.com/IE/feedback/details/' +
+               '685928/bad-this-binding-for-callback-in-string-' +
+               'prototype-replace'],
+      sections: ['15.5.4.11'],
+      tests: ['S15.5.4.11_A12']
+    },
+    {
+      description: 'getOwnPropertyDescriptor on strict "caller" throws',
+      test: test_CANT_GOPD_CALLER,
+      repair: repair_CANT_GOPD_CALLER,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://connect.microsoft.com/IE/feedback/details/' +
+               '685436/getownpropertydescriptor-on-strict-caller-throws'],
+      sections: ['15.2.3.3', '13.2', '13.2.3'],
+      tests: ['S13.2_A6_T1']
+    },
+    {
+      description: 'strict_function.hasOwnProperty("caller") throws',
+      test: test_CANT_HASOWNPROPERTY_CALLER,
+      repair: repair_CANT_HASOWNPROPERTY_CALLER,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398#c3'],
+      sections: ['15.2.4.5', '13.2', '13.2.3'],
+      tests: ['S13.2_A7_T1']
+    },
+    {
+      description: 'Cannot "in" caller on strict function',
+      test: test_CANT_IN_CALLER,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['11.8.7', '13.2', '13.2.3'],
+      tests: ['S13.2_A8_T1']
+    },
+    {
+      description: 'Cannot "in" arguments on strict function',
+      test: test_CANT_IN_ARGUMENTS,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['11.8.7', '13.2', '13.2.3'],
+      tests: ['S13.2_A8_T2']
+    },
+    {
+      description: 'Strict "caller" not poisoned',
+      test: test_STRICT_CALLER_NOT_POISONED,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: [],
+      sections: ['13.2'],
+      tests: ['S13.2.3_A1']
+    },
+    {
+      description: 'Strict "arguments" not poisoned',
+      test: test_STRICT_ARGUMENTS_NOT_POISONED,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: [],
+      sections: ['13.2'],
+      tests: ['S13.2.3_A1']
+    },
+    {
+      description: 'Built in functions leak "caller"',
+      test: test_BUILTIN_LEAKS_CALLER,
+      repair: repair_BUILTIN_LEAKS_CALLER,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1643',
+             'http://code.google.com/p/v8/issues/detail?id=1548',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable'],
+      sections: [],
+      tests: ['Sbp_A10_T1']
+    },
+    {
+      description: 'Built in functions leak "arguments"',
+      test: test_BUILTIN_LEAKS_ARGUMENTS,
+      repair: repair_BUILTIN_LEAKS_ARGUMENTS,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1643',
+             'http://code.google.com/p/v8/issues/detail?id=1548',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=591846',
+             'http://wiki.ecmascript.org/doku.php?id=' +
+               'conventions:make_non-standard_properties_configurable'],
+      sections: [],
+      tests: ['Sbp_A10_T2']
+    },
+    {
+      description: 'Bound functions leak "caller"',
+      test: test_BOUND_FUNCTION_LEAKS_CALLER,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=893',
+             'https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['15.3.4.5'],
+      tests: ['S13.2.3_A1', 'S15.3.4.5_A1']
+    },
+    {
+      description: 'Bound functions leak "arguments"',
+      test: test_BOUND_FUNCTION_LEAKS_ARGUMENTS,
+      repair: repair_MISSING_BIND,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=893',
+             'https://bugs.webkit.org/show_bug.cgi?id=63398'],
+      sections: ['15.3.4.5'],
+      tests: ['S13.2.3_A1', 'S15.3.4.5_A2']
+    },
+    {
+      description: 'Deleting built-in leaves phantom behind',
+      test: test_DELETED_BUILTINS_IN_OWN_NAMES,
+      repair: repair_DELETED_BUILTINS_IN_OWN_NAMES,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=70207'],
+      sections: ['15.2.3.4'],
+      tests: []
+    },
+    {
+      description: 'getOwnPropertyDescriptor on its own "caller" fails',
+      test: test_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,
+      repair: repair_GETOWNPROPDESC_OF_ITS_OWN_CALLER_FAILS,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1769'],
+      sections: ['13.2', '15.2.3.3'],
+      tests: []
+    },
+    {
+      description: 'JSON.parse confused by "__proto__"',
+      test: test_JSON_PARSE_PROTO_CONFUSION,
+      repair: repair_JSON_PARSE_PROTO_CONFUSION,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=621',
+             'http://code.google.com/p/v8/issues/detail?id=1310'],
+      sections: ['15.12.2'],
+      tests: ['S15.12.2_A1']
+    },
+    {
+      description: 'Prototype still mutable on non-extensible object',
+      test: test_PROTO_NOT_FROZEN,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=65832',
+             'https://bugs.webkit.org/show_bug.cgi?id=78438'],
+      sections: ['8.6.2'],
+      tests: ['S8.6.2_A8']
+    },
+    {
+      description: 'Prototype still redefinable on non-extensible object',
+      test: test_PROTO_REDEFINABLE,
+      repair: void 0,
+      preSeverity: severities.NOT_OCAP_SAFE,
+      canRepair: false,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=65832'],
+      sections: ['8.6.2'],
+      tests: ['S8.6.2_A8']
+    },
+    {
+      description: 'Defining __proto__ on non-extensible object fails silently',
+      test: test_DEFINING_READ_ONLY_PROTO_FAILS_SILENTLY,
+      repair: repair_DEFINE_PROPERTY,
+      preSeverity: severities.NO_KNOWN_EXPLOIT_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=2441'],
+      sections: ['8.6.2'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Strict eval function leaks variable definitions',
+      test: test_STRICT_EVAL_LEAKS_GLOBALS,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1624'],
+      sections: ['10.4.2.1'],
+      tests: ['S10.4.2.1_A1']
+    },
+    {
+      description: 'Eval breaks masking of named functions in non-strict code',
+      test: test_EVAL_BREAKS_MASKING,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=2396'],
+      sections: ['10.2'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'parseInt still parsing octal',
+      test: test_PARSEINT_STILL_PARSING_OCTAL,
+      repair: repair_PARSEINT_STILL_PARSING_OCTAL,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1645'],
+      sections: ['15.1.2.2'],
+      tests: ['S15.1.2.2_A5.1_T1']
+    },
+    {
+      description: 'E4X literals allowed in strict code',
+      test: test_STRICT_E4X_LITERALS_ALLOWED,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=695577',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=695579'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Assignment can override frozen inherited property',
+      test: test_ASSIGN_CAN_OVERRIDE_FROZEN,
+      repair: repair_ASSIGN_CAN_OVERRIDE_FROZEN,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=1169',
+             'http://code.google.com/p/v8/issues/detail?id=1475',
+             'https://mail.mozilla.org/pipermail/es-discuss/' +
+               '2011-November/017997.html',
+             'http://wiki.ecmascript.org/doku.php?id=strawman:' +
+               'fixing_override_mistake'],
+      sections: ['8.12.4'],
+      tests: ['15.2.3.6-4-405']
+    },
+    {
+      description: 'Array.prototype.pop ignores frozeness',
+      test: test_POP_IGNORES_FROZEN,
+      repair: repair_POP_IGNORES_FROZEN,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['https://bugs.webkit.org/show_bug.cgi?id=75788'],
+      sections: ['15.4.4.6'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Array.prototype.sort ignores frozeness',
+      test: test_SORT_IGNORES_FROZEN,
+      repair: repair_SORT_IGNORES_FROZEN,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=2419'],
+      sections: ['15.4.4.11'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Array.prototype.push ignores sealing',
+      test: test_PUSH_IGNORES_SEALED,
+      repair: repair_PUSH_IGNORES_SEALED,
+      preSeverity: severities.UNSAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=2412'],
+      sections: ['15.4.4.11'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Setting [].length can delete non-configurable elements',
+      test: test_ARRAYS_DELETE_NONCONFIGURABLE,
+      repair: void 0,
+      preSeverity: severities.NO_KNOWN_EXPLOIT_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=590690'],
+      sections: ['15.4.5.2'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Extending an array can modify read-only array length',
+      test: test_ARRAYS_MODIFY_READONLY,
+      repair: void 0,
+      preSeverity: severities.NO_KNOWN_EXPLOIT_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['http://code.google.com/p/v8/issues/detail?id=2379'],
+      sections: ['15.4.5.1.3.f'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Cannot redefine global NaN to itself',
+      test: test_CANT_REDEFINE_NAN_TO_ITSELF,
+      repair: repair_CANT_REDEFINE_NAN_TO_ITSELF,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: true,
+      urls: [], // Seen on WebKit Nightly. TODO(erights): report
+      sections: ['8.12.9', '15.1.1.1'],
+      tests: [] // TODO(erights): Add to test262
+    },
+    {
+      description: 'Firefox 15 cross-frame freeze problem',
+      test: test_FIREFOX_15_FREEZE_PROBLEM,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=784892',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=674195'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Error instances have unexpected properties',
+      test: test_UNEXPECTED_ERROR_PROPERTIES,
+      repair: void 0,
+      preSeverity: severities.NEW_SYMPTOM,
+      canRepair: false,
+      urls: [],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Error instances may have invisible properties',
+      test: test_ERRORS_HAVE_INVISIBLE_PROPERTIES,
+      repair: void 0,
+      preSeverity: severities.NOT_ISOLATED,
+      canRepair: false,
+      urls: ['https://bugzilla.mozilla.org/show_bug.cgi?id=726477',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=724768'],
+      sections: [],
+      tests: []
+    },
+    {
+      description: 'Strict getter must not box this, but does',
+      test: test_STRICT_GETTER_BOXES,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.ecmascript.org/show_bug.cgi?id=284',
+             'https://bugs.webkit.org/show_bug.cgi?id=79843',
+             'https://connect.microsoft.com/ie/feedback/details/727027',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=603201',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=732669'],
+             // Opera DSK-358415
+      sections: ['10.4.3'],
+      tests: [] // ['10.4.3-1-59-s']
+    },
+    {
+      description: 'Non-strict getter must box this, but does not',
+      test: test_NON_STRICT_GETTER_DOESNT_BOX,
+      repair: void 0,
+      preSeverity: severities.SAFE_SPEC_VIOLATION,
+      canRepair: false,
+      urls: ['https://bugs.ecmascript.org/show_bug.cgi?id=284',
+             'http://code.google.com/p/v8/issues/detail?id=1977',
+             'https://bugzilla.mozilla.org/show_bug.cgi?id=732669'],
+      sections: ['10.4.3'],
+      tests: [] // ['10.4.3-1-59-s']
+    }
+  ];
+
+  ////////////////////// Testing, Repairing, Reporting ///////////
+
+  var aboutTo = void 0;
+
+  /**
+   * Run a set of tests & repairs, and report results.
+   *
+   * <p>First run all the tests before repairing anything.
+   * Then repair all repairable failed tests.
+   * Some repair might fix multiple problems, but run each repair at most once.
+   * Then run all the tests again, in case some repairs break other tests.
+   * And finally return a list of records of results.
+   */
+  function testRepairReport(kludges) {
+    var beforeFailures = strictMapFn(kludges, function(kludge) {
+      aboutTo = ['pre test: ', kludge.description];
+      return kludge.test();
+    });
+    var repairs = [];
+    strictForEachFn(kludges, function(kludge, i) {
+      if (beforeFailures[i]) {
+        var repair = kludge.repair;
+        if (repair && repairs.lastIndexOf(repair) === -1) {
+          aboutTo = ['repair: ', kludge.description];
+          repair();
+          repairs.push(repair);
+        }
+      }
+    });
+    var afterFailures = strictMapFn(kludges, function(kludge) {
+      aboutTo = ['post test: ', kludge.description];
+      return kludge.test();
+    });
+
+    if (Object.isFrozen && Object.isFrozen(Array.prototype.forEach)) {
+      // Need to do it anyway, to repair the sacrificial freezing we
+      // needed to do to test. Once we can permanently retire this
+      // test, we can also retire the redundant repair.
+      repair_NEED_TO_WRAP_FOREACH();
+    }
+
+    return strictMapFn(kludges, function(kludge, i) {
+      var status = statuses.ALL_FINE;
+      var postSeverity = severities.SAFE;
+      var beforeFailure = beforeFailures[i];
+      var afterFailure = afterFailures[i];
+      if (beforeFailure) { // failed before
+        if (afterFailure) { // failed after
+          if (kludge.repair) {
+            postSeverity = kludge.preSeverity;
+            status = statuses.REPAIR_FAILED;
+          } else {
+            if (!kludge.canRepair) {
+              postSeverity = kludge.preSeverity;
+            } // else no repair + canRepair -> problem isn't safety issue
+            status = statuses.NOT_REPAIRED;
+          }
+        } else { // succeeded after
+          if (kludge.repair) {
+            if (!kludge.canRepair) {
+              // repair for development, not safety
+              postSeverity = kludge.preSeverity;
+              status = statuses.REPAIRED_UNSAFELY;
+            } else {
+              status = statuses.REPAIRED;
+            }
+          } else {
+            status = statuses.ACCIDENTALLY_REPAIRED;
+          }
+        }
+      } else { // succeeded before
+        if (afterFailure) { // failed after
+          if (kludge.repair || !kludge.canRepair) {
+            postSeverity = kludge.preSeverity;
+          } // else no repair + canRepair -> problem isn't safety issue
+          status = statuses.BROKEN_BY_OTHER_ATTEMPTED_REPAIRS;
+        } else { // succeeded after
+          // nothing to see here, move along
+        }
+      }
+
+      if (typeof beforeFailure === 'string') {
+        logger.error('New Symptom: ' + beforeFailure);
+        postSeverity = severities.NEW_SYMPTOM;
+      }
+      if (typeof afterFailure === 'string') {
+        logger.error('New Symptom: ' + afterFailure);
+        postSeverity = severities.NEW_SYMPTOM;
+      }
+
+      ses.updateMaxSeverity(postSeverity);
+
+      return {
+        description:   kludge.description,
+        preSeverity:   kludge.preSeverity,
+        canRepair:     kludge.canRepair,
+        urls:          kludge.urls,
+        sections:      kludge.sections,
+        tests:         kludge.tests,
+        status:        status,
+        postSeverity:  postSeverity,
+        beforeFailure: beforeFailure,
+        afterFailure:  afterFailure
+      };
+    });
+  }
+
+  try {
+    var reports = testRepairReport(baseKludges);
+    if (ses.ok()) {
+      reports.push.apply(reports, testRepairReport(supportedKludges));
+    }
+    logger.reportRepairs(reports);
+  } catch (err) {
+    ses.updateMaxSeverity(ses.severities.NOT_SUPPORTED);
+    var during = aboutTo ? '(' + aboutTo.join('') + ') ' : '';
+    logger.error('ES5 Repair ' + during + 'failed with: ', err);
+  }
+
+  logger.reportMax();
+
+})(this);
diff --git a/startSES.js b/startSES.js
new file mode 100644
index 0000000..a0aae32
--- /dev/null
+++ b/startSES.js
@@ -0,0 +1,1321 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Make this frame SES-safe or die trying.
+ *
+ * <p>Assumes ES5 plus a WeakMap that conforms to the anticipated ES6
+ * WeakMap spec. Compatible with ES5-strict or anticipated ES6.
+ *
+ * //provides ses.startSES
+ * @author Mark S. Miller,
+ * @author Jasvir Nagra
+ * @requires WeakMap
+ * @overrides ses, console, eval, Function, cajaVM
+ */
+var ses;
+
+
+/**
+ * The global {@code eval} function available to script code, which
+ * may or not be made safe.
+ *
+ * <p>The original global binding of {@code eval} is not
+ * SES-safe. {@code cajaVM.eval} is a safe wrapper around this
+ * original eval, enforcing SES language restrictions.
+ *
+ * <p>If {@code TAME_GLOBAL_EVAL} is true, both the global {@code
+ * eval} variable and {@code sharedImports.eval} are set to the safe
+ * wrapper. If {@code TAME_GLOBAL_EVAL} is false, in order to work
+ * around a bug in the Chrome debugger, then the global {@code eval}
+ * is unaltered and no {@code "eval"} property is available on {@code
+ * sharedImports}. In either case, SES-evaled-code and SES-script-code
+ * can both access the safe eval wrapper as {@code cajaVM.eval}.
+ *
+ * <p>By making the safe eval available on {@code sharedImports} only
+ * when we also make it be the genuine global eval, we preserve the
+ * property that SES-evaled-code differs from SES-script-code only by
+ * having a subset of the same variables in globalish scope. This is a
+ * nice-to-have that makes explanation easier rather than a hard
+ * requirement. With this property, any SES-evaled-code that does not
+ * fail to access a global variable (or to test whether it could)
+ * should operate the same way when run as SES-script-code.
+ *
+ * <p>See doc-comment on cajaVM for the restriction on this API needed
+ * to operate under Caja translation on old browsers.
+ */
+var eval;
+
+/**
+ * The global {@code Function} constructor is always replaced with a
+ * safe wrapper, which is also made available as
+ * {@code sharedImports.Function}.
+ *
+ * <p>Both the original Function constructor and this safe wrapper
+ * point at the original {@code Function.prototype}, so {@code
+ * instanceof} works fine with the wrapper. {@code
+ * Function.prototype.constructor} is set to point at the safe
+ * wrapper, so that only it, and not the unsafe original, is
+ * accessible.
+ *
+ * <p>See doc-comment on cajaVM for the restriction on this API needed
+ * to operate under Caja translation on old browsers.
+ */
+var Function;
+
+/**
+ * A new global exported by SES, intended to become a mostly
+ * compatible API between server-side Caja translation for older
+ * browsers and client-side SES verification for newer browsers.
+ *
+ * <p>Under server-side Caja translation for old pre-ES5 browsers, the
+ * synchronous interface of the evaluation APIs (currently {@code
+ * eval, Function, cajaVM.{compileExpr, compileModule, eval, Function}})
+ * cannot reasonably be provided. Instead, under translation we expect
+ * <ul>
+ * <li>Not to have a binding for {@code "eval"} on
+ *     {@code sharedImports}, just as we would not if
+ *     {@code TAME_GLOBAL_EVAL} is false.
+ * <li>The global {@code eval} seen by scripts is either unaltered (to
+ *     work around the Chrome debugger bug if {@code TAME_GLOBAL_EVAL}
+ *     is false), or is replaced by a function that throws an
+ *     appropriate EvalError diagnostic (if {@code TAME_GLOBAL_EVAL}
+ *     is true).
+ * <li>The global {@code Function} constructor, both as seen by script
+ *     code and evaled code, to throw an appropriate diagnostic.
+ * <li>The {@code Q} API to always be available, to handle
+ *     asynchronous, promise, and remote requests.
+ * <li>The evaluating methods on {@code cajaVM} -- currently {@code
+ *     compileExpr, compileModule, eval, and Function} -- to be remote
+ *     promises for their normal interfaces, which therefore must be
+ *     invoked with {@code Q.post}.
+ * <li>Since {@code Q.post} can be used for asynchronously invoking
+ *     non-promises, invocations like
+ *     {@code Q.post(cajaVM, 'eval', ['2+3'])}, for example,
+ *     will return a promise for a 5. This should work both under Caja
+ *     translation and (TODO(erights)) under SES verification when
+ *     {@code Q} is also installed, and so is the only portable
+ *     evaluating API that SES code should use during this transition
+ *     period.
+ * <li>TODO(erights): {@code Q.post(cajaVM, 'compileModule',
+ *     [moduleSrc]} should eventually pre-load the transitive
+ *     synchronous dependencies of moduleSrc before resolving the
+ *     promise for its result. It currently would not, instead
+ *     requiring its client to do so manually.
+ * </ul>
+ */
+var cajaVM;
+
+/**
+ * <p>{@code ses.startSES} should be called before any other potentially
+ * dangerous script is executed in this frame.
+ *
+ * <p>If {@code ses.startSES} succeeds, the evaluation operations on
+ * {@code cajaVM}, the global {@code Function} contructor, and perhaps
+ * the {@code eval} function (see doc-comment on {@code eval} and
+ * {@code cajaVM}) will only load code according to the <i>loader
+ * isolation</i> rules of the object-capability model, suitable for
+ * loading untrusted code. If all other (trusted) code executed
+ * directly in this frame (i.e., other than through these safe
+ * evaluation operations) takes care to uphold object-capability
+ * rules, then untrusted code loaded via these safe evaluation
+ * operations will be constrained by those rules. TODO(erights):
+ * explain concretely what the trusted code must do or avoid doing to
+ * uphold object-capability rules.
+ *
+ * <p>On a pre-ES5 platform, this script will fail cleanly, leaving
+ * the frame intact. Otherwise, if this script fails, it may leave
+ * this frame in an unusable state. All following description assumes
+ * this script succeeds and that the browser conforms to the ES5
+ * spec. The ES5 spec allows browsers to implement more than is
+ * specified as long as certain invariants are maintained. We further
+ * assume that these extensions are not maliciously designed to obey
+ * the letter of these invariants while subverting the intent of the
+ * spec. In other words, even on an ES5 conformant browser, we do not
+ * presume to defend ourselves from a browser that is out to get us.
+ *
+ * @param global ::Record(any) Assumed to be the real global object
+ *        for some frame. Since {@code ses.startSES} will allow global
+ *        variable references that appear at the top level of the
+ *        whitelist, our safety depends on these variables being
+ *        frozen as a side effect of freezing the corresponding
+ *        properties of {@code global}. These properties are also
+ *        duplicated onto the virtual global objects which are
+ *        provided as the {@code this} binding for the safe
+ *        evaluation calls -- emulating the safe subset of the normal
+ *        global object.
+ *        TODO(erights): Currently, the code has only been tested when
+ *        {@code global} is the global object of <i>this</i>
+ *        frame. The code should be made to work for cross-frame use.
+ * @param whitelist ::Record(Permit) where Permit = true | "*" |
+ *        "skip" | Record(Permit).  Describes the subset of naming
+ *        paths starting from {@code sharedImports} that should be
+ *        accessible. The <i>accessible primordials</i> are all values
+ *        found by navigating these paths starting from {@code
+ *        sharedImports}. All non-whitelisted properties of accessible
+ *        primordials are deleted, and then {@code sharedImports}
+ *        and all accessible primordials are frozen with the
+ *        whitelisted properties frozen as data properties.
+ *        TODO(erights): fix the code and documentation to also
+ *        support confined-ES5, suitable for confining potentially
+ *        offensive code but not supporting defensive code, where we
+ *        skip this last freezing step. With confined-ES5, each frame
+ *        is considered a separate protection domain rather that each
+ *        individual object.
+ * @param atLeastFreeVarNames ::F([string], Record(true))
+ *        Given the sourceText for a strict Program,
+ *        atLeastFreeVarNames(sourceText) returns a Record whose
+ *        enumerable own property names must include the names of all the
+ *        free variables occuring in sourceText. It can include as
+ *        many other strings as is convenient so long as it includes
+ *        these. The value of each of these properties should be
+ *        {@code true}. TODO(erights): On platforms with Proxies
+ *        (currently only Firefox 4 and after), use {@code
+ *        with(aProxy) {...}} to intercept free variables rather than
+ *        atLeastFreeVarNames.
+ * @param extensions ::F([], Record(any)]) A function returning a
+ *        record whose own properties will be copied onto cajaVM. This
+ *        is used for the optional components which bring SES to
+ *        feature parity with the ES5/3 runtime at the price of larger
+ *        code size. At the time that {@code startSES} calls {@code
+ *        extensions}, {@code cajaVM} exists but should not yet be
+ *        used. In particular, {@code extensions} should not call
+ *        {@code cajaVM.def} during this setup, because def would then
+ *        freeze priordials before startSES cleans them (removes
+ *        non-whitelisted properties). The methods that
+ *        {@code extensions} contributes can, of course, use
+ *        {@code cajaVM}, since those methods will only be called once
+ *        {@code startSES} finishes.
+ */
+ses.startSES = function(global,
+                        whitelist,
+                        atLeastFreeVarNames,
+                        extensions) {
+  "use strict";
+
+  /////////////// KLUDGE SWITCHES ///////////////
+
+  /////////////////////////////////
+  // The following are only the minimal kludges needed for the current
+  // Firefox or the current Chrome Beta. At the time of
+  // this writing, these are Firefox 4.0 and Chrome 12.0.742.5 dev
+  // As these move forward, kludges can be removed until we simply
+  // rely on ES5.
+
+  /**
+   * <p>TODO(erights): isolate and report this.
+   *
+   * <p>Workaround for Chrome debugger's own use of 'eval'
+   *
+   * <p>This kludge is safety preserving but not semantics
+   * preserving. When {@code TAME_GLOBAL_EVAL} is false, no {@code
+   * sharedImports.eval} is available, and the 'eval' available as a
+   * global to trusted (script) code is the original 'eval', and so is
+   * not safe.
+   */
+  //var TAME_GLOBAL_EVAL = true;
+  var TAME_GLOBAL_EVAL = false;
+
+  /**
+   * If this is true, then we redefine these to work around a
+   * stratification bug in the Chrome debugger. To allow this, we have
+   * also whitelisted these four properties in whitelist.js
+   */
+  //var EMULATE_LEGACY_GETTERS_SETTERS = false;
+  var EMULATE_LEGACY_GETTERS_SETTERS = true;
+
+  //////////////// END KLUDGE SWITCHES ///////////
+
+
+  var dirty = true;
+
+  var hop = Object.prototype.hasOwnProperty;
+
+  var getProto = Object.getPrototypeOf;
+  var defProp = Object.defineProperty;
+  var gopd = Object.getOwnPropertyDescriptor;
+  var gopn = Object.getOwnPropertyNames;
+  var keys = Object.keys;
+  var freeze = Object.freeze;
+  var create = Object.create;
+
+  /**
+   * Use to tamper proof a function which is not intended to ever be
+   * used as a constructor, since it nulls out the function's
+   * prototype first.
+   */
+  function constFunc(func) {
+    func.prototype = null;
+    return freeze(func);
+  }
+
+
+  function fail(str) {
+    debugger;
+    throw new EvalError(str);
+  }
+
+  if (typeof WeakMap === 'undefined') {
+    fail('No built-in WeakMaps, so WeakMap.js must be loaded first');
+  }
+
+
+  if (EMULATE_LEGACY_GETTERS_SETTERS) {
+    (function(){
+      function legacyDefineGetter(sprop, getter) {
+        sprop = '' + sprop;
+        if (hop.call(this, sprop)) {
+          defProp(this, sprop, { get: getter });
+        } else {
+          defProp(this, sprop, {
+            get: getter,
+            set: undefined,
+            enumerable: true,
+            configurable: true
+          });
+        }
+      }
+      legacyDefineGetter.prototype = null;
+      defProp(Object.prototype, '__defineGetter__', {
+        value: legacyDefineGetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyDefineSetter(sprop, setter) {
+        sprop = '' + sprop;
+        if (hop.call(this, sprop)) {
+          defProp(this, sprop, { set: setter });
+        } else {
+          defProp(this, sprop, {
+            get: undefined,
+            set: setter,
+            enumerable: true,
+            configurable: true
+          });
+        }
+      }
+      legacyDefineSetter.prototype = null;
+      defProp(Object.prototype, '__defineSetter__', {
+        value: legacyDefineSetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyLookupGetter(sprop) {
+        sprop = '' + sprop;
+        var base = this, desc = void 0;
+        while (base && !(desc = gopd(base, sprop))) { base = getProto(base); }
+        return desc && desc.get;
+      }
+      legacyLookupGetter.prototype = null;
+      defProp(Object.prototype, '__lookupGetter__', {
+        value: legacyLookupGetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+
+      function legacyLookupSetter(sprop) {
+        sprop = '' + sprop;
+        var base = this, desc = void 0;
+        while (base && !(desc = gopd(base, sprop))) { base = getProto(base); }
+        return desc && desc.set;
+      }
+      legacyLookupSetter.prototype = null;
+      defProp(Object.prototype, '__lookupSetter__', {
+        value: legacyLookupSetter,
+        writable: false,
+        enumerable: false,
+        configurable: false
+      });
+    })();
+  } else {
+    delete Object.prototype.__defineGetter__;
+    delete Object.prototype.__defineSetter__;
+    delete Object.prototype.__lookupGetter__;
+    delete Object.prototype.__lookupSetter__;
+  }
+
+
+  /**
+   * By this time, WeakMap has already monkey patched Object.freeze if
+   * necessary, so we can do the tamperProofing delayed from
+   * repairES5.js
+   */
+  var tamperProof = ses.makeDelayedTamperProof();
+
+  /**
+   * Code being eval'ed by {@code cajaVM.eval} sees {@code
+   * sharedImports} as its top-level {@code this}, as if {@code
+   * sharedImports} were the global object.
+   *
+   * <p>{@code sharedImports}'s properties are exactly the whitelisted
+   * global variable references. These properties, both as they appear
+   * on the global object and on this {@code sharedImports} object,
+   * are frozen and so cannot diverge. This preserves the illusion.
+   *
+   * <p>For code being evaluated by {@code cajaVM.compileExpr} and its
+   * ilk, the {@code imports} provided to the compiled function is bound
+   * to the top-level {@code this} of the evaluated code. For sanity,
+   * this {@code imports} should first be initialized with a copy of the
+   * properties of {@code sharedImports}, but nothing enforces this.
+   */
+  var sharedImports = create(null);
+
+  (function startSESPrelude() {
+
+    /**
+     * The unsafe* variables hold precious values that must not escape
+     * to untrusted code. When {@code eval} is invoked via {@code
+     * unsafeEval}, this is a call to the indirect eval function, not
+     * the direct eval operator.
+     */
+    var unsafeEval = eval;
+    var UnsafeFunction = Function;
+
+    /**
+     * Fails if {@code programSrc} does not parse as a strict Program
+     * production, or, almost equivalently, as a FunctionBody
+     * production.
+     *
+     * <p>We use Crock's trick of simply passing {@code programSrc} to
+     * the original {@code Function} constructor, which will throw a
+     * SyntaxError if it does not parse as a FunctionBody. We used to
+     * use Ankur's trick (need link) which is more correct, in that it
+     * will throw if {@code programSrc} does not parse as a Program
+     * production, which is the relevant question. However, the
+     * difference -- whether return statements are accepted -- does
+     * not matter for our purposes. And testing reveals that Crock's
+     * trick executes over 100x faster on V8.
+     */
+    function verifyStrictProgram(programSrc) {
+      try {
+        UnsafeFunction('"use strict";' + programSrc);
+      } catch (err) {
+        // debugger; // Useful for debugging -- to look at programSrc
+        throw err;
+      }
+    }
+
+    /**
+     * Fails if {@code exprSource} does not parse as a strict
+     * Expression production.
+     *
+     * <p>To verify that exprSrc parses as a strict Expression, we
+     * verify that (when followed by ";") it parses as a strict
+     * Program, and that when surrounded with parens it still parses
+     * as a strict Program. We place a newline before the terminal
+     * token so that a "//" comment cannot suppress the close paren.
+     */
+    function verifyStrictExpression(exprSrc) {
+      verifyStrictProgram(exprSrc + ';');
+      verifyStrictProgram('( ' + exprSrc + '\n);');
+    }
+
+    /**
+     * Make a virtual global object whose initial own properties are
+     * a copy of the own properties of {@code sharedImports}.
+     *
+     * <p>Further uses of {@code copyToImports} to copy properties
+     * onto this imports object will overwrite, effectively shadowing
+     * the {@code sharedImports}. You should shadow by overwriting
+     * rather than inheritance so that shadowing makes the original
+     * binding inaccessible.
+     *
+     * <p>The returned imports object is extensible and all its
+     * properties are configurable and non-enumerable. Once fully
+     * initialized, the caller can of course freeze the imports
+     * objects if desired. A reason not to do so it to emulate
+     * traditional JavaScript intermodule linkage by side effects to a
+     * shared (virtual) global object.
+     *
+     * <p>See {@code copyToImports} for the precise semantic of the
+     * property copying.
+     */
+    function makeImports() {
+      var imports = create(null);
+      copyToImports(imports, sharedImports);
+      return imports;
+    }
+
+    /**
+     * For all the own properties of {@code from}, copy their
+     * descriptors to {@code imports}, except that each property
+     * added to {@code imports} is unconditionally configurable
+     * and non-enumerable.
+     *
+     * <p>By copying descriptors rather than values, any accessor
+     * properties of {@code env} become accessors of {@code imports}
+     * with the same getter and setter. If these do not use their
+     * {@code this} value, then the original and any copied properties
+     * are effectively joined. If the getter/setter do use their
+     * {@code this}, when accessed with {@code imports} as the base,
+     * their {@code this} will be bound to the {@code imports} rather
+     * than {@code from}. If {@code from} contains writable value
+     * properties, this will copy the current value of the property,
+     * after which they may diverge.
+     *
+     * <p>We make these configurable so that {@code imports} can
+     * be further configured before being frozen. We make these
+     * non-enumerable in order to emulate the normal behavior of
+     * built-in properties of typical global objects, such as the
+     * browser's {@code window} object.
+     */
+    function copyToImports(imports, from) {
+      gopn(from).forEach(function(name) {
+        var desc = gopd(from, name);
+        desc.enumerable = false;
+        desc.configurable = true;
+        defProp(imports, name, desc);
+      });
+      return imports;
+    }
+
+    /**
+     * Make a frozen scope object which reflects all access onto
+     * {@code imports}, for use by {@code with} to prevent
+     * access to any {@code freeNames} other than those found on the.
+     * {@code imports}.
+     */
+    function makeScopeObject(imports, freeNames) {
+      var scopeObject = create(null);
+      // Note: Although this loop is a bottleneck on some platforms,
+      // it does not help to turn it into a for(;;) loop, since we
+      // still need an enclosing function per accessor property
+      // created, to capture its own unique binding of
+      // "name". (Embarrasing fact: despite having often written about
+      // this very danger, I engaged in this mistake in a misbegotten
+      // optimization attempt here.)
+      freeNames.forEach(function interceptName(name) {
+        var desc = gopd(imports, name);
+        if (!desc || desc.writable !== false || desc.configurable) {
+          // If there is no own property, or it isn't a non-writable
+          // value property, or it is configurable. Note that this
+          // case includes accessor properties. The reason we wrap
+          // rather than copying over getters and setters is so the
+          // this-binding of the original getters and setters will be
+          // the imports rather than the scopeObject.
+          desc = {
+            get: function scopedGet() {
+              if (name in imports) {
+                var result = imports[name];
+                if (typeof result === 'function') {
+                  // If it were possible to know that the getter call
+                  // was on behalf of a simple function call to the
+                  // gotten function, we could instead return that
+                  // function as bound to undefined. Unfortunately,
+                  // without parsing (or possibly proxies?), that isn't
+                  // possible.
+                }
+                return result;
+              }
+              // if it were possible to know that the getter call was on
+              // behalf of a typeof expression, we'd return the string
+              // "undefined" here instead. Unfortunately, without
+              // parsing or proxies, that isn't possible.
+              throw new ReferenceError('"' + name + '" blocked by Caja');
+            },
+            set: function scopedSet(newValue) {
+              if (name in imports) {
+                imports[name] = newValue;
+              }
+              throw new TypeError('Cannot set "' + name + '"');
+            },
+            enumerable: false
+          };
+        }
+        desc.enumerable = false;
+        defProp(scopeObject, name, desc);
+      });
+      return freeze(scopeObject);
+    }
+
+
+    /**
+     * Given SES source text that must not be run directly using any
+     * of the built-in unsafe evaluators on this platform, we instead
+     * surround it with a prelude and postlude.
+     *
+     * <p>Evaluating the resulting expression return a function that
+     * <i>can</i>be called to execute the original expression safely,
+     * in a controlled scope. See "makeCompiledExpr" for precisely the
+     * pattern that must be followed to call the resulting function
+     * safely.
+     *
+     * Notice that the source text placed around {@code exprSrc}
+     * <ul>
+     * <li>brings no variable names into scope, avoiding any
+     *     non-hygienic name capture issues, and
+     * <li>does not introduce any newlines preceding exprSrc, so
+     *     that all line number which a debugger might report are
+     *     accurate wrt the original source text. And except for the
+     *     first line, all the column numbers are accurate too.
+     * </ul>
+     *
+     * <p>TODO(erights): Find out if any platforms have any way to
+     * associate a file name and line number with eval'ed text, so
+     * that we can do something useful with the optional {@code
+     * opt_sourcePosition} to better support debugging.
+     */
+    function securableWrapperSrc(exprSrc, opt_sourcePosition) {
+      verifyStrictExpression(exprSrc);
+
+      return '(function() { ' +
+        // non-strict code, where this === scopeObject
+        '  with (this) { ' +
+        '    return function() { ' +
+        '      "use strict"; ' +
+        '      return ( ' +
+        // strict code, where this === imports
+        '        ' + exprSrc + '\n' +
+        '      );\n' +
+        '    };\n' +
+        '  }\n' +
+        '})';
+    }
+    ses.securableWrapperSrc = securableWrapperSrc;
+
+
+    /**
+     * Given a wrapper function, such as the result of evaluating the
+     * source that securableWrapperSrc returns, and a list of all the
+     * names that we want to intercept to redirect to the imports,
+     * return a corresponding <i>compiled expr</i> function.
+     *
+     * <p>A compiled expr function, when called on an imports
+     * object, evaluates the original expression in a context where
+     * all its free variable references that appear in freeNames are
+     * redirected to the corresponding property of imports.
+     */
+    function makeCompiledExpr(wrapper, freeNames) {
+      if (dirty) { fail('Initial cleaning failed'); }
+
+      function compiledCode(imports) {
+        var scopeObject = makeScopeObject(imports, freeNames);
+        return wrapper.call(scopeObject).call(imports);
+      };
+      compiledCode.prototype = null;
+      return compiledCode;
+    }
+    ses.makeCompiledExpr = makeCompiledExpr;
+
+    /**
+     * Compiles {@code exprSrc} as a strict expression into a function
+     * of an {@code imports}, that when called evaluates {@code
+     * exprSrc} in a virtual global environment whose {@code this} is
+     * bound to that {@code imports}, and whose free variables
+     * refer only to the properties of that {@code imports}.
+     *
+     * <p>When SES is provided primitively, it should provide an
+     * analogous {@code compileProgram} function that accepts a
+     * Program and return a function that evaluates it to the
+     * Program's completion value. Unfortunately, this is not
+     * practical as a library without some non-standard support from
+     * the platform such as a parser API that provides an AST.
+     *
+     * <p>Thanks to Mike Samuel and Ankur Taly for this trick of using
+     * {@code with} together with RegExp matching to intercept free
+     * variable access without parsing.
+     */
+    function compileExpr(exprSrc, opt_sourcePosition) {
+      var wrapperSrc = securableWrapperSrc(exprSrc, opt_sourcePosition);
+      var wrapper = unsafeEval(wrapperSrc);
+      var freeNames = atLeastFreeVarNames(exprSrc);
+      var result = makeCompiledExpr(wrapper, freeNames);
+      return freeze(result);
+    }
+
+
+    var directivePattern = (/^['"](?:\w|\s)*['"]$/m);
+
+    /**
+     * A stereotyped form of the CommonJS require statement.
+     */
+    var requirePattern = (/^(?:\w*\s*(?:\w|\$|\.)*\s*=)?\s*require\s*\(\s*['"]((?:\w|\$|\.|\/)+)['"]\s*\)$/m);
+
+    /**
+     * As an experiment, recognize a stereotyped prelude of the
+     * CommonJS module system.
+     */
+    function getRequirements(modSrc) {
+      var result = [];
+      var stmts = modSrc.split(';');
+      var stmt;
+      var i = 0, ilen = stmts.length;
+      for (; i < ilen; i++) {
+        stmt = stmts[i].trim();
+        if (stmt !== '') {
+          if (!directivePattern.test(stmt)) { break; }
+        }
+      }
+      for (; i < ilen; i++) {
+        stmt = stmts[i].trim();
+        if (stmt !== '') {
+          var m = requirePattern.exec(stmt);
+          if (!m) { break; }
+          result.push(m[1]);
+        }
+      }
+      return freeze(result);
+    }
+
+    /**
+     * A module source is actually any valid FunctionBody, and thus
+     * any valid Program.
+     *
+     * <p>In addition, in case the module source happens to begin with
+     * a streotyped prelude of the CommonJS module system, the
+     * function resulting from module compilation has an additional
+     * {@code "requirements"} property whose value is a list of the
+     * module names being required by that prelude. These requirements
+     * are the module's "immediate synchronous dependencies".
+     *
+     * <p>This {@code "requirements"} property is adequate to
+     * bootstrap support for a CommonJS module system, since a loader
+     * can first load and compile the transitive closure of an initial
+     * module's synchronous depencies before actually executing any of
+     * these module functions.
+     *
+     * <p>With a similarly lightweight RegExp, we should be able to
+     * similarly recognize the {@code "load"} syntax of <a href=
+     * "http://wiki.ecmascript.org/doku.php?id=strawman:simple_modules#syntax"
+     * >Sam and Dave's module proposal for ES-Harmony</a>. However,
+     * since browsers do not currently accept this syntax,
+     * {@code getRequirements} above would also have to extract these
+     * from the text to be compiled.
+     */
+    function compileModule(modSrc, opt_sourcePosition) {
+      // Note the EOL after modSrc to prevent trailing line comment in modSrc
+      // eliding the rest of the wrapper.
+      var exprSrc = '(function() {' + modSrc + '\n}).call(this)';
+
+      // Follow the pattern in compileExpr
+      var wrapperSrc = securableWrapperSrc(exprSrc, opt_sourcePosition);
+      var wrapper = unsafeEval(wrapperSrc);
+      var freeNames = atLeastFreeVarNames(exprSrc);
+      var moduleMaker = makeCompiledExpr(wrapper, freeNames);
+
+      moduleMaker.requirements = getRequirements(modSrc);
+      return freeze(moduleMaker);
+    }
+
+    /**
+     * A safe form of the {@code Function} constructor, which
+     * constructs strict functions that can only refer freely to the
+     * {@code sharedImports}.
+     *
+     * <p>The returned function is strict whether or not it declares
+     * itself to be.
+     */
+    function FakeFunction(var_args) {
+      var params = [].slice.call(arguments, 0);
+      var body = params.pop();
+      body = String(body || '');
+      params = params.join(',');
+      // Note the EOL after modSrc to prevent trailing line comment in body
+      // eliding the rest of the wrapper.
+      var exprSrc = '(function(' + params + '\n){' + body + '\n})';
+      return compileExpr(exprSrc)(sharedImports);
+    }
+    FakeFunction.prototype = UnsafeFunction.prototype;
+    FakeFunction.prototype.constructor = FakeFunction;
+    global.Function = FakeFunction;
+
+    /**
+     * A safe form of the indirect {@code eval} function, which
+     * evaluates {@code src} as strict code that can only refer freely
+     * to the {@code sharedImports}.
+     *
+     * <p>Given our parserless methods of verifying untrusted sources,
+     * we unfortunately have no practical way to obtain the completion
+     * value of a safely evaluated Program. Instead, we adopt a
+     * compromise based on the following observation. All Expressions
+     * are valid Programs, and all Programs are valid
+     * FunctionBodys. If {@code src} parses as a strict expression,
+     * then we evaluate it as an expression and correctly return its
+     * completion value, since that is simply the value of the
+     * expression.
+     *
+     * <p>Otherwise, we evaluate {@code src} as a FunctionBody and
+     * return what that would return from its implicit enclosing
+     * function. If {@code src} is simply a Program, then it would not
+     * have an explicit {@code return} statement, and so we fail to
+     * return its completion value.
+     *
+     * <p>When SES {@code eval} is provided primitively, it should
+     * accept a Program and evaluate it to the Program's completion
+     * value. Unfortunately, this is not possible on ES5 without
+     * parsing.
+     */
+    function fakeEval(src) {
+      try {
+        verifyStrictExpression(src);
+      } catch (x) {
+        src = '(function() {' + src + '\n}).call(this)';
+      }
+      return compileExpr(src)(sharedImports);
+    }
+
+    if (TAME_GLOBAL_EVAL) {
+      global.eval = fakeEval;
+    }
+
+    var defended = WeakMap();
+    var defending = WeakMap();
+    /**
+     * To define a defended object is to tamperProof it and all objects
+     * transitively reachable from it via transitive reflective
+     * property and prototype traversal.
+     */
+    function def(node) {
+      var defendingList = [];
+      function recur(val) {
+        if (!val) { return; }
+        var t = typeof val;
+        if (t === 'number' || t === 'string' || t === 'boolean') { return; }
+        if (defended.get(val) || defending.get(val)) { return; }
+        defending.set(val, true);
+        defendingList.push(val);
+
+        tamperProof(val);
+
+        recur(getProto(val));
+
+        // How to optimize? This is a performance sensitive loop, but
+        // forEach seems to be faster on Chrome 18 Canary but a
+        // for(;;) loop seems better on FF 12 Nightly.
+        gopn(val).forEach(function(p) {
+          if (typeof val === 'function' &&
+              (p === 'caller' || p === 'arguments')) {
+            return;
+          }
+          var desc = gopd(val, p);
+          recur(desc.value);
+          recur(desc.get);
+          recur(desc.set);
+        });
+      }
+      try {
+        recur(node);
+      } catch (err) {
+        defending = WeakMap();
+        throw err;
+      }
+      defendingList.forEach(function(obj) {
+        defended.set(obj, true);
+      });
+      return node;
+    }
+
+
+    /**
+     * makeArrayLike() produces a constructor for the purpose of
+     * taming things like nodeLists.  The result, ArrayLike, takes an
+     * instance of ArrayLike and two functions, getItem and getLength,
+     * which put it in a position to do taming on demand.
+     *
+     * <p>The constructor returns a new object that inherits from the
+     * {@code proto} passed in.
+     */
+    var makeArrayLike;
+    (function() {
+      var itemMap = WeakMap(), lengthMap = WeakMap();
+      function lengthGetter() {
+        var getter = lengthMap.get(this);
+        return getter ? getter() : void 0;
+      }
+      constFunc(lengthGetter);
+
+      var nativeProxies = global.Proxy && (function () {
+        var obj = {0: 'hi'};
+        var p = global.Proxy.create({
+          get: function () {
+            var P = arguments[0];
+            if (typeof P !== 'string') { P = arguments[1]; }
+            return obj[P];
+          }
+        });
+        return p[0] === 'hi';
+      })();
+      if (nativeProxies) {
+        (function () {
+          function ArrayLike(proto, getItem, getLength) {
+            if (typeof proto !== 'object') {
+              throw new TypeError('Expected proto to be an object.');
+            }
+            if (!(proto instanceof ArrayLike)) {
+              throw new TypeError('Expected proto to be instanceof ArrayLike.');
+            }
+            var obj = create(proto);
+            itemMap.set(obj, getItem);
+            lengthMap.set(obj, getLength);
+            return obj;
+          }
+
+          function ownPropDesc(P) {
+            P = '' + P;
+            if (P === 'length') {
+              return { get: lengthGetter };
+            } else if (typeof P === 'number' || P === '' + (+P)) {
+              return {
+                get: constFunc(function() {
+                  var getter = itemMap.get(this);
+                  return getter ? getter(+P) : void 0;
+                }),
+                enumerable: true,
+                configurable: true
+              };
+            }
+            return void 0;
+          }
+          function propDesc(P) {
+            var opd = ownPropDesc(P);
+            if (opd) {
+              return opd;
+            } else {
+              return gopd(Object.prototype, P);
+            }
+          }
+          function has(P) {
+            P = '' + P;
+            return (P === 'length') ||
+                (typeof P === 'number') ||
+                (P === '' + +P) ||
+                (P in Object.prototype);
+          }
+          function hasOwn(P) {
+            P = '' + P;
+            return (P === 'length') ||
+                (typeof P === 'number') ||
+                (P === '' + +P);
+          }
+          function getPN() {
+            var result = getOwnPN ();
+            var objPropNames = gopn(Object.prototype);
+            result.push.apply(result, objPropNames);
+            return result;
+          }
+          function getOwnPN() {
+            var lenGetter = lengthMap.get(this);
+            if (!lenGetter) { return void 0; }
+            var len = lenGetter();
+            var result = ['length'];
+            for (var i = 0; i < len; ++i) {
+              result.push('' + i);
+            }
+            return result;
+          };
+          function del(P) {
+            P = '' + P;
+            if ((P === 'length') || ('' + +P === P)) { return false; }
+            return true;
+          }
+
+          ArrayLike.prototype = global.Proxy.create({
+            getPropertyDescriptor: propDesc,
+            getOwnPropertyDescriptor: ownPropDesc,
+            has: has,
+            hasOwn: hasOwn,
+            getPropertyNames: getPN,
+            getOwnPropertyNames: getOwnPN,
+            'delete': del,
+            fix: function() { return void 0; }
+          }, Object.prototype);
+          tamperProof(ArrayLike);
+          makeArrayLike = function() { return ArrayLike; };
+        })();
+      } else {
+        (function() {
+          // Make BiggestArrayLike.prototype be an object with a fixed
+          // set of numeric getters.  To tame larger lists, replace
+          // BiggestArrayLike and its prototype using
+          // makeArrayLike(newLength).
+
+          // See
+          // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+          function nextUInt31PowerOf2(v) {
+            v &= 0x7fffffff;
+            v |= v >> 1;
+            v |= v >> 2;
+            v |= v >> 4;
+            v |= v >> 8;
+            v |= v >> 16;
+            return v + 1;
+          }
+
+          // The current function whose prototype has the most numeric getters.
+          var BiggestArrayLike = void 0;
+          var maxLen = 0;
+          makeArrayLike = function(length) {
+            if (!BiggestArrayLike || length > maxLen) {
+              var len = nextUInt31PowerOf2(length);
+              // Create a new ArrayLike constructor to replace the old one.
+              var BAL = function(proto, getItem, getLength) {
+                if (typeof(proto) !== 'object') {
+                  throw new TypeError('Expected proto to be an object.');
+                }
+                if (!(proto instanceof BAL)) {
+                  throw new TypeError(
+                      'Expected proto to be instanceof ArrayLike.');
+                }
+                var obj = create(proto);
+                itemMap.set(obj, getItem);
+                lengthMap.set(obj, getLength);
+                return obj;
+              };
+              // Install native numeric getters.
+              for (var i = 0; i < len; i++) {
+                (function(j) {
+                  function get() {
+                    return itemMap.get(this)(j);
+                  }
+                  defProp(BAL.prototype, j, {
+                    get: constFunc(get),
+                    enumerable: true
+                  });
+                })(i);
+              }
+              // Install native length getter.
+              defProp(BAL.prototype, 'length', { get: lengthGetter });
+              // TamperProof and cache the result
+              tamperProof(BAL);
+              tamperProof(BAL.prototype);
+              BiggestArrayLike = BAL;
+              maxLen = len;
+            }
+            return BiggestArrayLike;
+          };
+        })();
+      }
+    })();
+
+    global.cajaVM = { // don't freeze here
+
+      /**
+       * This is about to be deprecated once we expose ses.logger.
+       *
+       * <p>In the meantime, privileged code should use ses.logger.log
+       * instead of cajaVM.log.
+       */
+      log: constFunc(function log(str) {
+        if (typeof console !== 'undefined' && 'log' in console) {
+          // We no longer test (typeof console.log === 'function') since,
+          // on IE9 and IE10preview, in violation of the ES5 spec, it
+          // is callable but has typeof "object". See
+          // https://connect.microsoft.com/IE/feedback/details/685962/
+          //   console-log-and-others-are-callable-but-arent-typeof-function
+          console.log(str);
+        }
+      }),
+      tamperProof: constFunc(tamperProof),
+      constFunc: constFunc(constFunc),
+      // def: see below
+      is: constFunc(ses.is),
+
+      compileExpr: constFunc(compileExpr),
+      compileModule: constFunc(compileModule),
+      // compileProgram: compileProgram, // Cannot be implemented in ES5.1.
+      eval: fakeEval,               // don't freeze here
+      Function: FakeFunction,       // don't freeze here,
+
+      sharedImports: sharedImports, // don't freeze here
+      makeImports: constFunc(makeImports),
+      copyToImports: constFunc(copyToImports),
+
+      makeArrayLike: constFunc(makeArrayLike),
+      inES5Mode: true
+    };
+    var extensionsRecord = extensions();
+    gopn(extensionsRecord).forEach(function (p) {
+      defProp(cajaVM, p,
+              gopd(extensionsRecord, p));
+    });
+
+    // Move this down here so it is not available during the call to
+    // extensions().
+    global.cajaVM.def = constFunc(def);
+
+  })();
+
+  var propertyReports = {};
+
+  /**
+   * Report how a property manipulation went.
+   */
+  function reportProperty(severity, status, path) {
+    ses.updateMaxSeverity(severity);
+    var group = propertyReports[status] || (propertyReports[status] = {
+      severity: severity,
+      list: []
+    });
+    group.list.push(path);
+  }
+
+  /**
+   * Initialize accessible global variables and {@code sharedImports}.
+   *
+   * For each of the whitelisted globals, we read its value, freeze
+   * that global property as a data property, and mirror that property
+   * with a frozen data property of the same name and value on {@code
+   * sharedImports}, but always non-enumerable. We make these
+   * non-enumerable since ES5.1 specifies that all these properties
+   * are non-enumerable on the global object.
+   */
+  keys(whitelist).forEach(function(name) {
+    var desc = gopd(global, name);
+    if (desc) {
+      var permit = whitelist[name];
+      if (permit) {
+        var newDesc = {
+          value: global[name],
+          writable: false,
+          configurable: false,
+          enumerable: desc.enumerable // firefox bug 787262
+        };
+        try {
+          defProp(global, name, newDesc);
+        } catch (err) {
+          reportProperty(ses.severities.NEW_SYMPTOM,
+                         'Global ' + name + ' cannot be made readonly: ' + err);
+        }
+        defProp(sharedImports, name, newDesc);
+      }
+    }
+  });
+  if (TAME_GLOBAL_EVAL) {
+    defProp(sharedImports, 'eval', {
+      value: cajaVM.eval,
+      writable: false,
+      enumerable: false,
+      configurable: false
+    });
+  }
+
+  /**
+   * The whiteTable should map from each path-accessible primordial
+   * object to the permit object that describes how it should be
+   * cleaned.
+   *
+   * We initialize the whiteTable only so that {@code getPermit} can
+   * process "*" and "skip" inheritance using the whitelist, by
+   * walking actual superclass chains.
+   */
+  var whiteTable = WeakMap();
+  function register(value, permit) {
+    if (value !== Object(value)) { return; }
+    if (typeof permit !== 'object') {
+      return;
+    }
+    var oldPermit = whiteTable.get(value);
+    if (oldPermit) {
+      fail('primordial reachable through multiple paths');
+    }
+    whiteTable.set(value, permit);
+    keys(permit).forEach(function(name) {
+      if (permit[name] !== 'skip') {
+        var sub = value[name];
+        register(sub, permit[name]);
+      }
+    });
+  }
+  register(sharedImports, whitelist);
+
+  /**
+   * Should the property named {@code name} be whitelisted on the
+   * {@code base} object, and if so, with what Permit?
+   *
+   * <p>If it should be permitted, return the Permit (where Permit =
+   * true | "*" | "skip" | Record(Permit)), all of which are
+   * truthy. If it should not be permitted, return false.
+   */
+  function getPermit(base, name) {
+    var permit = whiteTable.get(base);
+    if (permit) {
+      if (hop.call(permit, name)) { return permit[name]; }
+    }
+    while (true) {
+      base = getProto(base);
+      if (base === null) { return false; }
+      permit = whiteTable.get(base);
+      if (permit && hop.call(permit, name)) {
+        var result = permit[name];
+        if (result === '*' || result === 'skip') {
+          return result;
+        } else {
+          return false;
+        }
+      }
+    }
+  }
+
+  var cleaning = WeakMap();
+
+  /**
+   * Delete the property if possible, else try to poison.
+   */
+  function cleanProperty(base, name, path) {
+    function poison() {
+      throw new TypeError('Cannot access property ' + path);
+    }
+    var diagnostic;
+
+    if (typeof base === 'function') {
+      if (name === 'caller') {
+        diagnostic = ses.makeCallerHarmless(base, path);
+        // We can use a severity of SAFE here since if this isn't
+        // safe, it is the responsibility of repairES5.js to tell us
+        // so. All the same, we should inspect the reports on all
+        // platforms we care about to see if there are any surprises.
+        reportProperty(ses.severities.SAFE,
+                       diagnostic, path);
+        return true;
+      }
+      if (name === 'arguments') {
+        diagnostic = ses.makeArgumentsHarmless(base, path);
+        // We can use a severity of SAFE here since if this isn't
+        // safe, it is the responsibility of repairES5.js to tell us
+        // so. All the same, we should inspect the reports on all
+        // platforms we care about to see if there are any surprises.
+        reportProperty(ses.severities.SAFE,
+                       diagnostic, path);
+        return true;
+      }
+    }
+
+    var deleted = void 0;
+    var err = void 0;
+    try {
+      deleted = delete base[name];
+    } catch (er) { err = er; }
+    var exists = hop.call(base, name);
+    if (deleted) {
+      if (!exists) {
+        reportProperty(ses.severities.SAFE,
+                       'Deleted', path);
+        return true;
+      }
+      reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+                     'Bounced back', path);
+    } else if (deleted === false) {
+      reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+                     'Strict delete returned false rather than throwing', path);
+    } else if (err instanceof TypeError) {
+      // This is the normal abnormal case, so leave it to the next
+      // section to emit a diagnostic.
+      //
+      // reportProperty(ses.severities.SAFE_SPEC_VIOLATION,
+      //                'Cannot be deleted', path);
+    } else {
+      reportProperty(ses.severities.NEW_SYMPTOM,
+                     'Delete failed with' + err, path);
+    }
+
+    try {
+      defProp(base, name, {
+        get: poison,
+        set: poison,
+        enumerable: false,
+        configurable: false
+      });
+    } catch (cantPoisonErr) {
+      try {
+        // Perhaps it's writable non-configurable, in which case we
+        // should still be able to freeze it in a harmless state.
+        var value = gopd(base, name).value;
+        defProp(base, name, {
+          value: value === null ? null : void 0,
+          writable: false,
+          configurable: false
+        });
+      } catch (cantFreezeHarmless) {
+        reportProperty(ses.severities.NOT_ISOLATED,
+                       'Cannot be poisoned', path);
+        return false;
+      }
+    }
+    var desc2 = gopd(base, name);
+    if (desc2.get === poison &&
+        desc2.set === poison &&
+        !desc2.configurable) {
+      try {
+        var dummy2 = base[name];
+      } catch (expectedErr) {
+        if (expectedErr instanceof TypeError) {
+          reportProperty(ses.severities.SAFE,
+                         'Successfully poisoned', path);
+          return true;
+        }
+      }
+    } else if ((desc2.value === void 0 || desc2.value === null) &&
+               !desc2.writable &&
+               !desc2.configurable) {
+      reportProperty(ses.severities.SAFE,
+                     'Frozen harmless', path);
+      return false;
+    }
+    reportProperty(ses.severities.NEW_SYMPTOM,
+                   'Failed to be poisoned', path);
+    return false;
+  }
+
+  /**
+   * Assumes all super objects are otherwise accessible and so will be
+   * independently cleaned.
+   */
+  function clean(value, prefix) {
+    if (value !== Object(value)) { return; }
+    if (cleaning.get(value)) { return; }
+    cleaning.set(value, true);
+    gopn(value).forEach(function(name) {
+      var path = prefix + (prefix ? '.' : '') + name;
+      var p = getPermit(value, name);
+      if (p) {
+        if (p === 'skip') {
+          reportProperty(ses.severities.SAFE,
+                         'Skipped', path);
+        } else {
+          var sub = value[name];
+          clean(sub, path);
+        }
+      } else {
+        cleanProperty(value, name, path);
+      }
+    });
+  }
+  clean(sharedImports, '');
+
+  /**
+   * This protection is now gathered here, so that a future version
+   * can skip it for non-defensive frames that must only be confined.
+   */
+  cajaVM.def(sharedImports);
+
+  keys(propertyReports).sort().forEach(function(status) {
+    var group = propertyReports[status];
+    ses.logger.reportDiagnosis(group.severity, status, group.list);
+  });
+
+  ses.logger.reportMax();
+
+  if (ses.ok(ses['severities'][ses.maxAcceptableSeverityName])) {
+    // We succeeded. Enable safe Function, eval, and compile* to work.
+    dirty = false;
+    ses.logger.log('initSES succeeded.');
+  } else {
+    ses.logger.error('initSES failed.');
+  }
+};
diff --git a/strict-debug-bug.html b/strict-debug-bug.html
new file mode 100644
index 0000000..8ea819c
--- /dev/null
+++ b/strict-debug-bug.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html><body>
+<p>Turn on &quot;Start Debugging JavaScript&quot;, open the JavaScript
+  console, refresh, and then type &quot;2+3&quot; in the JavaScript console.
+  If it shows an Error with an closed triangle, open the triangle to
+  see the error.
+<script>
+  (function(){
+    "use strict";
+    debugger;
+  })();
+</script></body></html>
diff --git a/useHTMLLogger.js b/useHTMLLogger.js
new file mode 100644
index 0000000..b71e71a
--- /dev/null
+++ b/useHTMLLogger.js
@@ -0,0 +1,292 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports a {@code ses.logger} which logs to elements
+ * on an HTML page.
+ *
+ * <p>To use the file, before loading <code>logger.js</code> or
+ * <code>initSES*.js</code> which includes <code>logger.js</code>, you
+ * must load and initialize this file. <code>logger.js</code> will
+ * then detect that there is already a logger in place and not
+ * overwrite it. For example, the beginning of your html file might
+ * read
+ * <pre>  &lt;div id="reports"&gt;&lt;/div&gt;
+ *   &lt;div id="console"&gt;&lt;/div&gt;
+ *   &lt;script src="useHTMLLogger.js"&gt;&lt;/script&gt;
+ *   &lt;script&gt;
+ *     function gebi(id) { return document.getElementById(id); };
+ *     useHTMLLogger(gebi("reports"), gebi("console"));
+ *   &lt;/script&gt;
+ *   &lt;script src="initSES.js"&gt;&lt;/script&gt;
+ * </pre>
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * @author Mark S. Miller
+ * @requires document
+ * @overrides ses, window
+ * @provides useHTMLLogger
+ */
+var ses;
+if (!ses) { ses = {}; }
+
+function useHTMLLogger(reportsElement, consoleElement) {
+  "use strict";
+
+  var slice = [].slice;
+
+  var maxElement = void 0;
+
+  /**
+   * Needs to work on ES3
+   */
+  function forEach(list, callback) {
+    for (var i = 0, len = list.length; i < len; i++) {
+      callback(list[i], i);
+    }
+  }
+
+  function appendNew(parent, tagName) {
+    var result = document.createElement(tagName);
+    parent.appendChild(result);
+    return result;
+  }
+
+  function prependNew(parent, tagName) {
+    var result = document.createElement(tagName);
+    parent.insertBefore(result, parent.firstChild);
+    return result;
+  }
+
+  function appendText(parent, text) {
+    var result = document.createTextNode(text);
+    parent.appendChild(result);
+    return result;
+  }
+
+  function textAdder(parent, style) {
+    return function(text) {
+      var p = appendNew(parent, 'p');
+      appendText(p, text);
+      p.className = style;
+      return p;
+    };
+  }
+
+  var INFLATE = '[+]';
+  var DEFLATE = '[-]';
+  function deflate(toggler, inflatables, opt_sep) {
+    var sep = opt_sep !== void 0 ? opt_sep : ' ';
+    var toggle = prependNew(toggler, 'tt');
+    var icon = appendText(toggle, INFLATE);
+    appendText(toggle, sep);
+    forEach(inflatables, function(inflatable) {
+      inflatable.style.display = 'none';
+    });
+    toggler.addEventListener('click', function(event) {
+      if (icon.data === INFLATE) {
+        forEach(inflatables, function(inflatable) {
+          inflatable.style.removeProperty('display');
+        });
+        icon.data = DEFLATE;
+      } else {
+        forEach(inflatables, function(inflatable) {
+          inflatable.style.display = 'none';
+        });
+        icon.data = INFLATE;
+      }
+    }, false);
+    toggler.style.cursor = 'pointer';
+  }
+
+  /** modeled on textAdder */
+  function makeLogFunc(parent, style) {
+    return function logFunc(var_args) {
+      var p = appendNew(parent, 'p');
+      var args = slice.call(arguments, 0);
+
+      // See debug.js
+      var getStack = ses.getStack;
+
+      for (var i = 0, len = args.length; i < len; i++) {
+        var span = appendNew(p, 'span');
+        appendText(span, '' + args[i]);
+
+        if (getStack) {
+          var stack = getStack(args[i]);
+          if (stack) {
+            var stackNode = appendNew(p, 'pre');
+            appendText(stackNode, stack);
+            deflate(span, [stackNode], '');
+          }
+        }
+      }
+      p.className = style;
+      return p;
+    };
+  }
+
+  var logger = {
+    log:   makeLogFunc(consoleElement, 'log'),
+    info:  makeLogFunc(consoleElement, 'info'),
+    warn:  makeLogFunc(consoleElement, 'warn'),
+    error: makeLogFunc(consoleElement, 'error')
+  };
+
+  var TestIDPattern = /^(Sbp|S)?([\d\.]*)/;
+
+  /**
+   *
+   */
+  function linkToTest(test) {
+    var match = TestIDPattern.exec(test);
+    if (match) {
+      var parts = match[2].split('.');
+      var result = 'http://hg.ecmascript.org/tests/test262/file/' +
+        'c84161250e66/' + // TODO(erights): How do I get the tip automatically?
+        'test/suite/';
+      if (match[1] === void 0) {
+        result += 'chapter';
+      } else if (match[1] === 'S') {
+        result += 'ch';
+      } else if (match[1] === 'Sbp') {
+        result += 'bestPractice';
+      }
+      var len = parts.length;
+      if (len === 0) {
+        result += '/';
+      } else {
+        result += (parts[0].length === 1 ? '0' : '') + parts[0] + '/';
+        for (var i = 1; i < len; i++) {
+          result += parts.slice(0, i+1).join('.') + '/';
+        }
+      }
+      result += test + '.js';
+      return result;
+    }
+
+    var site = test.charAt(0) === 'S' ?
+      '+site%3Acode.google.com' : '+site%3Aes5conform.svn.codeplex.com';
+    return 'http://www.google.com/search?btnI=&q=' +
+      encodeURIComponent(test) + site;
+  }
+
+  /**
+   * Logs a report suitable for display on a web page.
+   */
+  logger.reportRepairs = function reportRepairs(reports) {
+    var numFineElement = appendNew(reportsElement, 'p');
+    var ul = appendNew(reportsElement, 'ul');
+
+    var fineElements = [];
+
+    forEach(reports, function(report, i) {
+      var li = appendNew(ul, 'li');
+      if (report.status === ses.statuses.ALL_FINE) {
+        fineElements.push(li);
+        li.style.listStyleType = 'none';
+      }
+
+      var reportElement = appendNew(li, 'p');
+
+      var classification = ses.logger.classify(report.postSeverity);
+      reportElement.className = classification.consoleLevel;
+
+      appendText(reportElement, i + ') ' + report.status + ': ' +
+                 report.description + '. ' + classification.note);
+
+      if (typeof report.beforeFailure === 'string') {
+        var beforeElement = appendNew(reportElement, 'p');
+        appendText(beforeElement, 'New pre symptom: ' + report.beforeFailure);
+      }
+      if (typeof report.afterFailure === 'string') {
+        var afterElement = appendNew(reportElement, 'p');
+        appendText(afterElement, 'New post symptom: ' + report.afterFailure);
+      }
+
+      var linksBlock = appendNew(li, 'blockquote');
+      deflate(reportElement, [linksBlock]);
+
+      // TODO(erights): sort by URL relevance based on platform
+      forEach(report.urls, function(url, i) {
+        var linkElement = appendNew(linksBlock, 'p');
+        if (i === 0) { appendText(linkElement, 'See '); }
+        var link = appendNew(linkElement, 'a');
+        link.href = url;
+        link.target = '_blank';
+        appendText(link, url);
+        // TODO(erights): spawn a task to fetch the title of the bug
+        // and use it to replace the link text.
+      });
+
+      forEach(report.sections, function(section, i) {
+        var linkElement = appendNew(linksBlock, 'p');
+        if (i === 0) { appendText(linkElement, 'See '); }
+        var link = appendNew(linkElement, 'a');
+        link.href = 'http://es5.github.com/#x' + encodeURIComponent(section);
+        link.target = '_blank';
+        appendText(link, 'Section ' + section);
+      });
+
+      forEach(report.tests, function(test, i) {
+        var linkElement = appendNew(linksBlock, 'p');
+        if (i === 0) { appendText(linkElement, 'See '); }
+        var link = appendNew(linkElement, 'a');
+        link.href = linkToTest(test);
+        link.target = '_blank';
+        appendText(link, 'Test ' + test);
+      });
+    });
+
+    if (fineElements.length >= 1) {
+      appendText(numFineElement, fineElements.length + ' Fine.');
+      deflate(numFineElement, fineElements);
+    }
+  };
+
+  logger.reportMax = function reportMax() {
+    if (!maxElement) {
+      maxElement = appendNew(reportsElement, 'p');
+    } else {
+      maxElement.textContent = '';
+    }
+    if (ses.maxSeverity.level > ses.severities.SAFE.level) {
+      var maxClassification = ses.logger.classify(ses.maxSeverity);
+      maxElement.className = maxClassification.consoleLevel;
+      appendText(maxElement, 'Max Severity: ' + maxClassification.note);
+    }
+  };
+
+  logger.reportDiagnosis = function reportDiagnosis(severity,
+                                                    status,
+                                                    problemList) {
+    var diagnosisElement = appendNew(reportsElement, 'p');
+    var classification = ses.logger.classify(severity);
+    var head = textAdder(diagnosisElement, classification.consoleLevel)(
+      problemList.length + ' ' + status + '. ' + classification.note);
+    var tail = appendNew(diagnosisElement, 'blockquote');
+    textAdder(tail, classification.consoleLevel)(
+      problemList.sort().join(' '));
+    deflate(head, [tail]);
+  };
+
+  ses.logger = logger;
+}
+
+// Exports for closure compiler.
+if (typeof window !== 'undefined') {
+  window['useHTMLLogger'] = useHTMLLogger;
+}
diff --git a/whitelist.js b/whitelist.js
new file mode 100644
index 0000000..929f5da
--- /dev/null
+++ b/whitelist.js
@@ -0,0 +1,448 @@
+// Copyright (C) 2011 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Exports {@code ses.whitelist}, a recursively defined
+ * JSON record enumerating all the naming paths in the ES5.1 spec,
+ * those de-facto extensions that we judge to be safe, and SES and
+ * Dr. SES extensions provided by the SES runtime.
+ *
+ * <p>Assumes only ES3. Compatible with ES5, ES5-strict, or
+ * anticipated ES6.
+ *
+ * //provides ses.whitelist
+ * @author Mark S. Miller,
+ * @overrides ses, whitelistModule
+ */
+var ses;
+
+/**
+ * <p>Each JSON record enumerates the disposition of the properties on
+ * some corresponding primordial object, with the root record
+ * representing the global object. For each such record, the values
+ * associated with its property names can be
+ * <ul>
+ * <li>Another record, in which case this property is simply
+ *     whitelisted and that next record represents the disposition of
+ *     the object which is its value. For example, {@code "Object"}
+ *     leads to another record explaining what properties {@code
+ *     "Object"} may have and how each such property, if present,
+ *     and its value should be tamed.
+ * <li>true, in which case this property is simply whitelisted. The
+ *     value associated with that property is still traversed and
+ *     tamed, but only according to the taming of the objects that
+ *     object inherits from. For example, {@code "Object.freeze"} leads
+ *     to true, meaning that the {@code "freeze"} property of {@code
+ *     Object} should be whitelisted and the value of the property (a
+ *     function) should be further tamed only according to the
+ *     markings of the other objects it inherits from, like {@code
+ *     "Function.prototype"} and {@code "Object.prototype").
+ * <li>"*", in which case this property on this object is whitelisted,
+ *     as is this property as inherited by all objects that inherit
+ *     from this object. The values associated with all such properties
+ *     are still traversed and tamed, but only according to the taming
+ *     of the objects that object inherits from. For example, {@code
+ *     "Object.prototype.constructor"} leads to "*", meaning that we
+ *     whitelist the {@code "constructor"} property on {@code
+ *     Object.prototype} and on every object that inherits from {@code
+ *     Object.prototype} that does not have a conflicting mark. Each
+ *     of these is tamed as if with true, so that the value of the
+ *     property is further tamed according to what other objects it
+ *     inherits from.
+ * <li>"skip", in which case this property on this object is simply
+ *     whitelisted, as is this property as inherited by all objects
+ *     that inherit from this object, but we avoid taming the value
+ *     associated with that property. For example, as of this writing
+ *     {@code "Function.prototype.caller"} leads to "skip" because
+ *     some current browser bugs prevent us from removing or even
+ *     traversing this property on some platforms of interest.
+ * </ul>
+ *
+ * The "skip" markings are workarounds for browser bugs or other
+ * temporary problems. For each of these, there should be an
+ * explanatory comment explaining why or a bug citation. Ideally, we
+ * can retire all "skip" entries by the time SES is ready for secure
+ * production use.
+ *
+ * The members of the whitelist are either
+ * <ul>
+ * <li>(uncommented) defined by the ES5.1 normative standard text,
+ * <li>(questionable) provides a source of non-determinism, in
+ *     violation of pure object-capability rules, but allowed anyway
+ *     since we've given up on restricting JavaScript to a
+ *     deterministic subset.
+ * <li>(ES5 Appendix B) common elements of de facto JavaScript
+ *     described by the non-normative Appendix B.
+ * <li>(Harmless whatwg) extensions documented at
+ *     <a href="http://wiki.whatwg.org/wiki/Web_ECMAScript"
+ *     >http://wiki.whatwg.org/wiki/Web_ECMAScript</a> that seem to be
+ *     harmless. Note that the RegExp constructor extensions on that
+ *     page are <b>not harmless</b> and so must not be whitelisted.
+ * <li>(ES-Harmony proposal) accepted as "proposal" status for
+ *     EcmaScript-Harmony.
+ * <li>(Marked as "skip") See above.
+ * </ul>
+ *
+ * <p>With the above encoding, there are some sensible whitelists we
+ * cannot express, such as marking a property both with "*" and a JSON
+ * record. This is an expedient decision based only on not having
+ * encountered such a need. Should we need this extra expressiveness,
+ * we'll need to refactor to enable a different encoding.
+ *
+ * <p>We factor out {@code true} into the variable {@code t} just to
+ * get a bit better compression from simple minifiers.
+ */
+(function whitelistModule() {
+  "use strict";
+
+  if (!ses) { ses = {}; }
+
+  var t = true;
+  ses.whitelist = {
+    cajaVM: {                        // Caja support
+      log: t,
+      tamperProof: t,
+      constFunc: t,
+      def: t,
+      is: t,
+
+      compileExpr: t,
+      compileModule: t,              // experimental
+      compileProgram: t,             // Cannot be implemented in just ES5.1.
+      eval: t,
+      Function: t,
+
+      sharedImports: t,
+      makeImports: t,
+      copyToImports: t,
+
+      callWithEjector: t,
+      eject: t,
+      GuardT: {
+        coerce: t
+      },
+      makeTableGuard: t,
+      Trademark: {
+        stamp: t
+      },
+      guard: t,
+      passesGuard: t,
+      stamp: t,
+      makeSealerUnsealerPair: t,
+
+      makeArrayLike: {}
+    },
+    WeakMap: {       // ES-Harmony proposal as currently implemented by FF6.0a1
+      prototype: {
+        // Note: coordinate this list with maintenance of repairES5.js
+        get: t,
+        set: t,
+        has: t,
+        'delete': t
+      }
+    },
+    StringMap: {  // A specialized approximation of ES-Harmony's Map.
+      prototype: {} // Technically, the methods should be on the prototype,
+                    // but doing so while preserving encapsulation will be
+                    // needlessly expensive for current usage.
+    },
+// As of this writing, the WeakMap emulation in WeakMap.js relies on
+// the unguessability and undiscoverability of HIDDEN_NAME, a
+// secret property name. However, on a platform with built-in
+// Proxies, if whitelisted but not properly monkey patched, proxies
+// could be used to trap and thereby discover HIDDEN_NAME. So until we
+// (TODO(erights)) write the needed monkey patching of proxies, we
+// omit them from our whitelist.
+//    Proxy: {                         // ES-Harmony proposal
+//      create: t,
+//      createFunction: t
+//    },
+    escape: t,                       // ES5 Appendix B
+    unescape: t,                     // ES5 Appendix B
+    Object: {
+      // If any new methods are added here that may reveal the
+      // HIDDEN_NAME within WeakMap.js, such as the proposed
+      // getOwnPropertyDescriptors or getPropertyDescriptors, then
+      // extend WeakMap.js to monkey patch these to avoid revealing
+      // HIDDEN_NAME.
+      getPropertyDescriptor: t,      // ES-Harmony proposal
+      getPropertyNames: t,           // ES-Harmony proposal
+      is: t,                         // ES-Harmony proposal
+      prototype: {
+
+        // Whitelisted only to work around a Chrome debugger
+        // stratification bug (TODO(erights): report). These are
+        // redefined in startSES.js in terms of standard methods, so
+        // that we can be confident they introduce no non-standard
+        // possibilities.
+        __defineGetter__: t,
+        __defineSetter__: t,
+        __lookupGetter__: t,
+        __lookupSetter__: t,
+
+        constructor: '*',
+        toString: '*',
+        toLocaleString: '*',
+        valueOf: t,
+        hasOwnProperty: t,
+        isPrototypeOf: t,
+        propertyIsEnumerable: t
+      },
+      getPrototypeOf: t,
+      getOwnPropertyDescriptor: t,
+      getOwnPropertyNames: t,
+      create: t,
+      defineProperty: t,
+      defineProperties: t,
+      seal: t,
+      freeze: t,
+      preventExtensions: t,
+      isSealed: t,
+      isFrozen: t,
+      isExtensible: t,
+      keys: t
+    },
+    NaN: t,
+    Infinity: t,
+    undefined: t,
+    // eval: t,                      // Whitelisting under separate control
+                                     // by TAME_GLOBAL_EVAL in startSES.js
+    parseInt: t,
+    parseFloat: t,
+    isNaN: t,
+    isFinite: t,
+    decodeURI: t,
+    decodeURIComponent: t,
+    encodeURI: t,
+    encodeURIComponent: t,
+    Function: {
+      prototype: {
+        apply: t,
+        call: t,
+        bind: t,
+        prototype: '*',
+        length: '*',
+        arity: '*',                  // non-std, deprecated in favor of length
+        name: '*'                    // non-std
+      }
+    },
+    Array: {
+      prototype: {
+        concat: t,
+        join: t,
+        pop: t,
+        push: t,
+        reverse: t,
+        shift: t,
+        slice: t,
+        sort: t,
+        splice: t,
+        unshift: t,
+        indexOf: t,
+        lastIndexOf: t,
+        every: t,
+        some: t,
+        forEach: t,
+        map: t,
+        filter: t,
+        reduce: t,
+        reduceRight: t,
+        length: 'skip'               // can't be redefined on Mozilla
+        // See https://bugzilla.mozilla.org/show_bug.cgi?id=591059
+        // and https://bugzilla.mozilla.org/show_bug.cgi?id=598996
+      },
+      isArray: t
+    },
+    String: {
+      prototype: {
+        substr: t,                   // ES5 Appendix B
+        anchor: t,                   // Harmless whatwg
+        big: t,                      // Harmless whatwg
+        blink: t,                    // Harmless whatwg
+        bold: t,                     // Harmless whatwg
+        fixed: t,                    // Harmless whatwg
+        fontcolor: t,                // Harmless whatwg
+        fontsize: t,                 // Harmless whatwg
+        italics: t,                  // Harmless whatwg
+        link: t,                     // Harmless whatwg
+        small: t,                    // Harmless whatwg
+        strike: t,                   // Harmless whatwg
+        sub: t,                      // Harmless whatwg
+        sup: t,                      // Harmless whatwg
+        trimLeft: t,                 // non-standard
+        trimRight: t,                // non-standard
+        valueOf: t,
+        charAt: t,
+        charCodeAt: t,
+        concat: t,
+        indexOf: t,
+        lastIndexOf: t,
+        localeCompare: t,
+        match: t,
+        replace: t,
+        search: t,
+        slice: t,
+        split: t,
+        substring: t,
+        toLowerCase: t,
+        toLocaleLowerCase: t,
+        toUpperCase: t,
+        toLocaleUpperCase: t,
+        trim: t,
+        length: '*'
+      },
+      fromCharCode: t
+    },
+    Boolean: {
+      prototype: {
+        valueOf: t
+      }
+    },
+    Number: {
+      prototype: {
+        valueOf: t,
+        toFixed: t,
+        toExponential: t,
+        toPrecision: t
+      },
+      MAX_VALUE: t,
+      MIN_VALUE: t,
+      NaN: t,
+      NEGATIVE_INFINITY: t,
+      POSITIVE_INFINITY: t
+    },
+    Math: {
+      E: t,
+      LN10: t,
+      LN2: t,
+      LOG2E: t,
+      LOG10E: t,
+      PI: t,
+      SQRT1_2: t,
+      SQRT2: t,
+
+      abs: t,
+      acos: t,
+      asin: t,
+      atan: t,
+      atan2: t,
+      ceil: t,
+      cos: t,
+      exp: t,
+      floor: t,
+      log: t,
+      max: t,
+      min: t,
+      pow: t,
+      random: t,                     // questionable
+      round: t,
+      sin: t,
+      sqrt: t,
+      tan: t
+    },
+    Date: {                          // no-arg Date constructor is questionable
+      prototype: {
+        // Note: coordinate this list with maintanence of repairES5.js
+        getYear: t,                  // ES5 Appendix B
+        setYear: t,                  // ES5 Appendix B
+        toGMTString: t,              // ES5 Appendix B
+        toDateString: t,
+        toTimeString: t,
+        toLocaleString: t,
+        toLocaleDateString: t,
+        toLocaleTimeString: t,
+        valueOf: t,
+        getTime: t,
+        getFullYear: t,
+        getUTCFullYear: t,
+        getMonth: t,
+        getUTCMonth: t,
+        getDate: t,
+        getUTCDate: t,
+        getDay: t,
+        getUTCDay: t,
+        getHours: t,
+        getUTCHours: t,
+        getMinutes: t,
+        getUTCMinutes: t,
+        getSeconds: t,
+        getUTCSeconds: t,
+        getMilliseconds: t,
+        getUTCMilliseconds: t,
+        getTimezoneOffset: t,
+        setTime: t,
+        setFullYear: t,
+        setUTCFullYear: t,
+        setMonth: t,
+        setUTCMonth: t,
+        setDate: t,
+        setUTCDate: t,
+        setHours: t,
+        setUTCHours: t,
+        setMinutes: t,
+        setUTCMinutes: t,
+        setSeconds: t,
+        setUTCSeconds: t,
+        setMilliseconds: t,
+        setUTCMilliseconds: t,
+        toUTCString: t,
+        toISOString: t,
+        toJSON: t
+      },
+      parse: t,
+      UTC: t,
+      now: t                         // questionable
+    },
+    RegExp: {
+      prototype: {
+        exec: t,
+        test: t,
+        source: '*',
+        global: '*',
+        ignoreCase: '*',
+        multiline: '*',
+        lastIndex: '*',
+        sticky: '*'                  // non-std
+      }
+    },
+    Error: {
+      prototype: {
+        name: '*',
+        message: '*'
+      }
+    },
+    EvalError: {
+      prototype: t
+    },
+    RangeError: {
+      prototype: t
+    },
+    ReferenceError: {
+      prototype: t
+    },
+    SyntaxError: {
+      prototype: t
+    },
+    TypeError: {
+      prototype: t
+    },
+    URIError: {
+      prototype: t
+    },
+    JSON: {
+      parse: t,
+      stringify: t
+    }
+  };
+})();