diff --git a/lib/util.js b/lib/util.js
index 5627118..de59fb5 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -52,6 +52,9 @@ var can_define_prop = ( function()
} )();
+exports.Global = require( './util/Global' );
+
+
/**
* Freezes an object if freezing is supported
*
diff --git a/lib/util/Global.js b/lib/util/Global.js
new file mode 100644
index 0000000..597d47e
--- /dev/null
+++ b/lib/util/Global.js
@@ -0,0 +1,120 @@
+/**
+ * Global scope handling
+ *
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU ease.js.
+ *
+ * ease.js is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+// retrieve global scope; works with ES5 strict mode
+(0,eval)( 'var _the_global=this' );
+
+// prototype to allow us to augment the global scope for our own purposes
+// without polluting the global scope
+function _G() {}
+_G.prototype = _the_global;
+
+
+/**
+ * Provides access to and augmentation of global variables
+ *
+ * This provides a static method to consistently provide access to the
+ * object representing the global scope, regardless of environment. Through
+ * instantiation, its API permits augmenting a local object whose prototype
+ * is the global scope, providing alternatives to variables that do not
+ * exist.
+ */
+function Global()
+{
+ // allows omitting `new` keyword, consistent with ease.js style
+ if ( !( this instanceof Global ) )
+ {
+ return new Global();
+ }
+
+ // allows us to extend the global object without actually polluting the
+ // global scope
+ this._global = new _G();
+}
+
+
+/**
+ * Provides consistent access to the global scope through all ECMAScript
+ * versions, for any root variable name, and works with ES5 strict mode.
+ *
+ * As an example, Node.js exposes the variable `root` to represent global
+ * scope, but browsers expose `window`. Further, ES5 strict mode will provde
+ * an error when checking whether `typeof SomeGlobalVar === 'undefined'`.
+ *
+ * @return {Object} global object
+ */
+Global.expose = function()
+{
+ return _the_global;
+};
+
+
+Global.prototype = {
+ /**
+ * Provide a value for the provided global variable name if it is not
+ * defined
+ *
+ * A function returning the value to assign to NAME should be provided,
+ * ensuring that the alternative is never even evaluated unless it is
+ * needed.
+ *
+ * The global scope will not be polluted with this alternative;
+ * consequently, you must access the value using the `get` method.
+ *
+ * @param {string} name global variable name
+ * @param {function()} f function returning value to assign
+ *
+ * @return {Global} self
+ */
+ provideAlt: function( name, f )
+ {
+ if ( typeof this._global[ name ] !== 'undefined' )
+ {
+ return;
+ }
+
+ this._global[ name ] = f();
+ return this;
+ },
+
+
+ /**
+ * Retrieve global value or provided alternative
+ *
+ * This will take into account values provided via `provideAlt`; if no
+ * alternative was provided, the request will be deleagated to the
+ * global variable NAME, which may or may not be undefined.
+ *
+ * No error will be thrown if NAME is not globally defined.
+ *
+ * @param {string} name global variable name
+ *
+ * @return {*} value associated with global variable NAME or
+ * its provided alternative
+ */
+ get: function( name )
+ {
+ return this._global[ name ];
+ },
+};
+
+module.exports = Global;
+
diff --git a/test/Util/GlobalTest.js b/test/Util/GlobalTest.js
new file mode 100644
index 0000000..1b350ef
--- /dev/null
+++ b/test/Util/GlobalTest.js
@@ -0,0 +1,143 @@
+/**
+ * Tests global scope handling
+ *
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU ease.js.
+ *
+ * ease.js is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+var _global = this;
+
+require( 'common' ).testCase(
+{
+ caseSetUp: function()
+ {
+ this.Sut = this.require( 'util/Global' );
+ this.gobj = this.Sut.expose();
+ this.uniq = '___$$easejs$globaltest$$';
+ },
+
+
+ /**
+ * Check common environments and ensure that the returned object is
+ * strictly equal to the global object for that environment. For
+ * environments that we do *not* know about, just check for a common
+ * object that must exist in ES3 and above.
+ */
+ 'Global object represents environment global object': function()
+ {
+ switch ( true )
+ {
+ // browser
+ case _global.window:
+ this.assertStrictEqual( this.gobj, _global.window );
+ break;
+
+ // Node.js
+ case _global.root:
+ this.assertStrictEqual( this.gobj, _global.root );
+ break;
+
+ // something else; we'll just check for something that should
+ // exist in >=ES3
+ default:
+ this.assertStrictEqual( this.gobj.Array, Array );
+ }
+ },
+
+
+ /**
+ * Since ease.js makes use of ECMAScript features when they are
+ * available, it must also find a way to gracefully degrade to support
+ * less fortunate environments; the ability to define alternative
+ * definitions is key to that.
+ */
+ 'Providing alternative will set value if name does not exist':
+ function()
+ {
+ var sut = this.Sut();
+
+ var field = this.uniq,
+ value = { _: 'easejsOK' };
+
+ sut.provideAlt( field, function() { return value; } );
+ this.assertStrictEqual( sut.get( field ), value );
+ },
+
+
+ /**
+ * It is also important that our own definitions do not pollute the
+ * global scope; reasons for this are not just to be polite, but also
+ * because other code/libraries may provide their own definitions that
+ * we would not want to interfere with. (Indeed, we'd also want to use
+ * those definitions, if they already exist before provideAlt is
+ * called.)
+ */
+ 'Providing alternative will not pollute the global scope': function()
+ {
+ this.Sut().provideAlt( this.uniq, function() { return {} } );
+ this.assertEqual( this.gobj[ this.uniq ], undefined );
+ },
+
+
+ /**
+ * Our alternatives are unneeded if the object we are providing an
+ * alternative for is already defined.
+ */
+ 'Providing alternative will not modify global if name exists':
+ function()
+ {
+ var sut = this.Sut();
+
+ // a field that must exist in ES3+
+ var field = 'Array',
+ orig = this.gobj[ field ];
+
+ sut.provideAlt( field, function() { return {}; } );
+ this.assertStrictEqual( sut.get( field ), orig );
+ },
+
+
+ /**
+ * Once an alternative is defined, it shall be treated as though the
+ * value were defined globally; providing additional alternatives should
+ * therefore have no effect.
+ */
+ 'Providing alternative twice will not modify first alternative':
+ function()
+ {
+ var sut = this.Sut();
+ field = this.uniq,
+ expected = { _: 'easejsOK' };
+
+ // first should provide alternative, second should do nothing
+ sut.provideAlt( field, function() { return expected; } );
+ sut.provideAlt( field, function() { return 'oops'; } );
+
+ this.assertStrictEqual( sut.get( field ), expected );
+ },
+
+
+ 'provideAlt returns self for method chaining': function()
+ {
+ var sut = this.Sut();
+
+ this.assertStrictEqual( sut,
+ sut.provideAlt( 'foo', function() {} )
+ );
+ },
+} );
+
diff --git a/test/Util/IndexTest.js b/test/Util/IndexTest.js
new file mode 100644
index 0000000..d719a56
--- /dev/null
+++ b/test/Util/IndexTest.js
@@ -0,0 +1,41 @@
+/**
+ * Tests utility module entry point
+ *
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU ease.js.
+ *
+ * ease.js is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * N.B. Despite this saying that it tests the index (i.e. entry point), this
+ * is not yet the case; it will be in the future, though.
+ */
+
+require( 'common' ).testCase(
+{
+ caseSetUp: function()
+ {
+ this.Sut = this.require( 'util' );
+ },
+
+
+ 'Exposes Global prototype': function()
+ {
+ this.assertStrictEqual(
+ this.Sut.Global,
+ this.require( 'util/Global' )
+ );
+ },
+} );
+