// File: TagSystem/js/assemblies/Core.js
// Dependencies: Protocol class (TagSystem/js/assemblies/Protocol.js)



// Capacent static class
var JSON = {};
(function() {
	function f(n) {
		return n < 10 ? '0' + n : n;
	}
	if (typeof Date.prototype.toJSON !== 'function') {
		Date.prototype.toJSON = function(key) {
			return isFinite(this.valueOf()) ?
							this.getUTCFullYear() + '-' +
							f(this.getUTCMonth() + 1) + '-' +
							f(this.getUTCDate()) + 'T' +
							f(this.getUTCHours()) + ':' +
							f(this.getUTCMinutes()) + ':' +
							f(this.getUTCSeconds()) + 'Z' : null;
		};
		String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function(key) {
			return this.valueOf();
		};
	}
	var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
		escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
		gap,
		indent,
		meta = {
			'\b': '\\b',
			'\t': '\\t',
			'\n': '\\n',
			'\f': '\\f',
			'\r': '\\r',
			'"': '\\"',
			'\\': '\\\\'
		},
		rep;
	function quote(string) {
		escapable.lastIndex = 0;
		return escapable.test(string) ? '"' + string.replace(escapable, function(a) {
			var c = meta[a];
			return typeof c === 'string' ? c :
				'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
		}) + '"' : '"' + string + '"';
	};

	function str(key, holder) {
		var i, k, v, length, mind = gap, partial, value = holder[key];
		if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
			value = value.toJSON(key);
		}
		if (typeof rep === 'function') {
			value = rep.call(holder, key, value);
		}
		switch (typeof value) {
			case 'string':
				return quote(value);
			case 'number':
				return isFinite(value) ? String(value) : 'null';
			case 'boolean':
			case 'null':
				return String(value);
			case 'object':
				if (!value) {
					return 'null';
				}
				gap += indent;
				partial = [];
				if (Object.prototype.toString.apply(value) === '[object Array]') {
					length = value.length;
					for (i = 0; i < length; i += 1) {
						partial[i] = str(i, value) || 'null';
					}
					v = partial.length === 0 ? '[]' :
						gap ? '[\n' + gap +
						partial.join(',\n' + gap) + '\n' +
						mind + ']' :
						'[' + partial.join(',') + ']';
					gap = mind;
					return v;
				}
				if (rep && typeof rep === 'object') {
					length = rep.length;
					for (i = 0; i < length; i += 1) {
						k = rep[i];
						if (typeof k === 'string') {
							v = str(k, value);
							if (v) {
								partial.push(quote(k) + (gap ? ': ' : ':') + v);
							}
						}
					}
				} else {
					for (k in value) {
						if (Object.hasOwnProperty.call(value, k)) {
							v = str(k, value);
							if (v) {
								partial.push(quote(k) + (gap ? ': ' : ':') + v);
							}
						}
					}
				}
				v = partial.length === 0 ? '{}' :
					gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
					mind + '}' : '{' + partial.join(',') + '}';
				gap = mind;
				return v;
		}
	}
	if (typeof JSON.stringify !== 'function') {
		JSON.stringify = function(value, replacer, space) {
			var i;
			gap = '';
			indent = '';
			if (typeof space === 'number') {
				for (i = 0; i < space; i += 1) {
					indent += ' ';
				}
			} else if (typeof space === 'string') {
				indent = space;
			}
			rep = replacer;
			if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
				throw new Error('JSON.stringify');
			}
			return str('', { '': value });
		};
	}
	if (typeof JSON.parse !== 'function') {
		JSON.parse = function(text, reviver) {
			var j;
			function walk(holder, key) {
				var k, v, value = holder[key];
				if (value && typeof value === 'object') {
					for (k in value) {
						if (Object.hasOwnProperty.call(value, k)) {
							v = walk(value, k);
							if (v !== undefined) {
								value[k] = v;
							} else {
								delete value[k];
							}
						}
					}
				}
				return reviver.call(holder, key, value);
			}
			cx.lastIndex = 0;
			if (cx.test(text)) {
				text = text.replace(cx, function(a) {
					return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
				});
			}
			if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
				j = eval('(' + text + ')');
				return typeof reviver === 'function' ?
walk({ '': j }, '') : j;
			}
			throw new SyntaxError('JSON.parse');
		};
	}

	var Capacent = {

		Util: {
			attachEvent: function(element, eventName, fn) {
				var eventNameWithOn = 'on' + eventName;
				if (typeof element.addEventListener != 'undefined') {
					element.addEventListener(eventName, fn, false);
				}
				else if (typeof element.document != 'undefined' && typeof element.document.addEventListener != 'undefined') {
					element.document.addEventListener(eventName, fn, false);
				}
				else if (typeof element.attachEvent != 'undefined') {
					element.attachEvent(eventNameWithOn, fn);
				}
				else {
					if (typeof element[eventNameWithOn] == 'function') {
						var existing = element[eventNameWithOn];
						element[eventNameWithOn] = function() {
							existing();
							fn();
						};
					}
					else {
						//setup function
						element[eventNameWithOn] = fn;
					}
				}
			},
			onLoadExternal: function(mywindow, fn) {
				this.attachEvent(mywindow, 'load', fn);
			},
			_onLoadCalls: null,
			onLoad: function(fn) {
				if (this._onLoadCalls == null) {
					var self = this;
					this._onLoadCalls = new Capacent.CallsQueue();
					this.onLoadExternal(window, function() { self._onLoadCalls.call(); });
				}
				this._onLoadCalls.add(fn);
			},
			_isLoaded: false,
			onLoadGuaranteed: function(fn) {
				if (this._isLoaded) {
					fn();
				} else {
					this.onLoad(fn);
				}
			},
			isDomReady: function() {
				return !!(document && document.getElementsByTagName && document.getElementById && document.body);
			},
			onDomReady: function(fn) {
				var self = this;
				if (self.isMSIE()) {
					self.onLoadGuaranteed(fn);
				} else {
					if (!self.isDomReady()) {
						setTimeout(function() { self.onDomReady(fn); }, 20);
						return;
					}
					fn();
				}
			},
			isMSIE: function() {
				return /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent);
			},
			isMSIE6: function() {
				return /msie 6/i.test(navigator.userAgent);
			},
			isFirefox: function() {
				return /firefox/i.test(navigator.userAgent);
			},
			getUrl: function() {
				var url;
				try {
					var doc = window.top;
					while (true) {
						doc = window.top;
						url = doc.location.href;
						if (doc == window.top) {
							break;
						}
					};
				} catch (ex) {
					url = url;
				} finally {
					return url || document.location.href;
				}
			},
			getHostname: function() {
				return document.location.hostname;
			},
			getPageArgs: function(myWindow) {
				var args = {};
				var location = (myWindow || window).location.href.toString();
				(/[?](.+)/).exec(location);
				var urlQuery = RegExp.$1;
				if (urlQuery != "") {
					Capacent.Array.each(urlQuery.split('&'), function(kv) {
						var param = kv.split('=');
						args[param[0]] = param.length == 0 ? null : param[1];
					});
				}
				return args;
			},
			setPageArgs: function(args) {
				var location = window.location.href.toString();
				(/([^?]+)/).exec(location);
				var url = RegExp.$1;
				var splitter = "?";
				for (var k in args) {
					url += splitter + k + "=" + args[k];
					splitter = "&";
				}
				window.location = url;
			},
			setVisibilityForPendentControls: function(show) {
				var d = function(s) {
					var elements = document.getElementsByTagName(s);

					for (var i = 0; i < elements.length; i++) {
						var elem = elements[i];

						if(elem.className.indexOf('urp-no-hide') >= 0){						
						    continue;
						}

						if (!show && elem.style.visibility ==  'hidden') {
							continue;
						}
						var v = show ? (typeof (elem.old_vis) == "undefined" ? 'visible' : elem.old_vis) : 'hidden';
						if (!show) {
							elem.old_vis = elem.style.visibility;
						}
						elem.style.visibility = v;
					}
				}
				d('object');
				d('embed');
				d('iframe');

				if (this.isMSIE()) {
					d('select');
				}
			},
			cancelEvent: function(event) {
				event.cancel = true;
				if (event.preventDefault) event.preventDefault();
				if (event.stopPropagation) event.stopPropagation();
			},
			mergeObjects: function(obj1, obj2) {
				for (attrname in obj2) {
					obj1[attrname] = obj2[attrname];
				}
				return obj1;
			},
			random: function() {
				return Math.ceil(100000 * Math.random());
			},
			convertFunctionToString: function(f) {
				var fName = "__capacentMethod" + this.random().toString();
				window[fName] = f;
				return fName;
			}
		},

		Css: {
			registerexternal: function(mywindow, styleText) {
				var styleElement = mywindow.document.createElement("style");
				styleElement.type = "text/css";
				if (styleElement.styleSheet) {
					styleElement.styleSheet.cssText = styleText;
				} else {
					styleElement.appendChild(mywindow.document.createTextNode(styleText));
				}
				var id = "CustomCSS_" + Math.random();
				styleElement.id = id;
				mywindow.document.getElementsByTagName("head")[0].appendChild(styleElement);
				return id;

			},
			register: function(styleText) {
				this.registerexternal(window, styleText);
			},
			registerUrl: function(url) {
				this.registerUrlExternal(window, url);
			},
			registerUrlExternal: function(mywindow, url) {
				if(Capacent.Css.isRegisteredExternal(mywindow, url)){
					return;
				}
				var linkElement = mywindow.document.createElement("link");
				linkElement.rel = "stylesheet";
				linkElement.type = "text/css";
				linkElement.href = url;
				mywindow.document.getElementsByTagName("head")[0].appendChild(linkElement);
			},
			isRegisteredExternal : function(mywindow, url) {			
				var links = mywindow.document.getElementsByTagName("head")[0].getElementsByTagName('link');
				for(var i = 0; i < links.length; i++){
					if(links[i].href.indexOf(url) > 0){
						return true;
					}
				}
				return false;
			},
			isRegistered : function(url) {			
				return this.isRegisteredExternal(window, url);
			},
			createCssBuilder: function() {
				var cssBuilder = {
					_rules: [],
					_currentRule: null,
					createRule: function(selector) {
						this._currentRule = {
							selector: selector,
							properties: {}
						};
						this._rules.push(this._currentRule);
					},
					addProperty: function(name, value) {
						if (Capacent.String.isNullOrEmpty(value)) {
							return;
						}
						this._currentRule.properties[name] = value;
					},
					toString: function() {
						var result = '';
						for (var i = 0; i < this._rules.length; i++) {
							var rule = this._rules[i];
							result += rule.selector + '{';
							for (var property in rule.properties) {
								result += property + ': ' + rule.properties[property] + ';';
							}
							result += '}';
						}
						return result;
					}
				};
				return cssBuilder;
			}
		},

		Ajax: {
			_crossDomainCallInited: false,
			crossDomainCall: function(url, method, params, onSuccess, onFailure, timeout) {
				if (this._crossDomainCallInited == false) {
					// ONLY FOR BACKWARD COMPATIBILITY
					if (typeof ($__BPN) == 'undefined') {
						$__BPN = {};
					}
					if (typeof ($__BPN.Protocol) == 'undefined') {
						$__BPN.Protocol = {};
					}
					if (typeof ($__BPN.Protocol.Complete) == 'undefined') {
						$__BPN.Protocol.Complete = Protocol.Complete;
					}
					// ONLY FOR BACKWARD COMPATIBILITY
					this._crossDomainCallInited = true;
				}
				var request = new Protocol(url);
				if (typeof (timeout) != "undefined") {
					request.Timeout = timeout;
				}
				request.execute(method, params, onSuccess, onFailure);
			}
		},

		String: {
			isNullOrEmpty: function(str) {
				return str == undefined || str == null || /^\s*$/.test(str);
			},
			replaceEx: function(str, data) {
				for (var p in data) {
					var r = new RegExp("{" + p + "}", "gi");
					str = str.replace(r, data[p]);
				}
				return str;
			}
		},

		RegularCookie: {
			set: function(name, value, days) {
				value = this._escape(value);
				if (days) {
					var date = new Date();
					date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
					var expires = "; expires=" + date.toGMTString();
				} else {
					var expires = '';
				}
				document.cookie = name + "=" + value + expires + "; path=/";
			},
			get: function(name) {
				var nameEQ = name + "=";
				var ca = document.cookie.split(';');
				for (var i = 0; i < ca.length; i++) {
					var c = ca[i];
					while (c.charAt(0) == ' ') c = c.substring(1, c.length);
					if (c.indexOf(nameEQ) == 0) return this._unescape(c.substring(nameEQ.length, c.length));
				}
				return null;
			},
			clear: function(name) {
				this.set(name, "", -1);
			},
			_escape: function(s) {
				return escape(decodeURIComponent(s));
			},
			_unescape: function(s) {
				return decodeURIComponent(unescape(s));
			}
		},

		Array: {
			each: function(arr, callback) {
				var c = arr.length;
				for (var i = 0; i < c; i++) {
					callback(arr[i], i, c);
				}
			}
		},

		CallsQueue: function() {
			var operations = [];
			this.add = function(op) {
				operations.push(op);
			};
			this.call = function() {
				var _operations = operations;
				operations = [];
				for (var i = 0; i < _operations.length; i++) {
					_operations[i]();
				}
			};
		},

		LazyCalls: function(initState) {
			var lazy = initState || true;
			var callsQueue = new Capacent.CallsQueue();
			this.call = function(op) {
				if (lazy) {
					callsQueue.add(op);
				} else {
					op();
				}
			};
			this.flush = function() {
				lazy = false;
				callsQueue.call();
			};
		},

		Synchronization: function() {
			var busy = false;
			var callsQueue = new Capacent.CallsQueue();
			this.lock = function(op) {
				if (busy) {
					callsQueue.add(op);
				} else {
					busy = true;
					op();
				}
			};
			this.release = function() {
				busy = false;
				callsQueue.call();
			};
		},

		TimeoutCall: function(time, op) {
			var timer = setTimeout(op, time);
			this.cancel = function() {
				if (timer != null) {
					clearTimeout(timer);
				}
			};
		},

		StopWatch: function() {
			var startTime = null;
			this.reset = function() {
				startTime = new Date().getTime();
			};
			this.duration = function() {
				var stopTime = new Date().getTime();
				return (stopTime - startTime) / 1000;
			};
			this.reset();
		},

		JSON: {
			encode: function(obj) {
				return JSON.stringify(obj);
			},
			decode: function(str) {
				return JSON.parse(str);
			}
		},
		init: function() {
			this.Util.onLoad(function() { Capacent.Util._isLoaded = true; });
		}
	};

	Capacent.init();


	if (typeof (window.Capacent) == "undefined") {
		window.Capacent = Capacent;
	} else {
		Capacent.Util.mergeObjects(window.Capacent, Capacent);
	}
} ());
// File: TagSystem/js/assemblies/Protocol.js

