﻿<!--

/*
 * Validates Dutch phonenumbers and more.
 * Copyright (C) Doeke Zanstra 2001-2003
 * Distributed under the BSD License
 * See http://www.xs4all.nl/~zanstra/dzLib/telNr.htm for more info.
 */

//--| Lijst van regionale kengetallen (nummers moeten 10 cijfers hebben)
TelNr.prototype.regio4=',0111,0113,0114,0115,0117,0118,0161,0162,0164,0165,0166,0167,0168,0172,0174,0180,0181,0182,0183,0184,0186,0187,0222,0223,0224,0226,0227,0228,0229,0251,0252,0255,0294,0297,0299,0313,0314,0315,0316,0317,0318,0320,0321,0341,0342,0343,0344,0345,0346,0347,0348,0411,0412,0413,0416,0418,0475,0478,0481,0485,0486,0487,0488,0492,0493,0495,0497,0499,0511,0512,0513,0514,0515,0516,0517,0518,0519,0521,0522,0523,0524,0525,0527,0528,0529,0541,0543,0544,0545,0546,0547,0548,0561,0562,0566,0570,0571,0572,0573,0575,0577,0578,0591,0592,0593,0594,0595,0596,0597,0598,0599,';
TelNr.prototype.regio3=',010,013,015,020,023,024,026,030,033,035,036,038,040,043,045,046,050,053,055,058,070,071,072,073,074,075,076,077,078,079,';
//--| Kengetallen, niet beschikbaar voor reservering
TelNr.prototype.magNiet4=',0110,0112,0116,0119,0160,0163,0169,0170,0171,0173,0175,0176,0177,0178,0179,0185,0188,0189,0220,0221,0225,0250,0253,0254,0256,0257,0258,0259,0290,0291,0292,0293,0295,0296,0298,0310,0311,0312,0319,0322,0323,0324,0325,0326,0327,0328,0329,0340,0349,0410,0414,0415,0417,0419,0470,0471,0472,0473,0474,0476,0477,0479,0480,0482,0483,0484,0489,0490,0491,0494,0496,0498,0510,0520,0526,0540,0542,0549,0560,0563,0564,0565,0567,0568,0569,0574,0576,0579,0590,06761,06762,06763,06764,06765,06766,06767,06768,06769,0801,0802,0803,0804,0805,0806,0807,0808,0809,0901,0902,0903,0904,0905,0907,0908,';
TelNr.prototype.magNiet3=',012,014,019,021,027,028,037,039,042,060,068,069,081,083,085,086,088,089,091,092,093,094,095,096,097,098,099,';
//--| 0800,0900,0906 en 0909 nummers kunnen kort (8 tekens) zijn, zoals
//--| vermeldt in onderstaande arrays. Anders zijn ze lang (11 tekens).
TelNr.prototype.infoNrKort=
{ '0800':['00','01','03','04','05','06','07','08','09',
          '10','11','12','13','14','15','16','17','18','19',
          '20','21',
          '41','43','46','49',
          '50','51',
          '60','61',
          '70','71',
          '80','81',
          '90','91']
, '0900':['00','01','02','03','04','05','06','07','08','09',
          '13','14','15','17','18','19',
          '80','81','83','84','86','88',
          '92','93','95','96','97','98']
, '0906':['00','01','02','03','05','06','07','08','09',
          '13','14','15','17','18','19',
          '80','81','83','84','86','88',
          '92','93','95','96','97','98']
, '0909':['00','01','02','03','05','06','07','08','09',
          '13','14','15','17','18','19',
          '80','81','83','84','86','88',
          '92','93','95','96','97','98']
};
TelNr.prototype.landNr=31; //default landen nummer
TelNr.prototype.errors=
[ 'Nummer moet 10 cijfers hebben'
, 'Nummer moet 8 cijfers hebben'
, 'Nummer moet 11 cijfers hebben'
, 'Kengetal is niet beschikbaar voor toekenning of reservering'
, 'Het kengetal is niet herkend'
];
TelNr.prototype.toString=TelNr_toString;

