@if (@extensions != @extensions)

function Nz(value, def) {return value != null ? value : def }
function CNull(value) { return value ? value : null }

Boolean.prototype.toDate = function() { return this.valueOf() ? new Date() : new Date(0) }
Boolean.prototype.isBoolean = true

Number.prototype.toDate = function() { return new Date(this) }
Number.prototype.isNumber = true

String.prototype.toDate = function() { return new Date(this); }
String.prototype.padLeft = function(length, chr)
{
	if (typeof(chr) == 'undefined') chr = ' '
	var a = []
	length = length - this.length
	for (var i = 0; i < length; i++) a.push(chr)
	return a.join('') + this
}
String.prototype.isString = true

Date.prototype.toDate = function() { return new Date(this.valueOf()); }
Date.prototype.abbreviatedMonthNames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
Date.prototype.toString = function(s)
{
	
	if (!s) return this.toUTCString();
	var self = this;
		
	var fnTextForDatePart = function(s)
	{
		switch(s)
		{
			case "HH": return self.getHours().toString().padLeft(2,'0');
			case "mm": return self.getMinutes().toString().padLeft(2,'0');
			case "ss": return self.getSeconds().toString().padLeft(2,'0');
			case "yyyy": return self.getFullYear();
			case "dd": return self.getDate().toString().padLeft(2,'0');
			case "MMM":	return self.abbreviatedMonthNames[self.getMonth()];
		}
	}
 
	return s.replace(/HH|mm|ss|yyyy|dd|MMM/g, fnTextForDatePart);
}
Date.prototype.hasLocaleTime = function() { return (this.getHours() || this.getMinutes() || this.getSeconds() || this.getMilliseconds()); }
Date.prototype.isDate = true

@end


@if (@XMlBase != @XMLBase)

@set @XMLBase = 1

// ======== Common functions =========

//------
function isString(value) { return value != null ? value.isString : false; }
function isDate(value) {  return value != null ? value.isDate : false; }
function isNumber(value) { return value != null ? value.isNumber : false; }

//------
function getDOM()
{
	var oDOM
	
	if (typeof(Server) != "undefined")
	{
		oDOM = Server.CreateObject("MSXML2.DOMDocument.3.0");
	}
	else
	{
		oDOM = new ActiveXObject("MSXML2.DOMDocument.3.0");
	}
	oDOM.async = false
	oDOM.setProperty("SelectionLanguage", "XPath")
	
	return oDOM
}


//--------
function protGetText(elemParent, name, defValue) 
{
	var elemChild
	
	elemChild = elemParent.selectSingleNode(name);

	if (elemChild != null) { return elemChild.text; }
	else                   { return typeof(defValue) != 'undefined' ? defValue : ""; }
}


//-------
function protPutText(element, name, value)
{

	var oSubElem = element.selectSingleNode(name)

	if (value == null)
	{
		if (oSubElem != null) element.removeChild(oSubElem)
  }  
	else
  {
  
    if (oSubElem == null)
    {
      oSubElem = element.ownerDocument.createElement(name)
      element.appendChild(oSubElem)
    }
    
    if (value.isDate) oSubElem.text = formatSQLDateTime(value)
    else              oSubElem.text = value
    
	}

}

function protPutCData(element, name, value)
{
	var oSubElem = element.selectSingleNode(name)

	if (value == null)
	{
		if (oSubElem != null) element.removeChild(oSubElem)
  }  
	else
  {
    if (oSubElem == null)
    {
      oSubElem = element.ownerDocument.createElement(name)
      element.appendChild(oSubElem)
    }
    
    if (isDate(value)) putCDataValue(oSubElem, formatSQLDateTime(value))
    else               putCDataValue(oSubElem, value)
    
	}
}

function putCDataValue(element, value)
{
	var oNode

	while (element.firstChild && !oNode)
	{
		if (element.firstChild.nodeTypeString == 'cdatasection')
			oNode = element.firstChild
		else
			element.removeChild(element.firstChild)
	}

	if (!oNode)
		element.appendChild(element.ownerDocument.createCDATASection(value))
	else
		oNode.data = value
}

//--------
function putAttributeValue(element, name, value)
{
	if (value == null)
	{
		element.removeAttribute(name)
	}
	else
	{
    if (isDate(value)) element.setAttribute(name, formatSQLDateTime(value))
    else               element.setAttribute(name, value)
  }
} 

//-------
function getElement(elemParent, name, create)
{
	if (typeof(create) == "undefined") create = false;

	var elemChild = elemParent.selectSingleNode(name);
	
	if (elemChild == null && create)
	{
		elemChild = createElement(elemParent, name);
	}
	
	return elemChild;
}

