/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */
'use strict';

var installedIds = [];

// Provide a unique id for every object.
module.exports = function(opts) {
  opts = opts || {};

  var key = opts.key || '+UID';

  for (var i = 0; i < installedIds.length; i++) {
    if (installedIds[i] === key)
      throw new Error('Attempt to re-install object id "' + key + '"');
  }
  installedIds.push(key);

  var key__ = key + '__';
  var start = typeof opts.start === 'number' ? opts.start : 10000;
  var isValidId = opts.isValidId || function(id) {
    return typeof id === 'number' && id >= start;
  };
  var nextId = opts.nextId || (function() {
    // Leave space for "reserved IDs". Useful when values may mean
    // "object id or [some other id]".
    var id = start;
    return function() { return id++; };
  })();

  // Some objects cannot be trusted to to store their id as an own property
  // without subsequent gets of the property delegating to their prototype.
  // This occurs in the  non-[OverrideBuiltins] case of platform objects with
  // a named property getter and setter.
  // It also occurs on some systems where special objects such as the "named
  // properties object" in Firefox do not support Object.defineProperty().
  // To deal with such cases, store a short list of (object, id) pairs.
  var objectIdPairs = [];
  function getPairedId(o) {
    for ( var i = 0; i < objectIdPairs.length; i++ ) {
      if ( o === objectIdPairs[i][0] ) return objectIdPairs[i][1];
    }

    var id = nextId();
    objectIdPairs.push([o, id]);
    return id;
  }

  var descriptor = {
    get: function() {
      if ( ! this.hasOwnProperty(key__) ) {
        try {
          Object.defineProperty(this, key__, {
            value: nextId(),
            enumerable: false,
          });
        } catch (e) {
          return getPairedId(this);
        }
      }

      // Catch corner case: own property of this[key__] was not actually
      // created!
      if ( this.__proto__ && this.__proto__[key] === this[key__] ) {
        return getPairedId(this);
      } else {
        return this[key__];
      }
    },
    enumerable: false,
  };

  Object.defineProperty(Object.prototype, key, descriptor);

  function getId(v) {
    // Usual case: property generates id.
    var id = v[key];
    if ( isValidId(id) ) return id;

    console.log('!!! Extra id property define');

    // Corner case: Object doesn't descend from Object.prototype. Define
    // property manually.
    Object.defineProperty(v, key, descriptor);
    id = v[key];
    if ( isValidId(id) ) return id;

    console.log('!!! Fallback on paired id');

    // Last ditch effort: Just store a paired id.
    return getPairedId(v);
  }

  return {
    key: key,
    key__: key__,
    isValidId: isValidId,
    nextId: nextId,
    getId: getId,
  };
};

@@ -864,16 +864,20 @@
 edIds%5Bi%5D
+.key
  === key
@@ -881,84 +881,160 @@
 key)
+ %7B
 %0A      
-throw new Error('Attempt to re-install object id %22' + key + '%22');%0A  %7D
+if (!installedIds%5Bi%5D.data) throw new Error('Id install re-entry');%0A      return installedIds%5Bi%5D.data;%0A    %7D%0A  %7D%0A  var installedId = %7Bkey: key%7D;
 %0A  i
@@ -1050,19 +1050,27 @@
 ds.push(
-key
+installedId
 );%0A%0A  va
@@ -3381,22 +3381,34 @@
 %0A  %7D%0A%0A  
-return
+installedId.data =
  %7B%0A    k
@@ -3502,12 +3502,40 @@
 Id,%0A  %7D;
+%0A%0A  return installedId.data;
 %0A%7D;%0A

Return already installed ids, rather than erroring out (when possible)