AS3 Developer Console

by Torrunt
What        : AS3 Developer Console    (v1.05) - http://code.google.com/p/as3developerconsole/
Author    : Corey Zeke (Torrunt) Womack
Contact    : torrunt56@gmail.com
Type 'help' in console for help.
If your testing your project in the Flash IDE make sure 'Disable Keyboard Shortcuts' is ticked.
When testing your project in the Flash IDE you have to click the swf at least once to be able to see the text cursor.
♥0 | Line 678 | Modified 2011-09-08 22:06:49 | MIT License
play

ActionScript3 source code

/**
 * Copyright Torrunt ( http://wonderfl.net/user/Torrunt )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ilji
 */

// What        : AS3 Developer Console    (v1.05) - http://code.google.com/p/as3developerconsole/
// Author    : Corey Zeke (Torrunt) Womack
// Contact    : torrunt56@gmail.com

// Type 'help' in console for help.
// If your testing your project in the Flash IDE make sure 'Disable Keyboard Shortcuts' is ticked.
// When testing your project in the Flash IDE you have to click the swf at least once to be able to see the text cursor.

package {
    import flash.display.Sprite;
    import flash.text.*;
    import flash.events.KeyboardEvent;
    import flash.events.TextEvent;
    import flash.events.Event;
    import flash.utils.describeType;
    
    public class developerconsole extends Sprite {
        
        // Customisation
        public var consoleheight:Number                = 125;        // height of the console
        public var maxSuggestions:int                = 14;        // max suggestions that can be shown at once
        public var showTypes:Boolean                 = true;        // show data/return types of vars and functions
        public var returnFunctions:Boolean             = true;        // return function return values
        
        public var tracerView:Boolean                 = true;        // show the tracer table when using the tracer
        public var tracerActualTrace:Boolean         = true;        // actually use as3's trace() function when using the tracer
        public var tracerActualTraceLayout:String     = "name : value";
        public var tracerOneCiclePerLine:Boolean     = false;    // makes everything traced in one cicle only apear on one line
        public var tracerOneCiclePerLine_seperator:String = " ";
        
        
        private static var help:String = " - Type 'clear' to clear the console.\n - Type 'credits' to see the credits\n - Use the Up/Down arrow keys to go through your previous used commands or suggestions\n - Use Quotations when you want enter string literal with spaces (\")\n - Use Square Brackets when you want to use an arral literal (e.g:[0,1]).\n - You can do multiple commands at once by seperating them with ';'s.\n - You can also put x# after a ';' to do that command # many times.\n - Calculations are allowed when assigning or in parameters (+,-,*,/,%). BIMDAS is not supported.\n - type 'trace:something' to start tracing something or 'stoptrace:something' to stop tracing it.\n - Use pgUp and pgDown on your keyboard to scroll up and down";
        private static var credits:String = "Torrunt's AS3 Developer Console (v1.05) was programmed by Corey Zeke (Torrunt) Womack\ntorrunt56@gmail.com\ntorrunt.newgrounds.com\ntorrunt.wordpress.com";
        
        // Creating / Defaults
        private var main:*;
        
        private var suggesttext:TextField;
        private var consoleTextFormat:TextFormat;
        private var historytext:TextField;
        private var inputtext:TextField;
        private var tracerAlignX:Number;
        private var tracerAlignY:Number;
        
        private var tracer:TextField;
        private var tracerNames:TextField;
        private var traceVars:Array = new Array();
        
        private var cmdsuggest:Array = new Array();
        private var cmdhistory:Array = new Array();
        private var cicle:Array;
        private var hpos:int = -1;
        
        public var opened:Boolean = false;
        
        // Constructor
        public function developerconsole(_main:*){
            main = _main;    // Start off point for seeing/using variables and functions (stage or main class)
            
            // Customise Look
                // Text Format
            consoleTextFormat = new TextFormat();
            consoleTextFormat.size = 14;
            consoleTextFormat.font = "Arial";
            consoleTextFormat.color = 0xFFFFFF;
            
                // History Textbox
            historytext = new TextField();
            addChild(historytext);
            
            historytext.width = main.stage.stageWidth;
            historytext.height = consoleheight;
            historytext.alpha = 0.9;
            historytext.selectable = false;
            historytext.multiline = true;
            historytext.wordWrap = true;
            historytext.defaultTextFormat = consoleTextFormat;
            historytext.background = true;
            historytext.backgroundColor = 0x000000;
            
                // Input Textbox
            inputtext = new TextField();
            inputtext.type = TextFieldType.INPUT;
            addChild(inputtext);
            
            inputtext.width = main.stage.stageWidth;
            inputtext.height = 20;
            inputtext.y = historytext.height;
            inputtext.x = 0;
            inputtext.alpha = 0.8;
            inputtext.defaultTextFormat = consoleTextFormat;
            inputtext.background = true;
            inputtext.backgroundColor = 0x000000;
            
                // Suggest/auto-complete Textbox
            suggesttext = new TextField();
            addChild(suggesttext);
            
            suggesttext.width = 150;
            suggesttext.height = 20;
            suggesttext.y = inputtext.y + inputtext.height;
            suggesttext.alpha = 0.85;
            suggesttext.selectable = false;
            suggesttext.defaultTextFormat = consoleTextFormat;
            suggesttext.background = true;
            suggesttext.backgroundColor = 0x000000;
            suggesttext.autoSize = TextFieldAutoSize.LEFT;
            suggesttext.visible = false;
            
                // Tracer
            tracerAlignX = main.stage.stageWidth - 10;
            tracerAlignY = 10;
            
            consoleTextFormat.bold = true;
    
            tracer = new TextField();
            main.stage.addChild(tracer);
            
            tracer.alpha = 0.75;
            tracer.selectable = false;
            consoleTextFormat.align = "right";
            tracer.defaultTextFormat = consoleTextFormat;
            tracer.background = true;
            tracer.backgroundColor = 0x666666;
            tracer.autoSize = TextFieldAutoSize.LEFT;
            tracer.visible = false;
            
            
            tracerNames = new TextField();
            main.stage.addChild(tracerNames);
            
            tracerNames.alpha = 0.75;
            tracerNames.selectable = false;
            consoleTextFormat.align = "left";
            tracerNames.defaultTextFormat = consoleTextFormat;
            tracerNames.background = true;
            tracerNames.backgroundColor = 0x666666;
            tracerNames.autoSize = TextFieldAutoSize.LEFT;
            tracerNames.visible = false;
            
            // Startup Message
            echo("Welcome to Torrunt's AS3 Developer Console");
            
            visible = false;    // Hide self
        }
        
        //////////////////////////
        //        Open/Close        //
        /////////////////////////
        
        public function open():void {
            if (!opened){
                visible = true;
                opened = true;
                main.stage.focus = inputtext;
                
                main.parent.addEventListener(KeyboardEvent.KEY_UP, keyup);
                main.parent.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
                inputtext.addEventListener(TextEvent.TEXT_INPUT,typed);
            }
        }
        
        public function close():void {
            if (opened){
                visible = false;
                opened = false;
                inputtext.text = "";
                hpos = -1;
                
                main.parent.removeEventListener(KeyboardEvent.KEY_UP, keyup);
                main.parent.removeEventListener(KeyboardEvent.KEY_DOWN, keydown);
                inputtext.removeEventListener(TextEvent.TEXT_INPUT,typed);
            }
        }
        
        public function toggle():void {
            if (opened){
                close();
            } else {
                open();
            }
        }
        
        //////////////////////////
        //        Controls        //
        /////////////////////////
        
        private var pressedUp:Boolean = false;
        
        private function keydown(e:KeyboardEvent):void {
            // Enter
            if (e.keyCode == 13 && inputtext.text != ""){
                echo(inputtext.text);
                
                if (cmdhistory[cmdhistory.length-1] != inputtext.text){
                    cmdhistory.push(inputtext.text);
                    hpos = -1;
                }
                
                interpret(inputtext.text);
                
                inputtext.text = "";
                hidesuggestions();
            }
            
            // Backspace
            if (e.keyCode == 8){
                if(inputtext.length-1 <= 0){
                    hidesuggestions();
                } else {
                    showsuggestions(inputtext.text.substr(0,inputtext.length-1));
                }
            }
            
            // Up and Down
                // Pick array to go through
            if (suggesttext.visible){
                cicle = cmdsuggest;
            } else {
                cicle = cmdhistory;
            }
                // Up
            if (e.keyCode == 38 && cicle[cicle.length-1-(hpos+1)] != null){
                hpos++;
                changeInputbox();
                pressedUp = true;
            }
                // Down
            if (e.keyCode == 40){
                if (cicle[cicle.length-1-(hpos-1)] != null){
                    hpos--;
                    changeInputbox();
                } else if (cicle == cmdhistory) {
                    inputtext.text = "";
                    hpos = -1;
                }
            }
            
            // Scrolling Up and Down
                // Page Up
            if (e.keyCode == 33){
                historytext.scrollV--;
            }
                // Page Down
            if (e.keyCode == 34){
                historytext.scrollV++;
            }
        }
        
            // Fix cursor position if you press up when moving through history or suggestions
        private function keyup(e:KeyboardEvent):void {
            if (pressedUp){
                inputtext.setSelection(inputtext.length,inputtext.length);
                pressedUp = false;
            }
        }
        
        // Change inputbox contents to the next/previous history or suggestion item
        private function changeInputbox():void {
            // If going through suggestions: just replace the thing you're currently writing
            if (cicle == cmdsuggest){
                // if last suggestion added a '();' at the end - remove it
                if (inputtext.text.lastIndexOf("();")+3 == inputtext.length){
                    inputtext.text = inputtext.text.substr(0,inputtext.length-3);
                }
                
                // Remove text after last symbol or space
                    // get indexs of symbols
                var symbols:Array = fillArrayWithIndexsOf(symbols,inputtext.text,["."," ","(",",","-","+","/","*","%",";",":","["]);
                    // get highest index (last used symbol)
                var ls:int = symbols[0]; // (last symbol)
                for (var i:int = 1; i < symbols.length; i++){
                    if (symbols[i] > ls) ls = symbols[i];
                }
                
                // if the last symbol is a bracket and is the last thing in the inputbox: make it the second last symbol
                if (inputtext.text.charAt(ls) == "(" && (ls == inputtext.length-1)){
                    inputtext.text = inputtext.text.substr(0,ls);
                    changeInputbox();
                    return;
                }
                
                // Remove what you're currently writing
                inputtext.text = inputtext.text.substr(0,ls+1);
                // Appened suggestion
                inputtext.appendText(cicle[cicle.length-1-hpos]);
            } else {
            // Otherwise replace the whole inputtext
                inputtext.text = cicle[cicle.length-1-hpos]; // Replace text
            }
            
            inputtext.setSelection(inputtext.length,inputtext.length);
        }
        
        //////////////////////////
        //        Suggesting        //
        /////////////////////////
        
        // Defaulting
        private var areSuggestions:Boolean = false;
        private var hitMax:Boolean = false;
        
        // Update while typing
        private function typed(e:TextEvent):void {
            showsuggestions(inputtext.text+e.text);
        }
        
        private function showsuggestions(str:String):void {
            // reset to defaults
            hidesuggestions();    // hide previous
            areSuggestions = false;
            hitMax = false;
            
            // check for ';'s (end of commands)
            if (str.indexOf(";") > 1){
                str = str.slice(str.lastIndexOf(";")+1,str.length);
            }
            
            // change str to latest var user is writing
            str = stringReplaceAll(str," ");
            
            var symbols:Array = fillArrayWithIndexsOf(symbols,str,["(","=",",","-","+","/","*","%",":","["]);
            var startFrom:int = symbols[0];
            
            if (characterCount(str,"]") == characterCount(str,"[")) symbols.pop(); // Don't look for '[' if last one was closed
            
            for (var s = 1; s < symbols.length; s++){
                if (symbols[s] > startFrom) startFrom = symbols[s];
            }
            str = str.substring(startFrom+1,str.length);
            
            // Get all public Vars and Functions
            if (str != ""){
                try {
                    var ob = main;
                    var stre = str;
                    
                    if (str.indexOf(".") > -1){
                        var o:Array = str.split(".");
                        for (var i:int = 0; i < o.length-1; i++){
                            if (o[i].indexOf("[") > -1){
                                // if an Array Item
                                var tempAry = stringToArrayItem(o[i]);
                                ob = ob[tempAry[0]][tempAry[1]];
                            } else {
                                ob = ob[o[i]];
                            }
                        }
                        
                        stre = o[o.length-1];
                    }
                    
                    var description:XML = describeType(ob);
                    
                    var type = "";
                    
                    // Vars
                    for each (var v:XML in description.variable){
                        if (suggesttext.numLines < maxSuggestions){
                            if(v.@name.indexOf(stre) == 0){
                                if (showTypes) type = ":" + v.@type;
                                
                                cmdsuggest.push(v.@name);
                                suggesttext.appendText(v.@name + type + "\n");
                                areSuggestions = true;
                            }
                        } else {
                            hitMax = true;
                            break;
                        }
                    }
                    // Accessors
                    for each (var a:XML in description.accessor){
                        if (suggesttext.numLines < maxSuggestions){
                            if(a.@name.indexOf(stre) == 0){
                                if (showTypes) type = ":" + a.@type;
                                
                                cmdsuggest.push(a.@name);
                                suggesttext.appendText(a.@name + type + " (accessor)\n");
                                areSuggestions = true;
                            }
                        } else {
                            hitMax = true;
                            break;
                        }
                    }
                    // Methods / Functions
                    for each (var m:XML in description.method){
                        if (suggesttext.numLines < maxSuggestions){
                            if(m.@name.indexOf(stre) == 0){
                                if (showTypes) type = ":" + m.@returnType;
                                
                                suggesttext.appendText(m.@name + "(");
                                areSuggestions = true;
                                // Parameters
                                if (m.parameter != undefined) {
                                    for each (var p:XML in m.parameter){
                                        suggesttext.appendText(p.@type+",");
                                    }
                                    suggesttext.text = suggesttext.text.slice(0,suggesttext.text.length-1);
                                    cmdsuggest.push(m.@name+"(");
                                } else {
                                    cmdsuggest.push(m.@name+"();");
                                }
                                suggesttext.appendText(")" + type +"\n");
                            }
                        } else {
                            hitMax = true;
                            break;
                        }
                    }
                    
                    // If there are suggestions
                    if (areSuggestions){
                        // if there were more then what can be displayed; add a last item called "..."
                        if (hitMax){
                            suggesttext.appendText("...");
                        }
                        suggesttext.visible = true;
                        hpos = cmdsuggest.length;
                    }
                }
                catch(er:Error){
                    // do nothing
                }
            }
        }
        
        private function hidesuggestions():void {
            suggesttext.visible = false;
            suggesttext.text = "";
            suggesttext.height = 20;
            cmdsuggest = new Array();
            hpos = -1;
        }
        
        //////////////////////////
        //        Interpreting    //
        /////////////////////////
        
        // Seperate commands (by ;) and interpet them
        private function interpret(str:String):void {
            if (str.indexOf(";") > 1){
                var c:Array = str.split(";");
                for (var i:int = 0; i < c.length; i++){
                    
                    // if there's an x then look for x# and repeat for that #
                    if (c[i].indexOf("x") == 0){
                        c[i] = Number(c[i].slice(1,c[i].length));
                        for (var r = 1; r < c[i]; r++){
                            interpretString(c[i-1]);
                        }
                    } else {
                        if (c[i] != "") interpretString(c[i]);
                    }
                }
            } else {
                interpretString(str);
            }
        }
        
        // Interpret String/Command
        private function interpretString(str:String):void {
            // Remove ';'s and spaces outside of quotes
            str = stringReplaceAll(str, ";");
            str = stringReplaceButExclude(str," ","\"","",false);
            
            // Assigning
            if (str.indexOf("=") > 0){
                var ar = str.split("=");
                ar = checkShorthandCalculations(ar);
                ar[1] = stringToVarWithCalculation(ar[1]);
                changeVar(ar[0],ar[1]);
            } else 
            // Calling functions
            if (str.indexOf("(") > 0 && str.indexOf(")") > str.indexOf("(")){
                if (returnFunctions){
                    var rtrn:String = stringToFunc(str);
                    if (rtrn != null) warn("returned: "+rtrn);
                } else {
                    stringToFunc(str);
                }
            } else {
                // Console-only Commands and getVar
                if (str.indexOf("trace:") == 0){
                    setTrace(str);
                } else
                if (str.indexOf("stoptrace:") == 0){
                    stopTrace(str);
                } else {
                    switch(str){
                        case "clear": historytext.text = ""; break;
                        case "help": echo(help,"0099CC"); break;
                        case "credits": echo(credits,"0099CC"); break;
                        default: getVar(str); break;
                    }
                }
            }
        }
        
        // Echo var value / calculation
        private function getVar(varname):void {
            var rstring:String = varname + " is ";

            try {
                rstring += stringToVarWithCalculation(varname);
                echo(rstring);
            }
            catch(er:Error){
                error(er.message);
            }
        }
        
        // Assign a value to a variable
        private function changeVar(varname:String,vset):void {
            try {
                // check if vset is an array
                try {
                    vset = stringToArray(vset);
                }
                catch(er:Error){
                    // do nothing
                }
                
                // check if vset is a boolean
                if (vset == "true") vset = true;
                if (vset == "false") vset = false;
                
                // assign
                var v:Array = varname.split(".");
                
                var ob = main;
                var tempAry; // for array items if needed
                
                for (var i:int = 0; i < v.length-1; i++){
                    if (v[i].indexOf("[") > -1){
                        // if an Array Item
                        tempAry = stringToArrayItem(v[i]);
                        ob = ob[tempAry[0]][tempAry[1]];
                    } else {
                        ob = ob[v[i]];
                    }
                }
                
                if (v[v.length-1].indexOf("[") > -1){
                    // if an Array Item
                    tempAry = stringToArrayItem(v[v.length-1]);
                    ob[tempAry[0]][tempAry[1]] = vset;
                } else {
                    ob[v[v.length-1]] = vset;
                }
            }
            catch(er:Error){
                error(er.message);
            }
        }
        
        // Covert a string to useable variable
        private function stringToVar(str:String){
            var ob = str;
            
            if (str.indexOf("\"") == -1){
                var v:Array = str.split(".");
                
                ob = main;
                for (var i:int = 0; i < v.length; i++){
                    if (v[i].indexOf("[") > -1){
                        // if an Array Item
                        var tempAry = stringToArrayItem(v[i]);
                        ob = ob[tempAry[0]][tempAry[1]];
                    } else {
                        ob = ob[v[i]];
                    }
                }
            }
            
            return ob;
        }
        
        // Convert a string to a callable function
        private function stringToFunc(str:String, setval:Boolean = false){
            str = stringReplaceAll(str, ")");
            var ar = str.split("(");
            var pars;
            
            if (ar[1] == ""){
                pars = new Array();
            } else {
                pars = stringToPars(ar[1]);
            }
            
            if (!setval){
                return stringToVar(ar[0]).apply(null,pars);
            } else {
                return stringToVar(ar[0]).apply(null,pars);
            }
        }
        
        // Convert a string into an array of parameters/arguments
        private function stringToPars(str:String):Array {
            // change commas but leave commas inside array literals
            str = str.replace("[","|");
            str = str.replace("]","|");
            str = stringReplaceButExclude(str,",","|","`");
            // split the parameters
            var pars = str.split("`");
            
            // Convert pars to vals/funcs if they are
            for (var i:int = 0; i < pars.length; i++){
                try {
                    pars[i] = stringToVarWithCalculation(pars[i]);
                    
                    // convert to array if nessesary
                    if (pars[i].indexOf(",") > -1){
                        pars[i] = stringToArray(pars[i],false);
                    }
                }
                catch (er:Error){
                    // do nothing
                }
            }
            return pars;
        }
        
        // Convert a string into an array
        private function stringToArray(str,needSquareBrackets:Boolean = true):* {
            var res;
            
            // if there's square brackets - remove them and convert
            if (str.indexOf("[") == 0 && str.lastIndexOf("]") == str.length-1 || !needSquareBrackets){
                if (needSquareBrackets) str = str.substr(1,str.length-2); // remove brackets
                res = str.split(",");
                
                for (var i:int = 0; i < res.length; i++){
                    try {
                        res[i] = stringToVarWithCalculation(res[i]);
                    }
                    catch (er:Error){
                        // do nothing
                    }
                }
                
            } else {
                // if there was no square brackets and they were needed - just convert it to a var
                res = stringToVarWithCalculation(res);
            }
            
            return res;
        }
        
        // Conver a string into an array item
        private function stringToArrayItem(str):* {
            var res = str;
            
            // if there's square brackets - convert to array item
            if (str.indexOf("[") > -1 && str.lastIndexOf("]") == str.length-1){
                str = str.substr(0,str.length-1); // remove last bracket
                res = str.split("[");
                res[1] = Number(res[1]); // convert given index to number
            }
            
            return res;
        }
        
        // Convert to vars/func returns and do calucations with them
        private function stringToVarWithCalculation(str):* {
            if (str == "true"){
                return true;
            } else
            if (str == "false"){
                return false;
            } else
            if (containsOperators(str)){
                var operatorOrder:Array = new Array();
                var n:int = 0;
                
                var temp:String = "";
                var inExl:Boolean = false;
                var foundOperator:Boolean;
                var operators:Array = new Array("-","+","/","*","%");
                
                for (var i:int = 0; i < str.length; i++){
                    foundOperator = false;
                    
                    if (str.charAt(i) == "\""){ // doesn't do calculations in quotations
                        inExl = !inExl;
                    } else {
                        if (!inExl){
                            var op:int = 0;
                            
                            while (!foundOperator && op < operators.length){
                                if (str.charAt(i) == operators[op]){
                                    foundOperator = true;
                                    
                                    operatorOrder[n] = op;
                                    n++;
                                }
                                op++;
                            }
                        }
                        
                        if (foundOperator){
                            temp += "`"; // replace operator with ` for spliting
                        } else {
                            temp += str.charAt(i);
                        }
                    }
                }
                str = temp;
                
                // split by operators
                var t:Array = str.split("`");
                
                // Convert to vars/functions if they are
                for (var c = 0; c < t.length; c++){
                    if (!isNaN(t[c])){
                        t[c] = Number(t[c]);
                    } else
                    if (t[c].indexOf("(") > 0 && t[c].indexOf(")") > 0){
                        t[c] = stringToFunc(t[c],true);
                    } else {
                        try {
                            t[c] = stringToVar(t[c]);
                        }
                        catch (e:Error){
                            
                        }
                    }
                }
                
                // Calculate
                str = t[0];
                n = 0;
                for (var o = 1; o < t.length; o++){
                    switch (operatorOrder[n]){
                        case 0: str -= t[o]; break;
                        case 1: str += t[o]; break;
                        case 2: str /= t[o]; break;
                        case 3: str *= t[o]; break;
                        case 4: str %= t[o]; break;
                    }
                    n++;
                }
            } else {
                // If no operators - just convert to var or func
                str = stringReplaceAll(str,"\"");
                try {
                    if (str.indexOf("(") > 0 && str.indexOf(")") > str.indexOf("(")){
                        str = stringToFunc(str,true);
                    } else {
                        str = stringToVar(str);
                    }
                }
                catch (er:Error){
                    // do nothing
                }
            }
            
            return str;
        }
        
        
        private function checkShorthandCalculations(ar:Array):Array {
            if (ar[0].indexOf("+") == ar[0].length-1 || ar[0].indexOf("-") == ar[0].length-1 ||
                ar[0].indexOf("/") == ar[0].length-1 || ar[0].indexOf("*") == ar[0].length-1 ||
                ar[0].indexOf("%") == ar[0].length-1){
                ar[1] = ar[0] + ar[1];
                ar[0] = ar[0].substr(0,ar[0].length-1);
            }
            return ar;
        }
        
        private function containsOperators(str):Boolean {
            return str.indexOf("+") > -1 || str.indexOf("-") > -1 || str.indexOf("/") > -1 || str.indexOf("*") > -1 || str.indexOf("%") > -1;
        }
        
        //////////////////////////
        //      Misc Functions    //
        /////////////////////////
        
            // Messages
        public function echo(str, colour:String = "FFFFFF"):void {
            historytext.htmlText = historytext.htmlText + "<font color=\"#"+ colour +"\">" + str + "</font>\n";
            historytext.scrollV = historytext.maxScrollV;
        }
        public function error(str):void {
            echo(str,"FF0000");
        }
        public function warn(str):void {
            echo(str,"0000FF");
        }
        
            // Common String related functions
        private function stringReplaceAll(str:String, r:String, rw:String = ""):String {
            do {
                str = str.replace(r,rw);
            }
            while(str.indexOf(r) > - 1);
            
            return str;
        }
        
        private function stringReplaceButExclude(str:String, r:String, exl:String, rw:String = "", removeExls:Boolean = true):String {
            // Replaces all 'r's in a string with 'rw' excluding 'r's inside 'exl's
            var temp:String = "";
            
            if (str.indexOf(exl) > -1){
                var inExl:Boolean = false;
                
                for (var i:int = 0; i < str.length; i++){
                    if (str.charAt(i) == exl){
                        inExl = !inExl;
                        if (!removeExls) temp += exl;
                    } else
                    if (str.charAt(i) == r && !inExl){
                        temp += rw;
                    } else {
                        temp += str.charAt(i);
                    }
                }
            } else {
                temp = stringReplaceAll(str, r, rw);
            }
            return temp;
        }
        
        private function fillArrayWithIndexsOf(ar:Array, str:String, ar2:Array, startIndex:int = -1):Array {
            if (ar == null) ar = new Array();
            if (startIndex == -1) startIndex = str.length-1;
            
            for (var i:int = 0; i < ar2.length; i++){
                ar[i] = str.lastIndexOf(ar2[i],startIndex);
            }
            
            return ar;
        }
        
        private function characterCount(str:String, char:String):int {
            var count:int = 0;
            for (var i:int = 0; i < str.length; i++){
                if (str.charAt(i) == char) count++;
            }
            return count;
        }
        
        //////////////////////////
        //          Tracer        //
        /////////////////////////
        
        private function setTrace(str:String){
            var originalLength:Number = traceVars.length;
            
            str = str.replace("trace:","");
            
            var v:Array = str.split(",");
            for (var n = 0; n < v.length; n++) traceVars.push(v[n]);
            
            if (originalLength == 0 && traceVars.length != 0) tracer.addEventListener(Event.ENTER_FRAME, traceUpdate);
        }
        
        private function stopTrace(str:String){
            str = str.replace("stoptrace:","");
            
            if (str == "all"){
                traceVars = new Array();
            } else {
                var v:Array = str.split(",");
                for (var n = 0; n < v.length; n++){
                    for (var i:int = 0; i < traceVars.length; i++){
                        if (traceVars[i] == v[n]) traceVars.splice(i,1);
                    }
                }
            }
            
            if (traceVars.length == 0){
                tracer.removeEventListener(Event.ENTER_FRAME, traceUpdate);
                tracer.visible = false;
                tracerNames.visible = false;
            }
        }
        
        private function traceUpdate(e:Event){
            // actual trace
            if (tracerActualTrace){
                if (tracerOneCiclePerLine) var completeOutput:String = "";
                
                for (var t = 0; t < traceVars.length; t++){
                    var output:String = tracerActualTraceLayout;
                    output = output.replace("name",traceVars[t]);
                    output = output.replace("value",stringToVarWithCalculation(traceVars[t]));
                    
                    if (!tracerOneCiclePerLine){
                        trace(output);
                    } else {
                        completeOutput += output + tracerOneCiclePerLine_seperator;
                    }
                }
                
                if (tracerOneCiclePerLine) trace(completeOutput);
            }
            
            // tracer table
            if (tracerView){
                tracer.visible = true;
                tracerNames.visible = true;
                tracer.text = "";
                tracerNames.text = "";
                
                for (var i:int = 0; i < traceVars.length; i++){
                    tracerNames.appendText(traceVars[i] + "\n");
                    tracer.appendText(stringToVarWithCalculation(traceVars[i]) + "\n");
                }
                
                // position                
                tracerNames.x = tracerAlignX - tracerNames.width;
                tracer.x = tracerNames.x - tracer.width - 10;
                if (visible && tracerAlignY < consoleheight+inputtext.height){
                    tracer.y = 10 + inputtext.y + inputtext.height;
                    tracerNames.y = 10 +inputtext.y + inputtext.height;
                } else {
                    tracer.y = tracerAlignY;
                    tracerNames.y = tracerAlignY;
                }
            } else {
                tracer.visible = false;
                tracerNames.visible = false;
            }
        }
        
    }
}