//-------
function getElementPath(roElem)
{
  var sResult

  if (roElem.nodeTypeString == "element") sResult = getElementPath(roElem.parentNode) + "/"
    
  return sResult + roElem.tagName + "[" + elementIndex(roElem) + "]"
}       

//-------
function elementIndex(roElem)
{    
		var i = 0
		var e =  new Enumerator(roElem.parentNode.selectNodes(roElem.tagName))

    for ( ; !e.atEnd() && (e.item() != roElem); e.moveNext()) { i += 1; }
    
    return i
}

//------
function createElement(parent, name)
{
	var elemChild = parent.ownerDocument.createElement(name)
	parent.appendChild(elemChild)
	return elemChild
}

//------
function resolvePersona(persona)
{
  if (persona == null) return new GenericPersona("item")
  else                 return persona
}

//------
function formatSQLDateTime(inpDateTime)
{ 
	if (inpDateTime)
		return inpDateTime.hasLocaleTime() ? inpDateTime.toDate().toString('dd MMM yyyy HH:mm:ss') : inpDateTime.toDate().toString('dd MMM yyyy')
	else
		return '';
}

//======= Global functions =======
function getGeneric(source) { return new Generic(getXMLElem("<root/>", source)); }
function getElements(source, persona) { return new Elements(getXMLElem("<root/>", source), resolvePersona(persona)); }
function getXMLElem(rootXML, source)
{
		var oDOM = getDOM()
		var oElem

    if (typeof(source) == "undefined")
    {
        oDOM.loadXML(rootXML)
    }
    else if (isString(source))
    {
			switch (source.match(/\S/)[0]) {
				case '<': oDOM.loadXML(source); break;
				case '#': oDOM = document.all(source.slice(1)).XMLDocument; break;
				default: oDOM.load(source)
			}
    }        
    else if (typeof(source) == "object")
    {
      if (source.nodeTypeString == "document") oDOM = source
      else if (source.nodeTypeString == "element") oElem = source
      else if (typeof(source.lbound) != "undefined") oDOM.load(source)
      else oElem = source.element
    }            
    else
    {
      throw "Type mismatch in GetXLMElem"
    }    
    
    if (oDOM.parseError.errorCode != 0) throw new Error(oDOM.parseError.errorCode, oDOM.parseError.reason)
    
    if (typeof(oElem) == "undefined") oElem = oDOM.documentElement
    
    //try {oElem.ownerDocument.setProperty("SelectionLanguage", "XPath");} catch(e) {}
    
    return oElem    
}