function TelNr(strTelNr) 
{
  var intKengetalStart;
  var intAbonneeNrStart;
  var strKengetal, strSubKengetal;
	
//Zet landennummer
  this.landNr=this.landNr;
//Converteer naar string en verwijder alle non-getallen
  strTelNr=(''+strTelNr).replace(/[^0-9]/g,'');

  if(/^06[1-5]/.test(strTelNr)) 
  {
    //--| mobiel nummer (in 065 zit ook nog een stukje semafonie)
    //--| of internet (06760)
    intKengetalStart=0;
    intAbonneeNrStart=2;
		this.validated=(strTelNr.length==10); //mobile nr should have 10 digits
    if(!this.validated) this.error=this.errors[0];
    this.type='mobiel';
  } 
  else if(/^06760/.test(strTelNr)) 
  {
    //--| mobiel nummer (in 065 zit ook nog een stukje semafonie)
    //--| of internet (06760)
    intKengetalStart=0;
    intAbonneeNrStart=5;
		this.validated=(strTelNr.length==10); //mobile nr should have 10 digits
    if(!this.validated) this.error=this.errors[0];
    this.type='internet';
  } 
  else if(/^08[47]/.test(strTelNr)) 
  {
    //--| Persoonlijke-assistentdiensten (bijv. fax bij KPN fax-in-email/XOIP)
    intKengetalStart=0;
    intAbonneeNrStart=3;
		this.validated=(strTelNr.length==10); //mobile nr should have 10 digits
    if(!this.validated) this.error=this.errors[0];
    this.type='persoonlijke-assistentdiensten';
  } 
  else if(this.infoNrKort[strTelNr.substr(0,4)]) 
  { 
    //--| informatie nummer
    intKengetalStart=0;
    intAbonneeNrStart=4;
    strKengetal=strTelNr.substr(0,4); //eerste 4 cijfers
    strSubKengetal=strTelNr.substr(4,2); //volgende 2 cijfers
    //controleer lengte
    if(infoNrKort[strKengetal].exists(strSubKengetal)) 
    {
      this.validated=(strTelNr.length==8);
      if(!this.validated) this.error=this.errors[1];
    }
    else 
    {
      this.validated=(strTelNr.length==11);
      if(!this.validated) this.error=this.errors[2];
    }
    this.type='informatie';
  }
  else if(this.regio3.indexOf(','+strTelNr.substr(0,3)+',')>=0 )
  {
    //--| regionaal nummer, met kort kengetal
    intKengetalStart=0;
    intAbonneeNrStart=3;
		this.validated=(strTelNr.length==10); 
    if(!this.validated) this.error=this.errors[0];
    this.type='regio';
  }
  else if(this.regio4.indexOf(','+strTelNr.substr(0,4)+',')>=0 )
  {
    //--| regionaal nummer, met kort kengetal
    intKengetalStart=0;
    intAbonneeNrStart=4;
		this.validated=(strTelNr.length==10); 
    if(!this.validated) this.error=this.errors[0];
    this.type='regio';
  }
  else if(this.magNiet3.indexOf(','+strTelNr.substr(0,3)+',')>=0 
       || this.magNiet4.indexOf(','+strTelNr.substr(0,4)+',')>=0 )
  {
    intKengetalStart=0;
    intAbonneeNrStart=0;
		this.validated=false;
    this.error=this.errors[3];
    this.type=null;
  }
  else
  {
    //--| onbekend, neem aan dat kengetal 3 cijfers heeft
    intKengetalStart=0;
    intAbonneeNrStart=3;
		this.validated=null;
    this.error=this.errors[4];
    this.type=null;
  }
  this.kengetal=strTelNr.substring(intKengetalStart,intAbonneeNrStart);
  this.abonneeNr=strTelNr.substring(intAbonneeNrStart,strTelNr.length);
	return this;
}

TelNr.translator =
[ {token:'INT',	  method:'this.kengetal+this.abonneeNr'}
,	{token:'KG',	  method:'this.kengetal'}
, {token:'kg',	  method:'this.kengetal.substr(1)'}
, {token:'KPN',	  method:'"("+this.kengetal+") "+this.abonneeNr.group(2,2,true,sep)'}
, {token:'kpn',	  method:'"("+this.kengetal+") "+this.abonneeNr'}
, {token:'NORM',	method:'"("+this.kengetal+") "+this.abonneeNr.group(3,2,true,sep)'}
, {token:'NR2_',  method:'this.abonneeNr.group(2,2,false,sep)'}
, {token:'NR_2',  method:'this.abonneeNr.group(2,2,true,sep)'}
, {token:'NR3_',  method:'this.abonneeNr.group(3,2,false,sep)'}
, {token:'NR_3',  method:'this.abonneeNr.group(3,2,true,sep)'}
, {token:'NR',	  method:'this.abonneeNr'}
];