/************************************************************/
/********************** Protocol ****************************/
/************************************************************/
var addJS = function(src) {
	var s = window.document.createElement('script');
	s.setAttribute('type', 'text/javascript');
	s.setAttribute('charset', 'utf-8');
	s.setAttribute('src', src);
	window.document.documentElement.firstChild.appendChild(s);
};

Protocol = function(url) {
	this.ServiceURL = url;
};

// public properties
Protocol.prototype.ServiceURL = '';
Protocol.prototype.Timeout = 25000; // Default timeout is 25 sec
Protocol.prototype.RID = '';

// internal properties
Protocol.prototype.timerID = null;
Protocol.prototype.url = null;
Protocol.prototype.runing = false;

//Status codes
Protocol.ST_OK = 0;
Protocol.ST_METHOD_NOT_FOUND = 1;
Protocol.ST_SERVER_EXCEPTION = 2;
Protocol.ST_METHOD_EXCEPTION = 3;
Protocol.ST_TIMEOUT = 4;
Protocol.ST_OTHER = 10;

Protocol.ExplainCode = function(code) {
	switch (code) {
		case Protocol.ST_OK:
			return 'Ok';
		case Protocol.ST_METHOD_NOT_FOUND:
			return 'Method not found';
		case Protocol.ST_SERVER_EXCEPTION:
			return 'Serverside exception';
		case Protocol.ST_METHOD_EXCEPTION:
			return 'Unhandled method exception';
		case Protocol.ST_TIMEOUT:
			return 'Execution timeout';
		case Protocol.ST_OTHER:
			return 'Unknown';

	}
};