//======= Generic XML Element =======
function Generic(elem) { this.element = elem; }
Generic.prototype.getID = function() { return Nz(this.element.getAttribute("ID"),""); }
Generic.prototype.putID = function(value) { this.element.setAttribute("ID", Nz(value, "")); }
Generic.prototype.getText = function() { return this.element.text; }
Generic.prototype.putText = function(value)
{ 
	if (this.isComplex()) throw "Can not assign text to a complex element"
	value = Nz(value, "")
	this.element.text = value.isDate ? formatSQLDateTime(value) : value
}
Generic.prototype.getCData = function() { return this.element.text; }
Generic.prototype.putCData = function(value) { putCDataValue(this.element, value) ; }
Generic.prototype.getAttribute = function(name, def)
{
	if (typeof(def) == 'undefined') def = ''
	return Nz(this.element.getAttribute(name), def);
}
Generic.prototype.putAttribute = function(name, value) { putAttributeValue(this.element, name, value); }
Generic.prototype.getSimpleChild = function(name, def) { return protGetText(this.element, name, def); }
Generic.prototype.putSimpleChild = function(name, value) { protPutText(this.element, name, value); }
Generic.prototype.index = function() { return elementIndex(this.element); }
Generic.prototype.path = function() { return getElementPath(this.element); }
Generic.prototype.isComplex = function() { return (this.element.selectNodes("*").length > 0); }
Generic.prototype.addChild = function(name, constructor)
{ 
	if (!constructor) constructor = Generic
	return new constructor(createElement(this.element, name));
}
Generic.prototype.getChild = function(name, create, constructor)
{
	var oElem = getElement(this.element, name, create)
	if (oElem != null)
	{
		if (constructor == null) return new Generic(oElem)
		else                     return new constructor(oElem)
	}
	else
	{	
		return null
	}
}
Generic.prototype.removeChild = function(child)
{
	var oElem
	
	if (isString(child))
		oElem = getElement(this.element, child)
	else if (Generic.prototype.isPrototypeOf(child))
		oElem = child.element
	else
		oElem = child
	// end if
	
	if (oElem) this.element.removeChild(oElem)
}
Generic.prototype.getParent = function(constructor)
{
	if (!constructor) constructor = Generic
	
	var elem = this.element.parentNode
	if (elem) return new constructor(elem);
}
Generic.prototype.filter = function(nameOrPersona)
{
	if      (typeof(nameOrPersona) == "undefined") return new Elements(this.element, new GenericPersona("item"))
	else if (isString(nameOrPersona))              return new Elements(this.element, new GenericPersona(nameOrPersona))
	else if (typeof(nameOrPersona) == "object")    return new Elements(this.element, resolvePersona(nameOrPersona))
	else                                           throw "Type mismatch in Generic.getChildren"
}
Generic.prototype.childEnum = function(persona) { return new ElementsEnum(this.element.selectNodes("*"), persona); }
Generic.prototype.xpathEnum = function(xpath, persona) { return new ElementsEnum(this.element.selectNodes(xpath), persona); }
Generic.prototype.isValid = function() { return (this.element.selectSingleNode(".//brokenRule") == null); }
Generic.prototype.getBrokenRules = function() { return this.filter("brokenRule"); }
Generic.prototype.getClone = function(deep) { return new Generic(this.element.cloneNode(deep)); }
Generic.prototype.copyFrom = function(src)
{
	var genSrc = getGeneric(src)
	var oAttribs = genSrc.element.attributes
	for (var i = 0; i < oAttribs.length; i++)
		this.element.setAttributeNode(oAttribs.item(i).cloneNode(true))
	
	var oElems = genSrc.element.childNodes
	for (var oElem = oElems.nextNode(); oElem != null; oElem = oElems.nextNode())
		this.element.appendChild(oElem.cloneNode(true))
}
Generic.prototype.slice = function(copy)
{
	var elem = copy ? this.element.cloneNode(true) : this.element
	var dom = getDOM()
	dom.appendChild(elem)
	return copy ? new Generic(elem) : this
}
Generic.prototype.replace = function(source)
{
	var gen = getGeneric(source)
	this.element.parentNode.replaceChild(gen.element, this.element)
	this.element = gen.element
	return this
}
Generic.prototype.expand = function()
{
	var genExpanded = this.getExpanded.apply(this, arguments)
	if (genExpanded) this.replace(genExpanded)
}
Generic.prototype.isDocumentElement = function()
{ return this.element == this.element.ownerDocument.documentElement; }
Generic.prototype.getExpanded = function()
{
	var elem = this.isDocumentElement() ? this.element : this.slice(true).element
	
	var args = new Array()
	args.push(elem.ownerDocument)
	for (var i = 0; i < arguments.length; i++) args.push(arguments[i])
		
	var oExpanded = getExpandedXML.apply(window, args)
	if (oExpanded) return getGeneric(oExpanded)
}
Generic.prototype.drop = function(xpath)
{
	var e = this.element.selectNodes(xpath)
	var iDropCount = 0
	for (var elem = e.nextNode(); elem != null; elem = e.nextNode())
	{
		elem.parentNode.removeChild(elem)
		iDropCount += 1	
	}
	return iDropCount
}

//======= Generic Persona ======
function GenericPersona(name)
{ 
	if (typeof(name) == "undefined") name = "item"
  this.name = name; 
}
GenericPersona.prototype.createChild = function(elem) { return new this.childConstructor(elem); }
GenericPersona.prototype.createElements = function(elem) { return new Elements(elem, this); }
GenericPersona.prototype.getPredicate = function(ID) { return '[@ID="' + ID + '"]'; }
GenericPersona.prototype.setIDAttribs = function(elem, ID) { elem.setAttribute("ID", ID); }
GenericPersona.prototype.childConstructor = Generic


