Stage 2 Draft / July 25, 2019

Collection data normalization

1Data normalization operations

1.1NormalizeCoerceKey( collection , data )

  1. If collection does not have [[CoerceKey]] or collection.[[CoerceKey]] is undefined
    1. Return data.
  2. Else, return Call(collection.[[CoerceKey]], collection, « data »).

1.2NormalizeCoerceValue( collection , data )

  1. If collection does not have [[CoerceValue]] or collection.[[CoerceValue]] is undefined
    1. Return data.
  2. Else, return Call(collection.[[CoerceValue]], collection, « data »).

Modified algorithms

2Keyed Collections

2.1Map Objects

Map objects are collections of key/value pairs where both the keys and values may be arbitrary ECMAScript language values. A distinct key value may only occur in one key/value pair within the Map's collection. Distinct key values are discriminated using the SameValueZero comparison algorithm.

Map object must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection. The data structures used in this Map objects specification is only intended to describe the required observable semantics of Map objects. It is not intended to be a viable implementation model.

2.1.1The Map Constructor

The Map constructor:

  • is the intrinsic object %Map%.
  • is the initial value of the Map property of the global object.
  • creates and initializes a new Map object when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified Map behaviour must include a super call to the Map constructor to create and initialize the subclass instance with the internal state necessary to support the Map.prototype built-in methods.

2.1.1.1Map ( [ iterable [, options ] ] )

When the Map function is called with optional argument iterable, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%MapPrototype%", « [[MapData]], [[CoerceKey]], [[CoerceValue]] »).
  3. Set map.[[MapData]] to a new empty List.
  4. If options is not present, or is either undefined or null
    1. Set map.[[CoerceKey]] to undefined
    2. Set map.[[CoerceValue]] to undefined
  5. Else,
    1. Set map.[[CoerceKey]] to ? Get(options, "coerceKey").
    2. If map.[[CoerceKey]] is null set map.[[CoerceKey]] to undefined
    3. Set map.[[CoerceValue]] to ? Get(options, "coerceValue").
    4. If map.[[CoerceValue]] is null set map.[[CoerceValue]] to undefined
  6. If iterable is not present, or is either undefined or null, return map.
  7. Let adder be ? Get(map, "set").
  8. Return ? AddEntriesFromIterable(map, iterable, adder).
Note

If the parameter iterable is present, it is expected to be an object that implements an @@iterator method that returns an iterator object that produces a two element array-like object whose first element is a value that will be used as a Map key and whose second element is the value to associate with that key.

2.1.2Properties of the Map Prototype Object

The Map prototype object:

  • is the intrinsic object %MapPrototype%.
  • has a [[Prototype]] internal slot whose value is the intrinsic object %ObjectPrototype%.
  • is an ordinary object.
  • does not have a [[MapData]] internal slot.
  • does not have a [[CoerceKey]] internal slot.
  • does not have a [[CoerceValue]] internal slot.

2.1.2.1Map.prototype.delete ( key )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[MapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let entries be the List that is M.[[MapData]].
  6. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], normalizedKeykey) is true, then
      1. Set p.[[Key]] to empty.
      2. Set p.[[Value]] to empty.
      3. Return true.
  7. Return false.
Note

The value empty is used as a specification device to indicate that an entry has been deleted. Actual implementations may take other actions such as physically removing the entry from internal data structures.

2.1.2.2Map.prototype.get ( key )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[MapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let entries be the List that is M.[[MapData]].
  6. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], normalizedKeykey) is true, return p.[[Value]].
  7. Return undefined.

2.1.2.3Map.prototype.has ( key )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[MapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let entries be the List that is M.[[MapData]].
  6. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], normalizedKeykey) is true, return true.
  7. Return false.