// Static fields
Protocol._pool = {};

// Private static methods
Protocol._send = function(url, instance, onSuccessCallback, onFailureCallback) {
	Protocol._pool[instance.RID] = { instance: instance, onSuccess: onSuccessCallback, onFailure: onFailureCallback };
	addJS(url);
};


// Public static methods
Protocol.Complete = function(rid, statusCode, data) {
	try {
		if (data != null) {
			//data = data.replace(/\n\r|\r\n|\n|\r/gi, '__NewLine__');
			//data = JSON.parse(data);
			data = eval('(' + data + ')');
			//for (var p in data) {
			//	data[p] = data[p].replace(/__NewLine__/, '\n');
			//}
		}
	} catch (ex) {
//		debugger;
		log("Fail to parse: " + ex);
		data = null;
	};

	var record = Protocol._pool[rid];
	if (record != null && typeof (record) != 'undefined') {
		clearTimeout(record.instance.timerID);
		//log('&larr; RID: ' + rid);

		if (statusCode == Protocol.ST_OK) {
			if (typeof (record.onSuccess) == 'function')
				record.onSuccess(data);
		}
		else {
			if (typeof (record.onFailure) == 'function')
				record.onFailure(statusCode, data);
		}
		record.instance.runing = false;
		delete Protocol._pool[rid];
	}
};

