Source: decl.js

// Licensed Materials - Property of IBM
//
// IBM Watson Analytics
//
// (C) Copyright IBM Corp. 2015, 2018
//
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

( function(
        Object,
        Array,
        String,
        Error,
        TypeError,
        ObjectPolyfill,
        Map,
        Set,
        Symbol,
        WeakMap
    )
{
"use strict";

/*global console, setTimeout*/
/*jshint latedef:false*/

/**
 * Note: decl is not a constructor; call its static members.
 * @class module:barejs.decl
 * @abstract
 * @classdesc Module for declaring classes, interfaces, enums, and checking implementations.
 * decl uses the inheritance natively supported by JavaScript, instead of trying to emulate
 * multiple inheritance or providing "super" or "base" keyword emulation. This combined with the
 * fact that decl doesn't generate a constructor function (the defining code has to supply it)
 * leads to classes with no run-time overhead. It also means there is no "magic" performed.
 * Implementors using decl's inheritance are responsible for calling the base class
 * constructor and methods using the standard JavaScript call mechanism:
 *
 *      function A( _name )
 *      {
 *          this.name = _name;
 *      }
 *
 *      decl.declareClass( A,
 *      {
 *          toString: function()
 *          {
 *              return this.name;
 *          }
 *      }
 *
 *      function B( _name, _age )
 *      {
 *          // Invoke base class constructor on this object
 *          A.call( this, _name );
 *          this.age = _age;
 *      }
 *
 *      decl.declareClass( B, A,
 *      {
 *          toString: function()
 *          {
 *              // Invoke A::toString() and append our age to it.
 *              return A.prototype.toString.call( this ) + "; age " + this.age;
 *          }
 *      } );
 *
 * In the debug version of barejs, decl adds a lot of metadata to provide a great debugging experience.
 * When defined with named constructors, objects created with decl will be highly discoverable and debuggable in browsers like Chrome.
 */

// List of classes that are not allowed to be casted to.
var uncastable_types = new Set();
var uncastable_keys = new Map();

// Grab slice from an array
var slice = Array.prototype.slice;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var canWriteFnName = !!( Object.defineProperties && Object.getOwnPropertyDescriptor );
/*istanbul ignore else: NodeJS supports this*/
if ( canWriteFnName )
{
    canWriteFnName = Object.getOwnPropertyDescriptor( Function.prototype, "name" );
    canWriteFnName = !canWriteFnName || canWriteFnName.configurable;
}

var reSymbolProto = /^(?:@@([a-zA-Z0-9_\$]+)|\[\[([a-zA-Z0-9_\$]+)\]\])$/;
var reStaticIgnore = /^(?:constructor|prototype|name|interfaces|superclass|\$private)$/;
var metaData = new WeakMap();

/**
 * Convenience property to ease defining a read only property on an Interface.
 * It as simply a shortcut for '{ allowGet: true, allowSet: false }':
 *
 *      decl.declareInterface( function MyInterface() {},
 *      {
 *          // The following two definitions have exactly the same effect:
 *          myProperty: decl.readOnlyProperty,
 *          myProperty: { allowGet: true, allowSet: false }
 *      } );
 *
 * @member {object}
 * @readonly
 * @memberof module:barejs.decl
 */
var readOnlyProperty  = ObjectPolyfill.freeze( { allowGet: true, allowSet: false } );

var native_ctors = [ Object, Array, Function, Boolean, Number, Math, Date, String, RegExp, Symbol,
                    Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError ];

// Detect a bunch more of optional native constructors, so our native_ctor array is complete
//jshint -W117
/*istanbul ignore else*/
if ( typeof ArrayBuffer !== "undefined" )
    native_ctors.push( ArrayBuffer );
/*istanbul ignore else*/
if ( typeof Float32Array !== "undefined" )
    native_ctors.push( Float32Array );
/*istanbul ignore else*/
if ( typeof Float64Array !== "undefined" )
    native_ctors.push( Float64Array );
/*istanbul ignore else*/
if ( typeof Promise !== "undefined" )
    native_ctors.push( Promise );
/*istanbul ignore else*/
if ( typeof Proxy !== "undefined" )
    native_ctors.push( Proxy );
/*istanbul ignore else*/
if ( typeof Uint8Array !== "undefined" )
    native_ctors.push( Uint8Array );
/*istanbul ignore else*/
if ( typeof Uint8ClampedArray !== "undefined" )
    native_ctors.push( Uint8ClampedArray );
/*istanbul ignore else*/
if ( typeof Uint16Array !== "undefined" )
    native_ctors.push( Uint16Array );
/*istanbul ignore else*/
if ( typeof Uint32Array !== "undefined" )
    native_ctors.push( Uint32Array );
//jshint +W117


/**
 * Convenience property to ease defining a read/write property on an Interface.
 * It as simply a shortcut for '{ allowGet: true, allowSet: true }':
 *
 *      decl.declareInterface( function MyInterface() {},
 *      {
 *          // The following two definitions have exactly the same effect:
 *          myProperty: decl.readWriteProperty,
 *          myProperty: { allowGet: true, allowSet: true }
 *      } );
 *
 * @member {object}
 * @readonly
 * @memberof module:barejs.decl
 */
var readWriteProperty = ObjectPolyfill.freeze( { allowGet: true, allowSet: true } );

/*
 * Enable validating interfaces are implemented in debug mode
 * Except for Rhino, since it can't handle it...
 */
/*istanbul ignore else: We always test in DEBUG*/
if ( !__RELEASE__ &&
        // Detect Rhino so we can ignore it
        !( typeof load === "function" && ( typeof Packages === "function" || typeof Packages === "object" ) )
    )
{
    var validateQueue = [];

    /**
     * Validate a class implements all interface members.
     * @param {function} _class The class to validate.
     * @memberof module:barejs.decl~
     * @private
     */
    var validateInterfacesImplemented = function( _class )
    {
        var errors = [];

        if ( _class && _class.interfaces )
        {
            _class.interfaces.forEach( function( _interface, _idxInterface )
            {
                var lines = [];

                for ( var members = InterfaceMetaData.get( _interface ).members, i = 0, len = members.length; i < len; ++i )
                {
                    var member = members[i];
                    var error = null;

                    switch ( member.type )
                    {
                        case "function":
                            var def = member.interfaces[0].prototype[member.name];
                            var impl = _class.prototype[member.name];

                            if ( typeof impl !== "function" )
                                error = "Missing implementation for {def}";
                            else if ( ( impl.length !== def.length ) && ( impl.proxy !== true ) )
                                error = "Signature mismatch, {def} defines " + def.length + " arguments but implementation has " + impl.length;
                            break;

                        case "property":
                            if ( !( member.name in _class.prototype ) )
                                error = "Missing prototype definition for {def}";
                            break;
                    }

                    if ( error !== null )
                        lines.push( error.replace( "{def}", String( member ) ) );
                }

                if ( lines.length > 0 )
                {
                    errors.push(
                        "[" + describe( _interface ) + " @ index " + _idxInterface + "]\r\n\t\t" +
                        lines.join( "\r\n\t\t" )
                    );
                }
            }, this );
        }

        if ( errors.length > 0 )
            throw new Error( describe( _class ) + " has the following errors:\r\n\t" + errors.join( "\r\n\t" ) );
    };

    /**
     * Callback function to validate interfaces
     * @memberof module:barejs.decl~
     * @private
     */
    var handleValidateQueue = function()
    {
        // reset timeout id
        delete validateQueue.timeout;

        /*istanbul ignore if: sanity check, this function should not be called/queued with an empty queue*/
        if ( validateQueue.length < 1 )
            return;

        // The code below will report errors by throwing an exception. Ensure the validateQueue is empty
        var queue = validateQueue;
        validateQueue = [];

        queue.forEach( function( _class )
        {
            // For interfaces, just create the metadata; this will do basic validation
            if ( isInterface( _class ) )
                InterfaceMetaData.get( _class );
            else
                validateInterfacesImplemented( _class );
        } );
    };
}

/**
 * Generic getter method
 * @param {string} _name The name of the property.
 * @returns The value of the property
 * @memberof module:barejs.decl~
 * @private
 */
function _get( _name )
{
    /*jshint validthis:true*/
    return this[_name];
}

/**
 * Generic setter method.
 * @param {string} _name The name of the property.
 * @param _value The value to assign.
 * @returns The new value of the property
 * @memberof module:barejs.decl~
 * @private
 */
function _set( _name, _value )
{
    /*jshint validthis:true*/
    return ( this[_name] = _value );
}

/**
 * Used during object prototype expansion to resolve a getter definition
 * @memberof module:barejs.decl~
 * @private
 */
function resolvePropertyAccessor( _target )
{
    // It is possible the target is also a property definition. Resolve it
    if ( _target && ( typeof _target === "object" ) )
    {
        if ( hasOwnProperty.call( _target, "value" ) )
            return _target.value;
        else if ( hasOwnProperty.call( _target, "get" ) )
            return _target.get;
    }
    return _target;
}

/**
 * Iterator function that will modify the context to have a defineProperty
 * definition instead of direct properties. If the value is already a property definition, it is left
 * untouched. Once the object has been parsed, it can then be given to Object.create.
 * @memberof module:barejs.decl~
 * @private
 */
function toDefineProperty( _value, _name, _object, _lookup )
{
    var def;

    if ( _value && ( typeof _value === "object" ) )
    {
        if ( hasOwnProperty.call( _value, "value" ) )
        {
            def = _value;
        }
        // Guard against map values as they have
        else if ( hasOwnProperty.call( _value, "get" ) || hasOwnProperty.call( _value, "set" ) )
        {
            def = _value;
            // If there is no property support, we silently ignore properties
            /*istanbul ignore if: NodeJS supports properties*/
            if ( !ObjectPolyfill.propertyGetSetSupport )
                return null;

            // If there is a getter or setter, see if we need to resolve it
            if ( typeof def.get === "string" )
            {
                def.getterName = def.get;
                def.get = resolvePropertyAccessor( _object[def.get] || ( _lookup && _lookup[def.get] ) );
            }
            if ( typeof def.set === "string" )
            {
                def.setterName = def.set;
                def.set = resolvePropertyAccessor( _object[def.set] || ( _lookup && _lookup[def.set] ) );
            }
        }
    }

    if ( !def )
    {
        def =
        {
            // Make Symbols and string keys starting with "_" not enumerable by default
            enumerable: ObjectPolyfill.shouldBeEnumerable( _name ),
            writable: true,
            value: _value
        };
    }

    return def;
}

/**
 * Same purpose as toDefineProperty, but specialised for interfaces, on which we expect only
 * functions or objects that define get/set access. Performs validation no other properties are present.
 * @memberof module:barejs.decl~
 * @private
 */
function toDefinePropertyInterface( _value, _name )
{
    var ok = false;
    var allowGet, allowSet;

    switch ( _value && typeof _value )
    {
        case "function":
            // Functions are always OK
            ok = true;
            break;

        case "object":
            // If the decl constants where used, there is no sense in validating them
            ok = ( _value === readOnlyProperty ) || ( _value === readWriteProperty );

            // If not, validate the object given to us
            if ( !ok )
            {
                allowGet = ( "allowGet" in _value ) && _value.allowGet;
                allowSet = ( "allowSet" in _value ) && _value.allowSet;
                // allowGet, if defined, should be a boolean
                if ( typeof allowGet !== "boolean" )
                    throw new TypeError( "allowGet value is not a boolean" );
                // allowSet, if defined, should be a boolean
                if ( typeof allowSet !== "boolean" )
                    throw new TypeError( "allowSet value is not a boolean" );

                ok = allowGet || allowSet; // at least one needs to be true.
            }
            break;
    }

    if ( !ok )
        throw new TypeError( "Values on an interface prototype must be either a function or an object containing allowGet or allowSet boolean properties." );

    return { enumerable: true, value: _value };
}

/**
 * Convenience method that will add a displayName to _function if not present, by concatenating
 * _objectName and _propName with a '.', optionally appending _suffix after _propName.
 * @param {function} _function The function to add the displayName to.
 * @param {string} _objectName The name of the object, for example "MyClass.prototype"
 * @param {string} _propName The name of the property (the function is added as), for example "myMethod"
 * @param {string} [_suffix] Optional: part to append to the name, for example " [GET]" for a getter function
 * @memberof module:barejs.decl~
 * @private
 */
function displayName( _function, _objectName, _propName, _suffix )
{
    if ( canWriteFnName && !hasOwnProperty.call( _function, "name" ) )
        ObjectPolyfill.defineProperty( _function, "name", { configurable: true, value: _propName } );
    if ( !( "displayName" in _function ) )
        ObjectPolyfill.defineProperty( _function, "displayName", { configurable: true, value: _objectName + "." + _propName + ( _suffix || "" ) } );
}

/**
 * Utility method that returns _def expanded to a defineProperties argument.
 * Arguments that are a property definition are left alone, other are expanded to be a property definition
 * @param {object} _def The object whose properties to expand.
 * @param {function} _callback Function to use for the expand operation.
 * @param {string} [_objName] Optional: the logical name of _def, e.g. "MyClass.prototype"
 * @returns {object} _def made suitable for Object.defineProperties (or second argument of Object.create).
 * @memberof module:barejs.decl~
 * @private
 */
function expandDefineProperties( _def, _lookup, _callback, _objName )
{
    if ( _def )
    {
        // Ensure object
        _def = Object( _def );

        for ( var names = Object.keys( _def ), i = 0, len = names.length, name, prop, sym; i < len; ++i )
        {
            name = names[i];
            sym = reSymbolProto.exec( name );
            if ( sym )
            {
                //jshint -W122
                // The regexp matches one of two possible forms ("@@symbolName" or "[[symbolName]]"),
                // which means the symbol name may be in either capture group
                sym = Symbol[ sym[1] || sym[2] ];
                if ( typeof sym !== "symbol" )
                {
                    delete _def[name];
                    continue;
                }
                //jshint +W122
            }
            prop = _callback( _def[name], sym || name, _def, _lookup );

            if ( sym )
            {
                delete _def[name];
                _def[sym] = prop;
            }
            else if ( _def[name] !== prop )
            {
                // on rare occasions we may need to drop a property, e.g. when there is no getter/setter support.
                if ( prop === null )
                    delete _def[name];
                else
                    _def[name] = prop;
            }

            if ( prop && _objName )
            {
                if ( "value" in prop )
                {
                    if ( ObjectPolyfill.isCallable( prop.value ) )
                        displayName( prop.value, _objName, name );
                }
                else
                {
                    if ( prop.get && !prop.getterName )
                        displayName( prop.get, _objName, name, " [GET]" );
                    if ( prop.set && !prop.setterName )
                        displayName( prop.set, _objName, name, " [SET]" );
                }
            }
        }
    }

    return _def;
}

/**
 * Tells the proxy system casting to this type is not allowed. Should only be used for very low
 * level classes, otherwise performance will be impacted.
 * @param {function} _class The type to disallow casting to
 * @returns {Symbol} Key to cast to this type. NEVER export this key in any way.
 * @memberof module:barejs.decl
 */
function preventCast( _class ){
    if ( typeof _class !== "function" )
        throw new TypeError( "_class must be a function" );

    if ( uncastable_types.has( _class ) )
        throw new Error( "Already declared uncastable" );

    // Register uncastable, generate key and store it at the correct index
    // Symbol is meant to make a "private key", so it seems suitable enough to use as a key for preventCast.
    var key = Symbol( _class.name );
    uncastable_types.add( _class );
    uncastable_keys.set( key, _class );
    return key;
}

// Allow decl to cast back without knowing the right type
// NOTE: This value should never be exported
var ObjectKey = preventCast( Object );


/**
 * Method that sets up inheritance. Doesn't perform any validation, this should be done beforehand.
 * @param {function} _class Class to set up the inheritance for
 * @param {function} _base The class to derive from.
 * @returns {function} Class, now deriving from _base
 * @memberof module:barejs.decl~
 * @private
 */
function derive( _class, _base, _proto )
{
    // Apply prototype inheritance
    _class.prototype = Object.create( _base.prototype, _proto || undefined );

    // Reset the constructor (non enumerable, but writable, just like browsers set it).
    ObjectPolyfill.defineProperty( _class.prototype, "constructor", { writable : true, value : _class } );

    // Set superclass on constructor function
    // Note: decl methods should not rely too much on superclass being set, it's for convenience only
    return ObjectPolyfill.defineProperty( _class, "superclass", { value : _base } );
}

//
// Helper classes for metadata
//

/**
 * @classdesc Base class to gather information about a member of an interface.
 * @class module:barejs.decl~InterfaceMember
 * @param {function[]} _interfaces The interface(s) on which the method is defined.
 * @param {string} _name The name of the method on the interface.
 * @private
 */
function InterfaceMember( _interfaces, _name )
{
    this.interfaces = _interfaces;
    this.name = _name;
}

derive( InterfaceMember, Object,
/** @lends module:barejs.decl~InterfaceMember */
{
    type: { value: "member" },

    /**
     * Provides a string representation of the member, for example "member myFunction on interface IMyInterface".
     * @returns {string} The string representation of the member
     */
    toString: { value: function toString()
    {
        return this.type + " \"" + String( this.name ) + "\" defined on " + this.interfaces.map( describe ).join( ", " );
    } }
} );

/**
 * @classdesc Stores information about a method on an interface.
 * @class module:barejs.decl~InterfaceMethod
 * @param {function} _interface The interface on which the method is defined.
 * @param {string} _name The name of the method on the interface.
 * @private
 */
function InterfaceMethod( _interface, _name )
{
    InterfaceMember.call( this, [_interface], _name );
}

derive( InterfaceMethod, InterfaceMember,
/** @lends module:barejs.decl~InterfaceMethod */
{
    type: { value: "function" }
} );

/**
 * @classdesc Stores information about a property on an interface
 * @class module:barejs.decl~InterfaceProperty
 * @param {function[]} _interfaces The interfaces on which the property is defined.
 * @param {string} _name The name of the property on the interface.
 * @param {boolean} _allowGet Whether getting this property is allowed.
 * @param {boolean} _allowSet Whether setting this property is allowed.
 * @private
 */
function InterfaceProperty( _interfaces, _name, _allowGet, _allowSet )
{
    InterfaceMember.call( this, _interfaces, _name );

    this.allowGet = _allowGet;
    this.allowSet = _allowSet;
}

derive( InterfaceProperty, InterfaceMember,
/** @lends module:barejs.decl~InterfaceProperty */
{
    type: { value: "property" },

    /**
     * Merge two definitions into a new InterfaceProperty. Used to resolve collisions between interfaces
     * @param {module:barejs.decl~InterfaceProperty} _otherProperty The property to merge with.
     * @returns {module:barejs.decl~InterfaceProperty} The merged InterfaceProperty. Might be the original, if the interfaces was already known.
     */
    merge: { value: function( _otherProperty )
    {
        if ( _otherProperty === this ) // sanity
            return this;

        // merge interfaces arrays
        for ( var interfaces = this.interfaces.slice( 0 ), i = 0, len = _otherProperty.interfaces.length, iface; i < len; ++i )
        {
            if ( interfaces.indexOf( iface = _otherProperty.interfaces[i] ) )
                interfaces.push( iface );
        }

        return new InterfaceProperty( interfaces, this.name, this.allowGet || _otherProperty.allowGet, this.allowSet || _otherProperty.allowSet );
    } }
} );

/**
 * Stores metadata about members of this interface, members of base interfaces and the combined list.
 * This allows methods like hasInterface and proxy to quickly iterate over the list of members.
 * @class module:barejs.decl~InterfaceMetaData
 * @memberof module:barejs.decl~
 * @private
 */
function InterfaceMetaData()
{
    this.directMembers = [];
    this.inheritedMembers = [];
    this.members = null;
}

/**
 * merge directMembers and inheritedMembers into one
 */
InterfaceMetaData.prototype.merge = function()
{
    var mergeMap;
    var i, len, member;

    if ( this.members )
        return;

    if ( this.inheritedMembers.length < 1 )
    {
        this.members = this.directMembers;
    }
    else if ( this.directMembers.length < 1 )
    {
        this.members = this.inheritedMembers;
    }
    else
    {
        mergeMap = Object.create( null );

        // Start by copying the directMembers
        this.members = this.directMembers.slice( 0 );
        // Then iterate them to initialize the merge map
        for ( i = 0, len = this.members.length; i < len; ++i )
            mergeMap[this.members[i].name] = true;

        // Next, iterate inherited members
        for ( i = 0, len = this.inheritedMembers.length; i < len; ++i )
        {
            // No point in updating the merge map, this is the last iteration of the merge
            // Only add the member if it wasn't redefined
            if ( mergeMap[(member = this.inheritedMembers[i]).name] !== true )
                this.members.push( member );
        }

        this.members.sort( function( _a, _b )
        {
            if ( _a.name === _b.name )
                return 0;
            var ta = typeof _a.name;
            return ( ta ===  typeof _b.name ) && ( ta === "string" ) && ( _a.name > _b.name ) ? 1 : -1;
        } );
    }
};

/**
 * Build meta data for an interface, like the list of all methods required by the interface.
 */
InterfaceMetaData.get = function( _interface )
{
    if ( !isInterface( _interface ) )
        throw new TypeError( "_interface is not an Interface" );

    var meta = metaData.get( _interface );
    if ( !meta )
    {
        metaData.set( _interface, meta = new InterfaceMetaData() );

        var mergeMap = Object.create( null );

        // Merge inherited members
        if ( _interface.interfaces )
        {
            _interface.interfaces.forEach( function( _extendedInterface )
            {
                var members = InterfaceMetaData.get( _extendedInterface ).members, member, existing;
                for ( var i = 0, len = members.length; i < len; ++i )
                {
                    member = members[i];

                    if ( ( existing = mergeMap[member.name] ) && ( existing !== member ) )
                    {
                        // See if we need to do property merge magic
                        if ( ( existing.type === "property" ) && ( member.type === "property" ) )
                        {
                            meta.inheritedMembers[meta.inheritedMembers.indexOf( existing )] =
                                mergeMap[member.name] = existing.merge( member );
                        }
                        else
                        {
                            // Report the conflict
                            throw new Error( describe( _interface ) + " has a conflict in extended interfaces: The " + existing + " conflicts with " + member + "." );
                        }
                    }
                    else
                    {
                        mergeMap[member.name] = member;
                        meta.inheritedMembers.push( member );
                    }
                }
            } );
        }

        // Add direct members (freeze prototype too, to protect it from modification after metadata is built).
        for ( var names = Object.keys( ObjectPolyfill.freeze( _interface.prototype ) ).concat( ObjectPolyfill.getOwnPropertySymbols( _interface.prototype ) ), i = 0, len = names.length; i < len; ++i )
        {
            var name = names[i], target = _interface.prototype[name];

            // Protect proxy features from colliding with the interface.
            if ( ( name === "as" ) || ( name === "is" ) )
                throw new Error( "The " + ( new InterfaceMember( [_interface], name ) ) + " uses the reserved name \"" + name + "\", which is not allowed." );
            // Explicitly ignore the constructor property for Rhino
            if ( name === "constructor" )
                continue;

            var member = null, existing = mergeMap[name];

            // First, just create the metadata (not adding it)
            switch ( target && typeof target )
            {
                case "function":
                    member = new InterfaceMethod( _interface, name );
                    break;

                case "object":
                    if ( ( "allowGet" in target ) || ( "allowSet" in target  ) )
                    {
                        member = new InterfaceProperty( [_interface], name, target.allowGet === true, target.allowSet === true );
                        if ( !( member.allowGet || member.allowSet ) )
                            throw new Error( "The " + member + " is invalid: it doesn't allow get or set." );
                    }
                    break;
            }

            if ( !member )
            {
                throw new Error(
                    "The " + ( new InterfaceMember( [_interface], name ) ) + " is invalid: expected a function, " +
                    "or an object with allowGet or allowSet property, but got " + ( typeof target ) + target + " instead."
                );
            }

            // Override or report conflict
            if ( existing )
            {
                // Interfaces are allowed to redefine properties with more access (i.e. readWrite over read).
                // They are not allowed to revoke access or redefine a property with similar access
                if ( ( member.type === "property" ) && ( existing.type === "property" ) )
                {
                    // Test if the interface is removing access
                    if ( existing.allowGet && !member.allowGet )
                        throw new Error( "The " + member + " has a conflict with " + existing + ": it is removing get access." );
                    if ( existing.allowSet && !member.allowSet )
                        throw new Error( "The " + member + " has a conflict with " + existing + ": it is removing set access." );
                    if ( ( existing.allowGet === member.allowGet ) && ( existing.allowSet === member.allowSet ) )
                        throw new Error( "The " + member + " is redefining " + existing + " with equal get/set access (so it is obsolete)." );
                }
                else
                {
                    throw new Error( "The " + member + " conflicts with " + existing + "." );
                }
            }

            meta.directMembers.push( member );
        }

        meta.merge();
    }

    return meta;
};

/**
 * Stores metadata about names and values on an enum.
 * This allows for quick reverse lookup
 * @class module:barejs.decl~EnumMetaData
 * @private
 */
function EnumMetaData( _enum )
{
    this.names = ObjectPolyfill.freeze( Object.keys( _enum ) );
    // Use _get to resolve the enum property value
    this.values = ObjectPolyfill.freeze( this.names.map( _get, _enum ) );
}

/**
 * Perform a case insensitive name lookup for an enum
 * @param {module:barejs.decl~Enum} _enum The enum to look up the name for
 * @param {string} _name The name to match
 * @returns {string} the found name, or null if not found.
 */
EnumMetaData.prototype.ciName = function( _name )
{
    var nameLower = String( _name ).toLowerCase();

    for ( var i = this.names.length - 1; i >= 0; --i )
    {
        if ( nameLower === this.names[i].toLowerCase() )
            return this.names[i];
    }
    return null;
};

/**
 * Retrieve metadata for an enum
 */
EnumMetaData.get = function( _enum )
{
    var meta = metaData.get( _enum.constructor );
    if ( !meta )
        metaData.set( _enum.constructor, meta = new EnumMetaData( _enum ) );

    return meta;
};

//
// Helper classes
//

function NullObject() {}

NullObject.prototype = null;

/**
 * Internal class for decl, serving as a base class for {@link module:barejs.decl~Interface Interface} and {@link module:barejs.decl~Enum Enum}.
 * Does not have Object.prototype in its prototype chain, so objects deriving from SpecialType are not instanceof Object.
 * @class module:barejs.decl~SpecialType
 */
function SpecialType() {}

derive( SpecialType, NullObject,
/** @lends module:barejs.decl~SpecialType# */
{
    // JSHint complains hasOwnProperty is a really bad name, but we are simply "restoring" it on a special type.
    // jshint -W001
    /**
     * A SpecialType is not instanceof Object, but does have the Object.prototype.hasOwnProperty method.
     * @function
     * @param {string} _name The name of the property to check
     * @returns {boolean} True if the object has a direct property with _name, false otherwise.
     */
    hasOwnProperty: { value: hasOwnProperty }
    // jshint +W001
} );


/**
 * Base class for interfaces
 * @class module:barejs.decl~Interface
 * @extends module:barejs.decl~SpecialType
 */
function Interface() {}

// Make Interface a "special type" (new Interface() instanceof Object === false)
derive( Interface, SpecialType,
/** @lends module:barejs.decl~Interface# */
{
    /**
     * toString for Interface.
     * @function
     * @returns {string} The string [interface InterfaceName], where InterfaceName is
     * the name of the interface constructor function, or "Interface" for anonymous interfaces.
     */
    toString: { value: function toString()
    {
        return "[interface " + ( this.constructor.name || "Interface" ) + "]";
    } }
} );

/**
 * Base class for Enum types declared with {@link module:barejs.decl#declareEnum decl.declareEnum}
 * @class module:barejs.decl~Enum
 * @extends module:barejs.decl~SpecialType
 */
function Enum() {}

// Make Enum a "special type" (new Enum() instanceof Object === false)
derive( Enum, SpecialType,
/** @lends module:barejs.decl~Enum# */
{
    // Allow subclasses to redefine these methods (so make them writable)

    /**
     * Enum method: get the name of the specified value. If multiple names lead to the same value, the
     * first found name is returned
     * @function
     * @param {string} _value The value for which to get the name
     * @returns The name of the value, or null if not found
     */
    nameOf:
    {
        writable: true,
        value: function nameOf( _value )
        {
            var meta = EnumMetaData.get( this );

            return meta.names[meta.values.indexOf( _value )] || null;
        }
    },

    /**
     * Enum method: get the value of the specified name
     * @function
     * @param {string} _name The name of the value to get
     * @param {boolean} [_caseInsensitive=false] Optional, set to true to perform a case insensitive search
     * @returns {object} The enum value, or null if it wasn't found.
     */
    valueOf:
    {
        writable: true,
        value: function valueOf( _name, _caseInsensitive )
        {
            // Case sensitive or insensitive, see if the name is defined.
            if ( this.hasOwnProperty( _name ) )
                return this[_name];
            // If we're not case insensitive, we're not going to find the value
            if ( _caseInsensitive !== true )
                return null;

            // Do a case insensitive lookup
            _name = EnumMetaData.get( this ).ciName( _name );
            // ciName will return null if the name didn't match any entry
            return _name && this[_name];
        }
    },

    /**
     * Enum method: check if the enum has the specified name
     * @function
     * @param {string} _name The name to check
     * @param {boolean} [_caseInsensitive=false] Optional, set to true to perform a case insensitive search
     * @returns {boolean} True if the enum has the name, false otherwise.
     */
    hasName:
    {
        writable: true,
        value: function hasName( _name, _caseInsensitive )
        {
            // Always check hasOwnProperty first, to avoid the array lookup of case insensitive.
            return this.hasOwnProperty( _name ) || ( ( _caseInsensitive === true ) && ( EnumMetaData.get( this ).ciName( _name ) !== null ) );
        }
    },

    /**
     * Check if the enum has the specified value
     * @function
     * @param {object} _value The enum value to check for
     * @returns {boolean} True if the enum has the value, false otherwise.
     */
    hasValue:
    {
        writable: true,
        value: function hasValue( _value )
        {
            return EnumMetaData.get( this ).values.indexOf( _value ) >= 0;
        }
    },

    /**
     * Utility method to parse an enum value, for example from input parsed from JSON.
     * Takes the following steps:
     *
     *      1. if _value is an actual enum value, return _value.
     *      2. if _value is a name of enum, return the value of that name
     *      3. if _throw is true, throw a RangeError
     *      4. return null
     *
     * @function
     * @param _value The value to parse
     * @param {boolean} _caseInsensitive Whether name matching should be case insensitive.
     *                  Defaults to false, specify true for case insensitive.
     * @param {boolean} [_throw=false] Optional: set to true to perform strict validation.
     * @returns The parsed value, or null if the value didn't parse.
     */
    parse:
    {
        writable: true,
        value: function parse( _value, _caseInsensitive, _throw )
        {
            var enumMeta = EnumMetaData.get( this );

            if ( enumMeta.values.indexOf( _value ) >= 0 )
                return _value;
            // After this point, _value is considered to be a potential name
            var name = _value;
            // Perform case insensitive lookup if needed
            if ( !this.hasOwnProperty( name ) && ( _caseInsensitive === true ) )
                name = EnumMetaData.get( this ).ciName( name );
            if ( name && this.hasOwnProperty( name ) )
                return this[name];
            if ( _throw === true )
                throw new RangeError( "Could not parse enum value " + _value );
            return null;
        }
    },

    /**
     * Get the names of an enum
     * @function
     * @returns {Array} The names of an enum
     */
    names:
    {
        writable: true,
        value: function names()
        {
            return EnumMetaData.get( this ).names;
        }
    },

    /**
     * Get the values of an enum
     * @function
     * @returns {Array} The values of an enum
     */
    values:
    {
        writable: true,
        value: function values()
        {
            return EnumMetaData.get( this ).values;
        }
    },

    /**
     * Iterate over all enum name/value pairs. Signature attempts to match Array.prototype.forEach.
     * @function
     * @param {function} _callback The callback, called with _value, _name, _enum
     * @param {object} [_thisArg] Optional: the scope to call the callback in.
     */
    forEach:
    {
        writable: true,
        value: function forEach( _callback/*, _thisArg*/ )
        {
            for ( var meta = EnumMetaData.get( this ), idx = 0, len = meta.names.length, thisArg = ( arguments[1] || null ) && Object( arguments[1] ); idx < len; ++idx )
                _callback.call( thisArg, meta.values[idx], meta.names[idx], this );
        }
    },

    /**
     * toString for Enum.
     * @function
     * @returns {string} The string [enum EnumName], where EnumName is
     * the name of the enum constructor function, or "Enum" for anonymous enumerations.
     */
    toString: { value: function toString()
    {
        return "[enum " + ( this.constructor.name || "Enum" ) + "]";
    } }
} );

// These methods are added to a declareClass prototype
var classProtoExtension =
{
    /**
     * To be executed in the context of an object.
     * Allow "casting" between interface proxies and the original object.
     * @param {function} _class The type (constructor function) to cast to.
     * @param {boolean} [_strict=false] Optional: set to true to avoid a duck-type check, and only check `decl`
     * metadata for interfaces implemented.
     * @returns {object} A proxy, the original object, or null if the "cast" could not be performed.
     */
    as: { value : function as( _class, _strict )
    {
        // jshint validthis:true
        // Give ObjectKey special treatment, making it a "master key", allowing to cast back objects
        // that are not even instanceof Object.
        if ( _class === ObjectKey )
            return this;

        // _class is supposed to be either a constructor function or a proxy key
        if ( typeof _class !== "function" )
        {
            // Allow casting back by key (Symbol, handed out by preventCast).
            var type = uncastable_keys.get( _class );
            if ( type )
                return this instanceof type ? this : null;

            throw new TypeError( "as requires _class to be a (constructor) function" );
        }
        else if ( uncastable_types.has( _class ) )
        {
            throw new Error( "as does not allow casting to this type, specify a more specific type" );
        }

        // If we get here, _class is a function
        if ( isInterface( _class ) && hasInterface( this, _class, _strict ) )
            return proxy( this, _class );
        else if ( this instanceof _class )
            return this;

        // Type change failed
        return null;
    } },

    /**
     * To be executed in the context of an object.
     * Allow checking if an object adheres to a specific type, or equals an instance.
     * @param {function} _other (Type|Interface) to test for, OR {object} (Instance) to check equality against
     * @param {boolean} [_strict=false] Optional: if _other is an Interface, set to true to avoid a duck-type
     *                          check, and only check `decl` metadata for interfaces implemented.
     *                          If `_other` is not an Interface, this param is ignored.
     * @returns {boolean} True if this object adheres to the type, or equals the _other instance. False otherwise.
     */
    is: { value: function is( _other, _strict )
    {
        // jshint validthis:true
        if ( typeof _other === "function" )
            return ( this instanceof _other ) || ( ( isInterface( _other ) && hasInterface( this, _other, _strict ) ) );
        else if ( isProxy( _other ) )
            return this === _other.as( ObjectKey );
        else
            return this === _other;
    } }
};


//
// Helper methods
//

/**
 * Attempts to discover an object's base class.
 * @param {function} _class Class constructor function
 * @returns {function} The bas constructor, defaults to Object if the base cannot be determined.
 * @memberof module:barejs.decl~
 * @private
 */
function getBase( _class )
{
    var proto = null;

    if ( typeof _class === "function" )
    {
        proto = ObjectPolyfill.getPrototypeOf( _class.prototype );
        proto = proto && proto.constructor ? proto.constructor : Object;
    }
    return proto;
}


/**
 * Get the type of _target.
 * This is typeof enhanced.
 * @param _target The thing to get the type of.
 * @memberof module:barejs.decl~
 * @private
 */
function type( _target )
{
    var t = _target === null ? "null" : typeof _target;

    if ( t === "function" )
    {
        if ( _target.prototype instanceof Interface )
            t = "interface";
        else if ( _target.prototype instanceof Enum )
            t = "enum";
        else if ( !( "prototype" in _target ) )
            t = "native function";
        else if ( "superclass" in _target )
            t = "class";
    }
    else if ( t === "object" )
    {
        if ( Array.isArray( _target ) )
            return "array";
        else if ( _target instanceof Enum )
            t = "enum";
        else if ( _target instanceof Interface )
            t = "proxy";
    }

    return t;
}

/**
 * Helper method that tries to get the name of a class.
 * @param {function|Object} _target The object to get the name of
 * @returns {string} The name of target, or null
 * @memberof module:barejs.decl~
 * @private
 */
function name( _target )
{
    if ( !_target )
        return null;
    else if ( typeof _target === "function" )
        return _target.name || null;
    else if ( _target.constructor )
        return _target.constructor.name || null;
    return null;
}

/**
 * Helper method that tries to build a description of an object. It gets the right type description
 * using type, and tries to append the name to it. The name is only available in environments that
 * support the name property on functions, and of course the function must be named.
 * Example: describe( SampleClass );
 * If SampleClass is a named function this might return "class SampleClass".
 * Otherwise, it will return "class (Anonymous)".
 * @param {function} _fn The function to describe.
 * @memberof module:barejs.decl~
 * @private
 */
function describe( _target )
{
    var n = name( _target );

    return n ? type( _target ) + " " + n : type( _target );
}

/**
 * Check if the prototype object is clean (has no properties defined).
 * @param {function} _class The constructor function whose prototype object to check.
 * @param {string} [_requester] Optional: name of the function requesting the check
 * @memberof module:barejs.decl~
 * @private
 */
function checkCleanPrototype( _class, _requester )
{
    var props = Object.keys( _class.prototype ),
        idx = props.indexOf( "constructor" );

    if ( idx >= 0 )
        props.splice( idx, 1 );

    if ( props.length > 0 )
    {
        throw new Error(
            ( _requester ? _requester + ": " : "" ) + describe( _class ) + " already has properties defined on the prototype: " +
            props.join( ", " )
        );
    }
}

/**
 * Port "static" functions over from the base class.
 * @param {function} _class The constructor function to update with base class static functions.
 * @param {function} _base The base constructor to copy static functions of.
 * @memberof module:barejs.decl~
 * @private
 */
function applyStatic( _class, _base, _stat )
{
    if ( _base && ( native_ctors.indexOf( _base ) < 0 ) )
    {
        var descriptors = ObjectPolyfill.getOwnPropertyDescriptors( _base );
        var staticInherited;
        var keys = Object.keys( descriptors );
        for ( var i = 0, len = keys.length; i < len; ++i )
        {
            var key = keys[i];

            // Ignore keys that match reStaticIgnore,
            if ( ( typeof key !== "string" || !reStaticIgnore.test( key ) ) &&
                // or keys that are already on _class or _stat,
                ( !hasOwnProperty.call( _class, key ) && !( _stat && hasOwnProperty.call( _stat, key ) ) ) &&
                // or keys that are explicitly ignored using a $private function
                !( _base.$private && _base.$private( key ) ) )
            {
                var def = descriptors[key];
                if ( "value" in def && typeof def.value !== "function" && def.writable && ObjectPolyfill.propertyGetSetSupport )
                {
                    // Upgrade def to a get/set proxy
                    def =
                    {
                        configurable: def.configurable,
                        enumerable: def.enumerable,
                        "get": _get.bind( _base, key ),
                        "set": _set.bind( _base, key )
                    };
                }
                // Make sure the definition is always configurable, as we're "inheriting"
                def.configurable = true;
                if ( !staticInherited )
                    staticInherited = {};
                staticInherited[key] = def;
            }
        }

        if ( staticInherited )
            defineObject( _class, staticInherited );
    }

    if ( _stat )
        defineObject( _class, _stat );
}

/**
 * Helper function that sets the interfaces for a class and validates they are actually interfaces.
 * This method does not perform any validation on _class or its state.
 * @param {function} _class The class constructor
 * @param {Array} _interfaces The list of interfaces.
 * @param {Array} _baseInterfaces The list of interfaces on the base class.
 * @memberof module:barejs.decl~
 * @private
 */
function setInterfaces( _class, _interfaces, _baseInterfaces )
{
    var interfaces = ( _baseInterfaces && _baseInterfaces.slice( 0 ) ) || [];

    if ( _interfaces && _interfaces.length )
    {
        // Validate the interfaces specified are indeed interfaces.
        for ( var idx = 0, len = _interfaces.length; idx < len; ++idx )
        {
            // An interface should derive DIRECTLY from Interface.
            if ( getBase( _interfaces[idx] ) !== Interface )
                throw new Error( "Interface " + idx + " is not a valid interface." );

            if ( interfaces.indexOf( _interfaces[idx] ) < 0 )
                interfaces.push( _interfaces[idx] );
            else if ( !__RELEASE__ && ( typeof console !== "undefined" ) )
                console.info( describe( _class ) + " declares to implement " + describe( _interfaces[idx] ) + " also implemented by a base class." );
        }
    }

    // Freeze the interfaces array for security
    ObjectPolyfill.defineProperty( _class, "interfaces", { value : ObjectPolyfill.freeze( interfaces ) } );
}

/**
 * See if _interface matches _searchInterface. This includes looking at extended interfaces.
 * @param {function} _interface The interface to check
 * @param {function} _searchInterface The interface to look for in _interface's tree.
 * @returns {boolean} True if the interface matches, false otherwise
 */
function matchInterface( _interface, _searchInterface )
{
    if ( _interface === _searchInterface )
        return true;

    if ( _interface.interfaces )
    {
        for ( var idx = 0, len = _interface.interfaces.length; idx < len; ++idx )
        {
            if ( matchInterface( _interface.interfaces[idx], _searchInterface ) )
                return true;
        }
    }

    return false;
}

/**
 * Wrapper for {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is Object.is} that will "unproxy" values.
 *
 *      // This returns false, Object.is sees two different objects:
 *      Object.is( instance, instance.as( MyInterface );
 *
 *      // This returns true, decl will unproxy proxies.
 *      decl.is( instance, instance.as( MyInterface ) );
 *
 * @param _a Any value to check for equality
 * @param _b Any value to check for equality
 * @returns {boolean} True if the values are considered equal, false otherwise.
 * @memberof module:barejs.decl
 */
function is( _a, _b )
{
    return Object.is(
        isProxy( _a ) ? _a.as( ObjectKey ) : _a,
        isProxy( _b ) ? _b.as( ObjectKey ) : _b
    );
}

/**
 * Check if the _target is an interface.
 * Only works with class constructors, since there should be no instance of an interface.
 * @param {function} _target The class constructor to test if it is an interface.
 * @returns {boolean} True if _target is an interface, false otherwise.
 * @memberof module:barejs.decl
 */
function isInterface( _target )
{
    return ( typeof _target === "function" ) && ( _target.prototype instanceof Interface );
}

/**
 * Check if the _target is an enum.
 * Only works with instances, since enums should not expose their class constructor directly.
 * @param {object} _target The instance to test if it is an enum.
 * @returns {boolean} True if _target is an enum, false otherwise.
 * @memberof module:barejs.decl
 */
function isEnum( _target )
{
    // Enums should always be an instance
    return _target instanceof Enum;
}

/**
 * Check if the target is a proxy object.
 * @param {object} _target The object to check.
 * @returns {boolean} True if _target is a proxy object, false otherwise.
 * @memberof module:barejs.decl
 */
function isProxy( _target )
{
    // _target must be an object, instanceof Interface, having an "as" method directly on the object (the "is" method is not tested)
    return ( _target instanceof Interface ) && _target.hasOwnProperty( "as" );
}

/**
 * Checks if _class has _base as a superclass. Also true if _class === _base.
 * Do not use this method to check if an Object is of a specific type, use the instanceof operator
 * for that instead.
 * @param {function} _class The function to check.
 * @param {function} _base The base class to check for.
 * @returns {boolean} True if the class has the base class, false otherwise.
 * @memberof module:barejs.decl
 */
function hasBase( _class, _base )
{
    if ( typeof _class !== "function" )
        throw new TypeError( "_class is not a (constructor) function" );
    if ( typeof _base !== "function" )
        throw new TypeError( "_base is not a (constructor) function" );

    return ( _class === _base ) || ( _class.prototype instanceof _base );
}

/**
 * Create and return a proxy object for the target
 * @param {object} _target The object to proxy
 * @param {function} _interface The interface defining the members to proxy.
 * @returns {object} The proxy object (instanceof _interface).
 * @memberof module:barejs.decl
 */
function proxy( _target, _interface )
{
    if ( !isInterface( _interface ) )
        throw new TypeError( describe( _interface ) + " is not a valid Interface" );
    if ( !_target )
        throw new Error( "Cannot proxy " + describe( _target ) + " as " + describe( _interface ) );
    // Don't proxy a proxy, instead attempt to proxy on the source object
    if ( isProxy( _target ) )
        return proxy( _target.as( ObjectKey ), _interface );

    // Create the proxy object
    var props =
    {
        // Adding the constructor shows proxy objects named as the interface in the debugger
        // (provided the interface function is named)
        constructor: { value : _interface },
        // Add the as and is methods to the proxy, read-only and not enumerated
        as: { value : classProtoExtension.as.value.bind( _target ) },
        is: { value : classProtoExtension.is.value.bind( _target ) }
    };

    for ( var members = InterfaceMetaData.get( _interface ).members, idx = 0, len = members.length, member, prop; idx < len; ++idx )
    {
        switch ( ( member = members[idx] ).type )
        {
            case "function":
                prop = _target[member.name];
                if ( typeof prop !== "function" )
                    throw new Error( "as( " + describe( _interface ) + " ) expected " + member + " to be on " + describe( _target.constructor ) + ", but it is missing." );

                // Make the function proxies read-only, enumerable
                props[member.name] = { value : prop.bind( _target ), enumerable : true };
                break;

            case "property":
                if ( !( member.name in _target ) )
                    throw new Error( "as( " + describe( _interface ) + " ) expected " + member + " to be on " + describe( _target.constructor ) + ", but it is missing." );

                if ( ObjectPolyfill.propertyGetSetSupport )
                {
                    prop = { enumerable: true };
                    if ( member.allowGet )
                        prop.get = _get.bind( _target, member.name );
                    if ( member.allowSet )
                        prop.set = _set.bind( _target, member.name );
                    // No point in checking for property support: we already checked that in the if above
                    props[member.name] = prop;
                }
                else if ( typeof console !== undefined )
                {
                    console.warn( "interface proxy skipping " + member + ", since the environment doesn't support getters and setters." );
                }
                break;
        }
    }

    // Attempt to seal the proxy; we don't need to freeze since no properties are configurable
    return ObjectPolyfill.seal( Object.create( _interface.prototype, props ) );
}

/**
 * Duck-type check for compliance with an interface
 * @param {object} _target The object to validate
 * @param {function} _interface The interface to check for
 * @returns {boolean} True if the object seems to implement all members
 * @memberof module:barejs.decl~
 * @private
 */
function duckHasInterface( _target, _interface )
{
    var valid = !!_target;
    if ( valid )
    {
        // Ensure object
        _target = Object( _target );

        for ( var m = InterfaceMetaData.get( _interface ).members, i = m.length - 1; valid && i >= 0; --i )
        {
            switch( m[i].type )
            {
                case "function":
                    valid = typeof _target[m[i].name] === "function";
                    break;

                case "property":
                    valid = m[i].name in _target;
                    break;
            }
        }
    }

    return valid;
}

/**
 * Checks if _target (or a base class) implements the specified Interface.
 * Works on both instances and the class constructor.
 * @param {object|Function} _target The object or class constructor to check.
 * @param {function} _interface The interface to check for. If interface is not a valid interface,
 * this method always returns false.
 * @param {boolean} [_strict=false] Optional: set to true to avoid a duck-type check, and only check decl
 *                          metadata for interfaces implemented.
 * @returns {boolean} True if _target (or a base class) implements the interface, false otherwise.
 * @memberof module:barejs.decl
 */
function hasInterface( _target, _interface, _strict )
{
    if ( !isInterface( _interface ) )
        throw new TypeError( "hasInterface: _interface must be an interface defined with decl.declareInterface, but is " + describe( _interface ) );
    if ( !_target )
        return false;
    // Detect proxies
    if ( isProxy( _target ) )
        return hasInterface( _target.as( ObjectKey ), _interface, _strict );

    var isFn = typeof _target === "function";

    // Walk up the inheritance tree
    for ( var base = isFn ? _target : _target.constructor; base && ( base !== Object ) && ( base !== Interface ) && ( base !== Enum ); base = getBase( base ) )
    {
        if ( base.interfaces && matchInterface( base, _interface ) )
            return true;
    }

    // Resort to duck-type check
    return ( _strict !== true ) && duckHasInterface( isFn ? _target.prototype : _target, _interface );
}


//
// Start of Declare methods
//

/**
 * Helper method that unifies errors returned by declare* methods.
 * @param {string} _name The name of the function from which the error is triggered
 * @param {Array} _arguments or (arguments object) of arguments
 * @param {string} _message The custom part of the message
 * @returns {string} The error message
 * @memberof module:barejs.decl~
 * @private
 */
function formatErrorMessage( _name, _arguments, _message )
{
    return _name + "( " + Array.prototype.map.call( _arguments, describe ).join( ", " ) + " ): " + _message;
}

/**
 * Helper method that will validate the _class argument passed to declare(Class|Interface|Enum).
 * Ensures consistent validation across methods.
 * @param {function} _class The _class argument as received by the declare method.
 * @param {string} _method The name of the method requesting the validation.
 * @param {Array} _arguments The arguments passed to the requesting method.
 * @memberof module:barejs.decl~
 * @private
 */
function validateClassArg( _class, _method, _arguments )
{
    // Validation
    if ( !_class || ( typeof _class !== "function" ) )
        throw new TypeError( formatErrorMessage( _method, _arguments, "_class is not a function." ) );
    // Some special methods don't have a prototype, warn when these are passed to declareClass
    if ( !( "prototype" in _class ) )
        throw new Error( formatErrorMessage( _method, _arguments, "_class doesn't have a prototype property; it is probably a built-in function." ) );
    if ( ( "superclass" in _class ) || ( "interfaces" in _class ) )
        throw new Error( formatErrorMessage( _method, _arguments, "The " + describe( _class ) + " is already declared, cannot perform " + _method + "." ) );
    if ( native_ctors.indexOf( _class ) >= 0 )
        throw new Error( formatErrorMessage( _method, _arguments, "Attempt to call " + _method + " on built-in type" + ( _class.name ? " " + _class.name + "." : "" ) ) );
    // Note: this check can fail if the base prototype can not be detected. We still perform it as
    // a convenience for detecting errors, and hope the check for existing properties on the
    // prototype will catch the other cases.
    var base = getBase( _class );
    if ( base && ( base !== Object ) )
        throw new Error( formatErrorMessage( _method, _arguments, "_class already has a base " + describe( base ) + "." ) );

    // Throw an error if anything has been defined on the original prototype
    checkCleanPrototype( _class, _method );
}

/**
 * Helper method that will pop the last value of an array if it's not a function.
 * If the last argument is a function, or the array is empty, the _array is not modified and null is returned.
 * @param {Array} _array The array to pop the non-function from.
 * @memberof module:barejs.decl~
 * @private
 */
function popNonFunction( _array )
{
    var len = _array.length;
    return ( len > 0 ) && ( typeof _array[len - 1] !== "function" ) ? Object( _array.pop() ) : null;
}

/**
 * Helper method that perform the actual class definition for both abstractClass and declareClass.
 * @param {String} _definingName The function that is requesting a class be made, e.g. abstractClass or declareClass.
 * @param {arguments} _args The arguments passed along to the declare function.
 * @param {Boolean} [_validate=false] Optional: whether interfaces should be validated for implementation.
 * @memberof module:barejs.decl~
 * @private
 */
function makeClass( _definingName, _args, _validate )
{
    // normalize optional interfaces and/or prototype properties
    var cls = _args[0],
        base = null,
        interfaces = null,
        stat = null,
        proto = null;

    /*istanbul ignore else: We always test in DEBUG*/
    if ( !__RELEASE__ )
        validateClassArg( cls, _definingName, _args );

    if ( _args.length > 1 )
    {
        interfaces = slice.call( _args, 1, _args.length );

        // If the first additional argument is null or a constructor function (not an interface), it is a base class.
        if ( ( interfaces[0] === null ) || ( ( typeof interfaces[0] === "function" ) && ( !isInterface( interfaces[0] ) ) ) )
            base = interfaces.shift();

        // If the last argument is not a function, assume it's a prototype definition.
        proto = popNonFunction( interfaces );
        // If the second to last argument is not a function, assume it's a static definition.
        stat = popNonFunction( interfaces );
    }

    /*istanbul ignore else: We always test in DEBUG*/
    if ( !__RELEASE__ )
    {
        // If a base class is passed, validate it too
        if ( base )
        {
            if ( typeof base !== "function" )
            {
                throw new TypeError( formatErrorMessage( _definingName, _args, "_base is not a function.\r\n" +
                        "If you are passing a prototype definition, specify null as second argument." ) );
            }
            if ( cls === base )
                throw new Error( formatErrorMessage( _definingName, _args, "A class cannot extend itself." ) );
            if ( !( "prototype" in base ) )
                throw new Error( formatErrorMessage( _definingName, _args, "base doesn't have a prototype property; it is probably a built-in function." ) );
            if ( hasBase( base, Enum ) )
                throw new Error( formatErrorMessage( _definingName, _args, "Cannot extend an enum. To create an enum, use declareEnum." ) );
            if ( hasBase( base, Interface ) )
            {
                throw new Error( formatErrorMessage( _definingName, _args,
                        "Cannot extend an interface.\r\n" +
                        "To declare implementing interfaces, add them as arguments after _base; passing null as base class.\r\n" +
                        "To create an interface extending another interface, use declareInterface instead."
                ) );
            }
        }
    }

    if ( base === null )
        base = Object;

    derive( cls, base, expandDefineProperties( proto, base && base.prototype, toDefineProperty, ( cls.name || "(Class)" ) + ".prototype" ) );
    setInterfaces( cls, interfaces, base.interfaces );

    // Apply static definition
    if ( base !== Object || stat )
        applyStatic( cls, base, stat );

    // If not inherited from a base class, add certain utility methods like "is" and "as" to the class.
    if ( !( "as" in cls.prototype ) )
        ObjectPolyfill.defineProperties( cls.prototype, classProtoExtension );

    // If we or our base have any interfaces, and if we're validating
    /*istanbul ignore else: We always test in DEBUG*/
    if ( !__RELEASE__ && _validate && ( cls.interfaces.length > 0 ) )
    {
        // If we have a prototype definition ...
        if ( proto )
        {
            // validate immediately.
            validateInterfacesImplemented( cls );
        }
        else
        {
            // We can't validate immediately (since methods are expected to be added via
            // MyClass.prototype.method = function() {}; calls), so we queue validation.

            _validate.push( cls );
            if ( !( "timeout" in _validate ) )
                _validate.timeout = setTimeout( handleValidateQueue, 1 );
        }
    }

    return cls;
}

/**
 * Declare a constructor function to be an abstract class. Allows specifying an optional base class and interfaces implemented.
 * When reading or writing decl.abstractClass statements, it might help to know it was designed to mimic popular languages
 * in its format. Here's an example:
 *
 *      // With common languages
 *      abstract class ClassName : BaseClass, Interface1, Interface2 // C#
 *      abstract class ClassName extends BaseClass implements Interface1, Interface2 // Java
 *      {
 *          private String _name;
 *
 *          public ClassName( _name )
 *          {
 *              super( 42 );
 *              this._name = _name;
 *          }
 *
 *          public String toString()
 *          {
 *              return this._name;
 *          }
 *      }
 *
 *      // With barejs.decl:
 *
 *      function ClassName( _name )
 *      {
 *          BaseClass.call( this, 42 );
 *          this._name = _name;
 *      }
 *
 *      decl.abstractClass( ClassName, BaseClass, Interface1, Interface2,
 *      {
 *          // This puts the _name property as null on the prototype,
 *          // which is purely for clarity (e.g. stating it exists).
 *          _name: null,
 *
 *          toString: function()
 *          {
 *              return this._name;
 *          }
 *      }
 *
 *    - If a base class is provided, decl will ensure _class.prototype is instanceof _base.prototype.
 *    - For abstract classes, decl will not validate if interface methods are implemented.
 *    - If a _static argument is specified, it will be applied to the constructor function using {@link module:barejs.decl.defineObject defineObject}.
 *    - If a _prototype argument is specified, it will be applied to the prototype using {@link module:barejs.decl.defineObject defineObject}.
 *    - If only 1 object is supplied, it is always interpreted as prototype definition, never as static.
 *      You must specify null for the prototype object if you only want to specify static members.
 *
 * By default, any static members (except `name`, `prototype`, `constructor`, `superclass` and other metadata) will inherit.
 * A class can make static functions "private" by defining a static `$private` function, accepting a String/Symbol as key.
 * This function should return `true` for any keys that should *not* inherit. The `$private` function itself will never inherit.
 *
 * @param {function} _class The constructor function of the class
 * @param {function} [_base] Optional: Extended base class
 * @param {...function} [_interface] Optional: Any number of implemented interfaces
 * @param {object} [_static] Optional: static definition; properties that will be added to the constructor function.
 * @param {object} [_prototype] Optional: prototype definition: properties that will be added to the prototype
 * @returns {function} The constructor function (**_class**), so it can immediately be returned
 * @memberof module:barejs.decl
 */
function abstractClass( _class/*[, _base] [, _interface...] [, _static] [, _prototype] */ )
{
    return makeClass( "abstractClass", arguments );
}

/**
 * Declare a constructor function to be a class. Allows specifying an optional base class and interfaces implemented.
 * When reading or writing decl.declareClass statements, it might help to know it was designed to mimic popular languages
 * in its format. Here's an example:
 *
 *      // With common languages
 *      class ClassName : BaseClass, Interface1, Interface2 // C#
 *      class ClassName extends BaseClass implements Interface1, Interface2 // Java
 *      {
 *          private String _name;
 *
 *          public ClassName( _name )
 *          {
 *              super( 42 );
 *              this._name = _name;
 *          }
 *
 *          public String toString()
 *          {
 *              return this._name;
 *          }
 *      }
 *
 *      // With barejs.decl:
 *
 *      function ClassName( _name )
 *      {
 *          BaseClass.call( this, 42 );
 *          this._name = _name;
 *      }
 *
 *      decl.declareClass( ClassName, BaseClass, Interface1, Interface2,
 *      {
 *          // This puts the _name property as null on the prototype,
 *          // which is purely for clarity (e.g. stating it exists).
 *          _name: null,
 *
 *          toString: function()
 *          {
 *              return this._name;
 *          }
 *      }
 *
 *    - If a base class is provided, decl will ensure _class.prototype is instanceof _base.prototype.
 *    - If interfaces are declared, decl will validate methods are implemented.
 *    - If a _static argument is specified, it will be applied to the constructor function using {@link module:barejs.decl.defineObject defineObject}.
 *    - If a _prototype argument is specified, it will be applied to the prototype using {@link module:barejs.decl.defineObject defineObject}.
 *    - If only 1 object is supplied, it is always interpreted as prototype definition, never as static.
 *      You must specify null for the prototype object if you only want to specify static members.
 *
 * By default, any static members (except `name`, `prototype`, `constructor`, `superclass` and other metadata) will inherit.
 * A class can make static functions "private" by defining a static `$private` function, accepting a String/Symbol as key.
 * This function should return `true` for any keys that should *not* inherit. The `$private` function itself will never inherit.
 *
 * @param {function} _class The constructor function of the class
 * @param {function} [_base] Optional: Extended base class
 * @param {...function} [_interface] Optional: Any number of implemented interfaces
 * @param {object} [_static] Optional: static definition; properties that will be added to the constructor function.
 * @param {object} [_prototype] Optional: prototype definition: properties that will be added to the prototype
 * @returns {function} The constructor function (**_class**), so it can immediately be returned
 * @memberof module:barejs.decl
 */
function declareClass( _class/*[, _base] [, _interface...] [, _static] [, _prototype] */ )
{
    return makeClass( "declareClass", arguments, validateQueue );
}

/**
 * Declare an interface. An interface can extend multiple interfaces by passing them as additional parameters.
 * The constructor function _class will be made to derive from the special internal {@link module:barejs.decl~Interface Interface} type.
 * It is not meant to be instantiated, and decl will never call the interface's constructor.
 * @param {function} _class The "constructor" function to declare as an interface.
 * @param {...function} [_interface] Any number of interfaces to extend.
 * @param {object} [_static] Optional: static definition; properties that will be added to the constructor function.
 * @param {object} [_prototype] Optional: prototype to apply
 * @returns {function} The interface definition (_class).
 * @memberof module:barejs.decl
 */
function declareInterface( _class /*[, _interface...] [, _static] [, _prototype] */ )
{
    var interfaces = null,
        stat = null,
        proto = null;

    // Development time validation
    /*istanbul ignore else: We always test in DEBUG*/
    if ( !__RELEASE__ )
        validateClassArg( _class, "declareInterface", arguments );

    // If the interface extends other interfaces, set up the inheritance.
    if ( arguments.length > 1 )
    {
        interfaces = slice.call( arguments, 1, arguments.length );

        // If the last argument is not a function, assume it's a prototype definition.
        proto = popNonFunction( interfaces );
        // If the second to last argument is not a function, assume it's a static definition.
        stat = popNonFunction( interfaces );
    }

    // Each interface derives directly from Interface so it is easy to detect interfaces.
    derive( _class, Interface, expandDefineProperties( proto, Interface.prototype, toDefinePropertyInterface, _class.name || "(Interface)" ) );
    setInterfaces( _class, interfaces, null );
    if ( stat )
        applyStatic( _class, null, stat );

    // Development time validation
    /*istanbul ignore else: We always test in DEBUG*/
    if ( !__RELEASE__ && validateQueue )
    {
        // If we don't have a prototype definition ...
        if ( proto === null )
        {
            // We can't validate immediately (since methods are expected to be added via
            // MyInterface.prototype.method = function() {}; calls), so we queue validation.

            // Prepend interfaces so they get validated first
            validateQueue.unshift( _class );
            if ( !( "timeout" in validateQueue ) )
                validateQueue.timeout = setTimeout( handleValidateQueue, 1 );
        }
        else
        {
            // Otherwise just validate immediately.
            // Creating the interface metadata will perform validation of the interface.
            InterfaceMetaData.get( _class );
        }
    }

    return _class;
}

/**
 * Declare an enum. decl will make _class derive from the special internal {@link module:barejs.decl~Enum Enum} type,
 * and return a new instance of it. Enum values should be set on 'this' in the constructor, utility methods should be
 * added to the prototype.
 *
 *      var SampleEnum = decl.declareEnum( function SampleEnum()
 *      {
 *          this.Bit1 = 1;
 *          this.Bit2 = 2;
 *          this.Bit3 = 4;
 *          this.Bit4 = 8;
 *      },
 *      // End of constructor, what follows is the prototype definition:
 *      {
 *          hasBit: function( _bit, _value )
 *          {
 *              // hasValue is provided by the Enum base class
 *              if ( !this.hasValue( _bit ) )
 *                  throw new TypeError( "Unknown SampleEnum value: " + _bit );
 *              return _value & _bit === _bit
 *          }
 *      } );
 *
 *      // SampleEnum is now instanceof the SampleEnum function passed to decl.
 *      SampleEnum.hasBit( SampleEnum.Bit2, 3 ); // true
 *      // And it inherited decl's Enum type members
 *      SampleEnum.names(); // ["Bit1", "Bit2", "Bit3", "Bit4"]
 *      SampleEnum instanceof Object; // false
 *
 * Note that the prototype property, if specified, is applied using {@link module:barejs.decl.defineObject defineObject}.
 * @param {function} _class The "constructor" function to declare as an Enum.
 * @param {object} [_prototype] Optional: things to add to the enum prototype.
 * @returns {object} The enum instance (instanceof _class).
 * @memberof module:barejs.decl
 */
function declareEnum( _class/*[, _prototype]*/ )
{
    /*istanbul ignore else: We always test in DEBUG*/
    if ( !__RELEASE__ )
        validateClassArg( _class, "declareEnum", arguments );

    // An enum inherits directly from Enum, so they can be easily detected (and receive some helper methods).
    derive( _class, Enum, expandDefineProperties( arguments[1], Enum.prototype, toDefineProperty, ( _class.name || "(Enum)" ) ) );

    // jshint -W055
    // Return an instance for an enum
    return ObjectPolyfill.freeze( new _class() );
    // jshint +W055
}

/**
 * defineObject is similar to {@link module:barejs.decl.defineProperties decl.defineProperties}, but it expands the _definition's properties if needed.
 * It will update values of properties that are not property assigment definitions to be proper property definitions, defaulting to:
 *
 *      { configurable: false, writable: true, enumerable: true, value: &lt;value&gt; }
 *
 * (Note: enumerable will be `false` if the name starts with _ or is a Symbol).
 * defineObject will iterate the _definition object and expand properties on it. Please be aware of the following:
 *  1.  **_destination** will be modified. If that's a problem, use {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign Object.assign} to create a copy first.
 *  2.  Existing properties are scanned for presence of a **value**, **get** or **set** property. If these are present on a value, you **must** use the full property syntax:
 *
 *          decl.defineObject( MyClass,
 *          {
 *              // Since the object we want to assign to the MyClass constructor function has properties that make it look like
 *              // a property definition, we have to wrap it in a property definition as required by Object.defineProperties.
 *              staticFlags: { enumerable: true, value: { get: true, set: false } }
 *          } );
 *
 *  3.  defineObject will silently ignore getter/setter properties in environments that don't support them, unlike {@link module:barejs.decl.defineProperties}.
 *  4.  You can reference a getter or setter by name, provided it is also on the definition object:
 *
 *          decl.defineObject( {},
 *          {
 *              // underlying data Array, not enumerable, configurable or writable
 *              _values: { value: [] },
 *              // getSize function that returns the length of the _values
 *              getSize: function() { return this._values.length; },
 *              // Size property. Refers to the getSize function for the getter, instead of using an inline function.
 *              size: { enumerable: true, get: "getSize" }
 *          } );
 *
 * @param {object} _target The target object
 * @param {object} _definition The definitions to assign to _target. Note that _definition will be modified to contain property definitions(!).
 * @param {string} [_objectName] Optional: the name of the object. If passed, decl will generate displayName properties on methods for an enhanced debugging experience.
 * For example: if "decl" is passed as name, and there's an "is" function on _definition, the displayName of the "is" function will be set to "decl.is").
 * @returns _target The target object, expanded
 * @memberof module:barejs.decl
 */
function defineObject( _target, _definition/*, _objectName*/ )
{
    if ( !_definition )
        throw new Error( "Missing definition" );
    return ObjectPolyfill.defineProperties( _target, expandDefineProperties( _definition, _target, toDefineProperty, arguments.length > 2 ? String( arguments[2] ) : _target.name ) );
}

/**
 * Interpret `_target` as implementing a Java Functional Interface. A functional interface is an Interface with exactly
 * 1 function defined. Java allows lambda expressions to be generated for arguments of this type of interface.
 * This method allows normalizing a function or object to a "Functional Interface Object", so Java behavior can be
 * emulated.
 * This function will accept:
 *   - `null`/`undefined` (then `null` is returned)
 *   - A function (an 'instance' of _functionalInterface is returned, with this function in place).
 *   - An object complying with _functionalInterface
 *
 * Any other argument will throw a {@link TypeError}.
 * @param {object|function} _target The target object or function.
 * @param {function} _functionalInterface The interface to use as functional interface. May only have a single method defined.
 * @param {boolean} [_strict=false] Optional: set to true to avoid a duck-type check, and only check `decl`
 * metadata for interfaces implemented.
 * @returns Either an object compliant with `_functionalInterface`, or `null`.
 * @throws {TypeError} A TypeError may occur if `_functionalInterface` is not a valid functional interface,
 * or if _target does not comply with the interface.
 * @memberof module:barejs.decl
 */
function asFunctional( _target, _functionalInterface, _strict )
{
    if ( !isInterface( _functionalInterface ) )
        throw new TypeError( _functionalInterface + " is not an interface" );
    var meta = InterfaceMetaData.get( _functionalInterface );
    var fn = meta.members[ 0 ];
    if ( meta.members.length !== 1 || fn.type !== "function" )
        throw new TypeError( _functionalInterface.prototype + " is not a functional interface, functional interfaces have a single method" );
    if ( _target === null || _target === undefined )
        return null;

    // If this is a function, return an object that can be used instead.
    if ( typeof _target === "function" )
    {
        var def = {};
        def[fn.name] = { enumerable: true, value: _target };
        return Object.create( _functionalInterface.prototype, def );
    }
    if ( hasInterface( _target, _functionalInterface, _strict ) )
        return _target;

    throw new TypeError( _target + " does not implement " + _functionalInterface.prototype );
}


defineObject( exports,
{
    // Exports
    isInterface:        isInterface,
    isEnum:             isEnum,
    isProxy:            isProxy,
    is:                 is,
    hasBase:            hasBase,
    hasInterface:       hasInterface,
    proxy:              proxy,
    abstractClass:      abstractClass,
    declareClass:       declareClass,
    declareInterface:   declareInterface,
    declareEnum:        declareEnum,
    defineObject:       defineObject,
    asFunctional:       asFunctional,
    // Convenience properties to define interface properties
    readOnlyProperty:     readOnlyProperty,
    readWriteProperty:    readWriteProperty,
    // Allows certain low level classes to disallow casting to them
    preventCast:          preventCast
}, "decl" );

// We do NOT want to add a displayName to methods from other modules, so use a separate defineObject
defineObject( exports,
/** @lends module:barejs.decl */
{
    // Helper methods/flags for property definitions
    /**
     * This convenience property is true if the environment supports property getters and setters.
     * @member {boolean}
     */
    hasPropertySupport: ObjectPolyfill.propertyGetSetSupport,
    /**
     * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty Object.defineProperty}.
     *
     * If the native version is not available, a fall-back is used. The fallback supports the same syntax as the original, but falls back to simple assignment
     * or deprecated constructs like {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__defineGetter__ __defineGetter__}.
     * Be aware that property getters or setters may not be supported in some environments, which is indicated by {@link module:barejs.decl.hasPropertySupport hasPropertySupport} being false.
     * @function
     * @param {object} _target The object to define the property on
     * @param {string|Symbol} _key The name or {@link module:barejs.Symbol Symbol} to set
     * @param {object} _definition Object containing either a **value** property, or a **get** and/or **set** property (function).
     * @param {function} [_definition.get] A getter function, taking no arguments and returning the property value.
     * @param {function} [_definition.set] A setter function, taking a value as argument.
     * @param {*} [_definition.value] The value to assign to the property.
     * @param {boolean} [_definition.writable=false] (Only in combination with value) Whether assigning to the property is allowed.
     *                      For properties with get/set, the writable is implicit (by absence or presence of a setter function).
     * @param {boolean} [_definition.configurable=false] Whether the property may be altered via delete or a next defineProperty call.
     * @param {boolean} [_definition.enumerable=false] Whether the property shows up in object property enumerations.
     * @returns {object} The object the properties where defined on (_target).
     */
    defineProperty: ObjectPolyfill.defineProperty,
    /**
     * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties Object.defineProperties}.
     *
     * If the native version is not available, a fall-back is used. The fallback supports the same syntax as the original, and uses the {@link module:barejs.decl.defineProperty defineProperty} fallback.
     * @function
     * @param {object} _target The object to define the property on
     * @param {object} _definitions Object containing properties, each of which have a value that is a definition as passed to defineProperty.
     * @returns {object} The object the properties where defined on (_target).
     */
    defineProperties: ObjectPolyfill.defineProperties,
    // Helper methods for object strictness (seal/freeze)
    /**
     * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal Object.seal}.
     *
     * If the native version is not available, a **no-operation** function is used. The object is not altered in any way and simply returned.
     * @function
     * @param {object} _target The object to seal.
     * @returns {object} The object that was passed (_target).
     */
    seal: ObjectPolyfill.seal,
    /**
     * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed Object.isSealed}.
     * A sealed object may not be altered by adding or removing properties. Existing properties may be altered (provided they are writable).
     *
     * If the native version is not available, a **no-operation** function is used. The object is not altered by the fallback, and it always returns false (since sealing objects is not supported).
     *
     * @function
     * @param {object} _target The object to evaluate.
     * @returns {boolean} True if the object (_target) is sealed, false otherwise. The fallback always returns false.
     */
    isSealed: ObjectPolyfill.isSealed,
    /**
     * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze Object.freeze}.
     * A frozen object may not be altered in any way. No properties may be added or removed (like seal), and all values are made read-only.
     *
     * If the native version is not available, a **no-operation** function is used. The object is not altered in any way and simply returned.
     *
     * @function
     * @param {object} _target The object to freeze.
     * @returns {object} The object that was passed (_target).
     */
    freeze: ObjectPolyfill.freeze,
    /**
     * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen Object.isFrozen}.
     *
     * If the native version is not available, a **no-operation** function is used. The object is not altered by the fallback, and it always returns false (since freezing objects is not supported).
     * @function
     * @param {object} _target The object to evaluate.
     * @returns {boolean} True if the object (_target) is frozen, false otherwise. The fallback always returns false.
     */
    isFrozen: ObjectPolyfill.isFrozen
} /*DO NOT ADD NAME*/ );
exports.freeze( exports );

// End of define
}(
    Object,
    Array,
    String,
    Error,
    TypeError,
    require( "./polyfill/Object" ),
    require( "./NMap" ),
    require( "./NSet" ),
    require( "./Symbol" ),
    require( "./WeakMap" ),
    // Unreferenced: decl depends on the Array polyfills too.
    require( "./polyfill/Array" )
) );