/*
 * JSReg
 * Version 3.6.33
 * 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] = obj[prop];
        		} else {        			
        			obj.prototype[protection+prop+protection] = (function(obj, prop){ 
        				function func() {	        				
	        				var that = this, args = arguments;        				
	        				return that[prop].apply(that, args);
	        				
	        			}
        				func.valueOf = function() {
        					return 'function '+prop+'() {\n [jsreg code] \n}';
        				}
        				return func;
        			})(obj, prop);
        		}
        	}
        	return obj;
        }
        function isNewline(chr) {
    		return /^[\f\n\r\u000b\u2028\u2029]$/.test(chr);
    	}
        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];
        		}
        	}        	
        }        
        	var newLines = /[\f\n\r\u000b\u2028\u2029]+/,   
        	spaceChars = /[\t\v \u0000\u0085\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u205f\u202f\u3000\ufffe\ufeff]/,
        	eos = /[;]/,
			unicode = /\\u[0-9a-fA-F]{4}/,					 
			endStatement = /[;]+/, spaces = /\s*/, 			
			variable = new RegExp("(?:[^\\x00-\\x7f\\s]|[a-zA-Z_$]|" + unicode.source + ")(?:[^\\x00-\\x7f\\s]|[\\w$_]|" + unicode.source + ")*"),		
			operators = /(?:[&|+\-]{2}|[\/][=]|[=]{1,3}|[>]{1,3}[=]?|[<]{1,2}[=]?|[!][=]{0,2}|[\^<>%&+*\-|][=]?|[~*^&|+\-])/, 									 			 			
			statements = /^\s*(?:for|with|while|if|switch|catch|else|else\s*if|try|do|finally)\s*(?=[({])/,
			reservedWords = /^(?:(?:in(?:stanceof)?)|else|function|delete|this|Infinity|NaN|void|case|default|return|var|continue|undefined|null|new|typeof|throw|break|true|false|do)$/,
			objects = new RegExp('(?:[.]?' + spaces.source + variable.source + spaces.source+ ')'),						
			parenOpen = /(?:[(])/,
			parenClose = /(?:[)])/,
			strings = new RegExp("(?:(?:['](?:\\\\{2}|\\\\[']|[^'])*['])|(?:[\"](?:\\\\{2}|\\\\[\"]|[^\"])*[\"]))"), 									
			squareOpen = new RegExp(spaces.source+"[\\[]"),	
			squareClose = new RegExp(spaces.source+"[\\]]"),
			numbers = new RegExp('(?:[0][xX][0-9a-fA-F]*)|(?:[0]|[1-9]\\d+)?(?:[.]?\\d+)+(?:[eE][+-]?\\d+)?'), 
			objectIdentifiers = new RegExp('(?:[,\\{]' + spaces.source + '(?:' + numbers.source + '|' + strings.source + '|' + variable.source + '))' + spaces.source + '(?=[:])'),  						
			endCurlyBrace = /[}]/,						 
		Parser = function(){
            this.init();
        };       
        var allowedProperties = /\b(?:length|global|ignoreCase|input|multiline|source|lastIndex|prototype)\b/;                
        Parser.prototype = {                      
            debugObjects: {},
            extendObject: function(name, value) {
            	this.environment.contentWindow.Object.prototype[name] = value;
            },
            extendWindow: function(name, value) {
            	this.environment.contentWindow[name] = value;                
            },                        
            setDebugObjects: function(obj){
                this.debugObjects = obj;
            },                        
            init: function(){            	                               
                this.loopNumber = 0;
                this.maxFuncCalls = 100000;                
                parseTree = [];
            },
            rewriteLines:function(code) {
            	var that = this, converted  = '';
            	code = this.normalize(code);
            	that.checkSyntax(code); 
            	converted = that.rewrite(code);            	
                if (that.debugObjects.converted) {
                    that.debugObjects.converted(converted);
                }
                that.checkSyntax(converted);
            	
                return converted;
            },
            normalize: function(code) {            	            	            	
            	code = code.replace(new RegExp(newLines.source,'g'),'\n');
            	code = code.replace(new RegExp(spaceChars.source,'g'),' ');
            	code = code.replace(/\\[\f\n\r\u000b\u2028\u2029]/g,'\\n');
            	return code;
            },            
            'eval': function(code, thisObject, alreadySandboxed) {            	
                if (this.debugObjects.onStart) {
                    this.debugObjects.onStart();
                }
                parseTree = [];
                if (this.debugObjects.clearTree) {
                    this.debugObjects.clearTree();
                }               
                if (typeof thisObject == 'undefined') {
                    thisObject = window;
                }
                var that = this;
                var result;                                
                try {
                	if(alreadySandboxed) {                		
                		execCode.apply(thisObject, [true]);
                	} else {
                		execCode.apply(thisObject, []);
                	}
                } 
                catch (e) {
                    if (that.debugObjects.errorHandler) {
                        that.debugObjects.errorHandler(e, that);
                    }
                }                              
                
                function execCode(alreadySandboxed) {                    	
                	var freshWindow  = $window$  = that.environment.contentWindow,
                		maxFuncCalls = that.maxFuncCalls,
                		setTimeoutIDS = {},
                		setIntervalIDS = {},
                		J = {                        
                    		'P': 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;
								}
						},
						R: function(prop) {	
							if(typeof prop == 'undefined') {
								return false;
							}																						
							if(!/^[$]/.test(prop) && !/[$]$/.test(prop) && /[^\d]/.test(prop)) {
								return false;
							}
							prop = (prop+'').replace(/^[$]|[$]$/g, '');
							return prop;
						},
						A: function(args) {
							var args = [].slice.call(args,0);
							args.$callee$=arguments.callee.caller;
							return args;
						},
                        F: function(funct){
                            var 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;
                            }
                        }
                    };                      
                    function FUNCTION(){                    	
                        if(!J.F()) {
                        	return null;
                        }                                                
                        var parser = that;                                                                        
                    	var converted = freshWindow.Function.apply(this, arguments) + '';                    	                    	
                        converted = parser.rewriteLines('('+converted+')');                                                                                               
                        if (parser.debugObjects.functionCode) {
                            parser.debugObjects.functionCode(converted);
                        }
                        if (parser.debugObjects.doNotFunctionEval) {
                            return converted;
                        } else {
                        	if (parser.debugObjects.strict) {
                        		converted = '"use strict";undefined;' + converted;
                        	}                        	
                            return eval(converted);
                        }
                    };
                    FUNCTION.$constructor$ = FUNCTION;                                                                                                                                          
                    $Function$ = FUNCTION;                                                                                                                                                        
                    Boolean.$constructor$ = $Function$;
                    Boolean.prototype.$constructor$ = Boolean;                                       
                    $Boolean$ = Boolean;                                                            
                    Function.prototype.$constructor$ = $Function$;
                    objWhitelist(freshWindow.Function, 'call,apply');                                                            
                    objWhitelist(freshWindow.String,'charAt,charCodeAt,concat,indexOf,lastIndexOf,localeCompare,match,replace,search,slice,split,substr,substring,toLocaleLowerCase,toLocaleString,toLocaleUpperCase,toLowerCase,toUpperCase');
                    String = objWhitelist(freshWindow.String, 'fromCharCode', true);
                    String.prototype.$constructor$ = String;
                    String.$constructor$ = $Function$;                                                            
                    $String$ = String;
                                                                                                      
                    objWhitelist(freshWindow.Array,'sort,join,pop,push,reverse,shift,slice,splice,unshift,concat');                                                                                                                                     
                    Array.prototype.$constructor$ = Array;
                    Array.$constructor$ = $Function$;                                                                                     
                    $Array$ = freshWindow.Array;                                                             
                    objWhitelist(freshWindow.RegExp,'compile,exec,test');                    
                    RegExp.prototype.$constructor$ = RegExp;                        
                    RegExp.$lastMatch$ = RegExp.lastMatch;                    
                    RegExp.$lastParen$ = RegExp.lastParen;                    
                    RegExp.$leftContext$ = RegExp.leftContext;                                                            
                    RegExp.$constructor$ = $Function$;    
                    $RegExp$ = RegExp;                     
                    objWhitelist(freshWindow.Number,'toExponential,toFixed,toPrecision');                    
                    constWhitelist(Number, 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY');                                                          
                    Number.$constructor$ = $Function$;
                    Number.prototype.$constructor$ = Number;
                    $Number$ = Number;                                                         
                    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$;                    
                    $Date$ = Date;                         
                    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$ = freshWindow.Object;
                    $Math$ = Math;                    
                    constWhitelist(freshWindow,'decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,escape,isFinite,isNaN,parseFloat,parseInt,unescape', freshWindow);                                        
                    function CLEAR_INTERVAL(id){
                    	if(!J.F()) {
                        	return null;
                        }
                        id = +id;
                        if (typeof setIntervalIDS[id] == 'undefined') {
                            return null;
                        }
                        return freshWindow.clearInterval(id);
                    };                    
                    $clearInterval$ = CLEAR_INTERVAL;                      
                    var CLEAR_TIMEOUT = function(id){
                    	if(!J.F()) {
                        	return null;
                        }
                        id = +id;
                        if (typeof setTimeoutIDS[id] == 'undefined') {
                            return null;
                        }
                        return freshWindow.clearTimeout(id);
                    };                    
                    $clearTimeout$ = CLEAR_TIMEOUT;                                        
                    var SET_TIMEOUT = function(func, time){
                    	if(!J.F()) {
                        	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.");
                        }
                    };                     
                    $setTimeout$ = SET_TIMEOUT;                                          
                    var SET_INTERVAL = function(func, time){
                    	if(!J.F()) {
                        	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.");
                        }
                    };                    
                    $setInterval$ = SET_INTERVAL;                                         
                    var ALERT = function(str){
                    	$alert$.maxFuncCalls = 20;
                    	if(!J.F()) {
                        	return null;
                        }
                        freshWindow.alert(str);
                    };   
                    $alert$ = ALERT;
                    var EVAL = function(str){
                    	if(!J.F()) {
                        	return null;
                        }
                        var parser = that;
                        parser.rewrite.previousMatch = '';
                        if(typeof str != 'function') {                        	 
                        	str = str+'';                        	                     	                        	                        
    	                    var converted = that.rewriteLines(str);    	                        	                                            	                        	                                                      
                        } else {
                            converted = str;
                        }                        
                        if (parser.debugObjects.evalCode) {
                            parser.debugObjects.evalCode(converted);
                        }
                        if (parser.debugObjects.evalCode) {
                            parser.debugObjects.evalCode(converted);
                        }
                        
                        if (parser.debugObjects.doNotEval) {
                            return converted;
                        } else { 
                        	if (parser.debugObjects.strict) {
                        		converted = '"use strict";undefined;' + converted;
                        	}
                            converted = eval(converted);                            
                            return converted;
                        }
                    };                   
                    $eval$ = EVAL;                    
                    var Object = freshWindow.Object;
                    Object.$constructor$ = $Function$;                                        
                    Object.prototype.$constructor$ = Object;                    
                    Object.prototype.$hasOwnProperty$ = function(prop){
                        return this.hasOwnProperty(protection + prop + protection);
                    };
                    objWhitelist(freshWindow.Object, 'valueOf');
                    objWhitelist(freshWindow.Object, 'toString');                                                                                                               
                    Object.prototype.I = function() {
                    	var val = this.toString();
                        if (/[^\d]/.test(val)) {
                            return '$' + val + '$';
                        } else {
                            return +val;
                        }                    	
                    }                                    
                    $Object$ = Object;                                           
                    winProp = null; 
                    if(!alreadySandboxed) {                    		                    	                   
	                    var converted = '';
	                    that.code = code;	    	                    
	                    converted = that.rewriteLines(code);                    	                    	                    
	                    if (that.debugObjects.converted) {
	                        that.debugObjects.converted(converted);
	                    }
                    }                                                            
                    undefined = freshWindow.undefined;                                                               
                    NaN = freshWindow.NaN;                                                              
                    Infinity = freshWindow.Infinity;                                                                             	                                        	                	            	                                                           
                    if (that.debugObjects.doNotMainEval) {
                        result = converted;
                    } else {                    	                    	                    	
                		if(alreadySandboxed) { 
                			if (that.debugObjects.strict) {
                				code = '"use strict";undefined;' + code;
                			}                			
                			result = eval(code);
                		} else {
                			if (that.debugObjects.strict) {
                				converted = '"use strict";undefined;' + converted;
                			}
                			result = eval(converted);
                		}                    	
                    }                    
                    if (that.debugObjects.parseTree) {
                        that.debugObjects.parseTree(parseTree);
                    }
                    if (that.debugObjects.result) {
                        that.debugObjects.result(result);
                    }                    
                };
                if (that.debugObjects.onComplete) {
                    that.debugObjects.onComplete();
                }                 
                return result;
            },               
            rewrite: function(code) {            	
            	
            	var output = '', pos = 0, chr, currentText = '', next, prev, matchStr, left,
            		that = this, lookups = {squareSyntaxCheck:{},curlyLookup:{},arrayLookup:{},parenLookup:{},loopVariableLookup:{}}, 
            		counters = {curlyCounter:0,squareCounter:0,parenCounter:0}, lastState = '',
            		states = [], lastForVariable, lastStatement, functionOpen, functionExpression, commentState = 0,
            		forStatement = false, correctedOutput = '';
            	function isValidSyntax(str) {
            		try {
            			Function(str);
            			return true;
            		} catch(e){
            			return false;
            		}
            	}            
                function rewriteNewLines($newLines) {                	
                	parseTree.push("New lines");										
                    return $newLines;  
                }
                function rewriteComments($comments) {                	 				
                    return '';    
                }
                function trim(str) {                
                	if(typeof str != 'undefined') {
                		str = str + '';
                		return str.replace(/^\s+|\s+$/g,'');
                	}
                }
                function rewriteStatements($statements) {                	
                	$statements = statements.exec($statements)[0];
                	parseTree.push("statements(" + $statements + ")");
                	lastState = $statements;                	
                	return $statements;
                }
                function rewriteParenOpen($parenOpen) {
                	parseTree.push("parenOpen(" + $parenOpen + ")");
                	counters.parenCounter++;                    	
                	lookups.parenLookup[counters.parenCounter] = lastState;                       	
                	if(trim(lastState) === 'for') { 
                		forStatement = true;
                		var loopVariable = currentText;                		
                		loopVariable = new RegExp("^\\s*(?:var\\s)?\\s*[(\\s]*("+variable.source+')[\\s)]*[\\s)]in').exec(loopVariable.replace(/^[(]+/,''));                		                		
                		if(loopVariable) {                			
                			lookups.loopVariableLookup[counters.parenCounter] = rewriteObjects(loopVariable[1]);
                		}
                	}  else if(functionOpen && !functionExpression) {
                		lookups.parenLookup[counters.parenCounter] = 'function';
                	}  else if(functionOpen && functionExpression) {
                		lookups.parenLookup[counters.parenCounter] = 'functionExpression';                		
                	}                	
                	return '(';       
                }
                function rewriteParenClose($parenClose) {
                	parseTree.push("parenClose(" + $parenClose + ") - "+lookups.parenLookup[counters.parenCounter]);                 	                	
                	if(/^(?:do|if|with|while|for|switch|catch|else\s+if)$/.test(trim(lookups.parenLookup[counters.parenCounter]))) {
                		left = 0;
                		lastState = 'statements';  
                		lastForVariable = lookups.loopVariableLookup[counters.parenCounter];
                		lastStatement = lookups.parenLookup[counters.parenCounter]; 
                		if(trim(lastStatement) === 'for') {
                			forStatement = false;
                		}
                		lookups.loopVariableLookup[counters.parenCounter] = '';
                		lookups.parenLookup[counters.parenCounter] = '';
                		if(!/^[)]\s*[{]/.test(currentText)) {                			
                			foundCurly = false;                			
                			left = 0;
                			lastState = 'statements';                			
                		}                		
                	} else {            
                		lastState = 'parenClose';
                		left = 1;                		
                		if(/^(?:function|functionExpression)$/.test(lookups.parenLookup[counters.parenCounter])) {                			
                			if(!/^\s*[)]\s*[{]/.test(currentText) && functionOpen) { 
                				error("Syntax error: Missing curly for function.");                				
                    		} 
                		}                		                		
                	}                	
                	counters.parenCounter--;
                	return ')';       
                }
                function rewriteSquareOpen($squareOpen) {
                	parseTree.push("Square open(" + $squareOpen + ")");
                	counters.squareCounter++; 
                	lastState = 'squareOpen';
                	if(!left) {
                		lookups.arrayLookup[counters.squareCounter] = true;                		            			            			
                		return $squareOpen;
                	} else {
                		lookups.arrayLookup[counters.squareCounter] = false;
                		lookups.squareSyntaxCheck[counters.squareCounter] = pos;                		
                		return $squareOpen + 'J.P(';                		
                	}                	
                }
                function rewriteSquareClose($squareClose) { 
                	var beginSquarePos;
                	parseTree.push("Square close(" + $squareClose + ")");
                	lastState = 'squareClose';
                	if(lookups.arrayLookup[counters.squareCounter]) {
                		lookups.arrayLookup[counters.squareCounter] = '';
                		counters.squareCounter--;
                		arrayFound = true;
                		return $squareClose;
                	} else {
                		beginSquarePos = lookups.squareSyntaxCheck[counters.squareCounter];
                		lookups.arrayLookup[counters.squareCounter] = '';
                		lookups.squareSyntaxCheck[counters.squareCounter] = '';
                		counters.squareCounter--;                		                		               		                		                		
                		if(!isValidSyntax('['+code.slice(beginSquarePos, pos-1)+']')) {                			
                			error("Syntax error: Invalid object accessor");
                		}                		
                		return  ')' + $squareClose;
                	}                			     
                }                
                function rewriteObjectIdentifiers($objectIdentifiers) {                 	
                	parseTree.push("Object identifiers(" + $objectIdentifiers + ")");                 	
                	if(/^[{]/.test($objectIdentifiers)) {
                		counters.curlyCounter++;                      		                		                		
                		lookups.curlyLookup[counters.curlyCounter] = 'objectLiteral';                			               			                			                		
                	}                	
                    $objectIdentifiers = $objectIdentifiers.replace(new RegExp('([{,]' + spaces.source + ')(' + strings.source + '|' + numbers.source + '|' + variable.source + ')(' + spaces.source + ')'), function($0, $start, $ident, $end){                                                    	                    	
                    	if(!new RegExp('^(?:'+numbers.source+')$').test($ident)) {                    		
                            if (new RegExp('^' + spaces.source + variable.source + spaces.source + protection).test($ident)) {                                
                                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;
                        }						
                        return $start + $ident + $end;
                    });
                    return $objectIdentifiers;	     
                }
                function rewriteNumbers($numbers) {                	
                	parseTree.push("Numbers(" + $numbers + ")");                    
					return $numbers;     	     
                }                  
                function rewriteRegexps($regexps) {                	  
                	var state = {open:1, square: 0, escaping: 0, flags: {}}, 
                		regexPos = 0, next, prev, chr, regexOutput = '';
                	regexOutput += '/';
                	regexPos++;	
                	pos++;                	
            		while(true) {
            			next = $regexps.substr(regexPos+1, 1);
                    	prev = $regexps.substr(regexPos-1, 1);   
            			chr = $regexps.substr(regexPos, 1);  		
            			if(!state.open) {			
            				if(/[igm]/.test(chr) && !state.flags[chr]) {
            					state.flags[chr] = 1;
            					if(!/[igm]/.test(next)) {
            						regexOutput += chr;
            						regexPos++;
            						pos++;
            						parseTree.push("RegExps(" + regexOutput + ")");
            						return regexOutput;            						
            					}
            				} else {
            					parseTree.push("RegExps(" + regexOutput + ")");
            					pos++;
            					return regexOutput;            
            				}
            			} else if(chr === '/' && !state.escaping && !state.square) {
            				state.open = 0;
            				if(!/[igm]/.test(next)) {
            					regexOutput += chr;
            					parseTree.push("RegExps(" + regexOutput + ")");
            					pos++;
            					return regexOutput;
            				}            			            				
            			} else if(state.escaping) {            				
            				state.escaping = 0;
            			} else if(chr === '\\' && !state.escaping) {
            				state.escaping = 1;
            			} else if(chr === '[' && !state.escaping && !state.square) {            				
            				if(next === ']' || (next === '^' &&  $regexps.substr(regexPos+2, 1) === ']')) {            					
            					error("Syntax error empty character class");            					
            				}
            				state.square = 1;            			
            			} else if(chr === '[' && !state.escaping && state.square) {            				
            				regexOutput += '\\';
            			} else if(chr === ']' && !state.escaping && state.square) {
            				state.square = 0;
            			} else if(chr === ']' && !state.escaping && !state.square) {
            				regexOutput += '\\';
            			} else if(isNewline(chr)) {
            				error('Syntax error expected "/"');
            			} else {
            				state.escaping = 0;
            			}			
            			if(regexPos === $regexps.length - 1) {				
            				if(state.open) {
            					error('Syntax error expected "/"');
            				}            				            				            				
            				regexOutput += chr;            				
        					parseTree.push("RegExps(" + regexOutput + ")");
        					pos++;
        					return regexOutput;
            			}
            			
            			if(state.square && chr === '/' && !state.escaping) {
            				regexOutput += '\\';            				
            			}
            			
            			regexOutput += chr;
            			regexPos++;
            			pos++;
            		}                	                	                    	                    	                	      	    
                }
                function rewriteStrings($strings) {                	
                	parseTree.push("Strings(" + $strings + ")");
                    return $strings;    	     
                }
                function rewriteObjects($objects) {   
                	
                	if(reservedWords.test(trim($objects))) {
                		parseTree.push("reservedWord(" + $objects + ")");
                		lastState = 'statements';
                		left = 0;                  		                		                		
                		return $objects;
                	}
                	
                	parseTree.push("Objects(" + $objects + ")");                	                             	
                    var beginDot = /^\s*[.]/.test($objects);
                    if (beginDot) {
                        $objects = $objects.replace(/^(\s*)[.]/, '$1');
                    }
                    if($objects == 'length' && beginDot) {                    	
                    	return '.length';
                    }
                    $objects = $objects.split('.');
                    for (var i = 0; i < $objects.length; i++) {
                        if (i == 0) {                                                               
                            var objName = protection + $objects[i].replace(new RegExp(spaces.source, 'g'), '') + protection;                                
                            $objects[i] = objName;
                        } else {
                            if (allowedProperties.test($objects[i].replace(/[\s]/g, ''))) {
                                $objects[i] = $objects[i].replace(/[\s]/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]/g, '');
                            $objects = $objects.replace(/^[$]|[$]$/g, '');
                        }
                        $objects = '.' + $objects;
                    }                    
                    return $objects;   	     
                }
                function lookahead() {
                	var lookaheadChr, lookaheadNext, lookaheadPos = pos, comment = 0;
                	while(lookaheadPos < code.length) {
                		lookaheadChr = code.substr(lookaheadPos,1);                		               	                                        
                		lookaheadNext = code.substr(lookaheadPos+1, 1);                    	   
                		if(comment === 1 && isNewline(lookaheadChr)) {
                			lookaheadPos++;
                			comment = 0;
                		} else if(comment === 2 && lookaheadChr === '*' && lookaheadNext === '/') {
                			lookaheadPos += 2;
                			comment = 0;
                		} else if(comment) {
                			lookaheadPos++;
                		} else if(lookaheadChr === '/' && lookaheadNext === '/') {
                			lookaheadPos+=2;
                			comment = 1;
                		} else if(lookaheadChr === '/' && lookaheadNext === '*') {
                			lookaheadPos+=2;
                			comment = 2;
                		} else if(/^\s$/.test(lookaheadChr)) {
                			lookaheadPos++;
                		} else {
                			return lookaheadChr;
                			break;
                		}
                	}
                	return false;
                }
                function objLiteralString(str) {                	
                	if(/^\s*'/.test(str)) {
                		str = str.replace(/^\s*'/,"'$$");                		
                		str = str.replace(/'\s*$/,"$$'");
                	} else if(/^\s*"/.test(str)) {
                		str = str.replace(/^\s*"/,'"$');
                		str = str.replace(/"\s*$/,'$"');
                	}
                	return str;
                }
                function outputSpace() {
                	if(output.slice(-1) !== ' ') {
                		output += ' ';
                		correctedOutput += ' ';
                	}
                }
                function outputChrs(chr, raw) {
                	if(typeof raw !== 'undefined') {
                		correctedOutput += raw;
                	} else {
                		correctedOutput += chr;
                	}
                	output += chr;
                }
                function outputEos() {  
                	if(lastState === 'comma') {
                		return '';
                	}                	                	
                	if(output.slice(-1) !== ';' || forStatement) {
	                	left = 0;
	            		parseTree.push("eos(;)");
	            		lastState = 'eos';                	                		
	            		output += ';'; 
	            		correctedOutput += ';';
	        			states = [];
                	}
                }
                function rewriteEos($eos) {                	
                	parseTree.push("eos(" + $eos + ")");                	
                	return $eos;  	     
                }                
                function rewriteOperators($operators) {                	
                	parseTree.push("operators(" + $operators + ")");                	
                	return $operators;  	     
                }
                function rewriteEndCurlyBrace($endCurlyBrace) {                   	                	                	
                	if(lookups.curlyLookup[counters.curlyCounter] === 'objectLiteral') {                		
        				lastState = 'objectLiteral';
                		left = 1;   
                		lookups.curlyLookup[counters.curlyCounter] = '';
        				counters.curlyCounter--; 
        				foundObjLiteral = true;                       		
        			} else if(lookups.curlyLookup[counters.curlyCounter] === 'function') {
        				left = 0;        				
        				lastState = 'function';
        				lookups.curlyLookup[counters.curlyCounter] = '';
        				counters.curlyCounter--;
        			} else if(lookups.curlyLookup[counters.curlyCounter] === 'functionExpression') {
        				lastState = 'functionExpression';
        				left = 1;
        				lookups.curlyLookup[counters.curlyCounter] = '';
        				counters.curlyCounter--;
        			} else {
        				left = 0;
        				lastState = 'blockStatement';
        				lookups.curlyLookup[counters.curlyCounter] = '';
        				counters.curlyCounter--;
        			}                	
                	parseTree.push(lastState+"(" + $endCurlyBrace + ")");
                	return $endCurlyBrace;   	     
                }                             
                function test(regexp, str) {
                	return new RegExp('^(?:'+regexp.source+')').test(str);
                }
                function match(regexp, str) {                	
                	return new RegExp('^(?:'+regexp.source+')').exec(str).toString();
                } 
                function isObjLiteral() {                     	
                	return !left && output.slice(-1) !== ')' && (lastState === 'colon' || lastState === 'squareOpen' || lastState === 'questionMark' || lastState === 'parenOpen' ||  lastState === 'operators' || lastState === 'statements' || lastState === 'comma' || lastState === 'ternary' || lastState === 'inInstanceofOperator' || lastState === 'divide');
                }
                pos = 0; 
                left = 0;
                while(pos < code.length) {                	
                	chr = code.substr(pos, 1);                	
                	prevText = code.substr(0, pos);
                	currentText = code.substr(pos);                	
                	next = code.substr(pos+1, 1);
                	prev = code.substr(pos-1, 1);   
                	
                	
                	if(commentState === 1 && !newLines.test(chr)) {
                		if(/^@cc_on/.test(code.substr(pos))) {
                			error("Syntax error: Conditional comments are not allowed.");	
                		}
                		pos++;                		
                		continue;
                	} else if(newLines.test(chr) && commentState === 1) {
                		if(commentState) {
                			commentState = 0;
                			outputSpace();
                			continue;
                		}
                	} else if(commentState === 2 && !(chr === '*' && next === '/')) {
                		if(/^@cc_on/.test(code.substr(pos))) {
                			error("Syntax error: Conditional comments are not allowed.");	
                		}
                		pos++;                		
                		continue;
                	} else if(commentState === 2 && chr === '*' && next === '/') {
                		if(commentState) {
                			commentState = 0; 
                			pos += 2;
                			outputSpace();
                			continue;
                		}
                	}                	                		            	              	             
                	if(chr === '/' && output.slice(-1) === '/') {	                		
                		outputSpace();
                	}
                	
                	if(output.slice(-1) === '<' || chr === '>' ) {
                		outputSpace();
                	}                	                	                               	                	                	
                	if(test(newLines, chr)) {                		
                		matchStr = match(newLines, chr);                		
                		pos += matchStr.length;                 		
                		if(lastState !== 'divide' && lastState !== 'questionMark' && lastState !== 'operators' && !left && !/^\s*(?:catch|else)[\s\{]/.test(code.slice(pos)) && lastState !== 'squareOpen' && lastState !== 'eos' && output.slice(-1) !== ';' && output.slice(-1) !== ':' && output.slice(-1) !== '{' && output.slice(-1) !== ',' && output.slice(-1) !== '(' && lastState !== 'statements') {                  			                			                			                			                			                			                			                			                			                			                			                			                			                				                				                				                			                		
                			outputEos();  	                			
                		} else if(new RegExp("^\\s*"+operators.source).test(code.slice(pos)) && lastState !== 'divide' && lastState !== 'operators' && lastState !== 'statements' && !functionOpen && output.slice(-1) === ')' && !/^\s*[,\/\]\[{]/.test(code.slice(pos))) {                			                			                				                				                				                			
                			outputEos();
                		} else if(lastState !== 'divide' && lastState !== 'operators' && (lastState === 'numbers' || lastState === 'objects') && /^\s*[\\\w$]/.test(code.slice(pos))) {                			                			                			                				                			
                			outputEos();
                		}  else if(lastState === 'regexps' && /^\s*function[\s(]/.test(code.slice(pos))) {	                			
                			outputEos();
                		}  else if(lastState === 'divide' || lastState === 'regexps') {
                			outputSpace();	                			
                		} else if(left && /^\s*[\\\w$]/.test(code.slice(pos))) {                				                			
                			outputEos();
                		}                		
                		continue;                	               		                	               		
                	} else if(chr === '<' && !left) {
                		error("E4X not allowed.");                	               		
                	} else if(chr === '{' && !isObjLiteral()) {                  		                		
                		counters.curlyCounter++;                		
                		if(functionOpen && !functionExpression) {
                			lookups.curlyLookup[counters.curlyCounter] = 'function';
                		} else if(functionOpen && functionExpression) {	
                			lookups.curlyLookup[counters.curlyCounter] = 'functionExpression';
                		} else if(/(?:[-]{2}|[+]{2})\s*$/.test(output)) {
                			lookups.curlyLookup[counters.curlyCounter] = 'objectLiteral'; 
                			outputChrs("(");               			
                		} else {
                			lookups.curlyLookup[counters.curlyCounter] = 'blockStatement';                 			                		
                			if(!/(?:\b(?:try|do|finally|else|catch)|[)])\s*$/.test(output)) {                				                				
                				outputEos();                				
                			}
                		}
                		outputChrs(chr);
            			pos++;
            			if(functionOpen) {
            				outputChrs('J.F();var $arguments$=J.A(arguments);','');            				
            			}             			
            			if(lastState === 'statements' && /^(?:for)$/.test(trim(lastStatement)) && lastForVariable) {            				
            				outputChrs(lastForVariable+'=J.R('+lastForVariable+');if('+lastForVariable+'===false)continue;','');            				
            			} 
            			functionExpression = functionOpen = lastStatement = lastForVariable = '';              			
            			parseTree.push("blockStatement(" + chr + ")");
            			lastState = 'blockStatement';              			            			
            			left = 0;    
            			curlyOpen = true;
                	} else if(test(objectIdentifiers, currentText) && !lastStatement) {                		                 	
                		matchStr = match(objectIdentifiers, currentText);
                		pos += matchStr.length; 
                		if(chr === '{') {               		
                			outputChrs('(');
                		}                		                  		
                		outputChrs(trim(rewriteObjectIdentifiers(matchStr).replace(/^\s*\{\s*/,'{').replace(/^\s+|\s$/g,'').replace(/^\s*,\s*/,',')), matchStr);                		
                		left = 0;
                		lastState = 'objectIdentifiers';                	                		
                	} else if(test(strings, currentText)) {
                		matchStr = match(strings, currentText);
                		pos += matchStr.length;
                		var noRewrite = matchStr;                			
                		if(lookahead() === ':' && lastState !== 'colon' && lastState !== 'statements' && lastState !== 'questionMark' && lastState !== 'operators') {
                			matchStr = objLiteralString(matchStr,noRewrite);
                		}
                		outputChrs(rewriteStrings(matchStr),noRewrite);
                		left = 1;
                		lastState = 'strings';                	
                	} else if((chr === '/' && next !== '/' && next !== '*') && !left && (!lastState || lastState === 'colon' || lastState === 'divide' || lastState === 'label' || lastState === 'comma' || lastState === 'blockStatement' || lastState === 'function' || lastState === 'operators' || lastState === 'parenOpen' || lastState == 'inInstanceofOperator' || lastState == 'statements' || lastState == 'eos' || lastState === 'squareOpen' || lastState === 'questionMark' || lastState === 'ternary')) {                		                		                		                		                		                		                		                		                		
                		if(output.slice(-1) === '}') {
                			outputEos();
                		}
                		matchStr = rewriteRegexps(currentText);                           		
                		outputChrs('/(?:)/.$constructor$(' + matchStr + ')', matchStr);                		              	
                		left = 1;
                		lastState = 'regexps';
                	} else if(test(statements, currentText)) {                		
                		matchStr = rewriteStatements(currentText);                		
                		pos += matchStr.length;                		                		
                		outputChrs('' + matchStr + ''); 
                		if(!/^[ \[\]\{\}'"\(\s]$/.test(code.substr(pos, 1))) {                			                			
                			outputSpace();
            			}  
                		left = 0;                		
                	} else if(test(numbers, currentText)) {                  		
                		matchStr = match(numbers, currentText);
                		pos += matchStr.length;                		
                		outputChrs(rewriteNumbers(matchStr));
                		left = 1;
                		lastState = 'numbers';
                	} else if(test(squareOpen, currentText)) {  
                		if(!/[!&|?:\/=~+-]/.test(output.slice(-1)) && !left && lastState !== 'squareOpen' && lastState !== 'operators' && lastState != 'eos' && output.slice(-1) !== ';' && output.slice(-1) !== ',' && output.slice(-1) !== '(' && !/[\w\\$]/.test(output.slice(-1))) {                			                			                			                			
                			outputChrs(';');
                		}
                		matchStr = match(squareOpen, currentText);
                		pos += matchStr.length;
                		outputChrs(rewriteSquareOpen(matchStr), '[');
                		left = 0;
                		lastState = 'squareOpen';
                		continue;                	
                	} else if(test(squareClose, currentText)) {
                		var arrayFound = false;
                		matchStr = match(squareClose, currentText);
                		pos += matchStr.length;
                		outputChrs(rewriteSquareClose(matchStr), ']');
                		left = 1;
                		lastState = 'squareClose';                		
                		if(!/\s*[!&|?:\/=~+-]/.test(code.slice(pos)) && !new RegExp("^\\s*"+operators.source).test(code.slice(pos)) && !/^\s*[.,\]\/\[\{\(\)\}]/.test(code.slice(pos)) && lastState !== 'eos' && arrayFound && !/^\s*(?:in(?:stanceof)?[^\w\\$])/.test(code.slice(pos))) {                			                			                			                			
                			outputEos();              			
                		}
                		if(new RegExp('^\\s*'+newLines.source+'(?:[+]{2}|[-]{2})').test(code.slice(pos))) {                			
                			outputEos();
                		}
                		continue;                	            		
                	} else if(test(objects, currentText)) {                		
                		if(output.slice(-1) === '}' && lastState !== 'statement' && !/^\s*[.,\]\/\[\{\(\)\}]/.test(code.slice(pos))) {                			
                			outputEos();
                		}
                		matchStr = match(objects, currentText);
                		pos += matchStr.length;                		
                		if(!reservedWords.test(trim(matchStr))) {                			                			                			                			                			
                			left = 1;
                			lastState = 'objects';                			
                			outputChrs(rewriteObjects(trim(matchStr)));                			                			             			
                			if((lastState === 'numbers' || lastState === 'objects') && (/^\s*[\\\w$]/.test(code.slice(pos)) && !/^\s*(?:in(?:stanceof)?[^\w\\$])/.test(code.slice(pos)) )) {
                				outputEos();
                    		} else if(new RegExp('^\\s*(?:[+]{2}|[-]{2})').test(code.slice(pos)) && new RegExp(newLines.source+'$').test(matchStr)) {
                    			outputEos();
                    		}                			
                		} else if(/^(?:break)$/.test(trim(matchStr)) || new RegExp('^return'+spaceChars.source+'*'+newLines.source).test(trim(currentText))) {
                			if(new RegExp('^'+newLines.source).test(code.slice(pos))) {                				
                				outputChrs(rewriteObjects(trim(matchStr)));                				                				
                				outputEos();                				
                			} else {
            					outputChrs(rewriteObjects(trim(matchStr)));                					                					
            					if(/^\s*[\w$]/.test(code.substr(pos))) {
            						outputSpace();
            					}            					                				
                			}
                		} else {                  			
                			if(!new RegExp("for\\s*[(]\\s*(?:var\\s)?\\s*[(\\s]*("+variable.source+')[\\s)]*$').test(prevText) && trim(matchStr) === 'in') {
                				outputChrs('.I()');
                			} else if(trim(matchStr) === 'function') {
                				if(trim(output.slice(-9)) === 'function') {
                					error("Syntax error: Function statement cannot follow function statement");
                				}                				
                				functionOpen = true;                			
                				if(lastState != 'function' && lastState != 'label' && lastState && lastState != 'eos' && lastState != 'blockStatement' && output.slice(-1) !== '{' && output.slice(-1) !== ')' && output.slice(-1) !== ']') {                					                					                					                					
                					functionExpression = true;
                				} else {
                					outputEos();
                				}
                			}                 			
                			if(/[\w\\$]\s*$/.test(output.slice(-1))) {                				
                				outputSpace();
                			}
                			
                			if(functionExpression) {
                				outputChrs('(');
                			}                			
                			outputChrs('' + rewriteObjects(trim(matchStr)) + '');                			
                			if(!/^\s*[{]/.test(code.slice(pos)) && trim(matchStr) === 'do') {                				
                    			left = 0;
                    			lastState = 'statements';
                			}  
                			
                			if(/^\s*[\w\\$]/.test(code.slice(pos)) && /^(?:true|false|Infinity|NaN|undefined|null|this)$/.test(trim(matchStr))) {
                				outputEos();
                			} else {
	                			if(!/^[ \[\]\{\}'"\(\s]$/.test(code.substr(pos, 1))) {	                				
	                				outputSpace();
	                			}       
                			}
                			if(/^(?:true|false|Infinity|NaN|undefined|null|this)$/.test(trim(matchStr))) {
                				left = 1;                				
                			}                			                			                			
                		}                		                		                		
                	} else if(chr === ';') {                		
                		matchStr = match(eos, currentText);
                		pos += matchStr.length;                 		
                		outputEos();                       		
                	} else if(test(operators, currentText)) {                 		                		                		                		                		               	
                		matchStr = match(operators, currentText);
                		if(next === '=' && !left) {
                			error("Syntax error: unexpected operator.");
                		}                		                		
                		pos += matchStr.length;                		
                		if((matchStr === '++' || matchStr === '--') && left) {                		
                			left = 1;                   			
                		} else {
                			left = 0;
                		}
                		outputChrs(rewriteOperators(matchStr));
                		if(new RegExp('^'+newLines.source+'[+-]').test(code.slice(pos)) && (chr === '+' || chr === '-')) {
                			outputSpace();                			
                		}
                		lastState = 'operators';
                		if(left && !/[.,\]\/\[\{\(\)\}&|]/.test(lookahead())) {
                			outputEos();
                		}
                	} else if(test(endCurlyBrace, currentText)) {
                		var foundObjLiteral = false;                		                		
                		matchStr = match(endCurlyBrace, currentText);
                		pos += matchStr.length;
                		outputChrs(rewriteEndCurlyBrace(matchStr));   
                		if(lastState === 'function') {
                			outputEos();
                		} else if (lastState === 'functionExpression' || foundObjLiteral){                			
                			outputChrs(')');
                		}
                		curlyOpen = false;
                	} else if(test(parenOpen, currentText)) {                		
                		matchStr = match(parenOpen, currentText);
                		pos += matchStr.length;
                		outputChrs(rewriteParenOpen(matchStr));
                		left = 0;
                		lastState = 'parenOpen';
                	} else if(test(parenClose, currentText)) { 
                		var foundCurly = true;
                		matchStr = match(parenClose, currentText);
                		pos += matchStr.length;
                		outputChrs(rewriteParenClose(matchStr));                 		
                		if(!foundCurly) {                    			
                			if(lastState === 'statements' && /^(?:for)$/.test(trim(lastStatement)) && lastForVariable) {                				                				                				
            					outputChrs('if(');
            					outputChrs(lastForVariable+'=J.R('+lastForVariable+')');
            					outputChrs(')');                				
                				lastState = 'blockStatement';
                			} else {
                				lastState = 'statements';
                			}
                			
                			functionExpression = functionOpen = lastStatement = lastForVariable = '';                 			
                			left = 0;                			
                		} else {
                			curlyOpen = true;
                		}
                	} else if(chr === ':' && next === ':') {
                		error("Syntax error namespaces not allowed.");                	
                	} else if(chr === ':' && lastState === 'objects') {
                		if(states[states.length-2] === 'questionMark' || (lastState === 'objects'  && states[states.length-2] === 'ternary')) {
                			lastState = 'ternary';	
                		} else {
                			lastState = 'label';
                		}
                		outputChrs(chr);
            			pos++; 
            			left = 0;            			
            			parseTree.push(lastState+"(" + chr + ")");            			
                	} else if(chr === '?') {
                		states = [];
                		left = 0;
                		outputChrs(chr);
            			pos++;            			
            			parseTree.push("questionMark(" + chr + ")");
            			lastState = 'questionMark';            			
                	} else if(chr === ':') {
                		left = 0;
                		outputChrs(chr);
            			pos++;
            			parseTree.push("colon(" + chr + ")");
            			lastState = 'colon';
                	} else if(chr === ',') {
            			left = 0; 
            			states = [];
            			lastState = 'comma';
            			outputChrs(chr);
            			pos++; 
            			parseTree.push("comma(" + chr + ")");
                	} else if(chr === '/' && next !== '/' && next !== '*') {                   		
                		lastState = 'divide';
                		parseTree.push("divide(" + chr + ")");                		
                		if(!left) {
                			error("Syntax error unexpected division");
                		}
                		left = 0;
                		outputChrs(chr);
            			pos++;
                	} else if(chr === '{') {                  		
                		parseTree.push("curly(" + chr + ")");
                		counters.curlyCounter++;                		
            			if(isObjLiteral() && !/^(?:if|with|while|for|switch|catch)$/.test(trim(lastStatement))) {                    		                				            				
            				lookups.curlyLookup[counters.curlyCounter] = 'objectLiteral';
            				outputChrs("(");            				
                		} else {                                 			
                			lookups.curlyLookup[counters.curlyCounter] = 'blockStatement';
                			left = 0;
                			lastState = '';
                			if(!/(?:\b(?:try|do|finally|else)|[)])\s*$/.test(output)) {                				
                				outputEos();                				
                			}
                		}             			
            			outputChrs(chr);            			
            			if((lastState === 'statements' || !lastState) && /^(?:for)$/.test(trim(lastStatement)) && lastForVariable) {            				
            				outputChrs(lastForVariable+'=J.R('+lastForVariable+');if('+lastForVariable+'===false)continue;');             				
            			} 
            			if(functionOpen) {
            				outputChrs('J.F();var $arguments$=J.A(arguments);','');
            			}
            			functionExpression = functionOpen = lastStatement = lastForVariable = '';  
            			pos++;            			
                	} else if(/^\s$/.test(chr)) {                 		
                		if((lastState==='operators' || lastState==='objects') && !/^\s$/.test(output.slice(-1)) || prev === '/') {	                			
                			outputSpace();
                		}                		
                		pos++;
                	} else if(chr === '/' && next === '/') {
                		matchStr = code.substr(pos, 2);
                		outputChrs(rewriteComments(matchStr));                		
                		commentState = 1;
                		continue; 
                	} else if(chr === '/' && next === '*') {
                		matchStr = code.substr(pos, 2);
                		outputChrs(rewriteComments(matchStr));                		
                		commentState = 2;
                		pos+=2;
                		continue;                 		
                	} else {                		
                		error("Syntax error: unexpected"+chr);
                	}                	
                	states.push(lastState);
                }  
                that.checkSyntax(correctedOutput); 
                if(that.debugObjects.correctedOutput) {
                    that.debugObjects.correctedOutput(correctedOutput);
                }
            	return output;                                                                                            
            },            
            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");
                }
            },            
            destroy: function(){
                this.environment.parentNode.removeChild(this.environment);
            }
        };
        
        return new Parser;
    };
    var JSReg = {
    	single: function() {
    		if(this.instance) {
    			return this.instance;
    		} else {
    			return this.create(true);
    		}
    	},
    	compile: function (code) {
    		var parser = JSReg_Environment();
    		return parser.rewriteLines(code);	
    	},
        create: function(single) {    		
	    	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;
	        if(single) {
	        	this.instance = obj;
	        }
	        return obj;
        }        
    };  
    if ("object" === typeof window) window.JSReg = JSReg;
    if ("object" === typeof exports) exports.JSReg = JSReg;
})();
