<commit_before>var Node = require('./node.js'),
	NodeList = require('./nodelist.js'),
	helper = require('../helper.js'),
	factory = require('../simple/factory.js'),
	sys = require('sys');

/**
 *  The Document interface represents the entire HTML or XML document. Conceptually, it is the root of the document
 *  tree, and provides the primary access to the document's data.
 *  @name    Document
 *  @type    function
 *  @access  internal
 *  @param   simple
 *  @return  void
 *  @note    Since elements, text nodes, comments, processing instructions, etc. cannot exist outside the context
 *           of a Document, the Document interface also contains the factory methods needed to create these objects.
 *           The Node objects created have a ownerDocument attribute which associates them with the Document within
 *           whose context they were created.
 */
function Document(simple)
{
	console.log(this);
	Document.super_.apply(this, [simple || factory.create(9, '#document')]);
}
//  Document extends Node
sys.inherits(Document, Node);

/**
 *  ___property
 *  @name    ___property
 *  @type    method
 *  @access  internal (exposed)
 *  @param
 *  @return  void
 */
Document.prototype.___property = function()
{
	return helper.combine({
		//  readonly attribute DocumentType doctype;
		//  The Document Type Declaration (see DocumentType) associated with this document. For XML documents
		//  without a document type declaration this returns null. For HTML documents, a DocumentType object may
		//  be returned, independently of the presence or absence of document type declaration in the HTML document.
		//  This provides direct access to the DocumentType node, child node of this Document. This node can be set
		//  at document creation time and later changed through the use of child nodes manipulation methods, such
		//  as Node.insertBefore, or Node.replaceChild. Note, however, that while some implementations may
		//  instantiate different types of Document objects supporting additional features than the "Core", such
		//  as "HTML" [DOM Level 2 HTML], based on the DocumentType specified at creation time, changing it
		//  afterwards is very unlikely to result in a change of the features supported.
		doctype: {},
		//  readonly attribute DOMImplementation implementation;
		//  The DOMImplementation object that handles this document. A DOM application may use objects from
		//  multiple implementations.
		implementation: {},
		//  readonly attribute Element documentElement;
		//  This is a convenience attribute that allows direct access to the child node that is the document
		//  element of the document.
		documentElement: {},

		// Introduced in DOM Level 3:

		//  readonly attribute DOMString inputEncoding;
		//  An attribute specifying the encoding used for this document at the time of the parsing. This is null
		//  when it is not known, such as when the Document was created in memory.
		inputEncoding: {},
		//  readonly attribute DOMString xmlEncoding;
		//  An attribute specifying, as part of the XML declaration, the encoding of this document. This is null
		//  when unspecified or when it is not known, such as when the Document was created in memory.
		xmlEncoding: {},
		//  attribute boolean xmlStandalone;
		//  An attribute specifying, as part of the XML declaration, whether this document is standalone. This is
		//  false when unspecified.
		//  Note: No verification is done on the value when setting this attribute. Applications should use
		//  Document.normalizeDocument() with the "validate" parameter to verify if the value matches the validity
		//  constraint for standalone document declaration as defined in [XML 1.0].
		//  Exceptions on setting: DOMException NOT_SUPPORTED_ERR: Raised if this document does not support the
		//  "XML" feature.
		xmlStandalone: {},
		//  attribute DOMString xmlVersion;
		//  An attribute specifying, as part of the XML declaration, the version number of this document. If there
		//  is no declaration and if this document supports the "XML" feature, the value is "1.0". If this document
		//  does not support the "XML" feature, the value is always null. Changing this attribute will affect
		//  methods that check for invalid characters in XML names. Application should invoke
		//  Document.normalizeDocument() in order to check for invalid characters in the Nodes that are already
		//  part of this Document.
		//  DOM applications may use the DOMImplementation.hasFeature(feature, version) method with parameter
		//  values "XMLVersion" and "1.0" (respectively) to determine if an implementation supports [XML 1.0]. DOM
		//  applications may use the same method with parameter values "XMLVersion" and "1.1" (respectively) to
		//  determine if an implementation supports [XML 1.1]. In both cases, in order to support XML, an
		//  implementation must also support the "XML" feature defined in this specification. Document objects
		//  supporting a version of the "XMLVersion" feature must not raise a NOT_SUPPORTED_ERR exception for the
		//  same version number when using Document.xmlVersion.
		//  Exceptions on setting: DOMException NOT_SUPPORTED_ERR: Raised if the version is set to a value that is
		//  not supported by this Document or if this document does not support the "XML" feature.
		xmlVersion: {},
		//  attribute boolean strictErrorChecking;
		//  An attribute specifying whether error checking is enforced or not. When set to false, the
		//  implementation is free to not test every possible error case normally defined on DOM operations, and
		//  not raise any DOMException on DOM operations or report errors while using Document.normalizeDocument().
		//  In case of error, the behavior is undefined. This attribute is true by default.
		strictErrorChecking: {},
		//  attribute DOMString documentURI;
		//  The location of the document or null if undefined or if the Document was created using
		//  DOMImplementation.createDocument. No lexical checking is performed when setting this attribute; this
		//  could result in a null value returned when using Node.baseURI.
		//  Beware that when the Document supports the feature "HTML" [DOM Level 2 HTML], the href attribute of the
		//  HTML BASE element takes precedence over this attribute when computing Node.baseURI.
		documentURI: {},
		//  readonly attribute DOMConfiguration domConfig;
		//  The configuration used when Document.normalizeDocument() is invoked
		domConfig: {}
	}, Node.prototype.___property());
};

/**
 *  ___get_documentElement
 *  @name    ___get_documentElement
 *  @type    method
 *  @access  internal (exposed)
 *  @param
 *  @return  void
 */
Document.prototype.___get_documentElement = function()
{
	var list = this.___simple(function(){
			return this.find(1);
		});

	return list.length > 0 ? factory.instance(list[0]) : null;
};

/**
 *  createElement
 *  @name    createElement
 *  @type    method
 *  @access  public
 *  @param   name
 *  @return  void
 */
