Source: core/uuid.js

/* <notice>
 Code from node-uuid: https://github.com/broofa/node-uuid/raw/master/uuid.js
 MIT license https://github.com/broofa/node-uuid/blob/master/LICENSE.md
 </notice> */

/**
 * @module montage/core/uuid
*/

/**
 * @class Uuid
 * @extends Montage
 */
var Montage = require("core/core").Montage,
    CHARS = '0123456789ABCDEF'.split(''),
    PROTO = "__proto__",
    VALUE = "value",
    FORMAT = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.split('');

function generate() {
    var c = CHARS, id = FORMAT, r;

    id[0] = c[(r = Math.random() * 0x100000000) & 0xf];
    id[1] = c[(r >>>= 4) & 0xf];
    id[2] = c[(r >>>= 4) & 0xf];
    id[3] = c[(r >>>= 4) & 0xf];
    id[4] = c[(r >>>= 4) & 0xf];
    id[5] = c[(r >>>= 4) & 0xf];
    id[6] = c[(r >>>= 4) & 0xf];
    id[7] = c[(r >>>= 4) & 0xf];

    id[9] = c[(r = Math.random() * 0x100000000) & 0xf];
    id[10] = c[(r >>>= 4) & 0xf];
    id[11] = c[(r >>>= 4) & 0xf];
    id[12] = c[(r >>>= 4) & 0xf];
    id[15] = c[(r >>>= 4) & 0xf];
    id[16] = c[(r >>>= 4) & 0xf];
    id[17] = c[(r >>>= 4) & 0xf];

    id[19] = c[(r = Math.random() * 0x100000000) & 0x3 | 0x8];
    id[20] = c[(r >>>= 4) & 0xf];
    id[21] = c[(r >>>= 4) & 0xf];
    id[22] = c[(r >>>= 4) & 0xf];
    id[24] = c[(r >>>= 4) & 0xf];
    id[25] = c[(r >>>= 4) & 0xf];
    id[26] = c[(r >>>= 4) & 0xf];
    id[27] = c[(r >>>= 4) & 0xf];

    id[28] = c[(r = Math.random() * 0x100000000) & 0xf];
    id[29] = c[(r >>>= 4) & 0xf];
    id[30] = c[(r >>>= 4) & 0xf];
    id[31] = c[(r >>>= 4) & 0xf];
    id[32] = c[(r >>>= 4) & 0xf];
    id[33] = c[(r >>>= 4) & 0xf];
    id[34] = c[(r >>>= 4) & 0xf];
    id[35] = c[(r >>>= 4) & 0xf];

    return id.join('');
}

exports.generate = generate;

var Uuid = exports.Uuid = Object.create(Object.prototype, /** @lends Uuid# */ {
    /**
     * Returns a univerally unique ID (UUID).
     * @function Uuid.generate
     * @returns {string} The UUID.
     */
    generate: {
        enumerable: false,
        value: generate
    }
});

// TODO figure out why this code only works in this module.  Attempts to move
// it to core/extras/object resulted in _uuid becoming enumerable and tests
// breaking. - @kriskowal

// var UUID = require("./uuid");

// HACK: This is to fix an IE10 bug where a getter on the window prototype chain
// gets some kind of proxy Window object which cannot have properties defined
// on it, instead of the `window` itself. Adding the uuid directly to the
// window removes the needs to call the getter.
// if (typeof window !== "undefined") {
//     window.uuid = UUID.generate();
// }
var uuidGetGenerator = function () {

    var uuid = generate(),
        info = Montage.getInfoForObject(this);
    try {
        if (info !== null && info.isInstance === false) {
            this._uuid = uuid;
            Object.defineProperty(this, "uuid", {
                get: function () {
                    if (this.hasOwnProperty("uuid")) {
                        // we are calling uuid on the prototype
                        return this._uuid;
                    } else {
                        // we are calling uuid on instance of this prototype
                        return uuidGetGenerator.call(this);
                    }
                }
            });
        } else {
            //This is needed to workaround some bugs in Safari where re-defining uuid doesn't work for DOMWindow.
            if (info.isInstance) {
                Object.defineProperty(this, "uuid", {
                    configurable: true,
                    enumerable: false,
                    writable: false,
                    value: uuid
                });
            }
            //This is really because re-defining the property on DOMWindow actually doesn't work, so the original property with the getter is still there and return this._uuid if there.
            if (this instanceof Element || !info.isInstance || !(VALUE in (Object.getOwnPropertyDescriptor(this, "uuid")||{})) || !(PROTO in this /* lame way to detect IE */)) {
                //This is needed to workaround some bugs in Safari where re-defining uuid doesn't work for DOMWindow.
                this._uuid = uuid;
            }
        }
    } catch(e) {
        // NOTE Safari (as of Version 5.0.2 (6533.18.5, r78685)
        // doesn't seem to allow redefining an existing property on a DOM Element
        // Still want to redefine the property where possible for speed
    }

    // NOTE Safari (as of Version 6.1 8537.71) has a bug related to ES5
    // property values. In some situations, even when the uuid has already
    // been defined as a property value, accessing the uuid of an object can
    // make it go through the defaultUuidGet as if the property descriptor
    // was still the original one. When that happens, a new uuid is created
    // for that object. To avoid this, we always make sure that the object
    // has a _uuid that will be looked up at defaultUuidGet() before
    // generating a new one. This mechanism was created to work around an
    // issue with Safari that didn't allow redefining property descriptors
    // in DOM elements.
    this._uuid = uuid;

    return uuid;
};

var defaultUuidGet = function defaultUuidGet() {
    //return this._uuid || (this._uuid = uuidGetGenerator.call(this));
    return ((Object.prototype.hasOwnProperty.call(this, "_uuid") &&  this._uuid) ? this._uuid : uuidGetGenerator.call(this));
};


Montage.defineUuidProperty = function(object) {
    /**
        @private
    */
    Object.defineProperty(object, "_uuid", {
        enumerable: false,
        value: void 0,
        writable: true
    });

    /**
        Contains an object's unique ID.
        @member external:Object#uuid
        @default null
    */
    Object.defineProperty(object, "uuid", {
        configurable: true,
        get: defaultUuidGet,
        set: Function.noop,
        enumerable: false
    });
};