2.1.2.4Map.prototype.set ( key, value )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[MapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let normalizedValue be ? NormalizeCoerceValue(M, value).
  6. Let entries be the List that is M.[[MapData]].
  7. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValueZero(p.[[Key]], normalizedKeykey) is true, then
      1. Set p.[[Value]] to normalizedValuevalue.
      2. Return M.
  8. If key is -0, set key to +0.
  9. Let p be the Record { [[Key]]: key, [[Value]]: normalizedValuevalue }.
  10. Append p as the last element of entries.
  11. Return M.

2.1.2.5Properties of Map Instances

Map instances are ordinary objects that inherit properties from the Map prototype. Map instances also have [[MapData]], [[CoerceKey]], and [[CoerceValue]] internal slots.

2.1.3Set Objects

Set objects are collections of ECMAScript language values. A distinct value may only occur once as an element of a Set's collection. Distinct values are discriminated using the SameValueZero comparison algorithm.

Set objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection. The data structures used in this Set objects specification is only intended to describe the required observable semantics of Set objects. It is not intended to be a viable implementation model.

2.1.3.1The Set Constructor

The Set constructor:

  • is the intrinsic object %Set%.
  • is the initial value of the Set property of the global object.
  • creates and initializes a new Set object when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified Set behaviour must include a super call to the Set constructor to create and initialize the subclass instance with the internal state necessary to support the Set.prototype built-in methods.

2.1.3.1.1Set ( [ iterable [, options ]] )

When the Set function is called with optional argument iterable, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let set be ? OrdinaryCreateFromConstructor(NewTarget, "%SetPrototype%", « [[SetData]] »).
  3. Set set.[[SetData]] to a new empty List.
  4. If options is not present, or is either undefined or null
    1. Set set.[[CoerceValue]] to undefined
  5. Else,
    1. Set set.[[CoerceValue]] to ? Get(options, "coerceValue").
    2. If set.[[CoerceValue]] is null set set.[[CoerceValue]] to undefined
  6. If iterable is not present, set iterable to undefined.
  7. If iterable is either undefined or null, return set.
  8. Let adder be ? Get(set, "add").
  9. If IsCallable(adder) is false, throw a TypeError exception.
  10. Let iteratorRecord be ? GetIterator(iterable).
  11. Repeat,
    1. Let next be ? IteratorStep(iteratorRecord).
    2. If next is false, return set.
    3. Let nextValue be ? IteratorValue(next).
    4. Let status be Call(adder, set, « nextValue »).
    5. If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).

2.1.3.2Properties of the Set Prototype Object

The Set prototype object:

  • is the intrinsic object %SetPrototype%.
  • has a [[Prototype]] internal slot whose value is the intrinsic object %ObjectPrototype%.
  • is an ordinary object.
  • does not have a [[SetData]] internal slot.
  • does not have a [[CoerceValue]] internal slot.

2.1.3.2.1Set.prototype.add ( value )

The following steps are taken:

  1. Let S be the this value.
  2. If Type(S) is not Object, throw a TypeError exception.
  3. If S does not have a [[SetData]] internal slot, throw a TypeError exception.
  4. Let normalizedValue be ? NormalizeCoerceValue(S, value).
  5. Let entries be the List that is S.[[SetData]].
  6. For each e that is an element of entries, do
    1. If e is not empty and SameValueZero(e, normalizedValuevalue) is true, then
      1. Return S.
  7. If value is -0, set value to +0.
  8. Append value as the last element of entries.
  9. Return S.

2.1.3.2.2Set.prototype.delete ( value )

The following steps are taken:

  1. Let S be the this value.
  2. If Type(S) is not Object, throw a TypeError exception.
  3. If S does not have a [[SetData]] internal slot, throw a TypeError exception.
  4. Let normalizedValue be ? NormalizeCoerceValue(S, value).
  5. Let entries be the List that is S.[[SetData]].
  6. For each e that is an element of entries, do
    1. If e is not empty and SameValueZero(e, normalizedValuevalue) is true, then
      1. Replace the element of entries whose value is e with an element whose value is empty.
      2. Return true.
  7. Return false.
Note

The value empty is used as a specification device to indicate that an entry has been deleted. Actual implementations may take other actions such as physically removing the entry from internal data structures.