Document.prototype.createElement = function(name)
{
	var simple = factory.create(1, name);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createTextNode
 *  @name    createTextNode
 *  @type    method
 *  @access  public
 *  @param   data
 *  @return  void
 */
Document.prototype.createTextNode = function(data)
{
	var simple = factory.create(3, '#text', data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createComment
 *  @name    createComment
 *  @type    method
 *  @access  public
 *  @param   data
 *  @return  void
 */
Document.prototype.createComment = function(data)
{
	var simple = factory.create(8, '#comment', data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createCDATASection
 *  @name    createCDATASection
 *  @type    method
 *  @access  public
 *  @param   data
 *  @return  void
 */
Document.prototype.createCDATASection = function(data)
{
	var simple = factory.create(3, '#cdata-section', data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createProcessingInstruction
 *  @name    createProcessingInstruction
 *  @type    method
 *  @access  public
 *  @param   target, data
 *  @return  void
 */
Document.prototype.createProcessingInstruction = function(target, data)
{
	var simple = factory.create(7, target, data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createAttribute
 *  @name    createAttribute
 *  @type    method
 *  @access  public
 *  @param   name
 *  @return  void
 */
Document.prototype.createAttribute = function(name)
{
	var simple = factory.create(2, name);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createEntityReference
 *  @name    createEntityReference
 *  @type    method
 *  @access  public
 *  @param   name
 *  @return  void
 */
Document.prototype.createEntityReference = function(name)
{
	var simple = factory.create(5, name);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  Returns a NodeList of all the Elements in document order with a given tag name and are contained in the
 *  document.
 *  @name    getElementsByTagName
 *  @type    method
 *  @access  public
 *  @param   tagname
 *  @return  NodeList
 */
Document.prototype.getElementsByTagName = function(tagname)
{
	return new NodeList(this.___simple(function(){
		return this.find(1, tagname, true);
	}));
};

/**
 *  Imports a node from another document to this document, without altering or removing the source node from the
 *  original document; this method creates a new copy of the source node.
 *  @name    importNode
 *  @type    method
 *  @access  public
 *  @param   importedNode, deep
 *  @return  Node
 *  @note    The returned node has no parent; (parentNode is null). For all nodes, importing a node creates a node
 *           object owned by the importing document, with attribute values identical to the source node's nodeName
 *           and nodeType, plus the attributes related to namespaces (prefix, localName, and namespaceURI). As in
 *           the cloneNode operation, the source node is not altered. User data associated to the imported node is
 *           not carried over. However, if any UserDataHandlers has been specified along with the associated data
 *           these handlers will be called with the appropriate parameters before this method returns.
 *           Additional information is copied as appropriate to the nodeType, attempting to mirror the behavior
 *           expected if a fragment of XML or HTML source was copied from one document to another, recognizing that
 *           the two documents may have different DTDs in the XML case. The following list describes the specifics
 *           for each type of node.
 *  @note    Attr nodes are copied including its children, regardless of the deep argument
 *  @note    DocumentFragment nodes are copied respecting the deep argument
 *  @note    Document nodes cannot be imported
 *  @note    DocumentType nodes cannot be imported
 *  @note    Element nodes are copied, including any Attr child regardless of the deep argument
 *  @note    Entity nodes can be imported, however these can not be added to the DocumentType as it is read-only in
 *           DOM level 3
 *  @note    EntityReference nodes will be copied without any children, even if a deep import is requested, since
 *           the source and destination documents might have defined the entity differently. If the document being
 *           imported into provides a definition for this entity name, its value is assigned.
 *  @note    Notation nodes can be imported, however in DOM level 3 the DocumentType is readonly
 *  @note    ProcessingInstruction, Text, CDataSection and Comment nodes will be copied nodes will be copied (as
 *           these cannot contain child nodes the deep argument has no effect)
 */
Document.prototype.importNode = function(importedNode, deep)
{
	var simple;

	this.___simple(function(){
		simple = this;
	});

	return factory.instance(importedNode.___simple(function(){
		return this.clone(deep, simple);
	}));
};

/**
 *  createElementNS
 *  @name    createElementNS
 *  @type    method
 *  @access  public
 *  @param   namespaceURI, qualifiedName
 *  @return  void
 */
Document.prototype.createElementNS = function(namespaceURI, qualifiedName)
{
	//  TODO: implement Document.createElementNS
};

/**
 *  createAttributeNS
 *  @name    createAttributeNS
 *  @type    method
 *  @access  public
 *  @param   namespaceURI, qualifiedName
 *  @return  void
 */
Document.prototype.createAttributeNS = function(namespaceURI, qualifiedName)
{
	//  TODO: implement Document.createAttributeNS
};

/**
 *  getElementsByTagNameNS
 *  @name    getElementsByTagNameNS
 *  @type    method
 *  @access  public
 *  @param   namespaceURI, localName
 *  @return  void
 */
Document.prototype.getElementsByTagNameNS = function(namespaceURI, localName)
{
	//  TODO: implement Document.getElementsByTagNameNS
};

/**
 *  getElementById
 *  @name    getElementById
 *  @type    method
 *  @access  public
 *  @param   elementId
 *  @return  mixed node
 */
Document.prototype.getElementById = function(elementId)
{
	//  TODO: getElementById should respect the isId property of Attr instances instead of checking for blunt 'id'
	//  The DOM implementation is expected to use the attribute Attr.isId to determine if an attribute is of type ID
	var simple = this.___simple(function(){
		return this.find(2, 'id', true).filter(function(item){
			return elementId === item.data;
		});
	});

	//  Returns the Element that has an ID attribute with the given value.
	if (simple.length === 1)
		return factory.instance(simple[0].parent);
	//  If more than one element has an ID attribute with that value, what is returned is undefined.
	else if (simple.length > 1)
		return; //  undefined

	//  If no such element exists, this returns null.
	return null;
};
// Introduced in DOM Level 3:
/**
 *  adoptNode
 *  @name    adoptNode
 *  @type    method
 *  @access  public
 *  @param   source
 *  @return  void
 */
Document.prototype.adoptNode = function(source)
{
	//  TODO: implement Document.adoptNode
};

/**
 *  normalizeDocument
 *  @name    normalizeDocument
 *  @type    method
 *  @access  public
 *  @param
 *  @return  void
 */
Document.prototype.normalizeDocument = function()
{
	//  TODO: implement Document.normalizeDocument
};

/**
 *  renameNode
 *  @name    renameNode
 *  @type    method
 *  @access  public
 *  @param   n, namespaceURI, qualifiedName
 *  @return  void
 */
Document.prototype.renameNode = function(n, namespaceURI, qualifiedName)
{
	//  TODO: implement Document.renameNode
};

//  Expose the Document module
module.exports = Document;
<commit_msg>removed console.log<commit_after>var Node = require('./node.js'),
	NodeList = require('./nodelist.js'),
	helper = require('../helper.js'),
	factory = require('../simple/factory.js'),
	sys = require('sys');

/**
 *  The Document interface represents the entire HTML or XML document. Conceptually, it is the root of the document
 *  tree, and provides the primary access to the document's data.
 *  @name    Document
 *  @type    function
 *  @access  internal
 *  @param   simple
 *  @return  void
 *  @note    Since elements, text nodes, comments, processing instructions, etc. cannot exist outside the context
 *           of a Document, the Document interface also contains the factory methods needed to create these objects.
 *           The Node objects created have a ownerDocument attribute which associates them with the Document within
 *           whose context they were created.
 */
function Document(simple)
{
	Document.super_.apply(this, [simple || factory.create(9, '#document')]);
}
//  Document extends Node
sys.inherits(Document, Node);

/**
 *  ___property
 *  @name    ___property
 *  @type    method
 *  @access  internal (exposed)
 *  @param
 *  @return  void
 */
Document.prototype.___property = function()
{
	return helper.combine({
		//  readonly attribute DocumentType doctype;
		//  The Document Type Declaration (see DocumentType) associated with this document. For XML documents
		//  without a document type declaration this returns null. For HTML documents, a DocumentType object may
		//  be returned, independently of the presence or absence of document type declaration in the HTML document.
		//  This provides direct access to the DocumentType node, child node of this Document. This node can be set
		//  at document creation time and later changed through the use of child nodes manipulation methods, such
		//  as Node.insertBefore, or Node.replaceChild. Note, however, that while some implementations may
		//  instantiate different types of Document objects supporting additional features than the "Core", such
		//  as "HTML" [DOM Level 2 HTML], based on the DocumentType specified at creation time, changing it
		//  afterwards is very unlikely to result in a change of the features supported.
		doctype: {},
		//  readonly attribute DOMImplementation implementation;
		//  The DOMImplementation object that handles this document. A DOM application may use objects from
		//  multiple implementations.
		implementation: {},
		//  readonly attribute Element documentElement;
		//  This is a convenience attribute that allows direct access to the child node that is the document
		//  element of the document.
		documentElement: {},

		// Introduced in DOM Level 3:

		//  readonly attribute DOMString inputEncoding;
		//  An attribute specifying the encoding used for this document at the time of the parsing. This is null
		//  when it is not known, such as when the Document was created in memory.
		inputEncoding: {},
		//  readonly attribute DOMString xmlEncoding;
		//  An attribute specifying, as part of the XML declaration, the encoding of this document. This is null
		//  when unspecified or when it is not known, such as when the Document was created in memory.
		xmlEncoding: {},
		//  attribute boolean xmlStandalone;
		//  An attribute specifying, as part of the XML declaration, whether this document is standalone. This is
		//  false when unspecified.
		//  Note: No verification is done on the value when setting this attribute. Applications should use
		//  Document.normalizeDocument() with the "validate" parameter to verify if the value matches the validity
		//  constraint for standalone document declaration as defined in [XML 1.0].
		//  Exceptions on setting: DOMException NOT_SUPPORTED_ERR: Raised if this document does not support the
		//  "XML" feature.
		xmlStandalone: {},
		//  attribute DOMString xmlVersion;
		//  An attribute specifying, as part of the XML declaration, the version number of this document. If there
		//  is no declaration and if this document supports the "XML" feature, the value is "1.0". If this document
		//  does not support the "XML" feature, the value is always null. Changing this attribute will affect
		//  methods that check for invalid characters in XML names. Application should invoke
		//  Document.normalizeDocument() in order to check for invalid characters in the Nodes that are already
		//  part of this Document.
		//  DOM applications may use the DOMImplementation.hasFeature(feature, version) method with parameter
		//  values "XMLVersion" and "1.0" (respectively) to determine if an implementation supports [XML 1.0]. DOM
		//  applications may use the same method with parameter values "XMLVersion" and "1.1" (respectively) to
		//  determine if an implementation supports [XML 1.1]. In both cases, in order to support XML, an
		//  implementation must also support the "XML" feature defined in this specification. Document objects
		//  supporting a version of the "XMLVersion" feature must not raise a NOT_SUPPORTED_ERR exception for the
		//  same version number when using Document.xmlVersion.
		//  Exceptions on setting: DOMException NOT_SUPPORTED_ERR: Raised if the version is set to a value that is
		//  not supported by this Document or if this document does not support the "XML" feature.
		xmlVersion: {},
		//  attribute boolean strictErrorChecking;
		//  An attribute specifying whether error checking is enforced or not. When set to false, the
		//  implementation is free to not test every possible error case normally defined on DOM operations, and
		//  not raise any DOMException on DOM operations or report errors while using Document.normalizeDocument().
		//  In case of error, the behavior is undefined. This attribute is true by default.
		strictErrorChecking: {},
		//  attribute DOMString documentURI;
		//  The location of the document or null if undefined or if the Document was created using
		//  DOMImplementation.createDocument. No lexical checking is performed when setting this attribute; this
		//  could result in a null value returned when using Node.baseURI.
		//  Beware that when the Document supports the feature "HTML" [DOM Level 2 HTML], the href attribute of the
		//  HTML BASE element takes precedence over this attribute when computing Node.baseURI.
		documentURI: {},
		//  readonly attribute DOMConfiguration domConfig;
		//  The configuration used when Document.normalizeDocument() is invoked
		domConfig: {}
	}, Node.prototype.___property());
};

/**
 *  ___get_documentElement
 *  @name    ___get_documentElement
 *  @type    method
 *  @access  internal (exposed)
 *  @param
 *  @return  void
 */
Document.prototype.___get_documentElement = function()
{
	var list = this.___simple(function(){
			return this.find(1);
		});

	return list.length > 0 ? factory.instance(list[0]) : null;
};

/**
 *  createElement
 *  @name    createElement
 *  @type    method
 *  @access  public
 *  @param   name
 *  @return  void
 */
Document.prototype.createElement = function(name)
{
	var simple = factory.create(1, name);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createTextNode
 *  @name    createTextNode
 *  @type    method
 *  @access  public
 *  @param   data
 *  @return  void
 */
Document.prototype.createTextNode = function(data)
{
	var simple = factory.create(3, '#text', data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createComment
 *  @name    createComment
 *  @type    method
 *  @access  public
 *  @param   data
 *  @return  void
 */
Document.prototype.createComment = function(data)
{
	var simple = factory.create(8, '#comment', data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createCDATASection
 *  @name    createCDATASection
 *  @type    method
 *  @access  public
 *  @param   data
 *  @return  void
 */
Document.prototype.createCDATASection = function(data)
{
	var simple = factory.create(3, '#cdata-section', data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createProcessingInstruction
 *  @name    createProcessingInstruction
 *  @type    method
 *  @access  public
 *  @param   target, data
 *  @return  void
 */
Document.prototype.createProcessingInstruction = function(target, data)
{
	var simple = factory.create(7, target, data);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createAttribute
 *  @name    createAttribute
 *  @type    method
 *  @access  public
 *  @param   name
 *  @return  void
 */
Document.prototype.createAttribute = function(name)
{
	var simple = factory.create(2, name);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  createEntityReference
 *  @name    createEntityReference
 *  @type    method
 *  @access  public
 *  @param   name
 *  @return  void
 */
Document.prototype.createEntityReference = function(name)
{
	var simple = factory.create(5, name);
	this.___simple(function(){
		simple.owner = this;
	});

	return factory.instance(simple);
};

/**
 *  Returns a NodeList of all the Elements in document order with a given tag name and are contained in the
 *  document.
 *  @name    getElementsByTagName
 *  @type    method
 *  @access  public
 *  @param   tagname
 *  @return  NodeList
 */
Document.prototype.getElementsByTagName = function(tagname)
{
	return new NodeList(this.___simple(function(){
		return this.find(1, tagname, true);
	}));
};

/**
 *  Imports a node from another document to this document, without altering or removing the source node from the
 *  original document; this method creates a new copy of the source node.
 *  @name    importNode
 *  @type    method
 *  @access  public
 *  @param   importedNode, deep
 *  @return  Node
 *  @note    The returned node has no parent; (parentNode is null). For all nodes, importing a node creates a node
 *           object owned by the importing document, with attribute values identical to the source node's nodeName
 *           and nodeType, plus the attributes related to namespaces (prefix, localName, and namespaceURI). As in
 *           the cloneNode operation, the source node is not altered. User data associated to the imported node is
 *           not carried over. However, if any UserDataHandlers has been specified along with the associated data
 *           these handlers will be called with the appropriate parameters before this method returns.
 *           Additional information is copied as appropriate to the nodeType, attempting to mirror the behavior
 *           expected if a fragment of XML or HTML source was copied from one document to another, recognizing that
 *           the two documents may have different DTDs in the XML case. The following list describes the specifics
 *           for each type of node.
 *  @note    Attr nodes are copied including its children, regardless of the deep argument
 *  @note    DocumentFragment nodes are copied respecting the deep argument
 *  @note    Document nodes cannot be imported
 *  @note    DocumentType nodes cannot be imported
 *  @note    Element nodes are copied, including any Attr child regardless of the deep argument
 *  @note    Entity nodes can be imported, however these can not be added to the DocumentType as it is read-only in
 *           DOM level 3
 *  @note    EntityReference nodes will be copied without any children, even if a deep import is requested, since
 *           the source and destination documents might have defined the entity differently. If the document being
 *           imported into provides a definition for this entity name, its value is assigned.
 *  @note    Notation nodes can be imported, however in DOM level 3 the DocumentType is readonly
 *  @note    ProcessingInstruction, Text, CDataSection and Comment nodes will be copied nodes will be copied (as
 *           these cannot contain child nodes the deep argument has no effect)
 */
Document.prototype.importNode = function(importedNode, deep)
{
	var simple;

	this.___simple(function(){
		simple = this;
	});

	return factory.instance(importedNode.___simple(function(){
		return this.clone(deep, simple);
	}));
};

/**
 *  createElementNS
 *  @name    createElementNS
 *  @type    method
 *  @access  public
 *  @param   namespaceURI, qualifiedName
 *  @return  void
 */
Document.prototype.createElementNS = function(namespaceURI, qualifiedName)
{
	//  TODO: implement Document.createElementNS
};

/**
 *  createAttributeNS
 *  @name    createAttributeNS
 *  @type    method
 *  @access  public
 *  @param   namespaceURI, qualifiedName
 *  @return  void
 */
Document.prototype.createAttributeNS = function(namespaceURI, qualifiedName)
{
	//  TODO: implement Document.createAttributeNS
};

/**
 *  getElementsByTagNameNS
 *  @name    getElementsByTagNameNS
 *  @type    method
 *  @access  public
 *  @param   namespaceURI, localName
 *  @return  void
 */
Document.prototype.getElementsByTagNameNS = function(namespaceURI, localName)
{
	//  TODO: implement Document.getElementsByTagNameNS
};

/**
 *  getElementById
 *  @name    getElementById
 *  @type    method
 *  @access  public
 *  @param   elementId
 *  @return  mixed node
 */
Document.prototype.getElementById = function(elementId)
{
	//  TODO: getElementById should respect the isId property of Attr instances instead of checking for blunt 'id'
	//  The DOM implementation is expected to use the attribute Attr.isId to determine if an attribute is of type ID
	var simple = this.___simple(function(){
		return this.find(2, 'id', true).filter(function(item){
			return elementId === item.data;
		});
	});

	//  Returns the Element that has an ID attribute with the given value.
	if (simple.length === 1)
		return factory.instance(simple[0].parent);
	//  If more than one element has an ID attribute with that value, what is returned is undefined.
	else if (simple.length > 1)
		return; //  undefined

	//  If no such element exists, this returns null.
	return null;
};
// Introduced in DOM Level 3:
/**
 *  adoptNode
 *  @name    adoptNode
 *  @type    method
 *  @access  public
 *  @param   source
 *  @return  void
 */
Document.prototype.adoptNode = function(source)
{
	//  TODO: implement Document.adoptNode
};

/**
 *  normalizeDocument
 *  @name    normalizeDocument
 *  @type    method
 *  @access  public
 *  @param
 *  @return  void
 */
Document.prototype.normalizeDocument = function()
{
	//  TODO: implement Document.normalizeDocument
};

/**
 *  renameNode
 *  @name    renameNode
 *  @type    method
 *  @access  public
 *  @param   n, namespaceURI, qualifiedName
 *  @return  void
 */
Document.prototype.renameNode = function(n, namespaceURI, qualifiedName)
{
	//  TODO: implement Document.renameNode
};

//  Expose the Document module
module.exports = Document;
<|endoftext|>


<commit_before>import Ember from 'ember';

/**
  * @overview OAuth2 library for Emberjs that stores tokens in the browsers localStorage
  * @license   Licensed under MIT license
  *            See https://raw.github.com/amkirwan/ember-oauth2/master/LICENSE
  * @version   0.5.0
  *
  * @module ember-oauth2
  * @class ember-oauth2
  */
export default Ember.Object.extend(Ember.Evented, {
  /**
   * Initializes the Ember.OAuth2 object when using Ember.OAuth2.create({providerId: 'providerId'}). The following options are available for the configuring a provider: clientId, authBaseUri, redirectUri, scope, statePrefix and tokenPrefix. The clientId, authBaseUri and redirectUri are required. The statePrefix has a default value of 'state' and the tokenPrefix has a default value of 'token'.
   *
   * @method init
   */
  init: function() {
    this._super();
    /**
     * The configuration object for the given provider id.
     *  @property {Object} providerConfig
     *  @property {Object} providerConfig.providerId **Required**
     *  @property {String} providerConfig.providerId.clientId **Required**
     *  @property {String} providerConfig.providerId.authBaseUri **Required**
     *  @property {String} providerConfig.providerId.redirectUri **Required**
     *  @property {String} providerConfig.providerId.scope **Optional**
     *  @property {String} providerConfig.providerId.statePrefix **Default:** "state", **Optional**
     *  @property {String} providerConfig.providerId.tokenPrefix **Default:** "prefix", **Optional**
     *  @example
     *    App.oauth = Ember.OAuth2.create({providerId: 'google'});
     */

    // if Ember.OAuth2.config has keys use it instead of window.ENV
    if (Ember.OAuth2 && Ember.OAuth2.config && Object.keys(Ember.OAuth2.config).length) {
      Ember.Logger.warn("Ember.OAuth2.config is deprecated and will be removed in future versions. Set the config using window.ENV['ember-oauth2']");
      this.providerConfig = Ember.OAuth2.config[this.get('providerId')];
    } else {
      this.providerConfig = window.ENV['ember-oauth2'][this.get('providerId')];
    }
    /**
     * The prefix name for the state key stored in the localStorage.
     *
     * @property statePrefix
     * @type String
     * @default "state"
     */
    this.set('statePrefix', 'state');
    /**
     * The prefix name for the token key stored in the localStorage.
     *
     * @property tokenPrefix
     * @type String
     * @default "token"
     */
    this.set('tokenPrefix', 'token');

    /**
     * @property {String} clientId
     */
    /**
     * @property {String} authBaseUri
     */
    /**
     * @property {String} redirectUri
     */
    /**
     * @property {String} scope
     */
    // sets the properties from the providerConfig and overrides any default settings.
    this.setProperties(this.providerConfig);

    // Bind deprecated event handlers
    /**
     * @event redirect
     * @param {function} The function that handles the redirect.
     */
    this.on('redirect', this.handleRedirect);

    /**
     * @event success
     * @param {function} The function that handles the success callback.
     */
    this.on('success', this._onSuccess);

    /**
     * @event error
     * @param {function} The function that handles the error callback.
     */
    this.on('error', this._onError);
  },

  /**
   * @method version
   * @return {String} The current version number of Ember.OAuth2
   */
  version: function() {
    return VERSION;
  },

  /**
   * @method uuid
   * @return {String} A pseudo random uuid
   */
  uuid: function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
          var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
              return v.toString(16);
    });
  },

  /**
   * @method now
   * @return {Number} The current time in seconds rounded
   */
  now: function() {
    return Math.round(new Date().getTime()/1000.0);
  },

  /**
   * Creates and returns the request object.
   *
   * @method requestObj
   * @return {Object} request object
   */
  requestObj: function() {
    var request = { 'response_type': 'token' };
    request.providerId = this.get('providerId');
    request.state = this.get('state');
    request.client_id = this.get('clientId');
    request.state = this.get('state');
    if (this.get('scope')) request.scope = this.get('scope');
    return request;
  },

  /**
   * @method authUri
   * @return {String} Authorization uri for generating an OAuth2 token
   */
  authUri: function() {
    if (this.get('state') === null) this.set('state', this.uuid());
    var uri = this.get('authBaseUri');
    uri += '?response_type=token' +
        '&redirect_uri=' + encodeURIComponent(this.get('redirectUri')) +
        '&client_id=' + encodeURIComponent(this.get('clientId')) +
        '&state=' + encodeURIComponent(this.get('state'));
    if (this.get('scope')) uri += '&scope=' + encodeURIComponent(this.get('.scope')).replace('%20', '+');
    return uri;
  },

  /**
   * Open authorize window if the configuration object is valid.
   *
   * @method authorize
   * @return {Promise}
   */
  authorize: function() {
    if (!this.get('providerId')) throw new Error('No provider id given.');
    if (!this.get('clientId')) throw new Error('No client id given.');
    if (!this.get('authBaseUri')) throw new Error('No auth base uri given.');
    if (!this.get('redirectUri')) throw new Error('No redirect uri given.');
    var authorizeUri = this.authUri();
    this.clearStates();
    this.saveState(this.get('state'), this.requestObj());
    return this.openWindow(authorizeUri);
  },

  /**
   * Isolated function responsible for opening windows, to make it
   * easier to override this part in some environments (e.g. Phonegap)

    @param {String} url
    @return {Object} On resolve returns reference to the opened window.
                    On reject returns Object with reference to dialog and error.
   */
  openWindow: function(url) {
    var dialog = window.open(url, 'Authorize', 'height=600, width=450');
    if (window.focus && dialog) { dialog.focus(); }
    var self = this;
    return new Ember.RSVP.Promise(function(resolve, reject) {
      if (dialog) { resolve(dialog); }
      else { reject(new Error('Opening dialog login window failed.')); }
    });
  },

  /**
   @method authSuccess
    @param {Object} The params returned from the OAuth2 callback
    @return {String} the access_token from the params
  */
  authSuccess: function(params) {
    return params.access_token;
  },

  /**
   * Token properties
   * providerId
   * expiresIn
   * scope
   * token

    @method generateToken
    @return {Object} The access_token object with info about the token
   */
  generateToken: function(params) {
    var token = {};
    token.provider_id = this.get('providerId');
    token.expires_in = this.expiresIn(params.expires_in);
    token.scope = this.get('scope');
    token.access_token = params.access_token;
    return token;
  },

  /**
    @method expiresIn
    @return {Number} When the token expires in seconds.
  */
  expiresIn: function(expires) {
    return this.now() + parseInt(expires, 10);
  },

  /**
   * call on redirect from OAuth2 provider response
    @method onRedirect
    @deprecated Use `.trigger('redirect')` instead.
   */
  onRedirect: function(hash, callback) {
    Ember.Logger.warn("Ember.OAuth2.onRedirect is deprecated and will be removed in future versions. Please use .trigger('redirect') instead.");
    this.trigger('redirect', hash, callback);
  },

  /*
   * proxy functions for old event handlers
   *
   * Check if the token returned is valid and if so trigger `success` event else trigger `error`
   *
   * @method handleRedirect
   */
  handleRedirect: function(hash, callback) {
    var params = this.parseCallback(hash);
    if (this.authSuccess(params)) {
      var stateObj = this.getState(params.state);
      this.checkState(stateObj);
      this.saveToken(this.generateToken(params));
      this.trigger('success', stateObj);
    } else {
      this.trigger('error', params);
    }
    if (callback && typeof(callback) === "function") {
      callback();
    }
  },

  /**
   * This method will call the old onSuccess callback when using the old API: Ember.OAuth2.reopen({ onSuccess: function() { return 'hello, onSuccess' } });
   *
   * The old onSuccess method will only be called when onSuccess is defined as a function on the Ember.OAuth2 instance
   *
   * @method _onSuccess
   * @param {Object} stateObj
   * @private
   */
  _onSuccess: function(stateObj) {
    if (typeof(this.onSuccess) !== 'function')
      return;

    Ember.Logger.warn("Ember.OAuth2.onSuccess is deprecated and will be removed in future versions. Bind your callbacks using .on('success', fn) instead.");
    this.onSuccess(stateObj);
  },

  /**
   * This method will call the old onError callback when using the old API: Ember.OAuth2.reopen({ onError: function() { return 'hello, onError' } });
   *
   * The old onSuccess method will only be called when onError is defined as a function on the Ember.OAuth2 instance
   *
   * @method _onError
   * @param {Object} err object
   * @private
   */
  _onError: function(err) {
    if (typeof(this.onError) !== 'function')
      return;

    Ember.Logger.warn("Ember.OAuth2.onError is deprecated and will be removed in furture versions. Bind your callbacks using .on('error', fn) instead.");
    this.onError(err);
  },

  /**
   * Checks if the State returned from the server matches the state that was generated in the original request and saved in the browsers localStorage.
   *
   * @method checkState
   * @param {Object} stateObj The object returned from localStorage
   */
  checkState: function(stateObj) {
    if (!stateObj) throw new Error("Could not find state.");
    if (stateObj.state !== this.get('state')) throw new Error("State returned from the server did not match the local saved state.");
  },

  /**
   * Parse the callback function from the OAuth2 provider
   *
   * callback should have the following params if authentication is successful
   * state
   * access_token
   * token_type
   * expires_in
   *
   * @method parseCalback
   * @param {String} locationHash
   * @return {Object} The params returned from the OAuth2 provider
   */
  parseCallback: function(locationHash) {
    var oauthParams = {};
    var queryString = locationHash.substring(1);
    var regex = /([^#?&=]+)=([^&]*)/g;
    var match;
    while ((match = regex.exec(queryString)) !== null) {
      oauthParams[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
    }
    return oauthParams;
  },

  /**
   * @method saveState
   * @param {String} state The state uuid
   * @param {Object} requestObj Properties of the request state to save in localStorage
   */
  saveState: function(state, requestObj) {
    window.localStorage.setItem(this.get('statePrefix') + '-' + state, JSON.stringify(requestObj));
  },

  /**
   * Return the saved state and remove it from the localStoage.
   *
   * @method getState
   * @param {String} state The state uuid to retreive from localStorage
   * @return {Object} Properties of the request state
   */
  getState: function(state) {
    var obj = JSON.parse(window.localStorage.getItem(this.get('statePrefix') + '-'  + state));
    window.localStorage.removeItem(this.get('statePrefix') + '-' + state);

    return obj;
  },

  /**
    * Remove any states from localStorage if they exist
    * @method clearStates
    * @return {Array} Keys used to remove states from localStorage
    */
  clearStates: function() {
    var regex = new RegExp( '^' + this.get('statePrefix') + '-.*', 'g');

    var name;
    var toRemove = [];
    for(var i = 0, l = window.localStorage.length; i < l; i++) {
      name = window.localStorage.key(i);
      if (name.match(regex)) {
        toRemove.push(name);
      }
    }

    for(var j = 0, len = toRemove.length; j < len; j++) {
      name = toRemove[j];
      window.localStorage.removeItem(name);
    }
    return toRemove;
  },

  /**
   * saveToken stores the token by the tokenPrefix and the providerId
   * access_token
   * expires : time that the token expires
   * providerId: the providerId
   * scopes: array of scopes
   *
   * @method saveToken
   * @param {Object} token Saves the params in the response from the OAuth2 server to localStorage with the key 'tokenPrefix-providerId
   */
  saveToken: function(token) {
    window.localStorage.setItem(this.get('tokenPrefix') + '-' + this.get('providerId'), JSON.stringify(token));
  },

  /**
   * @method getToken
   * @return {Object} The params from the OAuth2 response from localStorage with the key 'tokenPrefix-providerId'.
   */
  getToken: function() {
    var token = JSON.parse(window.localStorage.getItem( this.get('tokenPrefix') + '-' + this.get('providerId')));
    if (!token) return null;
    if (!token.access_token) return null;
    return token;
  },

  /**
   * @method getAccessToken
   * @return {Object} The access_token param from the OAuth2 response from localStorage with the key 'tokenPrefix-providerId'.
   */
  getAccessToken: function() {
    var token = this.getToken();
    if (!token) return null;
    return token.access_token;
  },

  /**
   * @method accessTokenIsExpired
   * @return {Boolean} Check if the access_token is expired.
   */
  accessTokenIsExpired: function() {
    var token = this.getToken();
    if (!token) return true;
    if (this.now() >= token.expires_in) {
      return true;
    } else {
      return false;
    }
  },

  /**
   * Sets the access token expires_in time to 0 and saves the token to localStorage
   * @method expireAccessToken
   */
  expireAccessToken: function() {
    var token = this.getToken();
    if (!token) return null;
    token.expires_in = 0;
    this.saveToken(token);
  }
});

/**
 * @property {String} VERSION
 * @final
*/
var VERSION = "0.5.0";

/**
 * @method version
 * @static
 */
if (Ember.OAuth2) {
 Ember.OAuth2.version = VERSION;
}
<commit_msg>fix bug where the uuid for the state is not set<commit_after>import Ember from 'ember';

/**
  * @overview OAuth2 library for Emberjs that stores tokens in the browsers localStorage
  * @license   Licensed under MIT license
  *            See https://raw.github.com/amkirwan/ember-oauth2/master/LICENSE
  * @version   0.5.0
  *
  * @module ember-oauth2
  * @class ember-oauth2
  */
export default Ember.Object.extend(Ember.Evented, {
  /**
   * Initializes the Ember.OAuth2 object when using Ember.OAuth2.create({providerId: 'providerId'}). The following options are available for the configuring a provider: clientId, authBaseUri, redirectUri, scope, statePrefix and tokenPrefix. The clientId, authBaseUri and redirectUri are required. The statePrefix has a default value of 'state' and the tokenPrefix has a default value of 'token'.
   *
   * @method init
   */
  init: function() {
    this._super();
    /**
     * The configuration object for the given provider id.
     *  @property {Object} providerConfig
     *  @property {Object} providerConfig.providerId **Required**
     *  @property {String} providerConfig.providerId.clientId **Required**
     *  @property {String} providerConfig.providerId.authBaseUri **Required**
     *  @property {String} providerConfig.providerId.redirectUri **Required**
     *  @property {String} providerConfig.providerId.scope **Optional**
     *  @property {String} providerConfig.providerId.statePrefix **Default:** "state", **Optional**
     *  @property {String} providerConfig.providerId.tokenPrefix **Default:** "prefix", **Optional**
     *  @example
     *    App.oauth = Ember.OAuth2.create({providerId: 'google'});
     */

    // if Ember.OAuth2.config has keys use it instead of window.ENV
    if (Ember.OAuth2 && Ember.OAuth2.config && Object.keys(Ember.OAuth2.config).length) {
      Ember.Logger.warn("Ember.OAuth2.config is deprecated and will be removed in future versions. Set the config using window.ENV['ember-oauth2']");
      this.providerConfig = Ember.OAuth2.config[this.get('providerId')];
    } else {
      this.providerConfig = window.ENV['ember-oauth2'][this.get('providerId')];
    }
    /**
     * The prefix name for the state key stored in the localStorage.
     *
     * @property statePrefix
     * @type String
     * @default "state"
     */
    this.set('statePrefix', 'state');
    /**
     * The prefix name for the token key stored in the localStorage.
     *
     * @property tokenPrefix
     * @type String
     * @default "token"
     */
    this.set('tokenPrefix', 'token');

    /**
     * @property {String} clientId
     */
    /**
     * @property {String} authBaseUri
     */
    /**
     * @property {String} redirectUri
     */
    /**
     * @property {String} scope
     */
    // sets the properties from the providerConfig and overrides any default settings.
    this.setProperties(this.providerConfig);

    // Bind deprecated event handlers
    /**
     * @event redirect
     * @param {function} The function that handles the redirect.
     */
    this.on('redirect', this.handleRedirect);

    /**
     * @event success
     * @param {function} The function that handles the success callback.
     */
    this.on('success', this._onSuccess);

    /**
     * @event error
     * @param {function} The function that handles the error callback.
     */
    this.on('error', this._onError);
  },

  /**
   * @method version
   * @return {String} The current version number of Ember.OAuth2
   */
  version: function() {
    return VERSION;
  },

  /**
   * @method uuid
   * @return {String} A pseudo random uuid
   */
  uuid: function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
          var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
              return v.toString(16);
    });
  },

  /**
   * @method now
   * @return {Number} The current time in seconds rounded
   */
  now: function() {
    return Math.round(new Date().getTime()/1000.0);
  },

  /**
   * Creates and returns the request object.
   *
   * @method requestObj
   * @return {Object} request object
   */
  requestObj: function() {
    var request = { 'response_type': 'token' };
    request.providerId = this.get('providerId');
    request.state = this.get('state');
    request.client_id = this.get('clientId');
    request.state = this.get('state');
    if (this.get('scope')) request.scope = this.get('scope');
    return request;
  },

  /**
   * @method authUri
   * @return {String} Authorization uri for generating an OAuth2 token
   */
  authUri: function() {
    if (!this.get('state')) { this.set('state', this.uuid()); }
    var uri = this.get('authBaseUri');
    uri += '?response_type=token' +
        '&redirect_uri=' + encodeURIComponent(this.get('redirectUri')) +
        '&client_id=' + encodeURIComponent(this.get('clientId')) +
        '&state=' + encodeURIComponent(this.get('state'));
    if (this.get('scope')) uri += '&scope=' + encodeURIComponent(this.get('.scope')).replace('%20', '+');
    return uri;
  },

  /**
   * Open authorize window if the configuration object is valid.
   *
   * @method authorize
   * @return {Promise}
   */
  authorize: function() {
    if (!this.get('providerId')) throw new Error('No provider id given.');
    if (!this.get('clientId')) throw new Error('No client id given.');
    if (!this.get('authBaseUri')) throw new Error('No auth base uri given.');
    if (!this.get('redirectUri')) throw new Error('No redirect uri given.');
    var authorizeUri = this.authUri();
    this.clearStates();
    this.saveState(this.get('state'), this.requestObj());
    return this.openWindow(authorizeUri);
  },

  /**
   * Isolated function responsible for opening windows, to make it
   * easier to override this part in some environments (e.g. Phonegap)

    @param {String} url
    @return {Object} On resolve returns reference to the opened window.
                    On reject returns Object with reference to dialog and error.
   */
  openWindow: function(url) {
    var dialog = window.open(url, 'Authorize', 'height=600, width=450');
    if (window.focus && dialog) { dialog.focus(); }
    var self = this;
    return new Ember.RSVP.Promise(function(resolve, reject) {
      if (dialog) { resolve(dialog); }
      else { reject(new Error('Opening dialog login window failed.')); }
    });
  },

  /**
   @method authSuccess
    @param {Object} The params returned from the OAuth2 callback
    @return {String} the access_token from the params
  */
  authSuccess: function(params) {
    return params.access_token;
  },

  /**
   * Token properties
   * providerId
   * expiresIn
   * scope
   * token

    @method generateToken
    @return {Object} The access_token object with info about the token
   */
  generateToken: function(params) {
    var token = {};
    token.provider_id = this.get('providerId');
    token.expires_in = this.expiresIn(params.expires_in);
    token.scope = this.get('scope');
    token.access_token = params.access_token;
    return token;
  },

  /**
    @method expiresIn
    @return {Number} When the token expires in seconds.
  */
  expiresIn: function(expires) {
    return this.now() + parseInt(expires, 10);
  },

  /**
   * call on redirect from OAuth2 provider response
    @method onRedirect
    @deprecated Use `.trigger('redirect')` instead.
   */
  onRedirect: function(hash, callback) {
    Ember.Logger.warn("Ember.OAuth2.onRedirect is deprecated and will be removed in future versions. Please use .trigger('redirect') instead.");
    this.trigger('redirect', hash, callback);
  },

  /*
   * proxy functions for old event handlers
   *
   * Check if the token returned is valid and if so trigger `success` event else trigger `error`
   *
   * @method handleRedirect
   */
  handleRedirect: function(hash, callback) {
    var params = this.parseCallback(hash);
    if (this.authSuccess(params)) {
      var stateObj = this.getState(params.state);
      this.checkState(stateObj);
      this.saveToken(this.generateToken(params));
      this.trigger('success', stateObj);
    } else {
      this.trigger('error', params);
    }
    if (callback && typeof(callback) === "function") {
      callback();
    }
  },

  /**
   * This method will call the old onSuccess callback when using the old API: Ember.OAuth2.reopen({ onSuccess: function() { return 'hello, onSuccess' } });
   *
   * The old onSuccess method will only be called when onSuccess is defined as a function on the Ember.OAuth2 instance
   *
   * @method _onSuccess
   * @param {Object} stateObj
   * @private
   */
  _onSuccess: function(stateObj) {
    if (typeof(this.onSuccess) !== 'function')
      return;

    Ember.Logger.warn("Ember.OAuth2.onSuccess is deprecated and will be removed in future versions. Bind your callbacks using .on('success', fn) instead.");
    this.onSuccess(stateObj);
  },

  /**
   * This method will call the old onError callback when using the old API: Ember.OAuth2.reopen({ onError: function() { return 'hello, onError' } });
   *
   * The old onSuccess method will only be called when onError is defined as a function on the Ember.OAuth2 instance
   *
   * @method _onError
   * @param {Object} err object
   * @private
   */
  _onError: function(err) {
    if (typeof(this.onError) !== 'function')
      return;

    Ember.Logger.warn("Ember.OAuth2.onError is deprecated and will be removed in furture versions. Bind your callbacks using .on('error', fn) instead.");
    this.onError(err);
  },

  /**
   * Checks if the State returned from the server matches the state that was generated in the original request and saved in the browsers localStorage.
   *
   * @method checkState
   * @param {Object} stateObj The object returned from localStorage
   */
  checkState: function(stateObj) {
    if (!stateObj) throw new Error("Could not find state.");
    if (stateObj.state !== this.get('state')) throw new Error("State returned from the server did not match the local saved state.");
  },

  /**
   * Parse the callback function from the OAuth2 provider
   *
   * callback should have the following params if authentication is successful
   * state
   * access_token
   * token_type
   * expires_in
   *
   * @method parseCalback
   * @param {String} locationHash
   * @return {Object} The params returned from the OAuth2 provider
   */
  parseCallback: function(locationHash) {
    var oauthParams = {};
    var queryString = locationHash.substring(1);
    var regex = /([^#?&=]+)=([^&]*)/g;
    var match;
    while ((match = regex.exec(queryString)) !== null) {
      oauthParams[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
    }
    return oauthParams;
  },

  /**
   * @method saveState
   * @param {String} state The state uuid
   * @param {Object} requestObj Properties of the request state to save in localStorage
   */
  saveState: function(state, requestObj) {
    window.localStorage.setItem(this.get('statePrefix') + '-' + state, JSON.stringify(requestObj));
  },

  /**
   * Return the saved state and remove it from the localStoage.
   *
   * @method getState
   * @param {String} state The state uuid to retreive from localStorage
   * @return {Object} Properties of the request state
   */
  getState: function(state) {
    var obj = JSON.parse(window.localStorage.getItem(this.get('statePrefix') + '-'  + state));
    window.localStorage.removeItem(this.get('statePrefix') + '-' + state);

    return obj;
  },

  /**
    * Remove any states from localStorage if they exist
    * @method clearStates
    * @return {Array} Keys used to remove states from localStorage
    */
  clearStates: function() {
    var regex = new RegExp( '^' + this.get('statePrefix') + '-.*', 'g');

    var name;
    var toRemove = [];
    for(var i = 0, l = window.localStorage.length; i < l; i++) {
      name = window.localStorage.key(i);
      if (name.match(regex)) {
        toRemove.push(name);
      }
    }

    for(var j = 0, len = toRemove.length; j < len; j++) {
      name = toRemove[j];
      window.localStorage.removeItem(name);
    }
    return toRemove;
  },

  /**
   * saveToken stores the token by the tokenPrefix and the providerId
   * access_token
   * expires : time that the token expires
   * providerId: the providerId
   * scopes: array of scopes
   *
   * @method saveToken
   * @param {Object} token Saves the params in the response from the OAuth2 server to localStorage with the key 'tokenPrefix-providerId
   */
  saveToken: function(token) {
    window.localStorage.setItem(this.get('tokenPrefix') + '-' + this.get('providerId'), JSON.stringify(token));
  },

  /**
   * @method getToken
   * @return {Object} The params from the OAuth2 response from localStorage with the key 'tokenPrefix-providerId'.
   */
  getToken: function() {
    var token = JSON.parse(window.localStorage.getItem( this.get('tokenPrefix') + '-' + this.get('providerId')));
    if (!token) return null;
    if (!token.access_token) return null;
    return token;
  },

  /**
   * @method getAccessToken
   * @return {Object} The access_token param from the OAuth2 response from localStorage with the key 'tokenPrefix-providerId'.
   */
  getAccessToken: function() {
    var token = this.getToken();
    if (!token) return null;
    return token.access_token;
  },

  /**
   * @method accessTokenIsExpired
   * @return {Boolean} Check if the access_token is expired.
   */
  accessTokenIsExpired: function() {
    var token = this.getToken();
    if (!token) return true;
    if (this.now() >= token.expires_in) {
      return true;
    } else {
      return false;
    }
  },

  /**
   * Sets the access token expires_in time to 0 and saves the token to localStorage
   * @method expireAccessToken
   */
  expireAccessToken: function() {
    var token = this.getToken();
    if (!token) return null;
    token.expires_in = 0;
    this.saveToken(token);
  }
});

/**
 * @property {String} VERSION
 * @final
*/
var VERSION = "0.5.0";

/**
 * @method version
 * @static
 */
if (Ember.OAuth2) {
 Ember.OAuth2.version = VERSION;
}
<|endoftext|>


<commit_before>var Q        = require('q');
var logger   = require('../logger');
var versions = require('../versions');
var semver   = require('semver');
var _        = require('lodash');
var iojs     = require('./iojs');

function resolveNodeVersion (desired, versions) {
  var version;

  logger.debug('resolving node version %s', desired || 'undefined');

  if (desired === 'latest' || desired === '*') {
    return versions.latest;
  } else {
    version = semver.maxSatisfying(versions.all, desired || null);
  }

  return version;
}

exports.resolveVersion = function (options) {
  var deferred = Q.defer();

  if (options.engines.iojs) return iojs.resolveVersion(options);

  versions
    .getNodeVersions()
    .then(function(versions) {
      var version = resolveNodeVersion(options.engines.node, versions);
      if (version) return deferred.resolve(version);
      if (!options.engines.node) {
        logger.info('no node version specified, using latest version');
        return deferred.resolve(versions.latest);
      }
      logger.info('no node version found, falling back to iojs');
      var extendedOptions = _.extend(options, {
        engines: { iojs: options.engines.node },
        allowBlank: true
      });
      iojs.resolveVersion(extendedOptions).then(function (ioVersion) {
        deferred.resolve(ioVersion || versions.latest);
      });
    });

  return deferred.promise;
};
<commit_msg>Remove unnecessary variable assignment<commit_after>var Q        = require('q');
var logger   = require('../logger');
var versions = require('../versions');
var semver   = require('semver');
var _        = require('lodash');
var iojs     = require('./iojs');

function resolveNodeVersion (desired, versions) {
  logger.debug('resolving node version %s', desired || 'undefined');

  if (desired === 'latest' || desired === '*') {
    return versions.latest;
  }
  return semver.maxSatisfying(versions.all, desired || null);
}

exports.resolveVersion = function (options) {
  var deferred = Q.defer();

  if (options.engines.iojs) return iojs.resolveVersion(options);

  versions
    .getNodeVersions()
    .then(function(versions) {
      var version = resolveNodeVersion(options.engines.node, versions);
      if (version) return deferred.resolve(version);
      if (!options.engines.node) {
        logger.info('no node version specified, using latest version');
        return deferred.resolve(versions.latest);
      }
      logger.info('no node version found, falling back to iojs');
      var extendedOptions = _.extend(options, {
        engines: { iojs: options.engines.node },
        allowBlank: true
      });
      iojs.resolveVersion(extendedOptions).then(function (ioVersion) {
        deferred.resolve(ioVersion || versions.latest);
      });
    });

  return deferred.promise;
};
<|endoftext|>


<commit_before>'use strict';

let EPGPArchive = require('./models/archive');
let EPGPCharacter = require('./models/character');
let characterService = require('../character/service');
let guildService = require('../guild/service');
let _ = require('lodash');
let mongoose = require('mongoose');
let ObjectId = mongoose.Schema.ObjectId;

// Returns a promise resolving the archive request
function archiveEPGP(guildName, epgpData) {
  return new Promise((resolve, reject) => {
    guildService
      .getGuild(guildName)
      .then((guild) => {
        if(!guild) {
          reject('Unable to find guild: ' + guildName);
        }

        var archive = new EPGPArchive({
          data: epgpData,
          guildId: guild._id
        });

        archive.save(function(err, archive) {
          if(err) {
            reject(err);
          }
          resolve(JSON.parse(archive.data));
        });
      });
  });
}

function bulkUpdateCharacters(epgpData) {
  return new Promise((resolve, reject) => {
    let charactersPromises = [];

    let epgpCharObjs = [];

    _.forEach(epgpData.roster, (member) => {
      let character = member[0].split('-')[0];

      let characterEPGP = {
        character: character,
        totalEarned: member[1],
        totalSpent: member[2]
      };

      charactersPromises.push(
        updateCharacter(epgpData.guild, character, characterEPGP)
      );
    });

    Promise.all(charactersPromises)
      .then((data) => {
        resolve(epgpData);
      }, (error) => {
        reject(error);
      });
  });
}

function getEPGP(guildName, characterName) {
  return new Promise((resolve, reject) => {
    characterService
      .getCharacters(guildName, characterName)
      .then((character) => {
        if(!character) {
          reject('Unable to find characterName: ' + character);
        }

        EPGPCharacter
          .find({characterId: character._id})
          .exec()
          .then((epgpData) => {
            resolve(epgpData);
          }, (error) => {
            reject(error);
          });
      }, (error) => {
        reject(error);
      });
  });
}

function getMembersEPGP(guildName) {
  return new Promise((resolve, reject) => {
    characterService
      .getCharacters(guildName)
      .then((character) => {

        EPGPCharacter
          .find()
          .populate({
            path: 'characterId',
            select: 'name rank thumbnail level gender race class items'
          })
          .exec()
          .then((epgpData) => {
            resolve(epgpData);
          }, (error) => {
            reject(error);
          });
      }, (error) => {
        reject(error);
      });
  });
}

function getRaidersEPGP(guildName) {
  return new Promise((resolve, reject) => {
    characterService
      .getCharacters(guildName)
      .then((character) => {

        EPGPCharacter
          .find({characterId: { $ne: null}})
          .populate({
            path: 'characterId',
            select: 'name rank thumbnail level gender race class items',
            match: {
              rank: { $in: [0, 1, 4, 5] }
            }
          })
          .exec()
          .then((epgpData) => {
            resolve(
              _.sortBy(
                _.filter(epgpData, (o) => { return o.characterId; }),
                function(item) {
                  return [item.characterId.name];
                }
              )
            );
          }, (error) => {
            reject(error);
          });
      }, (error) => {
        reject(error);
      });
  });
}

function updateCharacter(guildName, characterName, epgpData) {
  return new Promise((resolve, reject) => {
    characterService.findOrCreateCharacter(guildName, characterName)
      .then((character) => {

        EPGPCharacter
           .findOneAndUpdate({characterId: character._id}, epgpData, {upsert: true})
           .exec()
           .then((data) => {
             resolve(data);
           }, (error) => {
             reject(error);
           });
      });
  });
}

function updateGuildConfig(epgpData) {
  return new Promise((resolve, reject) => {
    resolve(epgpData);
  });
}

module.exports = {
  archiveEPGP: archiveEPGP,
  bulkUpdateCharacters: bulkUpdateCharacters,
  getEPGP: getEPGP,
  getMembersEPGP: getMembersEPGP,
  getRaidersEPGP: getRaidersEPGP,
  updateCharacter: updateCharacter,
  updateGuildConfig: updateGuildConfig
};
<commit_msg>Added spec<commit_after>'use strict';

let EPGPArchive = require('./models/archive');
let EPGPCharacter = require('./models/character');
let characterService = require('../character/service');
let guildService = require('../guild/service');
let _ = require('lodash');
let mongoose = require('mongoose');
let ObjectId = mongoose.Schema.ObjectId;

// Returns a promise resolving the archive request
function archiveEPGP(guildName, epgpData) {
  return new Promise((resolve, reject) => {
    guildService
      .getGuild(guildName)
      .then((guild) => {
        if(!guild) {
          reject('Unable to find guild: ' + guildName);
        }

        var archive = new EPGPArchive({
          data: epgpData,
          guildId: guild._id
        });

        archive.save(function(err, archive) {
          if(err) {
            reject(err);
          }
          resolve(JSON.parse(archive.data));
        });
      });
  });
}

function bulkUpdateCharacters(epgpData) {
  return new Promise((resolve, reject) => {
    let charactersPromises = [];

    let epgpCharObjs = [];

    _.forEach(epgpData.roster, (member) => {
      let character = member[0].split('-')[0];

      let characterEPGP = {
        character: character,
        totalEarned: member[1],
        totalSpent: member[2]
      };

      charactersPromises.push(
        updateCharacter(epgpData.guild, character, characterEPGP)
      );
    });

    Promise.all(charactersPromises)
      .then((data) => {
        resolve(epgpData);
      }, (error) => {
        reject(error);
      });
  });
}

function getEPGP(guildName, characterName) {
  return new Promise((resolve, reject) => {
    characterService
      .getCharacters(guildName, characterName)
      .then((character) => {
        if(!character) {
          reject('Unable to find characterName: ' + character);
        }

        EPGPCharacter
          .find({characterId: character._id})
          .exec()
          .then((epgpData) => {
            resolve(epgpData);
          }, (error) => {
            reject(error);
          });
      }, (error) => {
        reject(error);
      });
  });
}

function getMembersEPGP(guildName) {
  return new Promise((resolve, reject) => {
    characterService
      .getCharacters(guildName)
      .then((character) => {

        EPGPCharacter
          .find()
          .populate({
            path: 'characterId',
            select: 'name rank thumbnail level gender race class items'
          })
          .exec()
          .then((epgpData) => {
            resolve(epgpData);
          }, (error) => {
            reject(error);
          });
      }, (error) => {
        reject(error);
      });
  });
}

function getRaidersEPGP(guildName) {
  return new Promise((resolve, reject) => {
    characterService
      .getCharacters(guildName)
      .then((characters) => {

        EPGPCharacter
          .find()
          .populate({
            path: 'characterId',
            select: 'name rank thumbnail level gender race class items spec',
            match: {
              rank: { $in: [0, 1, 4, 5] }
            }
          })
          .exec()
          .then((epgpData) => {
            resolve(
              _.sortBy(
                _.filter(epgpData, (o) => { return o.characterId; }),
                function(item) {
                  return [item.characterId.name];
                }
              )
            );
          }, (error) => {
            reject(error);
          });
      }, (error) => {
        reject(error);
      });
  });
}

function updateCharacter(guildName, characterName, epgpData) {
  return new Promise((resolve, reject) => {
    characterService.findOrCreateCharacter(guildName, characterName)
      .then((character) => {

        EPGPCharacter
           .findOneAndUpdate({characterId: character._id}, epgpData, {upsert: true})
           .exec()
           .then((data) => {
             resolve(data);
           }, (error) => {
             reject(error);
           });
      });
  });
}

function updateGuildConfig(epgpData) {
  return new Promise((resolve, reject) => {
    resolve(epgpData);
  });
}

module.exports = {
  archiveEPGP: archiveEPGP,
  bulkUpdateCharacters: bulkUpdateCharacters,
  getEPGP: getEPGP,
  getMembersEPGP: getMembersEPGP,
  getRaidersEPGP: getRaidersEPGP,
  updateCharacter: updateCharacter,
  updateGuildConfig: updateGuildConfig
};
<|endoftext|>


<commit_before>'use strict';

const ExtendableEvent = require('./ExtendableEvent');
const FetchEvent = require('./FetchEvent');
const MessageEvent = require('./MessageEvent');
const NotificationEvent = require('./NotificationEvent');
const PushEvent = require('./PushEvent');

module.exports = {
  create,
  handle,
  mixin
};

/**
 * Create 'event' instance
 * @param {String} type
 * @returns {ExtendableEvent}
 */
function create(type, ...args) {
  switch (type) {
    case 'fetch':
      return new FetchEvent(...args);
    case 'notificationclick':
      return new NotificationEvent(...args);
    case 'push':
      return new PushEvent(...args);
    case 'message':
      return new MessageEvent(...args);
    default:
      return new ExtendableEvent();
  }
}

/**
 * Handle event 'type' from 'source'
 * @param {Object} source
 * @param {String} type
 * @returns {Promise}
 */
function handle(source, type, ...args) {
  const listeners = (source._listeners[type] && source._listeners[type].slice()) || [];
  const onevent = source[`on${type}`];

  if (onevent) {
    listeners.push(onevent);
  }

  if ((type === 'error' || type === 'unhandledrejection') && !listeners.length) {
    throw args[0] || Error(`unhandled error of type ${type}`);
  }

  if (listeners.length === 1) {
    return doHandle(listeners[0], type, args);
  }

  return Promise.all(listeners.map(fn => doHandle(fn, type, args)));
}

/**
 * Execute handle of 'listener'
 * @param {Function} listener
 * @param {String} type
 * @param {Array} args
 * @returns {Promise}
 */
function doHandle(listener, type, args) {
  const event = create(type, ...args);

  listener(event);
  return event.promise || Promise.resolve();
}

function mixin(instance) {
  instance._listeners = {};
  instance.addEventListener = function addEventListener(event, fn) {
    if (!instance._listeners[event]) {
      instance._listeners[event] = [];
    }
    instance._listeners[event].push(fn);
  };
}
<commit_msg>add removeEventListener<commit_after>'use strict';

const ExtendableEvent = require('./ExtendableEvent');
const FetchEvent = require('./FetchEvent');
const MessageEvent = require('./MessageEvent');
const NotificationEvent = require('./NotificationEvent');
const PushEvent = require('./PushEvent');

module.exports = {
  create,
  handle,
  mixin
};

/**
 * Create 'event' instance
 * @param {String} type
 * @returns {ExtendableEvent}
 */
function create(type, ...args) {
  switch (type) {
    case 'fetch':
      return new FetchEvent(...args);
    case 'notificationclick':
      return new NotificationEvent(...args);
    case 'push':
      return new PushEvent(...args);
    case 'message':
      return new MessageEvent(...args);
    default:
      return new ExtendableEvent();
  }
}

/**
 * Handle event 'type' from 'source'
 * @param {Object} source
 * @param {String} type
 * @returns {Promise}
 */
function handle(source, type, ...args) {
  const listeners = (source._listeners[type] && source._listeners[type].slice()) || [];
  const onevent = source[`on${type}`];

  if (onevent) {
    listeners.push(onevent);
  }

  if ((type === 'error' || type === 'unhandledrejection') && !listeners.length) {
    throw args[0] || Error(`unhandled error of type ${type}`);
  }

  if (listeners.length === 1) {
    return doHandle(listeners[0], type, args);
  }

  return Promise.all(listeners.map(fn => doHandle(fn, type, args)));
}

/**
 * Execute handle of 'listener'
 * @param {Function} listener
 * @param {String} type
 * @param {Array} args
 * @returns {Promise}
 */
function doHandle(listener, type, args) {
  const event = create(type, ...args);

  listener(event);
  return event.promise || Promise.resolve();
}

function mixin(instance) {
  instance._listeners = {};
  instance.addEventListener = function addEventListener(event, fn) {
    if (!instance._listeners[event]) {
      instance._listeners[event] = [];
    }
    instance._listeners[event].push(fn);
  };
  instance.removeEventListener = function removeEventListener(event, fn) {
    if (!instance._listeners[event]) {
      return;
    }
    instance._listeners[event].splice(instance._listeners[event].indexOf(fn), 1);
  };
}
<|endoftext|>