Protocol.prototype.execute = function(methodName, params, onSuccessCallback, onFailureCallback) {
	if (this.runing) {
		log('Already runned');
		return;
	}

	this.runing = true;
	var rid = 'PROTOCOL-' + Math.random();
	//log('&rarr; RID: ' + rid);
	this.RID = rid;
	var stringParams = '';
	for (var i = 0; i < params.length; i++) {
		var v = params[i];
		if (typeof (v) != 'number') {
			v = '"' + v + '"';
		}
		stringParams += v + (i != params.length - 1 ? ',' : '');
	}
	stringParams = '[' + stringParams + ']';

	var url = this.ServiceURL + '?methodName=' + escape(methodName) + '&params=' + escape(stringParams) + '&rid=' + rid + '&r=' + Math.random();
	//	log('-&gt;&nbsp;URL:&nbsp;' + escapeHTML(url));
	this.timerID = setTimeout(function() {
		Protocol.Complete(rid, Protocol.ST_TIMEOUT, null);
	}, this.Timeout);

	Protocol._send(url, this, onSuccessCallback, onFailureCallback);
};

window.$__Protocol = Protocol;
// File: TagSystem/js/assemblies/Logger.js

// Log class
Capacent.Log = function(constructorParams) {
	this.Enable = true;
	this.ModuleName = "";
	this._container = null;
	this._containerHTML = "";
	this.init = function() {
		if (typeof (Capacent.Log._container) == 'undefined') {
			if (document.body == null) {
				setTimeout(arguments.callee, 50);
				return;
			}
			var l = document.createElement('div');
			l.style.position = 'absolute';
			l.style.width = '400px';
			l.style.height = '500px';
			l.style.right = '0';
			l.style.top = '0';
			l.style.border = '2px solid #000';
			l.style.background = '#ddd';
			l.style.overflow = 'auto';
			l.style.padding = '5px';
			l.style.zIndex = '1000';
			l.style.fontFamily = 'Monospace';
			l.style.fontSize = '8pt';
			l.style.MozBoxSizing = 'border-box';
			Capacent.Log._container = document.body.appendChild(l);
			l.innerHTML = this._containerHTML;
			this._containerHTML = "";
		}
		this._container = Capacent.Log._container;
	};

	this.write = function(message) {
		if (this.Enable) {
			if (message != null && message != '') {
				var html = '&bull;&nbsp;' + this.ModuleName + ": " + message + '<br />';
				if (this._container == null) {
					this._containerHTML += html;
				} else {
					this._container.innerHTML += html;
				}
			}
		}
	};

	// read constructor parameters
	Capacent.Util.mergeObjects(this, constructorParams || {});

	if (typeof (constructorParams) != 'undefined') {
		this.Enable = typeof (constructorParams.Enable) != 'undefined' ? constructorParams.Enable : this.Enable;
		this.ModuleName = typeof (constructorParams.ModuleName) != 'undefined' ? constructorParams.ModuleName : this.ModuleName;
	}

	if (this.Enable) {
		this.init();
	}
};

// File: TagSystem/js/assemblies/CrossDomain.js
// Dependencies: Core (TagSystem/js/assemblies/Core.js)
//               Logger (TagSystem/js/assemblies/Logger.js)
//               Protocol (TagSystem/js/assemblies/Protocol.js)
/// <reference path="Core.js" />
/// <reference path="Protocol.js" />
/// <reference path="Logger.js" />

Capacent.CrossDomain = {
	StringStream: function(sessionId) {
		/// <summary>String stream communication between two sides: reader (message listner), writer (message sender)</summary>
		/// <param name="sessionId" type="String">Session within the scope of its communication goes</param>

		var self = this;
		this.className = "Capacent.CrossDomain.StringStream";
		this.log = function() { };
		var log = function(m) { self.log(m); };
		var isDisposed = false;
		var listenTimeout = 20000;
		var writeTimeout = 100;

		var hosts = ['//tag.userreport.com/CrossDomainProxy.ashx'];
		var usedHosts = [];
		var getUrl = function() {
			function randomUpTo(max) {
				return Math.floor(Math.random() * max);
			}

			if (usedHosts.length == 0 && hosts.length == 0) {
				log("Comet urls are not configured!");
				throw "Comet urls are not configured!";
			}
			if (hosts.length == 0) {
				hosts = usedHosts;
				usedHosts = [];
			}
			var i = randomUpTo(hosts.length);
			var host = hosts[i];
			usedHosts.push(host);
			hosts = hosts.slice(0, i).concat(hosts.slice(i + 1));

			return host;
		};
		var url = getUrl();
		var writeUrl = getUrl();
		this.write = function(str, callback) {
			///<summary>Write message and get callback when done</summary>
			///<param name="str">Text of message which will be sent</param>
			///<param name="callback">Function which will be invoked when message sent</param>

			if (!isDisposed) {
				log("Begin write '" + str + "'");
				Capacent.Ajax.crossDomainCall(writeUrl, "Write", [sessionId, str], callback, callback, writeTimeout);
			}
		};
		this.read = function(callback) {
			///<summary>Read message via get callback when new message comes</summary>
			///<param name="callback">Function which will be invoked when new message comes</param>

			if (!isDisposed) {
				// SetTimeout needs for suppress "Page loading..." message in Safari
				function listen(callback) {
					if (isDisposed) {
						log("Listener disposed");
					} else {
						log("Start listen...");
						var onSuccessCallback = function(result) {
							if (result.Value.Error) {
								log("Server error. Error=" + result.Value.Error);
							} else {
								if (!isDisposed) {
									log("Data received");
									callback(result.Value.Content);
								}
							}
							listen(callback);
						};
						var onFailureCallback = function(errorCode) {
							if (errorCode == 4) {
								log("Listener reconnection...");
							} else {
								log("Protocol error. Error-code=" + errorCode);
							}
							listen(callback);
						};
						Capacent.Ajax.crossDomainCall(url, "Read", [sessionId], onSuccessCallback, onFailureCallback, listenTimeout);
					}
				}
				log("Begin read...");
				listen(callback);
			}
		};
		this.close = function() {
			///<summary>Close communication channel</summary>

			if (!isDisposed) {
				isDisposed = true;
				log("Marked as disposed");
							}
		};
	}
};
// File: TagSystem/js/assemblies/Cookie.js
// Dependencies: Core (TagSystem/js/assemblies/Core.js)
//               Logger (TagSystem/js/assemblies/Logger.js)
//               Protocol (TagSystem/js/assemblies/Protocol.js)