2.1.3.2.3Set.prototype.has ( value )

The following steps are taken:

  1. Let S be the this value.
  2. If Type(S) is not Object, throw a TypeError exception.
  3. If S does not have a [[SetData]] internal slot, throw a TypeError exception.
  4. Let normalizedValue be ? NormalizeCoerceValue(S, value).
  5. Let entries be the List that is S.[[SetData]].
  6. For each e that is an element of entries, do
    1. If e is not empty and SameValueZero(e, normalizedValuevalue) is true, return true.
  7. Return false.

2.1.4WeakMap Objects

WeakMap objects are collections of key/value pairs where the keys are objects and values may be arbitrary ECMAScript language values. A WeakMap may be queried to see if it contains a key/value pair with a specific key, but no mechanism is provided for enumerating the objects it holds as keys. If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap. WeakMap implementations must detect and remove such key/value pairs and any associated resources.

An implementation may impose an arbitrarily determined latency between the time a key/value pair of a WeakMap becomes inaccessible and the time when the key/value pair is removed from the WeakMap. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to observe a key of a WeakMap that does not require the observer to present the observed key.

WeakMap objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of key/value pairs in the collection. The data structure used in this WeakMap objects specification are only intended to describe the required observable semantics of WeakMap objects. It is not intended to be a viable implementation model.

Note

WeakMap and WeakSets are intended to provide mechanisms for dynamically associating state with an object in a manner that does not “leak” memory resources if, in the absence of the WeakMap or WeakSet, the object otherwise became inaccessible and subject to resource reclamation by the implementation's garbage collection mechanisms. This characteristic can be achieved by using an inverted per-object mapping of weak map instances to keys. Alternatively each weak map may internally store its key to value mappings but this approach requires coordination between the WeakMap or WeakSet implementation and the garbage collector. The following references describe mechanism that may be useful to implementations of WeakMap and WeakSets:

Barry Hayes. 1997. Ephemerons: a new finalization mechanism. In Proceedings of the 12th ACM SIGPLAN conference on Object-oriented programming, systems, languages, and applications (OOPSLA '97), A. Michael Berman (Ed.). ACM, New York, NY, USA, 176-183, http://doi.acm.org/10.1145/263698.263733.

Alexandra Barros, Roberto Ierusalimschy, Eliminating Cycles in Weak Tables. Journal of Universal Computer Science - J.UCS, vol. 14, no. 21, pp. 3481-3497, 2008, http://www.jucs.org/jucs_14_21/eliminating_cycles_in_weak

2.1.4.1The WeakMap Constructor

The WeakMap constructor:

  • is the intrinsic object %WeakMap%.
  • is the initial value of the WeakMap property of the global object.
  • creates and initializes a new WeakMap object when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified WeakMap behaviour must include a super call to the WeakMap constructor to create and initialize the subclass instance with the internal state necessary to support the WeakMap.prototype built-in methods.

2.1.4.1.1WeakMap ( [ iterable [, options ]] )

When the WeakMap function is called with optional argument iterable, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakMapPrototype%", « [[WeakMapData]] »).
  3. Set map.[[WeakMapData]] to a new empty List.
  4. If options is not present, or is either undefined or null
    1. Set map.[[CoerceKey]] to undefined
    2. Set map.[[CoerceValue]] to undefined
  5. Else,
    1. Set map.[[CoerceKey]] to ? Get(options, "coerceKey").
    2. If map.[[CoerceKey]] is null set map.[[CoerceKey]] to undefined
    3. Set map.[[CoerceValue]] to ? Get(options, "coerceValue").
    4. If map.[[CoerceValue]] is null set map.[[CoerceValue]] to undefined
  6. If iterable is not present, or is either undefined or null, return map.
  7. Let adder be ? Get(map, "set").
  8. Return ? AddEntriesFromIterable(map, iterable, adder).
Note

If the parameter iterable is present, it is expected to be an object that implements an @@iterator method that returns an iterator object that produces a two element array-like object whose first element is a value that will be used as a WeakMap key and whose second element is the value to associate with that key.

2.1.4.2Properties of the WeakMap Prototype Object

The WeakMap prototype object:

  • is the intrinsic object %WeakMapPrototype%.
  • has a [[Prototype]] internal slot whose value is the intrinsic object %ObjectPrototype%.
  • is an ordinary object.
  • does not have a [[WeakMapData]] internal slot.
  • does not have a [[CoerceKey]] internal slot.
  • does not have a [[CoerceValue]] internal slot.

2.1.4.2.1WeakMap.prototype.delete ( key )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[WeakMapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let entries be the List that is M.[[WeakMapData]].
  6. If Type(key) is not Object, return false.
  7. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValue(p.[[Key]], normalizedKeykey) is true, then
      1. Set p.[[Key]] to empty.
      2. Set p.[[Value]] to empty.
      3. Return true.
  8. Return false.
Note

The value empty is used as a specification device to indicate that an entry has been deleted. Actual implementations may take other actions such as physically removing the entry from internal data structures.

2.1.4.2.2WeakMap.prototype.get ( key )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[WeakMapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let entries be the List that is M.[[WeakMapData]].
  6. If Type(key) is not Object, return undefined.
  7. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValue(p.[[Key]], normalizedKeykey) is true, return p.[[Value]].
  8. Return undefined.

2.1.4.2.3WeakMap.prototype.has ( key )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[WeakMapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let entries be the List that is M.[[WeakMapData]].
  6. If Type(key) is not Object, return false.
  7. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValue(p.[[Key]], normalizedKeykey) is true, return true.
  8. Return false.

2.1.4.2.4WeakMap.prototype.set ( key, value )

The following steps are taken:

  1. Let M be the this value.
  2. If Type(M) is not Object, throw a TypeError exception.
  3. If M does not have a [[WeakMapData]] internal slot, throw a TypeError exception.
  4. Let normalizedKey be ? NormalizeCoerceKey(M, key).
  5. Let normalizedValue be ? NormalizeCoerceValue(M, value).
  6. Let entries be the List that is M.[[WeakMapData]].
  7. If Type(key) is not Object, throw a TypeError exception.
  8. For each Record { [[Key]], [[Value]] } p that is an element of entries, do
    1. If p.[[Key]] is not empty and SameValue(p.[[Key]], normalizedKeykey) is true, then
      1. Set p.[[Value]] to value.
      2. Return M.
  9. Let p be the Record { [[Key]]: key, [[Value]]: normalizedValuevalue }.
  10. Append p as the last element of entries.
  11. Return M.

2.1.4.3WeakSet Objects

WeakSet objects are collections of objects. A distinct object may only occur once as an element of a WeakSet's collection. A WeakSet may be queried to see if it contains a specific object, but no mechanism is provided for enumerating the objects it holds. If an object that is contained by a WeakSet is only reachable by following a chain of references that start within that WeakSet, then that object is inaccessible and is automatically removed from the WeakSet. WeakSet implementations must detect and remove such objects and any associated resources.

An implementation may impose an arbitrarily determined latency between the time an object contained in a WeakSet becomes inaccessible and the time when the object is removed from the WeakSet. If this latency was observable to ECMAScript program, it would be a source of indeterminacy that could impact program execution. For that reason, an ECMAScript implementation must not provide any means to determine if a WeakSet contains a particular object that does not require the observer to present the observed object.

WeakSet objects must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection. The data structure used in this WeakSet objects specification is only intended to describe the required observable semantics of WeakSet objects. It is not intended to be a viable implementation model.

Note

See the NOTE in 2.1.4.

2.1.4.3.1The WeakSet Constructor

The WeakSet constructor:

  • is the intrinsic object %WeakSet%.
  • is the initial value of the WeakSet property of the global object.
  • creates and initializes a new WeakSet object when called as a constructor.
  • is not intended to be called as a function and will throw an exception when called in that manner.
  • is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified WeakSet behaviour must include a super call to the WeakSet constructor to create and initialize the subclass instance with the internal state necessary to support the WeakSet.prototype built-in methods.

2.1.4.3.1.1WeakSet ( [ iterable ] )

When the WeakSet function is called with optional argument iterable, the following steps are taken:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let set be ? OrdinaryCreateFromConstructor(NewTarget, "%WeakSetPrototype%", « [[WeakSetData]] »).
  3. Set set.[[WeakSetData]] to a new empty List.
  4. If options is not present, or is either undefined or null
    1. Set set.[[CoerceValue]] to undefined
  5. Else,
    1. Set set.[[CoerceValue]] to ? Get(options, "coerceValue").
    2. If set.[[CoerceValue]] is null set set.[[CoerceValue]] to undefined
  6. If iterable is not present, set iterable to undefined.
  7. If iterable is either undefined or null, return set.
  8. Let adder be ? Get(set, "add").
  9. If IsCallable(adder) is false, throw a TypeError exception.
  10. Let iteratorRecord be ? GetIterator(iterable).
  11. Repeat,
    1. Let next be ? IteratorStep(iteratorRecord).
    2. If next is false, return set.
    3. Let nextValue be ? IteratorValue(next).
    4. Let status be Call(adder, set, « nextValue »).
    5. If status is an abrupt completion, return ? IteratorClose(iteratorRecord, status).

2.1.4.3.2Properties of the WeakSet Prototype Object

The WeakSet prototype object:

  • is the intrinsic object %WeakSetPrototype%.
  • has a [[Prototype]] internal slot whose value is the intrinsic object %ObjectPrototype%.
  • is an ordinary object.
  • does not have a [[WeakSetData]] internal slot.
  • does not have a [[CoerceValue]] internal slot.

2.1.4.3.2.1WeakSet.prototype.add ( value )

The following steps are taken:

  1. Let S be the this value.
  2. If Type(S) is not Object, throw a TypeError exception.
  3. If S does not have a [[WeakSetData]] internal slot, throw a TypeError exception.
  4. Let normalizedValue be ? NormalizeCoerceValue(S, value).
  5. If Type(value) is not Object, throw a TypeError exception.
  6. Let entries be the List that is S.[[WeakSetData]].
  7. For each e that is an element of entries, do
    1. If e is not empty and SameValue(e, normalizedValuevalue) is true, then
      1. Return S.
  8. Append value as the last element of entries.
  9. Return S.

2.1.4.3.2.2WeakSet.prototype.delete ( value )

The following steps are taken:

  1. Let S be the this value.
  2. If Type(S) is not Object, throw a TypeError exception.
  3. If S does not have a [[WeakSetData]] internal slot, throw a TypeError exception.
  4. Let normalizedValue be ? NormalizeCoerceValue(S, value).
  5. If Type(value) is not Object, return false.
  6. Let entries be the List that is S.[[WeakSetData]].
  7. For each e that is an element of entries, do
    1. If e is not empty and SameValue(e, normalizedValuevalue) is true, then
      1. Replace the element of entries whose value is e with an element whose value is empty.
      2. Return true.
  8. Return false.
Note

The value empty is used as a specification device to indicate that an entry has been deleted. Actual implementations may take other actions such as physically removing the entry from internal data structures.

2.1.4.3.2.3WeakSet.prototype.has ( value )

The following steps are taken:

  1. Let S be the this value.
  2. If Type(S) is not Object, throw a TypeError exception.
  3. If S does not have a [[WeakSetData]] internal slot, throw a TypeError exception.
  4. Let normalizedValue be ? NormalizeCoerceValue(S, value).
  5. Let entries be the List that is S.[[WeakSetData]].
  6. If Type(value) is not Object, return false.
  7. For each e that is an element of entries, do
    1. If e is not empty and SameValue(e, normalizedValuevalue) is true, return true.
  8. Return false.

ACopyright & Software License

Copyright Notice

© 2019 Bradley Farias

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.