function TelNr_toString(format,sep)
//--#Converteert een telefoonnummer naar een string.
//--@format;type=string;optional;default='NORM'@Formaat van de string. Zie tabel.
//--@sep;type=string@Tussenvoegsel voor gegroepeerde nummers
/*$Tabel:Tokens in de formaterings string
KG    :Kengetal (bijv: '050', '0515' of '06')
kg    :Kengetal zonder nul (bijv: '50', '515' of '6')
NR    :Abonneenummer (bijv: '23466808', '521276' of '3090127')
NR2_  :Abonneenummer 
       Groepjes van 2. Afwijkende groepjes achteraan (minimum lengte groepje is 2)
       Bijv: '23 46 68 08', '52 12 76' of '30 90 127')
NR_2  :Abonneenummer 
       Groepjes van 2. Afwijkende groepjes vooraan (minimum lengte groepje is 2)
       Bijv: '23 46 68 08', '52 12 76' of '309 01 27')
NR3_  :Abonneenummer 
       Groepjes van 3. Afwijkende groepjes achteraan (minimum lengte groepje is 2)
       Bijv: '234 668 08',  '521 276'  of '309 01 27')
NR_3  :Abonneenummer 
       Groepjes van 3. Afwijkende groepjes vooraan (minimum lengte groepje is 2)
       Bijv: '23 466 808',  '521 276'  of '30 90 127')
KPN   :KPN formaat: '(KG) NR_2' 
kpn   :KPN formaat zonder groepering: '(KG) NR'
NORM  :Hoe het volgens de auteur zou moeten: '(KG) NR_3'
KG-NR :Hoe de meeste mensen het spellen: 'KG-NR'
INT   :Internationaal: '+31-(0)kg-NR'
*/
{
  var sRes="";
	var i=0;
	var bFound;
  if(typeof format=='undefined') format='kpn';
	while(i<format.length) 
	{	
    for(var j=0; j<TelNr.translator.length; j++) 
		{	
      if(format.indexOf(TelNr.translator[j].token,i)==i)
			{	
        sRes+=eval(TelNr.translator[j].method);
				i+=TelNr.translator[j].token.length;
				break;	
			}
		}
		if(j==TelNr.translator.length) //not found
		{	
      sRes+=format.substr(i,1);
			i++;
		}
	}
	return sRes;
}


/*---Handy methods--*/
Array.prototype.top=function(n) 
{ 
  n=(n||0)+1; 
  return this[this.length-n]||null; 
}
if(!Array.prototype.pop) Array.prototype.pop=function()
{
  var r=this[this.length-1];
  delete this[this.length-1];
  this.length--;
  return r;
}
Array.prototype.exists=Array_exists;
function Array_exists(value) {
	for(var i=0; i<this.length; i++) {
		if(this[i]==value) {
			return true;
		}
	}
	return false;
}
String.prototype.reverse=function() {
  var s='';
  for(var i=this.length-1; i>=0; i--)
  {
    s+=this.charAt(i);
  }
  return s;
}
String.prototype.group=function String_group(n1,n2,b,sep)
/*--#Formateer de string in groepjes van [n1] cijfers. Gebruik [n2] als minimale
grootte van een groepje. Als [b] true is, doe het afwijkende groepje vooraan, 
anders achteraan. Gebruik [sep] als tussenvoegsel tussen de groepjes*/
//--@n1;type=integer;optional;default=3@Hoe groot een groepje cijfers moet zijn. n1>=1
//--@n2;type=integer;optional;default=2@Minimale lengte van een groepje cijfers. n2<=n1
//--@b;type=boolean;optional;default=false@Of het afwijkende groepje (indien deze voorkomt) vooraan moet staan.
//--@sep;type=string;optional;default=' '@De seperator.
{
  var re=new RegExp('([0-9]{1,'+n1+'})','g');
  var a, s;
  var ret=[];

  if(typeof n1=='undefined') n1=3;
  if(typeof n2=='undefined') n2=2;
  if(typeof b=='undefined') b=false;
  if(typeof sep=='undefined') sep=' ';
  if(b) s=this.reverse();
  else s=this;
  while(a=re.exec(s))
  {
    ret.push( a[1] );
  }
  if(ret.length>=2 && ret.top().length<n2)
  {
    //zijn er tenminste 2 groepjes en is de lengte van het laatste groepje te kort?
    var k=ret.top(1), l=ret.top(); //één-na-laatste en laatste
    if(parseInt((k.length+l.length)/2,10)>=n2) 
    {
      //2 groepjes maken
      ret[ret.length-1]=ret[ret.length-2].substr(n2)+ret[ret.length-1];
      ret[ret.length-2]=ret[ret.length-2].substring(0,n2);
    }
    else
    {
      //laatste 2 groepjes samenvoegen
      ret[ret.length-2]+=ret.pop();
    }
  }
  if(b) return ret.join(sep).reverse();
  else return ret.join(sep);
}