Capacent.Cookie = {};
Capacent.Cookie.Result = function(id, sender, time) {
	this.Id = id || null;
	this.Sender = sender || null;
	this.Time = time || null;
	this.toString = function() {
		return "Id=" + this.Id
			+ " Sender=" + (this.Sender == null ? "" : this.Sender.className)
			+ " Time=" + (this.Time == null ? "" : this.Time);
	};
	this.serialize = function() {
		return "{id:'" + this.Id + "', senderClassName:'" + (this.Sender == null ? "" : this.Sender.className) + "', time:" + this.Time + "}";
	};
};
Capacent.Cookie.Silverlight = function(silverlightCookieUrl) {
	var self = this;
	var onready = new Capacent.LazyCalls();
	this._movie = null;
	this.className = "Capacent.Cookie.Silverlight";
	var url = silverlightCookieUrl;
	this.isEnabled = function() {
		function isInstalled(version) {
			if (version == undefined)
				version = null;

			var isVersionSupported = false;
			var container = null;

			try {
				var control = null;
				var tryNS = false;

				if (window.ActiveXObject) {
					try {
						control = new ActiveXObject('AgControl.AgControl');
						if (version === null) {
							isVersionSupported = true;
						}
						else if (control.IsVersionSupported(version)) {
							isVersionSupported = true;
						}
						control = null;
					}
					catch (e) {
						tryNS = true;
					}
				}
				else {
					tryNS = true;
				}
				if (tryNS) {
					var plugin = navigator.plugins["Silverlight Plug-In"];
					if (plugin) {
						if (version === null) {
							isVersionSupported = true;
						}
						else {
							var actualVer = plugin.description;
							if (actualVer === "1.0.30226.2")
								actualVer = "2.0.30226.2";
							var actualVerArray = actualVer.split(".");
							while (actualVerArray.length > 3) {
								actualVerArray.pop();
							}
							while (actualVerArray.length < 4) {
								actualVerArray.push(0);
							}
							var reqVerArray = version.split(".");
							while (reqVerArray.length > 4) {
								reqVerArray.pop();
							}

							var requiredVersionPart;
							var actualVersionPart;
							var index = 0;

							do {
								requiredVersionPart = parseInt(reqVerArray[index]);
								actualVersionPart = parseInt(actualVerArray[index]);
								index++;
							}
							while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);

							if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) {
								isVersionSupported = true;
							}
						}
					}
				}
			}
			catch (e) {
				isVersionSupported = false;
			}

			return isVersionSupported;
		}
		return isInstalled();
	};
	this.init = function() {
		function registerPlugin(params) {
			var html = [];
			html.push('<object type=\"application/x-silverlight\" data="data:application/x-silverlight,"');
			var id = params.id || ("__slPlugin" + Capacent.Util.random().toString());
			html.push(' id="' + id + '"');
			html.push(' width="1"');
			html.push(' height="1"');
			html.push(' >');
			var movie = null;
			for (key in params) {
				var value = params[key];
				if (value) {
					if (typeof (value) == 'function') {
						var f = value;
						value = Capacent.Util.convertFunctionToString(function() { f(movie); });
					};
					html.push('<param name="' + key + '" value="' + value + '" />');
				}
			}
			html.push('<\/object>');

			var l = document.createElement('div');
			l.style.width = '0px';
			l.style.height = '0px';
			l.style.position = 'absolute';
			l.style.left = '-10px';
			document.body.appendChild(l);
			l.innerHTML = html.join('');
			movie = l.firstChild;
			return movie;
		}
		registerPlugin({
			source: url,
			enableHtmlAccess: 'true',
			onLoad: function(movie) {
				self._movie = movie;
				onready.flush();
			}
		});
	};
	this.get = function(callback) {
		var time = new Capacent.StopWatch();
		onready.call(function() {
			var id = self._movie.Content.SLCookie.Get("UserId");
			callback(new Capacent.Cookie.Result(id == "" || id == "null" ? null : id, self, time.duration()));
		});
	};
	this.set = function(id, callback) {
		onready.call(function() {
			self._movie.Content.SLCookie.Set("UserId", id);
			callback(new Capacent.Cookie.Result(id, self));
		});
	};
};
Capacent.Cookie.Flash = function(flashCookieUrl) {
	var self = this;
	var onready = new Capacent.LazyCalls();
	this._movie = null;
	this.className = "Capacent.Cookie.Flash";
	var url = flashCookieUrl;
	this.isEnabled = function() {
		function isInstalled() {
			var getActiveXObject = function(name) {
				var obj = -1;
				try {
					obj = new ActiveXObject(name);
				} catch (err) {
					obj = { activeXError: true };
				}
				return obj;
			};
			var activeXDetectRules = [
				{ "name": "ShockwaveFlash.ShockwaveFlash.7" },
				{ "name": "ShockwaveFlash.ShockwaveFlash.6" },
				{ "name": "ShockwaveFlash.ShockwaveFlash" }
			];

			var flashDetect = function() {
				if (navigator.plugins && navigator.plugins.length > 0) {
					var type = 'application/x-shockwave-flash';
					var mimeTypes = navigator.mimeTypes;
					if (mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin && mimeTypes[type].enabledPlugin.description) {
						return true;
					}
				} else if (navigator.appVersion.indexOf("Mac") == -1 && window.execScript) {
					for (var i = 0; i < activeXDetectRules.length; i++) {
						var obj = getActiveXObject(activeXDetectRules[i].name);
						if (!obj.activeXError) {
							return true;
						}
					}
				}
				return false;
			};
			return flashDetect();
		}
		return isInstalled();
	};
	this.init = function() {
		function registerPlugin(params) {
			var insertFlash = function(node, id, url, width, height, params) {
				var object, param, key;
				function newParam(name, value) {
					if (0/*@cc_on + 1@*/) return ['<PARAM name="', name, '" value="', value, '" />'].join('');
					else {
						param = document.createElement('param');
						param.name = name;
						param.value = value;
						return param;
					}
				}
				if (0/*@cc_on + 1@*/) {
					object = ['<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="' + id + '" width="', width, '" height="', height, '"><PARAM name="movie" value="', url, '" />'];
					if (params) for (key in params) if (params.hasOwnProperty(key)) object.push(newParam(key, params[key]));
					object.push('</OBJECT>');
					node.innerHTML = object.join('');
				}
				else {
					object = document.createElement('object');
					object.type = 'application/x-shockwave-flash';
					object.id = id;
					object.data = url;
					object.width = width;
					object.height = height;
					if (params) for (key in params) if (params.hasOwnProperty(key)) object.appendChild(newParam(key, params[key]));
					while (node.firstChild) node.removeChild(node.firstChild);
					node.appendChild(object);
				}
			};

			var l = document.createElement('div');
			l.style.width = '1px';
			l.style.height = '1px';
			l.style.position = 'absolute';
			l.style.left = '-10px';
			document.body.appendChild(l);
			var id = params.id || ("__fshPlugin" + Capacent.Util.random().toString());
			delete params.id;
			var source = params.source;
			delete params.source;
			var movie = null;
			var runOnLoadAfter = false;
			if (typeof (params.onLoad) == 'function') {
				// IMPORTANT!!!: onFlashReady method should be implemented in flash movie, otherwise onLoad functionality will doesn't work!!!
				params.flashvars = "onFlashReady=" + Capacent.Util.convertFunctionToString(function() {
					if (movie == null) {
						runOnLoadAfter = true;
					} else {
						params.onLoad(movie);
					}
				});
			}
			insertFlash(l, id, source, 1, 1, params);
			movie = l.firstChild;
			if (runOnLoadAfter) {
				params.onLoad(movie);
			}
			return movie;
		}

		registerPlugin({
			source: url,
			allowScriptAccess: "always",
			onLoad: function(movie) {
				if (typeof (movie.getCookie) != "undefined" && typeof (movie.setCookie) != "undefined") {
					self._movie = movie;
					onready.flush();
				}
			}
		});

	};
	this.get = function(callback) {
		var time = new Capacent.StopWatch();
		onready.call(function() {
			var id = self._movie.getCookie();
			callback(new Capacent.Cookie.Result(id == "" || id == "null" ? null : id, self, time.duration()));
		});
	};
	this.set = function(id, callback) {
		onready.call(function() {
			self._movie.setCookie(id);
			callback(new Capacent.Cookie.Result(id, self));
		});
	};
};
Capacent.Cookie.LocalDomStorage = function() {
	var self = this;
	this.className = "Capacent.Cookie.LocalDomStorage";
	this.cookieKey = "BpnKey";
	ieStorage = null;
	this.get = function() {
		if (typeof (globalStorage) != "undefined") {
			try {
				var id = globalStorage[document.domain][this.cookieKey] || null;
				return Capacent.String.isNullOrEmpty(id) ? null : id;
			}
			catch (ex) {
				return null;
			}
		} else if (ieStorage != null) {
			return ieStorage.getAttribute(this.cookieKey);
		}
		return null;
	};
	this.set = function(id) {
		id = Capacent.String.isNullOrEmpty(id) ? null : id;
		if (typeof (globalStorage) != "undefined") {
			try {
				globalStorage[document.domain][this.cookieKey] = id;
			}
			catch (ex) { }
		} else if (ieStorage != null) {
			ieStorage.setAttribute(this.cookieKey, id);
			ieStorage.save(this.className);
		}
	};
	this.init = function() {
		var l = document.createElement('div');
		l.style.display = "none";
		if (l.addBehavior) {
			l.addBehavior("#default#userData");
			document.body.appendChild(l);
			ieStorage = l;
			ieStorage.load(this.className);
		}
	};
	this.initWindow = function() {
		// read args
		var args = Capacent.Util.getPageArgs();
		var id = args.Id || null;
		var result = args.Result || null;

		// run engine
		var action = (id == null) ? "get" : "set";
		if (result == null) {
			switch (action) {
				case "get":
					args.Result = self.get() || "null";
					Capacent.Util.setPageArgs(args);
					break;
				case "set":
					self.set(id);
					args.Result = id;
					Capacent.Util.setPageArgs(args);
					break;
			}
		}
	};
	Capacent.Util.onLoadGuaranteed(function() {
		self.init();
		self.initWindow();
	});
};
Capacent.Cookie.DomStorage = function(connectionStrings) {
	var self = this;
	this.className = "Capacent.Cookie.DomStorage";
	var url = connectionStrings.DomStorageUrl;
	var iframe = null;
	var requestTimeout = 1000;
	var onready = new Capacent.LazyCalls();
	var tagBackend = new Capacent.TagBackend(connectionStrings.BackendUrl);
	var sync = new Capacent.Synchronization();
	var getRequestResult = function(requestId, callback, timeoutState) {
		if (typeof (timeoutState) == "undefined") {
			timeoutState = { retry: true };
			var timeout = new Capacent.TimeoutCall(requestTimeout, function() { timeoutState.retry = false; });
		}
		tagBackend.getRequestResult(requestId, callback, function(args) {
			// if timeout, then retry
			if (args.Error == 4 && timeoutState.retry) {
				getRequestResult(requestId, callback, timeoutState);
			}
		}, timeoutState);
	};
	var getRequestId = function() { return Capacent.Util.random().toString() + Capacent.Util.random().toString() };
	this.isEnabled = function() {
		return (Capacent.Util.isFirefox() && typeof (globalStorage) != "undefined") || Capacent.Util.isMSIE();
	}
	this.init = function() {
		Capacent.Util.onDomReady(function() {
			if (self.isEnabled()) {
				var l = document.createElement('div');
				l.style.width = '1px';
				l.style.height = '1px';
				l.style.position = 'absolute';
				l.style.left = '-10px';
				l.innerHTML = "<iframe scrolling='no' frameborder='0' style='width:1px;height:1px'></iframe>";
				document.body.appendChild(l);
				iframe = l.firstChild;
				onready.flush();
			}
		});
	};
	var currentId = "undefined";
	this.get = function(callback) {
		var time = new Capacent.StopWatch();
		onready.call(function() {
			sync.lock(function() {
				var requestId = getRequestId();
				iframe.src = url + "?RequestId=" + requestId;
				getRequestResult(requestId, function(requestResult) {
					currentId = requestResult;
					sync.release();
					callback(new Capacent.Cookie.Result(requestResult, self, time.duration()));
				});
			});
		});
	};
	this.set = function(id, callback) {
		onready.call(function() {
			sync.lock(function() {
				if (id == currentId) {
					sync.release();
					callback(new Capacent.Cookie.Result(currentId, self));
				} else {
					var requestId = getRequestId();
					iframe.src = url + "?RequestId=" + requestId + "&Id=" + ((id == null || id == "") ? "null" : id.toString());
					getRequestResult(requestId, function(requestResult) {
						currentId = requestResult;
						sync.release();
						callback(new Capacent.Cookie.Result(requestResult, self));
					});
				}
			});
		});
	};
};
Capacent.Cookie.Proxy = function(connectionStrings) {
	var self = this;
	var timeoutTime = 3000;
	this.log = function() { };
	var log = function(m) { self.log(m); };
	//var modules = [new Capacent.Cookie.Silverlight(connectionStrings.SilverlightCookieUrl), new Capacent.Cookie.Flash(connectionStrings.FlashCookieUrl), new Capacent.Cookie.DomStorage(connectionStrings.domStorageUrl)];
	var modules = [new Capacent.Cookie.Silverlight(connectionStrings.SilverlightCookieUrl), new Capacent.Cookie.Flash(connectionStrings.FlashCookieUrl)];
	this.get = function(callback) {
		var isCallbackDone = false;
		function doCallbackOnce(result) {
			if (!isCallbackDone) {
				isCallbackDone = true;
				callback(result || new Capacent.Cookie.Result(null, null));
			}
		}
		var info = [];
		var returned = false;
		var c = modules.length;
		var i = 0;
		if (c == 0) {
			doCallbackOnce();
			self.onGetCompleted(info);
		} else {
			var additionalInfo = "";
			var timeout = new Capacent.TimeoutCall(timeoutTime, function() {
				log("Get timeout occurred. Executed for: " + additionalInfo);
				doCallbackOnce();
				self.onGetCompleted(info);
			});
			Capacent.Array.each(modules, function(module) {
				module.get(function(result) {
					additionalInfo += module.className + " ";
					i++;
					if (!returned && result.Id != null) {
						returned = true;
						// if is exist we set its to another modules
						self.set(result.Id, function() { });
						// call first callback
						doCallbackOnce(result);
					}
					info.push(result);
					// return if nothing found
					if (i == c) {
						timeout.cancel();
						doCallbackOnce();
						self.onGetCompleted(info);
					}
				});
			});
		}
	};
	this.onGetCompleted = function(info) { };
	this.set = function(id, callback) {
		var returned = false;
		var additionalInfo = "";
		var timeout = new Capacent.TimeoutCall(timeoutTime, function() {
			log("Set timeout occurred. Executed for: " + additionalInfo);
			callback(new Capacent.Cookie.Result(returned ? id : null, null));
		});
		var c = modules.length;
		var i = 0;
		Capacent.Array.each(modules, function(module) {
			module.set(id, function(res) {
				additionalInfo += module.className + " ";
				returned = true;
				i++;
				// waiting of all callbacks
				if (i == c) {
					timeout.cancel();
					callback(new Capacent.Cookie.Result(id, null));
				}
			});
		});
	};
	this.clear = function(callback) {
		this.set("", callback);
	};

	Capacent.Util.onDomReady(function() {
		// looking for enabled module
		var enabledModules = [];
		Capacent.Array.each(modules, function(module) {
			if (module.isEnabled()) {
				enabledModules.push(module);
			}
		});
		modules = enabledModules;
		// init
		Capacent.Array.each(modules, function(module) {
			module.init();
		});
	});
}
Capacent.TagBackend = function(backendUrl) {
	var self = this;
	this.log = function() { };
	var log = function(m) { self.log(m); };
	var url = backendUrl;
	this.getUser = function(localId, callback) {
		log('Send GetUser() request');
		Capacent.Ajax.crossDomainCall(url, "GetUser", [localId == null ? "" : localId],
			function(result) {
				result.executeClear = !Capacent.String.isNullOrEmpty(result.FlashIdToSet) && result.FlashIdToSet == "clear";
				result.idToSet = Capacent.String.isNullOrEmpty(result.FlashIdToSet) ? null : result.FlashIdToSet;
				callback(result);
			}, function(code, response) {
				log('Failed with code ' + code, response);
				callback({ Error: code });
			});
	};
	this.setUser = function(id, callback) {
		log('Send SetUser() request');
		Capacent.Ajax.crossDomainCall(url, "SetUser", [id],
			function(result) {
				result.executeClear = !Capacent.String.isNullOrEmpty(result.FlashIdToSet) && result.FlashIdToSet == "clear";
				result.idToSet = Capacent.String.isNullOrEmpty(result.FlashIdToSet) ? null : result.FlashIdToSet;
				callback(result);
			}, function(code, response) {
				log('Failed with code ' + code, response);
				callback({ Error: code });
			});
	};
	this.clearUser = function(callback) {
		log('Send ClearUser() request');
		Capacent.Ajax.crossDomainCall(url, "ClearUser", [],
			function(data) {
				callback({});
			}, function(code, response) {
				log('Failed with code ' + code, response);
				callback({ Error: code });
			});
	};
	this.getRequestResult = function(requestId, callback, errorCallback) {
		log('Send GetRequestResult(requestId=' + requestId + ') request');
		Capacent.Ajax.crossDomainCall(url, "GetRequestResult", [requestId],
			function(data) {
				callback(data.Value || null);
			}, function(code, response) {
				errorCallback({ Error: code, Response: response });
			});
	};
	this.writeDebugInfo = function(info) {
		log('Send WriteDebugInfo(' + info + ') request');
		Capacent.Ajax.crossDomainCall(url, "WriteDebugInfo", [info], function(data) { }, function(code, response) { });
	};
	this.writeMigrationInfo = function(userId) {
	var message = "User Migrated: " + userId;
	log('Send WriteLog(' + message + ') request');
		Capacent.Ajax.crossDomainCall(url, "WriteLog", [message], function(data) { }, function(code, response) { });
	}
};
Capacent.Tag = function(connectionStrings, performMigration) {
	performMigration = performMigration || false;
	var self = this;
	this.ConnectionStrings = {
		BackendUrl: '//tag.userreport.com/execute.ashx',
		FlashCookieUrl: '//tag.userreport.com/FlashCookieProxy.swf',
		SilverlightCookieUrl: '//tag.userreport.com/SilverlightCookieProxy.xap',
		DomStorageUrl: '//tag.userreport.com/DomStorageProxy.aspx'
	};

	Capacent.Util.mergeObjects(this.ConnectionStrings, connectionStrings);
	var cookie = new Capacent.Cookie.Proxy(this.ConnectionStrings);
	var backend = new Capacent.TagBackend(this.ConnectionStrings.BackendUrl);
	this.log = function() { };
	var log = function(m) { self.log(m); };
	cookie.log = log;
	backend.log = log;
	cookie.onGetCompleted = function(info) {
		var s = "[";
		var d = "";
		for (var i = 0; i < info.length; i++) {
			s += d + info[i].serialize();
			d = ",";
		}
		s += "]";
		backend.writeDebugInfo(s);
	};
	//var checkBVTRegex = /brugervenlighedstesten\.dk/i;
	var checkBVTRegex = /brugervenlighedstesten\.dk/i;
	this.get = function(callback) {
		log('Try to get local cookie');
		cookie.get(function(cookieResult) {
			log('Local cookie: ' + cookieResult.toString());
			backend.getUser(cookieResult.Id, function(backendResult) {
				log('GetUser() successfully completed', backendResult);
				if (backendResult.executeClear) {
					log("Clear local cookie");
					cookie.clear(function() { });
				}
				else if (backendResult.idToSet != null) {
					log("Update local cookie");
					cookie.set(backendResult.idToSet, function() { });
				}
				
				if (Capacent.String.isNullOrEmpty(backendResult.UserId) && performMigration) {
					//========= BEGIN Cookies Migration
					var scriptIncludes = document.getElementsByTagName("script");
					var loadedFromBVT = false;
					for (var i = 0; i < scriptIncludes.length; i++) {
						var script = scriptIncludes[i];
						if (checkBVTRegex.test(script.src)) {
							loadedFromBVT = true;
							break;
						}
					}
					if (loadedFromBVT == true) {
						log("=======================================");
						log("Script loaded from BVT. Try to migrate cookie");
						var bvtTAG = window.$__BVT_TAG;
						bvtTAG.GetUser(function(userId) {
							if (!Capacent.String.isNullOrEmpty(userId)) {
								log("<b>User id found: " + userId + "</b>");
								self.set(userId, function() {
									log("USER MIGRATED!");
								backend.writeMigrationInfo(userId);	
								});
							} else {
								log("User not found in BVT");
							}
							log("=======================================");
							callback(userId, backendResult, cookieResult);
						});
					} else {
						callback(backendResult.UserId, backendResult, cookieResult);
					}
					//========= END Cookies Migration
				} else {
					callback(backendResult.UserId, backendResult, cookieResult);
				}
			});
		});
	};

	this.set = function(id, callback) {
		backend.setUser(id, function(backendResult) {
			if (backendResult.executeClear) {
				log("Clear local cookie");
				cookie.clear(function() {
					if (callback) {
						callback(id);
					}
				});
			}
			else if (backendResult.idToSet != null) {
				log("Update local cookie");
				cookie.set(backendResult.idToSet, function() {
					if (callback) {
						callback(id);
					}
				});
			}
		});
	};

	this.clear = function(callback) {
		backend.clearUser(function(backendResult) {
			log("Clear local cookie");
			cookie.clear(function() {
				if (callback) {
					callback();
				}
			});

		});
	};
};

