/*
 * JSReg
 * Version 3.8.4.0
 * BSD License Template
 *
 * Copyright (c) 2009, Gareth Heyes.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials provided
 *        with the distribution.
 *     * Neither the name of Gareth Heyes nor the names of its
 *        contributors may be used to endorse or promote products derived
 *        from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
(function(){		
    var JSReg_Environment = function() {    	
        var msg = '', line, parseTree = [], protection = '$';
        function error(d){
            if (RegExp.lastMatch) {
                msg += '\n' + RegExp.lastMatch;
            }
            if (RegExp.lastParen) {
                msg += '\n' + RegExp.lastParen;
            }                          
            
            throw {
                description: d,
                msg: msg,
                line: line,
                parseTree: parseTree
            };
        }
        function objWhitelist(obj, list, noprototype) {          	
        	list = list.split(',');
        	for(var i=0;i<list.length;i++) {
        		var prop = list[i];
        		if(noprototype) {
        			obj[protection+prop+protection] = generateSafeFunc(obj, prop);
        		} else {
        			obj.prototype[protection+prop+protection] = generateSafeFunc(obj, prop);
        		}
        	}
        	return obj;
        }
        function constWhitelist(obj, list, transObj) {
        	list = list.split(',');
        	for(var i=0;i<list.length;i++) {
        		var prop = list[i];  
        		if(transObj) {
        			transObj[protection+prop+protection] = obj[prop];
        		} else {
        			obj[protection+prop+protection] = obj[prop];
        		}
        	}        	
        }
        function generateSafeFunc(obj, func, noArgsAllowed){        	        	
            var $window$ = generateSafeFunc[protection+'window'+protection];             
            return function (){            	          	
            	if(typeof obj['window'] == 'undefined' && obj['window'] === obj) {            		            
            		return $window$;
            	}  
            	            	
                for (var j = 0; j < arguments.length; j++) {
                    if (arguments[j] === null) {
                        return $window$;
                    }
                }
                var that = this, args = arguments;
                if (!that[func] && obj !== window.window) {
                    return $window$;
                }
                var result;
                result = (obj === window ? window : that)[func].apply(that, args);
                var win = (function(){                    
                	return this;
                    
                })();
                if (result === win) {
                    return $window$;
                }                
                return result;
            };
        }
        	var newLines = /[\r\n]+/,        	
			unicode = /\\u[0-9a-fA-F]{4}/,		
			natives = /(?:eval|setTimeout|setInterval|Function|window|alert|Object|Math|String|RegExp|Date|Number|Array)/, 
			endStatement = /(?:(?:^\s*|\s*$)|[,]|[;\n\r]+)/, spaces = /\s*/, 			
			variable = new RegExp("(?:[a-zA-Z_$]|" + unicode.source + ")(?:[\\w$_]|" + unicode.source + ")*"),
			operators = /(?:[!][=]{0,2}|[%][=]?|[&]{1,2}|[&][=]|[*][=]?|[+]{1,2}|[+][=]|[\-]{1,2}|[\-][=]|[\/][=]?|[<]{1,2}[=]?|[=]{1,3}|[>]{1,3}[=]?|[\^][=]?|[|][=]?|[|]{2})/, 
			jsregArrays = new RegExp('(?:@#[(])'),
			functionCalls = new RegExp('(?:[.]?'+spaces.source + '(?:' + variable.source + ')' + spaces.source + ')[(]'), 
			functionDec = new RegExp(spaces.source + '(?:function' + spaces.source + '(?:' + variable.source + ')?)' + spaces.source + '[(](?:' + spaces.source + variable.source + spaces.source + ')?(?:[,]' + spaces.source + variable.source + spaces.source + ')*' + '[)]' + spaces.source + '[{]'), 
			statements = new RegExp('(?:(?:\\s+(?:in(?:stanceof)?)\\s+)|' + spaces.source + '\\b(?:this|Infinity|NaN|void|do|else|case|default|return|var|continue|undefined|null|new|typeof|throw|break|try|finally|true|false)\\b' + spaces.source + '|' + spaces.source + '\\b(?:if|else\\s' + spaces.source + 'if|with|while|for|switch|catch)\\b' + spaces.source + '(?=[(]))'), 			 
			objects = new RegExp('(?:[.]?' + spaces.source + variable.source + ')'),
			regexpObj = new RegExp("(?:[\\/](?:\\[(?:\\\\[\\]]|[^\\]])+\\]|\\\\[\\/]|[^\\/*])(?:\\[(?:\\\\[\\]]|[^\\]])+|\\\\[\\/]|[^\\/])*?[\\/](?:[gmi]*))"), 
			regexpsLeft = new RegExp('(?:' + endStatement.source + '|' + operators.source + '|[(]+)' + spaces.source),
			regexps = new RegExp('(?:'+regexpObj.source+'|'+regexpsLeft.source+regexpObj.source + ')' + spaces.source + '(?:' + endStatement.source + '|' + operators.source + '|[)]+|(?=' + spaces.source + '[\\[.\\}\\]]))'), 
			strings = new RegExp("(?:(?:['](?:\\\\{2}|\\\\[']|\\\\[\\r\\n]|[^'])*['])|(?:[\"](?:\\\\{2}|\\\\[\"]|\\\\[\\r\\n]|[^\"])*[\"]))"), 									
			squareOpen = new RegExp(spaces.source+"[\\[]"),
			squareClose = new RegExp(spaces.source+"[\\]]"),
			forInStart = new RegExp("for"+spaces.source+"[(]"+spaces.source),
			forInDefine = new RegExp("(?:var\\s+)?"+variable.source),
			forInStatement = new RegExp("\\s+in"),
			forInEnd = new RegExp(spaces.source+"(?:"+strings.source+"|"+regexpObj.source+"|"+objects.source+"|[{](?:.|"+strings.source+"|"+regexpObj.source+")*[}]|[(](?:.|"+strings.source+"|"+regexpObj.source+")*[)])"+spaces.source+"[)]"+spaces.source+"[{]?"),
			forIn = new RegExp(forInStart.source+forInDefine.source+forInStatement.source+forInEnd.source),			
			numbers = new RegExp('(?:[0][xX][0-9a-fA-F]*)|(?:[0]|[1-9]\\d+)?(?:[.]?\\d+)+(?:[eE][+-]?\\d+)?'), 
			objectIdentifiers = new RegExp('[,\\{]' + spaces.source + '(?:' + strings.source + '|' + numbers.source + '|' + variable.source + ')' + spaces.source + '(?=[:])'), 
			inInstanceofOperator = new RegExp("\\s*in(?:stanceof)?(?=[\\/\\d\"'\\[\\s\\(\\{])"), 			
			eos = /[,;]/,
			endCurlyBrace = /[}]/,			 			
			mainRegExp = new RegExp('(' + newLines.source + ')|('+forIn.source+')|(' + inInstanceofOperator.source + ')|' + '(' + statements.source + ')|(' + objectIdentifiers.source + ')|(' + strings.source + ')|' + '(' + regexps.source + ')|' + '(' + numbers.source + ')|(' + squareOpen.source + ')|' + '(' + squareClose.source + ')|' + '(' + functionDec.source + ')|' + '(' + jsregArrays.source + ')|' + '(' + functionCalls.source + ')' + '|(' + objects.source + ')|('+eos.source+')|('+operators.source+')|('+endCurlyBrace.source+')', 'gm'), 
		Parser = function(){
            this.init();
        };       
        var allowedProperties = /\b(?:length|global|ignoreCase|input|multiline|source|lastIndex|prototype)\b/;
        var constants = false;
        (function(){
        	try {
        		eval("const CONSTANT_CHECK=1;");constants = true;
        	} catch(e){
        		constants = false;
        	}   
        	if(constants) {
	        	try {eval("CONSTANT_CHECK=2;");} catch(e){}
	        	if(CONSTANT_CHECK == 2) {
	        		constants = false;
	        	}
        	}
        	
        })();
        
        Parser.prototype = {
            doc: null,
            win: null,
            windowExtensions: [],
            objectExtensions: [],
            debugObjects: {},
            extendObject: function(name, value) {
            	this.objectExtensions.push({
                    name: name,
                    value: value
                });
            },
            extendWindow: function(name, value){
                this.windowExtensions.push({
                    name: name,
                    value: value
                });
            },
            getWindow: function(){
                return this.win;
            },
            setDocument: function(obj){
                this.doc = obj;
            },
            setWindow: function(obj){
                this.win = obj;
            },
            addSymbol: function(symbol){             	
                if (new RegExp('^['+protection+']' + natives.source + '['+protection+']$').test(symbol)) {
                    return false;
                }                                               
                if (!new RegExp('^['+protection+']' + variable.source + '['+protection+']$').test(symbol)) {                	                                 	
                	error('Parser error:Invalid symbol');
                    return false;
                }
                if (typeof this.symbolsMap[symbol] == "undefined") {
                    this.symbols.push(symbol);
                    this.symbolsMap[symbol] = true;
                }
            },
            setDebugObjects: function(obj){
                this.debugObjects = obj;
            },
            addGlobals: function(symbols){
                var code = '';
                for (var i = 0; i < symbols.length; i++) {
                    code += protection+'window'+protection+'.' + symbols[i] + '=' + symbols[i] + ';';
                }
                return code;
            },
            extractSymbols: function(code){
                if (this.symbols.length) {
                    var symbols = this.symbols;
                    if (symbols.length) {
                        var originalCode = code;
                        var symbolsList = [];
                        for (var i = 0; i < symbols.length; i++) {
                            var found = 0;
                            for (var j = 0; j < this.extractedSymbols.length; j++) {
                                if (this.extractedSymbols[j] == symbols[i]) {
                                    found = 1;
                                    break;
                                }
                            }
                            if (!found) {
                                symbolsList.push(symbols[i]);
                            }
                        }
                        if (symbolsList.length) {
                            code = 'var ' + symbolsList.join(',') + ';';
                            code += this.addGlobals(symbolsList) + '\n';
                            code += originalCode;
                            this.extractedSymbols.push(symbolsList);
                        }
                    }
                }
                return code;
            },
            init: function(){            	
                this.symbols = [];
                this.symbolsMap = {};
                this.extractedSymbols = [];                
                this.loopNumber = 0;
                this.maxFuncCalls = 100000;                
                parseTree = [];
                this.windowExtensions = [];
                this.objectExtensions = [];
                this.doc = null;
                this.win = null;
            },
            removeComments: function(str){   
            	
            	/* 
                This function is loosely based on the one found here:
                http://www.weanswer.it/blog/optimize-css-javascript-remove-comments-php/
                +
                from: http://james.padolsey.com/javascript/removing-comments-in-javascript/
                +
                patched by me
            	*/
            	
        	    str = str.split("");
        	    var mode = {
        	        singleQuote: false,
        	        doubleQuote: false,
        	        regex: false,
        	        blockComment: false,
        	        lineComment: false,
        	        condComp: false,
        	        escaping: false,
        	        regexSquare: false,
        	        multilineComment: false        	        
        	    }; // added escaping & square mode by gareth
        	    
        	    
        	    for (var i = 0, l = str.length; i < l; i++) {
        	 
        	        if (mode.regex) {  
        	        	/* Begin patch by Gareth */
        	        	if(str[i] === '\\' && mode.escaping == true) {
        	        		mode.escaping == false;
        	        	}
        	        	
        	        	if(str[i] === '\\' && mode.escaping == false) {
        	        		mode.escaping == true;
        	        	} 
        	        	
        	        	if(str[i] === '[' && !mode.escaping) {
        	        		mode.regexSquare = true;
        	        	}
        	        	
        	        	if(str[i] === ']' && !mode.escaping) {
        	        		mode.regexSquare = false;
        	        	}
        	        	/* End patch by Gareth */
        	        	
        	            if (str[i] === '/' && (str[i-1] !== '\\' || !mode.escaping) && !mode.regexSquare) {//added escapes and square detection by Gareth        	                        	            	
        	            	mode.regex = false;
        	            }
        	            continue;
        	        }
        	 
        	        if (mode.singleQuote) {
        	        	/* Begin patch by Gareth */
        	        	if(str[i] === '\\' && mode.escaping == true) {
        	        		mode.escaping == false;
        	        	}
        	        	
        	        	if(str[i] === '\\' && mode.escaping == false) {
        	        		mode.escaping == true;
        	        	} 
        	        	/* End patch by Gareth */
        	            if (str[i] === "'" && (str[i-1] !== '\\' || !mode.escaping)) {//added escaping by gareth
        	                mode.singleQuote = false;
        	            }
        	            continue;
        	        }
        	 
        	        if (mode.doubleQuote) {  
        	        	/* Begin patch by Gareth */
        	        	if(str[i] === '\\' && mode.escaping == true) {
        	        		mode.escaping == false;
        	        	}
        	        	
        	        	if(str[i] === '\\' && mode.escaping == false) {
        	        		mode.escaping == true;
        	        	}        	        	        	        	
        	        	/* End patch by Gareth */
        	            if (str[i] === '"' && (str[i-1] !== '\\' || !mode.escaping)) {//added escaping by gareth        	                
        	            	mode.doubleQuote = false;
        	            }
        	            continue;
        	        }
        	 
        	        if (mode.blockComment) {        	        	
        	            if (str[i] === '*' && str[i+1] === '/') {
        	                str[i+1] = '';
        	                mode.blockComment = false;
        	            }
        	            str[i] = '';
        	            continue;
        	        }
        	 
        	        if (mode.lineComment) {
        	            if (str[i+1] === '\n' || str[i+1] === '\r') {
        	                mode.lineComment = false;
        	            }
        	            str[i] = '';
        	            continue;
        	        }
        	 
        	        if (mode.condComp) {
        	            if (str[i-2] === '@' && str[i-1] === '*' && str[i] === '/') {
        	                mode.condComp = false;
        	            }
        	            continue;
        	        }
        	                	              	                	                	               	       
        	        mode.doubleQuote = str[i] === '"';
        	        mode.singleQuote = str[i] === "'";
        	 
        	        if (str[i] === '/') {
        	 
        	            if (str[i+1] === '*' && str[i+2] === '@') {
        	            	
        	            	if(str[i-1] === '\n' || i === 0) {
        	            		mode.multilineComment = true;
        	            	}
        	            	
        	                mode.condComp = true;
        	                continue;
        	            }
        	            if (str[i+1] === '*') { 
        	            	
        	            	if(str[i-1] === '\n' || i === 0) {
        	            		mode.multilineComment = true;
        	            	}
        	            	
        	            	str[i] = '';
        	            	str[i+1] = '';//patch by gareth
        	                mode.blockComment = true;
        	                continue;
        	            }
        	            if (str[i+1] === '/') {
        	                str[i] = '';
        	                mode.lineComment = true;
        	                continue;
        	            }  
        	             var leftContext = '';
        	             for(var j=20;j>0;j--) {
        	            	 if(typeof str[i-j] != 'undefined') {
        	            		 leftContext += str[i-j];
        	            	 }
        	             }
        	             if(i === 0 || new RegExp('(?:'+operators.source+'|[,;(])'+spaces.source+'$','im').test(leftContext)) {        	            	 
        	            	 mode.regex = true;
        	             } else {
        	            	 continue;
        	             }
        	            
        	 
        	        } 
        	        //Added crazy legacy stuff by gareth        	                	                	       
        	        if((mode.multilineComment || i === 0 || str[i-1] === '\n') &&  str[i] === '-' && str[i+1] === '-' && str[i+2] === '>') {
        	        	mode.lineComment = true;
        	        	str[i] = '';
        	        	str[i+1] = '';
        	        	str[i+2] = '';
        	        	continue;
        	        }
        	        
        	        if(str[i] === '<' && str[i+1] === '!' && str[i+2] === '-' && str[i+3] === '-') {
        	        	mode.lineComment = true;
        	        	str[i] = '';
        	        	str[i+1] = '';
        	        	str[i+2] = '';
        	        	str[i+3] = '';
        	        	continue;
        	        } 
        	        
        	        if(mode.multilineComment && !/\s/.test(str[i]) && !(str[i+1] === '-' && str[i+2] === '-' && str[i+3] === '>')) {
        	        	mode.multilineComment = false;
        	        }
        	        
        	    }          	            	            	    
        	    return str.join('');            	
            },
            'eval': function(code, thisObject){               	            	            	           
                if (this.debugObjects.onStart) {
                    this.debugObjects.onStart();
                }
                parseTree = [];
                if (this.debugObjects.clearTree) {
                    this.debugObjects.clearTree();
                }               
                if (typeof thisObject == 'undefined') {
                    thisObject = {};
                }
                var that = this;
                var result;
                try {
                    execCode.apply(thisObject, []);
                } 
                catch (e) {
                    if (that.debugObjects.errorHandler) {
                        that.debugObjects.errorHandler(e, that);
                    }
                }                               
                
                function execCode() {                	                    
                	var freshWindow = that.environment.contentWindow;                	                    
                    var maxLoops = that.maxLoops;
                    var maxLoopCounter = 0;
                    var maxFuncCalls = that.maxFuncCalls;
                    var setTimeoutIDS = {};
                    var setIntervalIDS = {};
                    var JSREG_FUNC = {                        
                    		'gp': function(){                               
	                        	var exp = arguments[arguments.length-1]; 	                        		                        		                        	
		                        if(typeof exp == 'undefined') {
		                                return null;
		                        }                        
		                        if (/[^\d]/.test(exp) || exp === '') {
									if (new RegExp("^" + allowedProperties.source + protection).test(exp)) {
									    return exp;
									}                                
									return protection + exp + protection;
								} else {                                    
									return +exp;
								}
						},
                    	getThis: function(obj){                         	                        	                        	
                        	if(typeof obj['window'] == 'undefined' && obj['window'] !== obj) {
                        		return obj;
                        	} else {
                        		return $window$;
                        	}                        	                           
                        },                        
                        checkMaxFunctCalls: function(funct){
                            var Static;
                            if (Static === undefined) {
                                Static = {};
                            }
                            Static = funct || arguments.callee.caller;
                            Static.counter = ++Static.counter || 1;
                            if(Static.maxFuncCalls) {
                            	var max = Static.maxFuncCalls; 
                            } else {
                            	var max = maxFuncCalls;
                            }
                            if (Static.counter > max) {
                                if (freshWindow.confirm('A function is recuring often, click ok to stop the function.')) {
                                	freshWindow = null;
                                	error("Parser error: Maximum amount of function calls hit.");                                	
                                	return false;
                                } else {                                	
                                	Static.counter = 0;
                                    return true;
                                }
                            } else {
                                return true;
                            }
                        }
                    };                                  
                    
                    var $document$ = {}, $window$ = {};
                    generateSafeFunc.$window$ = $window$;                                         
                    
                    function FUNCTION(){                    	
                        if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        var JSREG_A = function() {  
                        	return [].slice.call(arguments,0);                    	                    
                        }
                        var func;
                        var parser = that;
                        parser.rewrite.previousMatch = '';                                                 
                    	var converted = parser.rewriteArrays(freshWindow.Function.apply(this, arguments) + '');
                    	converted = parser.removeComments(converted);                    	
                        converted = "func=" + parser.rewrite(converted);                        
                        parser.checkSyntax(converted);                        
                        converted = parser.extractSymbols(converted);
                        if (parser.debugObjects.functionCode) {
                            parser.debugObjects.functionCode(converted);
                        }
                        if (parser.debugObjects.doNotFunctionEval) {
                            return converted;
                        } else {
                            return eval(converted);
                        }
                    };
                    FUNCTION.$constructor$ = FUNCTION;                                                                                                                      
                    if(constants) { 
                    	eval("const $Function$ = FUNCTION;")                    	
                    } else {
                    	$Function$ = FUNCTION;
                    }                    
                                                                                                   
                    var Boolean = freshWindow.Boolean;
                    Boolean.$constructor$ = $Function$;
                    Boolean.prototype.$constructor$ = Boolean;                                       
                    if(constants) { 
                    	eval("const $Boolean$ = Boolean;")                    	
                    } else {
                    	 $Boolean$ = Boolean;
                    }                     
                    var Function = freshWindow.Function;
                    Function.prototype.$constructor$ = $Function$;
                    Function.prototype.$call$ = generateSafeFunc(freshWindow.Function, 'call');
                    Function.prototype.$apply$ = generateSafeFunc(freshWindow.Function, 'apply');
                                        
                    var String = objWhitelist(freshWindow.String,'charAt,charCodeAt,concat,indexOf,lastIndexOf,localeCompare,match,replace,search,slice,split,substr,substring,toLocaleLowerCase,toLocaleString,toLocaleUpperCase,toLowerCase,toUpperCase');
                    String.$fromCharCode$ = generateSafeFunc(freshWindow.String, 'fromCharCode');
                    String.prototype.$constructor$ = String;
                    String.$constructor$ = $Function$;                                        
                    if(constants) { 
                    	eval("const $String$ = String;")                    	
                    } else {
                    	 $String$ = String;
                    }                                                                                  
                    var Array = objWhitelist(freshWindow.Array,'sort,join,pop,push,reverse,shift,slice,splice,unshift,concat');                                                                                                                                     
                    Array.prototype.$constructor$ = Array;
                    Array.$constructor$ = $Function$;                                                                  
                    if(constants) { 
                    	eval("const $Array$ = freshWindow.Array;")                    	
                    } else {
                    	 $Array$ = freshWindow.Array;
                    }                     
                    var JSREG_A = function() {  
                    	return [].slice.call(arguments,0);                    	                    
                    }                    
                    var RegExp = objWhitelist(freshWindow.RegExp,'compile,exec,test');
                    RegExp.prototype.$constructor$ = RegExp;                    
                    RegExp.$lastMatch$ = RegExp.lastMatch;
                    RegExp.$lastParen$ = RegExp.lastParen;
                    RegExp.$leftContext$ = RegExp.leftContext;
                    RegExp.$rightContext$ = RegExp.rightContext;
                    RegExp.$constructor$ = $Function$;                                        
                    if(constants) { 
                    	eval("const $RegExp$ = RegExp;")                    	
                    } else {
                    	 $RegExp$ = RegExp;
                    }                                                               
                    var Number = objWhitelist(freshWindow.Number,'toExponential,toFixed,toPrecision');
                    constWhitelist(Number, 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY');                                      
                    Number.$constructor$ = $Function$;                    
                    if(constants) { 
                    	eval("const $Number$ = Number;")                    	
                    } else {
                    	 $Number$ = Number;
                    }                                     
                    var Date = objWhitelist(freshWindow.Date,'getDate,getDay,getFullYear,getHours,getMilliseconds,getMinutes,getMonth,getSeconds,getTime,getTimezoneOffset,getUTCDate,getUTCDay,getUTCFullYear,getUTCHours,getUTCMilliseconds,getUTCMinutes,getUTCMonth,getUTCSeconds,getYear,setDate,setFullYear,setHours,setMilliseconds,setMinutes,setMonth,setSeconds,setTime,setUTCDate,setUTCFullYear,setUTCHours,setUTCMilliseconds,setUTCMinutes,setUTCMonth,setUTCSeconds,setYear,toDateString,toGMTString,toLocaleDateString,toLocaleString,toLocaleTimeString,toTimeString,toUTCString');                    
                    Date.prototype.$constructor$ = Date;
                    Date.$constructor$ = $Function$;
                    if(constants) { 
                    	eval("const $Date$ = Date;")                    	
                    } else {
                    	 $Date$ = Date;
                    }                                                              
                    var Math = objWhitelist(freshWindow.Math,'abs,acos,asin,atan,atan2,ceil,cos,exp,floor,log,max,min,pow,random,round,sin,sqrt,tan', true);
                    constWhitelist(Math, 'E,LN10,LN2,LOG10E,LOG2E,PI,SQRT1_2,SQRT2');                                                                                                  
                    Math.$constructor$ = Object;
                    if(constants) { 
                    	eval("const $Math$ = Math;")                    	
                    } else {
                    	 $Math$ = Math;
                    }                                       
                    constWhitelist(freshWindow,'decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,escape,isFinite,isNaN,parseFloat,parseInt,unescape', $window$);                    
                   function CLEAR_INTERVAL(id){
                    	if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        id = +id;
                        if (typeof setIntervalIDS[id] == 'undefined') {
                            return null;
                        }
                        return freshWindow.clearInterval(id);
                    };
                    if(constants) { 
                    	eval("const $clearInterval$ = CLEAR_INTERVAL;")                    	
                    } else {
                    	$clearInterval$ = CLEAR_INTERVAL;
                    }  
                    var CLEAR_TIMEOUT = function(id){
                    	if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        id = +id;
                        if (typeof setTimeoutIDS[id] == 'undefined') {
                            return null;
                        }
                        return freshWindow.clearTimeout(id);
                    };
                    if(constants) { 
                    	eval("const $clearTimeout$ = CLEAR_TIMEOUT;")                    	
                    } else {
                    	$clearTimeout$ = CLEAR_TIMEOUT;
                    }                     
                    var SET_TIMEOUT = function(func, time){
                    	if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        time = +time;
                        if (time && time >= 0) {
                            if (typeof func !== 'function') {
                                func = $Function$(func);
                            }
                            var id = +freshWindow.setTimeout(func, time);
                            setTimeoutIDS[id] = true;
                            return id;
                        } else {
                            error("Parser error:Incorrect second arguments supplied.");
                        }
                    }; 
                    if(constants) { 
                    	eval("const $setTimeout$ = SET_TIMEOUT;")                    	
                    } else {
                    	$setTimeout$ = SET_TIMEOUT;
                    }                      
                    var SET_INTERVAL = function(func, time){
                    	if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        time = +time;
                        if (time && time >= 0) {
                            if (typeof func !== 'function') {
                                func = $Function$(func);
                            }
                            var id = +freshWindow.setInterval(func, time);
                            setIntervalIDS[id] = true;
                            return id;
                        } else {
                            error("Parser error:Incorrect second arguments supplied.");
                        }
                    };
                    if(constants) { 
                    	eval("const $setInterval$ = SET_INTERVAL;")                    	
                    } else {
                    	$setInterval$ = SET_INTERVAL;
                    }                     
                    var ALERT = function(str){
                    	$alert$.maxFuncCalls = 20;
                    	if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        freshWindow.alert(str);
                    };
                    if(constants) { 
                    	eval("const $alert$ = ALERT;")                    	
                    } else {
                    	window.$alert$ = ALERT;
                    }                     
                    var EVAL = function(str){
                    	if(!JSREG_FUNC.checkMaxFunctCalls()) {
                        	return null;
                        }
                        var parser = that;
                        parser.rewrite.previousMatch = '';
                        if (typeof str == 'string') {                        	 
                        	var JSREG_A = function() {  
                            	return [].slice.call(arguments,0);                    	                    
                            }
                        	var converted = parser.removeComments(str);
                        	converted = parser.rewriteArrays(converted);
                        	converted = parser.rewrite(converted);                                                       
                            parser.checkSyntax(converted);
                        } else {
                            converted = str;
                        }
                        converted = parser.extractSymbols(converted);
                        if (parser.debugObjects.evalCode) {
                            parser.debugObjects.evalCode(converted);
                        }
                        if (parser.debugObjects.evalCode) {
                            parser.debugObjects.evalCode(converted);
                        }
                        
                        if (parser.debugObjects.doNotEval) {
                            return converted;
                        } else {
                            with ($window$) {
                                converted = eval(converted);
                            }
                            return converted;
                        }
                    };
                    if(constants) { 
                    	eval("const $eval$ = EVAL;")                    	
                    } else {
                    	$eval$ = EVAL;
                    }                                        
                    if (that.doc) {
                        $document$ = that.doc;
                    }
                    if (that.win) {
                        $window$ = that.win;
                    }                                                                              
                    var Object = freshWindow.Object;
                    Object.$constructor$ = $Function$;
                    Object.prototype.$constructor$ = Object;
                    Object.prototype.$hasOwnProperty$ = function(prop){
                        return this.hasOwnProperty(protection + prop + protection);
                    };
                    Object.prototype.$valueOf$ = generateSafeFunc(freshWindow.Object, 'valueOf');
                    Object.prototype.$toString$ = generateSafeFunc(freshWindow.Object, 'toString');                                                                                           
                    Object.prototype.JSREG_PROP = function(val) {                     	                    	                    	
                        if (/[^\d]/.test(val)) {
                            return this['$' + val + '$'];
                        } else {
                            return this[+val];
                        }                    	
                    }
                    Object.prototype.JSREG_ITEM = function() {
                    	var val = this.toString();
                        if (/[^\d]/.test(val)) {
                            return '$' + val + '$';
                        } else {
                            return +val;
                        }                    	
                    }  
                    for (var i = 0; i < that.windowExtensions.length; i++) {
                        var winProp = that.windowExtensions[i];                        
                        $window$[winProp.name] = winProp.value;
                        $window$[winProp.name].JSREG_PROP = Object.prototype.JSREG_PROP;
                        $window$[winProp.name].JSREG_ITEM = Object.prototype.JSREG_ITEM;
                    }  
                    for (var i = 0; i < that.objectExtensions.length; i++) {
                        var objProp = that.objectExtensions[i];
                        Object.prototype[objProp.name] = objProp.value;                        
                    }
                    if(constants) { 
                    	eval("const $Object$ = Object;")                    	
                    } else {
                    	$Object$ = Object;
                    }   
                    
                    winProp = null;    
                    code = that.removeComments(code);
                    var lines = code.split(/;\r?\n(?![\r\n]*[{)])/);
                    var converted = '';
                    that.code = code;
                    for(var i=0;i<lines.length;i++) {
	                    var line = lines[i];	                    	                    	                   	                    
	                    line = that.rewriteArrays(line);  	                    
	                    line = that.rewrite(line);	                    
	                    converted += line + ';\n';		                    
                    }                    
                    if (that.debugObjects.converted) {
                        that.debugObjects.converted(converted);
                    }
                    that.checkSyntax(code);
                    converted = that.extractSymbols(converted);
                    if (that.debugObjects.converted) {
                        that.debugObjects.converted(converted);
                    }
                    
                    
                    if(constants) { 
                    	eval("const undefined = freshWindow.undefined;")                    	
                    } else {
                    	undefined = freshWindow.undefined;
                    }    
                    
                    if(constants) { 
                    	eval("const NaN = freshWindow.NaN;")                    	
                    } else {
                    	NaN = freshWindow.NaN;
                    }  
                    
                    if(constants) { 
                    	eval("const Infinity = freshWindow.Infinity;")                    	
                    } else {
                    	Infinity = freshWindow.Infinity;
                    }                      
                    if(!constants) {                     	                                        	
                    	var globals = natives.toString().replace(/[^\w|]/g,'').split("|");                                          	                    	                    	
                    	if(Object.defineProperty) {                    
                    		for(var i=0;i<globals.length;i++) {
                    			if(globals[i] == 'window') {
                    				continue;
                    			}                    			
                    			Object.defineProperty(window, "$"+globals[i]+"$", {get:(function(val) { 
                    						return function() { return val; }
                    				})(window["$"+globals[i]+"$"])
                    						, set:function() {                    					
                    					return this.get
                    				}
                    			});
                    		}
                    	} else if(Object.__defineSetter__) {
                    		for(var i=0;i<globals.length;i++) {
	                    		if(globals[i] == 'window') {
	                				continue;
	                			}	
	                    		window.__defineGetter__("$"+globals[i]+"$", (function(val) {
	                    			return function() { return val; }
	                    		})(window["$"+globals[i]+"$"]));
	                    		window.__defineSetter__("$"+globals[i]+"$", (function(prop) { 
	                    			return function() {
	                    					error(prop + " is a constant you cannot modify it.");
	                    				}
	                			})(globals[i]));
                    		}
                    	}                    	
                    }                    
                    var __this__ = $window$;                    
                    if (that.debugObjects.doNotMainEval) {
                        result = converted;
                    } else {
                    	
                    	if($window$['window'] === $window$) {
                    		error("Window is leaking");
                    	}
                    	with($window$) {
                    		result = eval(converted);
                    	}
                    }
                    if (that.debugObjects.parseTree) {
                        that.debugObjects.parseTree(parseTree);
                    }
                    if (that.debugObjects.result) {
                        that.debugObjects.result(result);
                    }
                    that.setWindow($window$);
                };
                if (that.debugObjects.onComplete) {
                    that.debugObjects.onComplete();
                }                 
                return result;
            },
            rewriteFilters: {
            		functionCalls:function($functionCalls) {            	
		            	parseTree.push("Function calls(" + $functionCalls + ")");
		                $functionCalls = $functionCalls.replace(new RegExp('(' + unicode.source + ')', 'g'), function(m){
		                    return String.fromCharCode(parseInt(m.replace(/\\u/, ''), 16));
		                });		                		               		                
		                $functionCalls = $functionCalls.replace(new RegExp(spaces.source, 'g'), '');
		                var containsDot = false;
		                if(/[.]/.test($functionCalls)) {
		                	$functionCalls = $functionCalls.replace(/[.]/g,'');
		                	containsDot = true;
		                }
		                var funcName = protection + $functionCalls.slice(0, -1).replace(new RegExp(spaces.source, 'g'), '') + protection;
		                if(!containsDot) {
		                	this.addSymbol(funcName);
		                }
						this.rewrite.previousMatch = 'functionCalls';
						if(containsDot) {
							return '.'+funcName + '(';
						} else {
							return funcName + '(';
						}
            		}
            }, 
            rewriteArrays: function(code) {            	
            	var that = this,
            		lookup = {},            		
            		counter = 0,
            		leftContext = '',
            		mainArraysRegexp = new RegExp('('+strings.source+')|('+regexpObj.source+')|(\\[)|(,?\\s*\\])|(.)',"gi"),
            		converted = code.replace(mainArraysRegexp, function($0, $strings, $regexps, $square1, $square2, $1) {
	            		 if ($strings !== undefined && $strings.length) {            			 	            			 
	            			 leftContext += $strings;
	            			 return $strings;            			 
	            		 } else if($regexps !== undefined && $regexps.length) {            			 	            			 
	            			 leftContext += $regexps;	            			 
	            			 return $regexps;	            		 	            			 
	            		 } else if ($square1 !== undefined && $square1.length) {
	            			 counter++;		            			 
	            			 if(new RegExp("(?:^|[^\\w]*\\b(?:in(?:stanceof)?|do|delete|return|void|throw|else|else\s+if|typeof|case|default)|[({\\[:]|[\\n]+[}]|"+eos.source+"|"+operators.source+")\\s*$").test(leftContext)) {
	            				 leftContext += "[";
	            				 lookup[counter] = true;	            				 
	            				 return ' @#(';
	            			 } else {
	            				 lookup[counter] = false;	            				 
	            				 leftContext += "[";
	            				 return '[';
	            			 }
	            		 } else if ($square2 !== undefined && $square2.length) {            			 
	            			 if(lookup[counter]) {
	            				 counter--;	  
	            				 leftContext += "]";
	            				 return ')';
	            			 } else {
	            				 counter--;	     
	            				 leftContext += "]";
	            				 return ']';
	            			 }
	            		 } else if ($0 !== undefined && $0.length){	            			
	            			 leftContext += $0;
	            			 return $0;
	            		 } else if ($1 !== undefined && $1.length){	            			
	            			 leftContext += $1;
	            			 return $1;
	            		 }		            		 	            		 
	            		 
            		});                	
            	return converted;
            },
            rewrite: function rewrite(code) {            	            	            	
                var that = this;
                var converted = code.replace(mainRegExp, function($0, $newLines, $forIn, $inInstanceofOperator, $statements, $objectIdentifiers, $strings, $regexps, $numbers, $squareOpen, $squareClose, $functionDec, $jsregArrays, $functionCalls, $objects, $eos, $operators, $endCurlyBrace){
					if ($functionCalls !== undefined && $functionCalls.length) {                        
						return that.rewriteFilters['functionCalls'].apply(that,[$functionCalls]);
                    } else if ($functionDec !== undefined && $functionDec.length) {
                        parseTree.push("Function Declarations(" + $functionDec + ")");                        
						$functionDec = $functionDec.replace(new RegExp('^(' + spaces.source + 'function' + spaces.source + ')(' + variable.source + ')?(' + spaces.source + '[(].+)'), function($0, funcStatement, funcName, funcEnd){
                            if (funcName !== undefined && funcName.length) {
                                funcName = protection + funcName + protection;
                                that.addSymbol(funcName);
                            } else {
                                funcName = '';
                            }
                            if (funcEnd != '(){') {
                                funcEnd = that.rewrite(funcEnd);
                            }
                            return funcStatement + funcName + funcEnd;
                        });
						rewrite.previousMatch = 'functionDec';
                        return $functionDec + 'if(!JSREG_FUNC.checkMaxFunctCalls()){return false};var __this__=JSREG_FUNC.getThis(this);var $arguments$=[].slice.call(arguments,0);';
                    } else if ($newLines !== undefined && $newLines.length) {                        
						parseTree.push("New lines");
						rewrite.previousMatch = 'newLines';
                        return $newLines;
                    } else if ($jsregArrays !== undefined && $jsregArrays.length) {                        						
                    	parseTree.push("jsregArrays(" + $jsregArrays + ")"); 
                    	rewrite.previousMatch = 'jsregArrays';
                    	return 'JSREG_A(';                        
					} else if ($squareOpen !== undefined && $squareOpen.length) {
                        parseTree.push("Square open(" + $squareOpen + ")");                        																												                                                
						return $squareOpen + 'JSREG_FUNC.gp(';
                    } else if ($squareClose !== undefined && $squareClose.length) {
						return  ')' + $squareClose;						
                    } else if ($inInstanceofOperator !== undefined && $inInstanceofOperator.length) {
                        parseTree.push("in/instanceof Operator(" + $inInstanceofOperator + ")");
                        rewrite.previousMatch = 'inInstanceofOperator';
						return $inInstanceofOperator.replace(/(.*)(in(?:stanceof)?)/, function($0, $1, $2){
                            if ($2 == 'instanceof') {
                                return $1 + ' ' + $2;
                            } else {
                                return $1 + '.JSREG_ITEM()' + $2 + ' ';
                            }
                        });
                    } else if ($objectIdentifiers !== undefined && $objectIdentifiers.length) {
                        parseTree.push("Object identifiers(" + $objectIdentifiers + ")");
                        $objectIdentifiers = $objectIdentifiers.replace(new RegExp('([{,]' + spaces.source + ')(' + strings.source + '|' + numbers.source + '|' + variable.source + ')(' + spaces.source + ')'), function($0, $start, $ident, $end){
                            if (/[^\d]/.test($ident)) {
                                if (new RegExp('^' + spaces.source + variable.source + spaces.source + protection).test($ident)) {
                                    $ident = $ident.replace(new RegExp('(' + unicode.source + ')', 'g'), function(m){
                                        return String.fromCharCode(parseInt(m.replace(/\\u/, ''), 16));
                                    });
                                    if (!allowedProperties.test($ident)) {
                                        $ident = protection + $ident + protection;
                                    }
                                } else {
                                    $ident = $ident.split('');
                                    $ident[1] = protection + $ident[1];
                                    $ident[$ident.length - 1] = protection + $ident[$ident.length - 1];
                                    $ident = $ident.join('');
                                }
                            } else {
                                $ident = +$ident;
                            }
							rewrite.previousMatch = 'objectIdentifiers';
                            return $start + $ident + $end;
                        });
                        return $objectIdentifiers;
                    } else if ($numbers !== undefined && $numbers.length) {
                        parseTree.push("Numbers(" + $numbers + ")");
                        rewrite.previousMatch = 'numbers';
						return $numbers;                                            
                    } else if ($statements !== undefined && $statements.length) {
                        parseTree.push("Statements(" + $statements + ")");
                        rewrite.previousMatch = 'statements';
						if (/\s*this\s*/.test($statements)) {
							rewrite.previousMatch = 'this';
                            return '__this__';
                        }
                        return $statements + ' ';
                    } else if ($regexps !== undefined && $regexps.length) {                        
                    	parseTree.push("RegExps(" + $regexps + ")");
                    	rewrite.previousMatch = 'regexps';                    	
                    	return $regexps;                    							                      
                    } else if ($strings !== undefined && $strings.length) {
                        parseTree.push("Strings(" + $strings + ")");
                        rewrite.previousMatch = 'strings';
                        return $strings;                        
                    } else if ($objects !== undefined && $objects.length) {
                        parseTree.push("Objects(" + $objects + ")");
                        $objects = $objects.replace(/([\\]u[0-9a-f]{4})/g, function(m){
                            return String.fromCharCode(parseInt(m.replace(/\\u/, ''), 16));
                        });
                        var beginDot = /^\s*[.]/.test($objects);
                        if (beginDot) {
                            $objects = $objects.replace(/^(\s*)[.]/, '$1');
                        }
                        if($objects == 'length' && beginDot) {
                        	rewrite.previousMatch = 'objects';
                        	return '.length';
                        }
                        $objects = $objects.split('.');
                        for (var i = 0; i < $objects.length; i++) {
                            if (i == 0) {
                                if ($objects[i].replace(/[\s\n]/g, '') == 'this' && $objects.length > 1) {                                    
                                	$objects[i] = '__this__';
                                    continue;
                                }                                
                                var objName = protection + $objects[i].replace(new RegExp(spaces.source, 'g'), '') + protection;
                                if (!beginDot) {
                                    that.addSymbol(objName);
                                }
                                $objects[i] = objName;
                            } else {
                                if (allowedProperties.test($objects[i].replace(/[\s\n]/g, ''))) {
                                    $objects[i] = $objects[i].replace(/[\s\n]/g, '');
                                    continue;
                                }
                                $objects[i] = protection + $objects[i].replace(new RegExp(spaces.source, 'g'), '') + protection;
                            }
                        }                        
                        $objects = $objects.join(".");
                        if (beginDot) {
                            if (new RegExp('^[$]' + allowedProperties.source + '[$]$').test($objects)) {
                                $objects = $objects.replace(/[\s\n]/g, '');
                                $objects = $objects.replace(/^[$]|[$]$/g, '');
                            }
                            $objects = '.' + $objects;
                        }
                        rewrite.previousMatch = 'objects';
                        return $objects;
                    } else if($eos !== undefined && $eos.length) {
                    	parseTree.push("eos(" + $eos + ")");
                    	rewrite.previousMatch = 'endOfStatement';
                    	return $eos;
                    } else if($forIn !== undefined && $forIn.length) {
                    	parseTree.push("forIn(" + $forIn + ")");
                    	rewrite.previousMatch = 'forIn';
                    	forInConverted = '';                     
                    	$forIn.replace(new RegExp("^("+forInStart.source+")("+forInDefine.source+")("+forInStatement.source+")("+forInEnd.source+")$"), function($0, $start, $define, $forInStatement, $end) {
                    		$define = that.rewrite($define);
                    		$end = that.rewrite($end);
                    		forInConverted = $start + $define + $forInStatement + " " + $end;
                    		var loopVariable = $define.replace(/^\s*var\s*/,'');
                    		forInConverted += "if((" + loopVariable + '=' + loopVariable + ".replace(/^\\$|\\$$/g,'')) && /^(?:constructor|hasOwnProperty|valueOf|toString|JSREG_PROP|JSREG_ITEM)$/.test("+loopVariable+")){continue;} else ";
                    	});
                    	return forInConverted + ' ';                    	
                    } else if($operators !== undefined && $operators.length) {
                    	parseTree.push("operators(" + $operators + ")");
                    	rewrite.previousMatch = 'operators';
                    	return $operators; 
                    } else if($endCurlyBrace !== undefined && $endCurlyBrace.length) {
                    	parseTree.push("endCurlyBrace(" + $endCurlyBrace + ")");
                    	rewrite.previousMatch = 'endCurlyBrace';
                    	return $endCurlyBrace; 
                    } else if($objAssignment !== undefined && $objAssignment.length) {                    	                    	
                    	parseTree.push("objAssignment(" + $objAssignment + ")");
                    	$objAssignment = $objAssignment.replace(/^\s*\[|\]\s*$/g,'');
                    	that.rewrite.previousMatch = '';
                    	$objAssignment = that.rewrite($objAssignment);
                    	rewrite.previousMatch = 'objAssignment';                                        	
                    	return '[JSREG_FUNC.gp(' + $objAssignment + ')]';                      	
                    } else {                    	
                        return $0;
                    }
                });
                return converted;
            },
            checkSyntax: function(code){            	
                try {
                    throw new Error()
                } 
                catch (e) {
                    var relativeLineNumber = e.lineNumber
                }
                try {
                    code = new Function(code);
                } 
                catch (e) {                	
                    msg = e.message;
                    line = (e.lineNumber - relativeLineNumber - 1);
                    error("Syntax error");
                }
            },
            runCheck: function(){
                this.assert(this.removeComments('//test'), '', 1);
                this.assert(this.removeComments('//test\n'), '\n', 2);
                this.assert(this.removeComments('<!--test'), '', 3);
                this.assert(this.removeComments('<!--test\n'), '\n', 4);
                this.assert(this.removeComments('/*\n\r\t test*/'), '', 5);
                this.assert(this.removeComments('(/**/2+2/**/);'), '(2+2);', 6);                                             
                this.assert(this.rewrite("alert(1)"), "$alert$(1)", 11);                                
            },
            assert: function(op1, op2, id){
                if (op1 != op2) {
                    id = +id;
                    var msg = 'result:\n' + op1 + '\n' + 'expected:\n' + op2 + '\nid:\n' + id;
                    if (this.debugObjects.errorLog) {
                        this.debugObjects.errorLog(msg);
                    } else {                    
                        alert(msg);
                    }
                    
                    error("Parser error:Something went wrong. The RegExps are allowing data they shouldn't");
                }
                this.init();
            }
        };
        
        return new Parser;
    };
    window.JSReg = {
        create: function(callback){    	    	    		
	    	var iframe = document.createElement('iframe');
	        iframe.style.width = '1px';
	        iframe.style.height = '1px';
	        iframe.frameborder = "0";
	        iframe.style.position = 'absolute';
	        iframe.style.left = '-100px';
	        iframe.style.top = '-100px';
	        document.body.appendChild(iframe);
	        var code = "(function(JSREG){ return window.JSReg = JSREG();})(" + JSReg_Environment + ")";
	        if (window.opera) {
	            iframe.contentWindow.Function(code)();
	        } else {
	        	iframe.contentWindow.document.open();
	        	iframe.contentWindow.document.write('<meta http-equiv="X-UA-Compatible" content="IE=Edge" />');
	            iframe.contentWindow.document.write('<script type="text/javascript">' + code + '<\/script>');
	            iframe.contentWindow.document.close();
	        }
	        var obj = iframe.contentWindow.JSReg;
	        if (!obj) {
	            iframe.contentWindow.Function(code)();
	            obj = iframe.contentWindow.JSReg;
	        }
	        obj.environment = iframe;
	        return obj;
        }        
    };
    
})();