//======== Elements Class =======
function Elements(elem, persona)
{
	this.element = elem;
	this.persona = persona;

	if (persona.customize) persona.customize(this)
}
Elements.prototype.add = function(before)
{ 
  var oElem = this.element.ownerDocument.createElement(this.persona.name)  
  return this.insert(this.persona.createChild(oElem), before)
}
Elements.prototype.insert = function(item, before)
{
  if (typeof(before) == "undefined") this.element.appendChild(item.element)
  else                               this.element.insertBefore(item.element, before.element)

	return item
}
Elements.prototype.exists = function(indexKey) 
{
	return this.getElement(indexKey, false) != null;
}
Elements.prototype.getItem = function(indexKey, create)
{	
	var subElem = this.getElement(indexKey, create);
	
	if (subElem != null) return this.persona.createChild(subElem)
	else                 return null
}
Elements.prototype.count = function()
{ 
	return this.element.selectNodes(this.persona.name).length
}
Elements.prototype.index = function(indexKey)
{
  var oTarget = this.getElement(indexKey)    
  if (oTarget != null) return elementIndex(oTarget)
  else                 return null
}
Elements.prototype.remove = function(indexKey)
{
	var subElem = this.getElement(indexKey)
	if (subElem != null) this.element.removeChild(subElem);
}
Elements.prototype.removeAll = function()
{ 
	var e = new Enumerator(this.element.selectNodes(this.persona.name))
	
	for (; !e.atEnd(); e.moveNext() )
	{
		this.element.removeChild(e.item());
	}		
}
Elements.prototype.merge = function(source, clone)
{
	if (typeof(clone) == "undefined") clone = false
	
	for (var oItem = source.nextItem(); oItem != null; oItem = source.nextItem())
  {        
    if (clone) this.element.appendChild(oItem.element.cloneNode(true))
    else       this.element.appendChild(oItem.element)    
	}
}
Elements.prototype.mergeByID = function(source, clone, lastWinner)
{

	if (typeof(clone) == "undefined") clone = false
	if (typeof(lastWinner) == "undefined") lastWinner = false

	var oNewNode
	var oOldNode

	for (var oItem = source.nextItem(); oItem != null; oItem = source.nextItem())
  {        
        
    oOldNode = this.getElement(oItem.getID())
    
    if (!oOldNode || lastWinner)
    {
        
      if (clone) oNewNode = oItem.element.cloneNode(true)
      else oNewNode = oItem.element

      if (!oOldNode) this.element.appendChild(oNewNode)
      else this.element.replaceChild(oOldNode, oNewNode)
                    
    }
    	
	}
   
}
Elements.prototype.replaceItem = function(indexKey, newItem)
{
	var oOldNode = this.getElement(indexKey, false)
	var oNewNode
	
	if (Generic.prototype.isPrototypeOf(newItem)) oNewNode = newItem.element
	else                                          oNewNode = newItem
	
	if (oOldNode != null) this.element.replaceChild(oNewNode, oOldNode)
	else                  this.element.appendChild(oNewNode)
}
Elements.prototype.xml = function() { return this.element.xml; }
Elements.prototype.descendantEnum = function()
  { return new ElementsEnum(this.element.selectNodes(".//" + this.persona.name), this.persona); }
Elements.prototype.childEnum = function()
  { return new ElementsEnum(this.element.selectNodes(this.persona.name), this.persona); }
Elements.prototype.xpathEnum = function(xpath)
  { return new ElementsEnum(this.element.selectNodes(xpath), this.persona); }
Elements.prototype.getElement = function(indexKey, create)
{
	if (typeof(create) == "undefined") create = false
	
	var subElem
	
	if (isString(indexKey))
	{ 
		if (indexKey.substring(0,1) == "[")
			subElem = this.element.selectSingleNode(this.persona.name + indexKey)
		else
			subElem = this.element.selectSingleNode(this.persona.name + this.persona.getPredicate(indexKey))
	}
	else if (isNumber(indexKey))
	{
		subElem = this.element.selectNodes(this.persona.name).item(indexKey - 1);
	}
	else if (Generic.prototype.isPrototypeOf(indexKey))
	{
		subElem = indexKey.element
	}
	else if (typeOf(indexKey) == "object")
	{
		subElem = indexKey
	}

	if ((subElem == null) && create)
	{
		subElem = this.element.ownerDocument.createElement(this.persona.name);
		if (isString(indexKey)) this.persona.setIDAttribs(subElem, indexKey);
		this.element.appendChild(subElem);
	}
	
	return subElem;
}
Elements.prototype.isValid = function() { return (this.element.selectSingleNode(".//brokenRule") == null); }
Elements.prototype.getDescendant = function(indexKey)
{
	var oElem = this.element.selectSingleNode(".//" + this.persona.name + this.persona.getPredicate(indexKey))	
	if (oElem) return this.persona.createChild(oElem)
}

//======= Elements Enumerator =======
function ElementsEnum(list, persona)
{
	this.list = list
	if (persona)
	{
		if (persona.createChild) this.persona = persona
		else this.childConstructor = persona
	}
}
ElementsEnum.prototype.count = function() { return this.list.length }
ElementsEnum.prototype.reset = function() { this.list.reset() }
ElementsEnum.prototype.getItem = function(index) 
{
	var oElem = this.list.item(index)
	if (oElem != null) return this.createChild(oElem)
	else               return null
}
ElementsEnum.prototype.nextItem = function()
{
	var oElem = this.list.nextNode()
	if (oElem != null) return this.createChild(oElem)
	else               return null
}
ElementsEnum.prototype.seekItem = function(id)
{
	for (var res = this.nextItem(); res != null; res = this.nextItem())
	{
		if (res.getID() = id) break;
	}
	
	return res
}
ElementsEnum.prototype.createChild = function(elem)
{
	if (this.childConstructor) return new this.childConstructor(elem)
	else return this.persona.createChild(elem)
}
ElementsEnum.prototype.persona = new GenericPersona()


@end