//Only for backward compatibility 
(function() {
	var TagPublicInterface = function(connectionStrings) {
		this.newTag = null;
		this.GetUser = function(callback) {
			this.init();
			this.newTag.get(callback);
		};
		this.SetUser = function(userId, callback) {
			this.init();
			this.newTag.set(userId, callback);
		};
		this.ClearUser = function(callback) {
			this.init();
			this.newTag.clear(callback);
		};
		this.SetLogger = function(logger) {
			this.init();
			this.newTag.log = logger;
		};
		this.init = function() {
			if (this.newTag == null) {
				this.newTag = new Capacent.Tag(connectionStrings);
			}
		};
	};

	window.$__TAG = new TagPublicInterface(null, true);
	window.$__BVT_TAG = new TagPublicInterface({
		BackendUrl: '//tag.brugervenlighedstesten.dk/execute.ashx',
		FlashCookieUrl: '//cookieproxy.brugervenlighedstesten.dk/FlashCookieProxy.swf',
		SilverlightCookieUrl: '//tag.brugervenlighedstesten.dk/SilverlightCookieProxy.xap',
		DomStorageUrl: '//tag.brugervenlighedstesten.dk/DomStorageProxy.aspx'
	}, false);

	window.$__getTAG = TagPublicInterface;
})();