ace.define("ace/mode/crystal_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function (require, exports, module) {
    "use strict";

    var oop = require("../lib/oop");
    var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

    var CrystalHighlightRules = function () {

        var builtinFunctions = (
            "puts|initialize|previous_def|typeof|as|pointerof|sizeof|instance_sizeof"
        );

        var keywords = (
            "if|end|else|elsif|unless|case|when|break|while|next|until|def|return|class|new|getter|setter|property|lib"
            + "|fun|do|struct|private|protected|public|module|super|abstract|include|extend|begin|enum|raise|yield|with"
            + "|alias|rescue|ensure|macro|uninitialized|union|type|require"
        );

        var buildinConstants = (
            "true|TRUE|false|FALSE|nil|NIL|__LINE__|__END_LINE__|__FILE__|__DIR__"
        );

        var builtinVariables = (
            "$DEBUG|$defout|$FILENAME|$LOAD_PATH|$SAFE|$stdin|$stdout|$stderr|$VERBOSE|" +
            "root_url|flash|session|cookies|params|request|response|logger|self"
        );

        var keywordMapper = this.$keywords = this.createKeywordMapper({
            "keyword": keywords,
            "constant.language": buildinConstants,
            "variable.language": builtinVariables,
            "support.function": builtinFunctions
        }, "identifier");

        var hexNumber = "(?:0[xX][\\dA-Fa-f]+)";
        var decNumber = "(?:[0-9][\\d_]*)";
        var octNumber = "(?:0o[0-7][0-7]*)";
        var binNumber = "(?:0[bB][01]+)";
        var intNumber = "(?:[+-]?)(?:" + hexNumber + "|" + decNumber + "|" + octNumber + "|" + binNumber + ")(?:_?[iIuU](?:8|16|32|64))?\\b";
        var escapeExpression = /\\(?:[nsrtvfbae'"\\]|[0-7]{3}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u{[\da-fA-F]{1,6}})/;
        var extEscapeExspresssion = /\\(?:[nsrtvfbae'"\\]|[0-7]{3}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u{[\da-fA-F]{1,6}}|u{(:?[\da-fA-F]{2}\s)*[\da-fA-F]{2}})/;

        this.$rules = {
            "start": [
                {
                    token: "comment",
                    regex: "#.*$"
                }, {
                    token: "string.regexp",
                    regex: "[/]",
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string.regexp",
                        regex: "[/][imx]*(?=[).,;\\s]|$)",
                        next: "pop"
                    }, {
                        defaultToken: "string.regexp"
                    }]
                },
                [{
                    regex: "[{}]", onMatch: function (val, state, stack) {
                        this.next = val == "{" ? this.nextState : "";
                        if (val == "{" && stack.length) {
                            stack.unshift("start", state);
                            return "paren.lparen";
                        }
                        if (val == "}" && stack.length) {
                            stack.shift();
                            this.next = stack.shift();
                            if (this.next.indexOf("string") != -1)
                                return "paren.end";
                        }
                        return val == "{" ? "paren.lparen" : "paren.rparen";
                    },
                    nextState: "start"
                }, {
                    token: "string.start",
                    regex: /"/,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string",
                        regex: /\\#{/
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        token: "string.end",
                        regex: /"/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    token: "string.start",
                    regex: /`/,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string",
                        regex: /\\#{/
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        token: "string.end",
                        regex: /`/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "rpstring",
                    token: "string.start",
                    regex: /%[Qx]?\(/,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string.start",
                        regex: /\(/,
                        push: "rpstring"
                    }, {
                        token: "string.end",
                        regex: /\)/,
                        next: "pop"
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "spstring",
                    token: "string.start",
                    regex: /%[Qx]?\[/,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string.start",
                        regex: /\[/,
                        push: "spstring"
                    }, {
                        token: "string.end",
                        regex: /]/,
                        next: "pop"
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "fpstring",
                    token: "string.start",
                    regex: /%[Qx]?{/,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string.start",
                        regex: /{/,
                        push: "fpstring"
                    }, {
                        token: "string.end",
                        regex: /}/,
                        next: "pop"
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "tpstring",
                    token: "string.start",
                    regex: /%[Qx]?</,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string.start",
                        regex: /</,
                        push: "tpstring"
                    }, {
                        token: "string.end",
                        regex: />/,
                        next: "pop"
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "ppstring",
                    token: "string.start",
                    regex: /%[Qx]?\|/,
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "string.end",
                        regex: /\|/,
                        next: "pop"
                    }, {
                        token: "paren.start",
                        regex: /#{/,
                        push: "start"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "rpqstring",
                    token: "string.start",
                    regex: /%[qwir]\(/,
                    push: [{
                        token: "string.start",
                        regex: /\(/,
                        push: "rpqstring"
                    }, {
                        token: "string.end",
                        regex: /\)/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "spqstring",
                    token: "string.start",
                    regex: /%[qwir]\[/,
                    push: [{
                        token: "string.start",
                        regex: /\[/,
                        push: "spqstring"
                    }, {
                        token: "string.end",
                        regex: /]/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "fpqstring",
                    token: "string.start",
                    regex: /%[qwir]{/,
                    push: [{
                        token: "string.start",
                        regex: /{/,
                        push: "fpqstring"
                    }, {
                        token: "string.end",
                        regex: /}/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "tpqstring",
                    token: "string.start",
                    regex: /%[qwir]</,
                    push: [{
                        token: "string.start",
                        regex: /</,
                        push: "tpqstring"
                    }, {
                        token: "string.end",
                        regex: />/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    stateName: "ppqstring",
                    token: "string.start",
                    regex: /%[qwir]\|/,
                    push: [{
                        token: "string.end",
                        regex: /\|/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }, {
                    token: "string.start",
                    regex: /'/,
                    push: [{
                        token: "constant.language.escape",
                        regex: escapeExpression
                    }, {
                        token: "string.end",
                        regex: /'|$/,
                        next: "pop"
                    }, {
                        defaultToken: "string"
                    }]
                }], {
                    token: "text", // namespaces aren't symbols
                    regex: "::"
                }, {
                    token: "variable.instance", // instance variable
                    regex: "@{1,2}[a-zA-Z_\\d]+"
                }, {
                    token: "variable.fresh", // fresh variable
                    regex: "%[a-zA-Z_\\d]+"
                }, {
                    token: "support.class", // class name
                    regex: "[A-Z][a-zA-Z_\\d]+"
                }, {
                    token: "constant.other.symbol", // symbol
                    regex: "[:](?:(?:===|<=>|\\[]\\?|\\[]=|\\[]|>>|\\*\\*|<<|==|!=|>=|<=|!~|=~|<|\\+|-|\\*|\\/|%|&|\\||\\^|>|!|~)|(?:(?:[A-Za-z_]|[@$](?=[a-zA-Z0-9_]))[a-zA-Z0-9_]*[!=?]?))"
                }, {
                    token: "constant.numeric", // float
                    regex: "[+-]?\\d(?:\\d|_(?=\\d))*(?:(?:\\.\\d(?:\\d|_(?=\\d))*)?(?:[eE][+-]?\\d+)?)?(?:_?[fF](?:32|64))?\\b"
                }, {
                    token: "constant.numeric",
                    regex: intNumber
                }, {
                    token: "constant.other.symbol",
                    regex: ':"',
                    push: [{
                        token: "constant.language.escape",
                        regex: extEscapeExspresssion
                    }, {
                        token: "constant.other.symbol",
                        regex: '"',
                        next: "pop"
                    }, {
                        defaultToken: "constant.other.symbol"
                    }]
                }, {
                    token: "constant.language.boolean",
                    regex: "(?:true|false)\\b"
                }, {
                    token: "support.function",
                    regex: "(?:is_a\\?|nil\\?|responds_to\\?|as\\?)"
                }, {
                    token: keywordMapper,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$!?]*\\b"
                }, {
                    token: "variable.system",
                    regex: "\\$\\!|\\$\\?"
                }, {
                    token: "punctuation.separator.key-value",
                    regex: "=>"
                }, {
                    stateName: "heredoc",
                    onMatch: function (value, currentState, stack) {
                        var next = "heredoc";
                        var tokens = value.split(this.splitRegex);
                        stack.push(next, tokens[3]);
                        return [
                            {type: "constant", value: tokens[1]},
                            {type: "string", value: tokens[2]},
                            {type: "support.class", value: tokens[3]},
                            {type: "string", value: tokens[4]}
                        ];
                    },
                    regex: "(<<-)([']?)([\\w]+)([']?)",
                    rules: {
                        heredoc: [{
                            token: "string",
                            regex: "^ +"
                        }, {
                            onMatch: function (value, currentState, stack) {
                                if (value === stack[1]) {
                                    stack.shift();
                                    stack.shift();
                                    this.next = stack[0] || "start";
                                    return "support.class";
                                }
                                this.next = "";
                                return "string";
                            },
                            regex: ".*$",
                            next: "start"
                        }]
                    }
                }, {
                    regex: "$",
                    token: "empty",
                    next: function (currentState, stack) {
                        if (stack[0] === "heredoc")
                            return stack[0];
                        return currentState;
                    }
                }, {
                    token: "punctuation.operator",
                    regex: /[.]\s*(?![.])/,
                    push: [{
                        token : "punctuation.operator",
                        regex : /[.]\s*(?![.])/
                    }, {
                        token : "support.function",
                        regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                    }, {
                        regex: "",
                        token: "empty",
                        next: "pop"
                    }]
                }, {
                    token: "keyword.operator",
                    regex: "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|\\?|\\:|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\^|\\|"
                }, {
                    token: "punctuation.operator",
                    regex: /[?:,;.]/
                }, {
                    token: "paren.lparen",
                    regex: "[[({]"
                }, {
                    token: "paren.rparen",
                    regex: "[\\])}]"
                }, {
                    token: "text",
                    regex: "\\s+"
                }
            ]
        };

        this.normalizeRules();
    };

    oop.inherits(CrystalHighlightRules, TextHighlightRules);

    exports.CrystalHighlightRules = CrystalHighlightRules;
});

ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module) {
"use strict";

var Range = require("../range").Range;

var MatchingBraceOutdent = function() {};

(function() {

    this.checkOutdent = function(line, input) {
        if (! /^\s+$/.test(line))
            return false;

        return /^\s*\}/.test(input);
    };

    this.autoOutdent = function(doc, row) {
        var line = doc.getLine(row);
        var match = line.match(/^(\s*\})/);

        if (!match) return 0;

        var column = match[1].length;
        var openBracePos = doc.findMatchingBracket({row: row, column: column});

        if (!openBracePos || openBracePos.row == row) return 0;

        var indent = this.$getIndent(doc.getLine(openBracePos.row));
        doc.replace(new Range(row, 0, row, column-1), indent);
    };

    this.$getIndent = function(line) {
        return line.match(/^\s*/)[0];
    };

}).call(MatchingBraceOutdent.prototype);

exports.MatchingBraceOutdent = MatchingBraceOutdent;
});

ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"], function(require, exports, module) {
"use strict";

var oop = require("../../lib/oop");
var BaseFoldMode = require("./fold_mode").FoldMode;
var Range = require("../../range").Range;

var FoldMode = exports.FoldMode = function() {};
oop.inherits(FoldMode, BaseFoldMode);

(function() {

    this.getFoldWidgetRange = function(session, foldStyle, row) {
        var range = this.indentationBlock(session, row);
        if (range)
            return range;

        var re = /\S/;
        var line = session.getLine(row);
        var startLevel = line.search(re);
        if (startLevel == -1 || line[startLevel] != "#")
            return;

        var startColumn = line.length;
        var maxRow = session.getLength();
        var startRow = row;
        var endRow = row;

        while (++row < maxRow) {
            line = session.getLine(row);
            var level = line.search(re);

            if (level == -1)
                continue;

            if (line[level] != "#")
                break;

            endRow = row;
        }

        if (endRow > startRow) {
            var endColumn = session.getLine(endRow).length;
            return new Range(startRow, startColumn, endRow, endColumn);
        }
    };
    this.getFoldWidget = function(session, foldStyle, row) {
        var line = session.getLine(row);
        var indent = line.search(/\S/);
        var next = session.getLine(row + 1);
        var prev = session.getLine(row - 1);
        var prevIndent = prev.search(/\S/);
        var nextIndent = next.search(/\S/);

        if (indent == -1) {
            session.foldWidgets[row - 1] = prevIndent!= -1 && prevIndent < nextIndent ? "start" : "";
            return "";
        }
        if (prevIndent == -1) {
            if (indent == nextIndent && line[indent] == "#" && next[indent] == "#") {
                session.foldWidgets[row - 1] = "";
                session.foldWidgets[row + 1] = "";
                return "start";
            }
        } else if (prevIndent == indent && line[indent] == "#" && prev[indent] == "#") {
            if (session.getLine(row - 2).search(/\S/) == -1) {
                session.foldWidgets[row - 1] = "start";
                session.foldWidgets[row + 1] = "";
                return "";
            }
        }

        if (prevIndent!= -1 && prevIndent < indent)
            session.foldWidgets[row - 1] = "start";
        else
            session.foldWidgets[row - 1] = "";

        if (indent < nextIndent)
            return "start";
        else
            return "";
    };

}).call(FoldMode.prototype);

});

ace.define("ace/mode/crystal",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/crystal_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/mode/behaviour/cstyle","ace/mode/folding/coffee"], function(require, exports, module) {
"use strict";

var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var CrystalHighlightRules = require("./crystal_highlight_rules").CrystalHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var Range = require("../range").Range;
var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour;
var FoldMode = require("./folding/coffee").FoldMode;

var Mode = function() {
    this.HighlightRules = CrystalHighlightRules;
    this.$outdent = new MatchingBraceOutdent();
    this.$behaviour = new CstyleBehaviour();
    this.foldingRules = new FoldMode();
};
oop.inherits(Mode, TextMode);

(function() {


    this.lineCommentStart = "#";

    this.getNextLineIndent = function(state, line, tab) {
        var indent = this.$getIndent(line);

        var tokenizedLine = this.getTokenizer().getLineTokens(line, state);
        var tokens = tokenizedLine.tokens;

        if (tokens.length && tokens[tokens.length-1].type == "comment") {
            return indent;
        }

        if (state == "start") {
            var match = line.match(/^.*[\{\(\[]\s*$/);
            var startingClassOrMethod = line.match(/^\s*(class|def|module)\s.*$/);
            var startingDoBlock = line.match(/.*do(\s*|\s+\|.*\|\s*)$/);
            var startingConditional = line.match(/^\s*(if|else|when)\s*/);
            if (match || startingClassOrMethod || startingDoBlock || startingConditional) {
                indent += tab;
            }
        }

        return indent;
    };

    this.checkOutdent = function(state, line, input) {
        return /^\s+(end|else)$/.test(line + input) || this.$outdent.checkOutdent(line, input);
    };

    this.autoOutdent = function(state, session, row) {
        var line = session.getLine(row);
        if (/}/.test(line))
            return this.$outdent.autoOutdent(session, row);
        var indent = this.$getIndent(line);
        var prevLine = session.getLine(row - 1);
        var prevIndent = this.$getIndent(prevLine);
        var tab = session.getTabString();
        if (prevIndent.length <= indent.length) {
            if (indent.slice(-tab.length) == tab)
                session.remove(new Range(row, indent.length-tab.length, row, indent.length));
        }
    };

    this.$id = "ace/mode/crystal";
}).call(Mode.prototype);

exports.Mode = Mode;
});                (function() {
                    ace.require(["ace/mode/crystal"], function(m) {
                        if (typeof module == "object" && typeof exports == "object" && module) {
                            module.exports = m;
                        }
                    });
                })();
            