/*  Prototype JavaScript framework, version 1.4.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.4.0',
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

  emptyFunction: function() {},
  K: function(x) {return x}
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.inspect = function(object) {
  try {
    if (object == undefined) return 'undefined';
    if (object == null) return 'null';
    return object.inspect ? object.inspect() : object.toString();
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this;
  return function(event) {
    return __method.call(object, event || window.event);
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  }
});

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}

/*--------------------------------------------------------------------------*/

function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
}
Object.extend(String.prototype, {
  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(eval);
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  },

  toQueryParams: function() {
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair = pairString.split('=');
      params[pair[0]] = pair[1];
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, len = oStringList.length; i < len; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function() {
    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
  }
});

String.prototype.parseQuery = String.prototype.toQueryParams;

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != $continue) throw e;
        }
      });
    } catch (e) {
      if (e != $break) throw e;
    }
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },

  detect: function (iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.collect(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value >= (result || value))
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value <= (result || value))
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.collect(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.collect(Prototype.K);
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      iterator(value = collections.pluck(index));
      return value;
    });
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0; i < this.length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  shift: function() {
    var result = this[0];
    for (var i = 0; i < this.length - 1; i++)
      this[i] = this[i + 1];
    this.length--;
    return result;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
var Hash = {
  _each: function(iterator) {
    for (key in this) {
      var value = this[key];
      if (typeof value == 'function') continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject($H(this), function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      return pair.map(encodeURIComponent).join('=');
    }).join('&');
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }
}

function $H(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    do {
      iterator(value);
      value = value.succ();
    } while (this.include(value));
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responderToAdd) {
    if (!this.include(responderToAdd))
      this.responders.push(responderToAdd);
  },

  unregister: function(responderToRemove) {
    this.responders = this.responders.without(responderToRemove);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (responder[callback] && typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },

  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      parameters:   ''
    }
    Object.extend(this.options, options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }

      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

    } catch (e) {
      this.dispatchException(e);
    }
  },

  setRequestHeaders: function() {
    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type',
        'application/x-www-form-urlencoded');

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval(this.header('X-JSON'));
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + event, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.containers = {
      success: container.success ? $(container.success) : $(container),
      failure: container.failure ? $(container.failure) :
        (container.success ? null : $(container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, object) {
      this.updateContent();
      onComplete(transport, object);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.responseIsSuccess() ?
      this.containers.success : this.containers.failure;
    var response = this.transport.responseText;

    if (!this.options.evalScripts)
      response = response.stripScripts();

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        Element.update(receiver, response);
      }
    }

    if (this.responseIsSuccess()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  return $A(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(child);
    return elements;
  });
}

/*--------------------------------------------------------------------------*/


    var resolving = false;

    var txtPostalCode = new Object();
    var txtStreetNo = new Object();
    var txtStreetId = '<asp:Literal ID="litTxtStreetId" runat="server" />';
    var txtCityId = '<asp:Literal ID="litTxtCityId" runat="server" />';

    function handleResolveError(t)
    {
        window.status = 'Hard error in AJAX call: [' + t.status + '] ' + t.statusText;
        resolving = false;
    }

    function processResolveResponse(t)
    {
        var responseValues = t.responseText.split('|');
        
        if (parseInt(responseValues[0]) == 1)
        {
            var street = responseValues[1];
            var city = responseValues[2].toUpperCase();
            
            $(txtStreetId).value = street;
            $(txtCityId).value = city;
        }
        else
        {
            window.status = 'Soft error in AJAX call: [' + responseValues[0] + '] ' + responseValues[1];
        }
                
        resolving = false;
    }

    function autoResolveAddress(txtPostalCodeId, txtStreetNoId)
    {
        // store reference to input controls globally for processResolveResponse function
    
        txtPostalCode = $(txtPostalCodeId);
        txtStreetNo = $(txtStreetNoId);
    
        if (txtPostalCode.value.length >= 6 && txtStreetNo.value.length > 0)
        {
            var postalCode = txtPostalCode.value;
            var streetNo = txtStreetNo.value;
            
            var params = 'postalcode=' + postalCode + '&number=' + streetNo;
            
            if (resolving == false)
            {
                resolving = true;           
                
                // new Ajax.Request('/AuraTemplates/ResolvePostalcode.ashx?postalcode=6881WG&number=4');
                //, {asynchronous:true}

                var url = 'AuraTemplates/ResolvePostalcode.ashx?' + params;
                
                new Ajax.Request(
                        url, 
                        {
                            onSuccess:processResolveResponse, 
                            onFailure:handleResolveError
                        });
            }
        }
    }

-->