<commit_before>define([
    'rstjs/core',
    'javascript-state-machine',
    'rstjs/parser/grammar',
    'rstjs/parser/unicode',
    'rstjs/reader/line',
    'rstjs/tree',
    'rstjs/nodes',
    'rstjs/validator',
    'rstjs/parser/error'
], function (Core, StateMachine, Grammar, Unicode, LineReader, Tree, Nodes, Validator, ParserError) {
    'use strict';

    function Inliner() {
        this.groups = ['inline'];
        // Recompose initials inline grammar
        this.initial = Grammar.common.startString.source + '(';
        for (var i = 0, len = Grammar.inline.initial.length; i < len; i++) {
            var prefix = Grammar.inline.initial[i].prefix || '',
                suffix = Grammar.inline.initial[i].suffix || '';
            this.groups.push.apply(this.groups, Grammar.inline.initial[i].groups);
            if ((i + 1) === len) {
                this.initial += prefix + '(' + Grammar.inline.initial[i].pattern + ')' + suffix;
            } else {
                this.initial += prefix + '(' + Grammar.inline.initial[i].pattern + ')' + suffix + '|';
            }
        }
        this.initial = new RegExp(this.initial + ')', 'g');
    }
    Inliner.STATES = {
        '*':  'emphasis',
        '**': 'strong',
        '`':  'interpretedOrPhraseRef',
        '``': 'literal',
        '_`': 'target',
        ']_': 'footnote',
        '|':  'subsitution',
        '_':  'reference',
        '__': 'anonymous'
    };
    Inliner.prototype.parse = function(source) {
        var match;
        while ((match = this.initial.exec(source))) {
            var method = Inliner.STATES[
                match[this.groups.indexOf('start') + 1] ||
                match[this.groups.indexOf('backquote') + 1] ||
                match[this.groups.indexOf('refend') + 1] ||
                match[this.groups.indexOf('fnend') + 1]
            ];
            if (typeof this[method] === 'function') {
                console.log('\t' + method + ': ' + this[method](match));
            }
        }
        /*    if (Grammar.inline.prefix.test(source.charAt(match.index - 1)) &&
                    Grammar.inline.suffix.test(source.charAt(match.index + 1))) {
                var state = states[match[1]];
                if (state) {
                    console.log(state(match));
                }
            }
        }*/
    };
    Inliner.prototype.escape = function(source) {
        return source.replace(/\\(.)?/g, function(match, $1) { return common.escape.source + $1; });
    };
    Inliner.prototype.unescape = function(source, backslash) {
        backslash = backslash || false;
        if (backslash) {
            return source.replace('/\x00/g', '\\');
        } else {
            return source.replace('/\x00/g', ' ');
        }
    };
    Inliner.prototype.quoted = function(match) {
        var pre     = match.input[match.index],
            post    = match.input[match.index + match[0].length],
            openers = '"\'(<[{' + Unicode.openers,
            closers = '"\')>]}' + Unicode.closers;

        if (match.index > 0) {
            var index = openers.indexOf(pre);
            if ((index = openers.indexOf(pre)) >= 0) {
                return post === closers[index];
            }
        }
        return false;
    };
    Inliner.prototype.inline = function(type, match, final) {
        var endPosition = match.index + match[0].length,
            source      = match.input.substr(endPosition);
        if (!this.quoted(match)) {
            var pattern = new RegExp(final.pattern, 'g'),
                result;
            while ((result = pattern.exec(source)) && final.lookBehind(source, result.index)) {
                return this.unescape(source.substring(0, result.index), true);
            }
            throw new ParserError('Inline ' + type + ' start-string without end-string.');
        }

        return null;
    };
    Inliner.prototype.emphasis = function(match) {
        var type = 'emphasis';
        return this.inline(type, match, Grammar.inline.final[type]);
    };
    Inliner.prototype.strong = function(match) {
        var type = 'strong';
        return this.inline(type, match, Grammar.inline.final[type]);
    };
    Inliner.prototype.literal = function(match) {
        var type = 'literal';
        return this.inline(type, match, Grammar.inline.final[type]);
    };
    Inliner.prototype.reference = function(match) {
        match;
        var type          = 'reference',
            // Todo normalization need to be a function
            referenceName = match[this.groups.indexOf('refname') + 1].toLowerCase().replace(/\s{2,}/g, ' ');

        new Nodes.Reference(referenceName);

    };
    Inliner.prototype.interpretedOrPhraseRef = function(match) {
        var type        = 'interpreted',
            subject     = Grammar.inline.final[type],
            endPosition = match.index + match[0].length,
            source      = match.input.substr(endPosition),
            role;

        if (role) {
            role = {value: role.substr(1, role.length - 2), position: 'prefix'};
        } else if (this.quoted(match)) {
            return null;
        }

        var pattern = new RegExp(Grammar.inline.final[type].pattern, 'g'),
            found   = false,
            result;
        while ((result = pattern.exec(source)) && Grammar.inline.final[type].lookBehind(source, result.index)) {
            found = true;
            break;
        }

        if (found) {
            var value       = source.substring(0, result.index),
                suffixRole  = result[subject.groups.indexOf('role') + 1];
            if (suffixRole) {
                if (role) {
                    throw new ParserError('Multiple roles in interpreted text ' +
                        '(both prefix and suffix present; only one allowed).');
                } else {
                    role = {value: suffixRole.substr(1, suffixRole.length + 2), position: 'prefix'};
                }
            }

            var suffix = result[subject.groups.indexOf('suffix') + 1];
            if (suffix.charAt(suffix.length - 1) === '_') {
                if (role) {
                    throw new ParserError('Mismatch: both interpreted text role {0} and ' +
                        'reference suffix.'.format(rolePosition));
                }
                console.log('phrase_ref: ' + value);
                return this.phraseRef(value);
            } else {
                console.log('interpreted');
                return;
            }
            console.log(result);
        }
        throw new ParserError('Inline interpreted text or phrase reference start-string without end-string.');
    };
    Inliner.prototype.phraseRef = function(source) {
        var match,
            target;
        if ((match = Grammar.inline.embeddedLink.exec(source))) {
            var text    = this.unescape(source.substring(0, match.index)),
                alias   = {value: this.unescape(match[2], true)},
                isUri   = Validator.isUri(alias.value),
                isEmail = Validator.isEmail(alias.value);
            if (typeof alias.value === 'undefined') {
                throw new ParserError('problem with embedded link.');
            }
            if (alias.value.endsWith('_') && !(alias.value.endsWith('\\_') || (isUri || isEmail))) {
                alias.type = 'name';
                alias.value = alias.value.substr(0, alias.value.length - 1);
                // Normalize value
                alias.value = alias.value.toLowerCase().replace(/\s{2,}/g, ' ');
                target = new Nodes.Target(match[1], alias.value);
                // target.indirect_reference_name = aliastext[:-1]
            } else {
                alias.type = 'uri';
                alias.value = alias.value.replace(/ +/g, '');
                if (isEmail) {
                    alias.value = 'mailto:' + alias.value;
                }
                if (alias.value.endsWith('\\_')) {
                    alias.value = alias.value.substr(0, alias.value.length - 2) + '_';
                }
                target = new Nodes.Target(match[1], alias.value);
                // target.referenced = 1
            }
        }

        var refname = match.input.substring(0, match.index),
            reference = new Nodes.Reference(refname),
            nodes = [reference];

        //if (match.input.substring(0, -2));
        // TODO: finish the function lol
    };

    //---------------------------------------------------------------------------

    function StateRegistry() {
        this._states = {};
        this._instances = {};
    }
    StateRegistry.prototype.getState = function(name) {
        if (typeof this._instances[name] !== 'undefined') {
            return this._instances[name];
        }
        if (typeof this._states[name] !== 'undefined') {
            this._instances[name] = new this._states[name]();
        }
        return this._instances[name] || null;
    };
    StateRegistry.prototype.getTransitionsOf = function(name) {
        if (typeof this._states[name] !== 'undefined') {
            return this._states[name].TRANSITIONS;
        }
        return null;
    };
    StateRegistry.prototype.registerState = function(name, state) {
        this._states[name] = state;
        return this;
    };
    StateRegistry.prototype.getTransitions = function() {
        var list = [],
            key;
        for (key in this._states) {
            if (typeof this._states[key] !== 'undefined') {
                var state = this._states[key].name.slice(0, -5),
                    transitions = this._states[key].TRANSITIONS;
                for (var i = transitions.length - 1; i >= 0; i--) {
                    list.push({ name: transitions[i].name, from: state, to: transitions[i].to });
                }
            }
        }
        return list;
    };

    //---------------------------------------------------------------------------

    var tree            = new Tree(),
        inliner         = new Inliner(),
        stateRegistry   = new StateRegistry(),
        context         = [];

    //---------------------------------------------------------------------------

    function State() {}
    State.SECTION_LEVEL = 0;
    State.TITLE_STYLES = [];
    State.prototype.setLineReader = function(lineReader) {
        this.lineReader = lineReader;
    };
    State.prototype.checkHeader = function(level) {
        return (level === 0 && State.TITLE_STYLES.length === State.SECTION_LEVEL) || level === (State.SECTION_LEVEL);
    };
    State.prototype.createHeader = function(title, style, source) {
        var level = State.TITLE_STYLES.indexOf(style) + 1;
        if (!this.checkHeader(level)) {
            throw new ParserError('Title level inconsistent.', source, this.lineReader.getPosition() - 1);
        }

        // if level === 0 new header
        if (level === 0) {
            State.TITLE_STYLES.push(style);
        }
        State.SECTION_LEVEL = State.TITLE_STYLES.length;
        inliner.parse(title);
        tree.add(new Nodes.Header(title, State.SECTION_LEVEL));
    };

    function BodyState() {
        State.call(this);
    }
    BodyState.TRANSITIONS = [
        { name: 'text',             to: 'Text', pattern: Grammar.block.text },
        { name: 'line',             to: 'Line', pattern: Grammar.block.line },
        //{ name: 'anonymous',        pattern: Grammar.block.anonymous },
        //{ name: 'explicitMarkup',   pattern: Grammar.block.explicitMarkup },
        // simpleTable:
        // gridTable:
        //{ name: 'lineBlock',        pattern: Grammar.block.lineBlock },
        //{ name: 'doctest',          pattern: Grammar.block.doctest },
        // optionMarker
        //{ name: 'fieldMarker',      pattern: Grammar.block.fieldMarker },
        // enumerator:
        //{ name: 'bullet',           pattern: Grammar.block.bullet },
        { name: 'blank',            pattern: Grammar.block.blank}
    ];
    BodyState.prototype = Object.create(State.prototype);
    BodyState.prototype.constructor = BodyState;
    BodyState.prototype.text = function() {
        return [this.lineReader.current()];
    };
    stateRegistry.registerState('Body', BodyState);

    function TextState() {
        State.call(this);
    }
    TextState.TRANSITIONS = [
        { name: 'text',      to: 'Body', pattern: Grammar.block.text },
        { name: 'underline', to: 'Body', pattern: Grammar.block.line }
    ];
    TextState.prototype = Object.create(State.prototype);
    TextState.prototype.constructor = TextState;
    TextState.prototype.blank = function() {
        console.log(context);
    };
    TextState.prototype.text = function() {
        var lines = '';
        for (var i = context.length - 1; i >= 0; i--) {
            lines += context[i].rtrim();
        }
        lines += '\n' + this.lineReader.current().rtrim();

        while (this.lineReader.hasNext()) {
            var line = this.lineReader.next();
            if (!line.trim()) {
                break;
            }
            if (line[0] == ' ') {
                throw new ParserError('Unexpected indentation.', line, this.lineReader.getPosition() - 1);
            }
            lines += '\n' + line.rtrim();
        }

        inliner.parse(lines);

        // TODO: finish the function lol
        //lines;
        // paragraph(lines, lineno)

    };
    TextState.prototype.underline = function() {
        var title       = context[0],
            underline   = this.lineReader.current().rtrim(),
            source      = title + '\n' + underline;

        if (title.length > underline.length) {
            throw new ParserError('Title underline too short.', source , position);
        }

        this.createHeader(title, underline.charAt(0), source);
        return [];
    };
    stateRegistry.registerState('Text', TextState);

    function LineState() {
        State.call(this);
    }
    LineState.TRANSITIONS = [
        { name: 'text',      to: 'Body', pattern: Grammar.block.text },
        { name: 'underline', to: 'Body', pattern: Grammar.block.line }
    ];
    LineState.prototype = Object.create(State.prototype);
    LineState.prototype.constructor = LineState;
    LineState.prototype.text = function() {
        var position    = this.lineReader.getPosition(),
            overline    = this.lineReader.get(position - 1).rtrim(),
            title       = this.lineReader.get(position).rtrim(),
            underline   = this.lineReader.next(),
            source      = overline + '\n' + title + '\n' + underline;

        if (!underline.match(Grammar.block.line)) {
            throw new ParserError('Missing matching underline for section title overline.', source , position);
        } else if (overline !== underline) {
            throw new ParserError('Title overline & underline mismatch.', source , position);
        }

        if (title.length > overline.length) {
            throw new ParserError('Title overline too short.', source , position);
        }

        this.createHeader(title, overline.charAt(0) + underline.charAt(0), source);
        return [];
    };
    stateRegistry.registerState('Line', LineState);

    //---------------------------------------------------------------------------

    var fsm = StateMachine.create({
        initial: { state: 'Body', event: 'startup' },
        events: stateRegistry.getTransitions(),
        callbacks: {
            onafterevent: function(event, from, to, lineReader) {
                var state = stateRegistry.getState(from);
                if (state && typeof state[event] === 'function') {
                    state.setLineReader(lineReader);
                    context = state[event]();
                }
            }
        }
    });

    //---------------------------------------------------------------------------

    var run = function(self, lineReader) {
        while (lineReader.hasNext()) {
            var line = lineReader.next();
            var transitions = stateRegistry.getTransitionsOf(fsm.current);
            for (var i = transitions.length - 1; i >= 0; i--) {
                /*fsm.can(transitions[i].name) && */
                if (typeof fsm[transitions[i].name] === 'function' && line.match(transitions[i].pattern)) {
                    console.log(fsm.current.toString() + " => " + transitions[i].name + "\t\t" + line);
                    fsm[transitions[i].name](lineReader);
                    break;
                }
            }
        }
    };

    function Parser() {}
    Parser.prototype.parse = function(input) {
        run(this, new LineReader(input));
        return tree.toString();
    };

    return Parser;
});<commit_msg>fix warnings<commit_after>define([
    'rstjs/core',
    'javascript-state-machine',
    'rstjs/parser/grammar',
    'rstjs/parser/unicode',
    'rstjs/reader/line',
    'rstjs/tree',
    'rstjs/nodes',
    'rstjs/validator',
    'rstjs/parser/error'
], function (Core, StateMachine, Grammar, Unicode, LineReader, Tree, Nodes, Validator, ParserError) {
    'use strict';

    function Inliner() {
        this.groups = ['inline'];
        // Recompose initials inline grammar
        this.initial = Grammar.common.startString.source + '(';
        for (var i = 0, len = Grammar.inline.initial.length; i < len; i++) {
            var prefix = Grammar.inline.initial[i].prefix || '',
                suffix = Grammar.inline.initial[i].suffix || '';
            this.groups.push.apply(this.groups, Grammar.inline.initial[i].groups);
            if ((i + 1) === len) {
                this.initial += prefix + '(' + Grammar.inline.initial[i].pattern + ')' + suffix;
            } else {
                this.initial += prefix + '(' + Grammar.inline.initial[i].pattern + ')' + suffix + '|';
            }
        }
        this.initial = new RegExp(this.initial + ')', 'g');
    }
    Inliner.STATES = {
        '*':  'emphasis',
        '**': 'strong',
        '`':  'interpretedOrPhraseRef',
        '``': 'literal',
        '_`': 'target',
        ']_': 'footnote',
        '|':  'subsitution',
        '_':  'reference',
        '__': 'anonymous'
    };
    Inliner.prototype.parse = function(source) {
        var match;
        while ((match = this.initial.exec(source))) {
            var method = Inliner.STATES[
                match[this.groups.indexOf('start') + 1] ||
                match[this.groups.indexOf('backquote') + 1] ||
                match[this.groups.indexOf('refend') + 1] ||
                match[this.groups.indexOf('fnend') + 1]
            ];
            if (typeof this[method] === 'function') {
                console.log('\t' + method + ': ' + this[method](match));
            }
        }
        /*    if (Grammar.inline.prefix.test(source.charAt(match.index - 1)) &&
                    Grammar.inline.suffix.test(source.charAt(match.index + 1))) {
                var state = states[match[1]];
                if (state) {
                    console.log(state(match));
                }
            }
        }*/
    };
    Inliner.prototype.escape = function(source) {
        return source.replace(/\\(.)?/g, function(match, $1) { return Grammar.common.escape.source + $1; });
    };
    Inliner.prototype.unescape = function(source, backslash) {
        backslash = backslash || false;
        if (backslash) {
            return source.replace('/\x00/g', '\\');
        } else {
            return source.replace('/\x00/g', ' ');
        }
    };
    Inliner.prototype.quoted = function(match) {
        var pre     = match.input[match.index],
            post    = match.input[match.index + match[0].length],
            openers = '"\'(<[{' + Unicode.openers,
            closers = '"\')>]}' + Unicode.closers;

        if (match.index > 0) {
            var index = openers.indexOf(pre);
            if (index >= 0) {
                return post === closers[index];
            }
        }
        return false;
    };
    Inliner.prototype.inline = function(type, match, final) {
        var endPosition = match.index + match[0].length,
            source      = match.input.substr(endPosition);
        if (!this.quoted(match)) {
            var pattern = new RegExp(final.pattern, 'g'),
                result;
            if ((result = pattern.exec(source)) && final.lookBehind(source, result.index)) {
                return this.unescape(source.substring(0, result.index), true);
            }
            throw new ParserError('Inline ' + type + ' start-string without end-string.');
        }

        return null;
    };
    Inliner.prototype.emphasis = function(match) {
        var type = 'emphasis';
        return this.inline(type, match, Grammar.inline.final[type]);
    };
    Inliner.prototype.strong = function(match) {
        var type = 'strong';
        return this.inline(type, match, Grammar.inline.final[type]);
    };
    Inliner.prototype.literal = function(match) {
        var type = 'literal';
        return this.inline(type, match, Grammar.inline.final[type]);
    };
    Inliner.prototype.reference = function(match) {
        var type          = 'reference',
            // Todo normalization need to be a function
            referenceName = match[this.groups.indexOf('refname') + 1].toLowerCase().replace(/\s{2,}/g, ' ');

        new Nodes.Reference(referenceName);

    };
    Inliner.prototype.interpretedOrPhraseRef = function(match) {
        var type        = 'interpreted',
            subject     = Grammar.inline.final[type],
            endPosition = match.index + match[0].length,
            source      = match.input.substr(endPosition),
            role;

        if (role) {
            role = {value: role.substr(1, role.length - 2), position: 'prefix'};
        } else if (this.quoted(match)) {
            return null;
        }

        var pattern = new RegExp(Grammar.inline.final[type].pattern, 'g'),
            found   = false,
            result;
        // todo: review implementation
        if ((result = pattern.exec(source)) && Grammar.inline.final[type].lookBehind(source, result.index)) {
            found = true;
        }

        if (found) {
            var value       = source.substring(0, result.index),
                suffixRole  = result[subject.groups.indexOf('role') + 1];
            if (suffixRole) {
                if (role) {
                    throw new ParserError('Multiple roles in interpreted text ' +
                        '(both prefix and suffix present; only one allowed).');
                } else {
                    role = {value: suffixRole.substr(1, suffixRole.length + 2), position: 'prefix'};
                }
            }

            var suffix = result[subject.groups.indexOf('suffix') + 1];
            if (suffix.charAt(suffix.length - 1) === '_') {
                if (role) {
                    throw new ParserError('Mismatch: both interpreted text role {0} and ' +
                        'reference suffix.'.format(rolePosition));
                }
                console.log('phrase_ref: ' + value);
                return this.phraseRef(value);
            } else {
                console.log('interpreted');
                return;
            }
            console.log(result);
        }
        throw new ParserError('Inline interpreted text or phrase reference start-string without end-string.');
    };
    Inliner.prototype.phraseRef = function(source) {
        var match,
            target;
        if ((match = Grammar.inline.embeddedLink.exec(source))) {
            var text    = this.unescape(source.substring(0, match.index)),
                alias   = {value: this.unescape(match[2], true)},
                isUri   = Validator.isUri(alias.value),
                isEmail = Validator.isEmail(alias.value);
            if (typeof alias.value === 'undefined') {
                throw new ParserError('problem with embedded link.');
            }
            if (alias.value.endsWith('_') && !(alias.value.endsWith('\\_') || (isUri || isEmail))) {
                alias.type = 'name';
                alias.value = alias.value.substr(0, alias.value.length - 1);
                // Normalize value
                alias.value = alias.value.toLowerCase().replace(/\s{2,}/g, ' ');
                target = new Nodes.Target(match[1], alias.value);
                // target.indirect_reference_name = aliastext[:-1]
            } else {
                alias.type = 'uri';
                alias.value = alias.value.replace(/ +/g, '');
                if (isEmail) {
                    alias.value = 'mailto:' + alias.value;
                }
                if (alias.value.endsWith('\\_')) {
                    alias.value = alias.value.substr(0, alias.value.length - 2) + '_';
                }
                target = new Nodes.Target(match[1], alias.value);
                // target.referenced = 1
            }
        }

        var refname = match.input.substring(0, match.index),
            reference = new Nodes.Reference(refname),
            nodes = [reference];

        //if (match.input.substring(0, -2));
        // TODO: finish the function lol
    };

    //---------------------------------------------------------------------------

    function StateRegistry() {
        this._states = {};
        this._instances = {};
    }
    StateRegistry.prototype.getState = function(name) {
        if (typeof this._instances[name] !== 'undefined') {
            return this._instances[name];
        }
        if (typeof this._states[name] !== 'undefined') {
            this._instances[name] = new this._states[name]();
        }
        return this._instances[name] || null;
    };
    StateRegistry.prototype.getTransitionsOf = function(name) {
        if (typeof this._states[name] !== 'undefined') {
            return this._states[name].TRANSITIONS;
        }
        return null;
    };
    StateRegistry.prototype.registerState = function(name, state) {
        this._states[name] = state;
        return this;
    };
    StateRegistry.prototype.getTransitions = function() {
        var list = [],
            key;
        for (key in this._states) {
            if (this._states.hasOwnProperty(key) && typeof this._states[key] !== 'undefined') {
                var state = this._states[key].name.slice(0, -5),
                    transitions = this._states[key].TRANSITIONS;
                for (var i = transitions.length - 1; i >= 0; i--) {
                    list.push({ name: transitions[i].name, from: state, to: transitions[i].to });
                }
            }
        }
        return list;
    };

    //---------------------------------------------------------------------------

    var tree            = new Tree(),
        inliner         = new Inliner(),
        stateRegistry   = new StateRegistry(),
        context         = [];

    //---------------------------------------------------------------------------

    function State() {}
    State.SECTION_LEVEL = 0;
    State.TITLE_STYLES = [];
    State.prototype.setLineReader = function(lineReader) {
        this.lineReader = lineReader;
    };
    State.prototype.checkHeader = function(level) {
        return (level === 0 && State.TITLE_STYLES.length === State.SECTION_LEVEL) || level === (State.SECTION_LEVEL);
    };
    State.prototype.createHeader = function(title, style, source) {
        var level = State.TITLE_STYLES.indexOf(style) + 1;
        if (!this.checkHeader(level)) {
            throw new ParserError('Title level inconsistent.', source, this.lineReader.getPosition() - 1);
        }

        // if level === 0 new header
        if (level === 0) {
            State.TITLE_STYLES.push(style);
        }
        State.SECTION_LEVEL = State.TITLE_STYLES.length;
        inliner.parse(title);
        tree.add(new Nodes.Header(title, State.SECTION_LEVEL));
    };

    function BodyState() {
        State.call(this);
    }
    BodyState.TRANSITIONS = [
        { name: 'text',             to: 'Text', pattern: Grammar.block.text },
        { name: 'line',             to: 'Line', pattern: Grammar.block.line },
        //{ name: 'anonymous',        pattern: Grammar.block.anonymous },
        //{ name: 'explicitMarkup',   pattern: Grammar.block.explicitMarkup },
        // simpleTable:
        // gridTable:
        //{ name: 'lineBlock',        pattern: Grammar.block.lineBlock },
        //{ name: 'doctest',          pattern: Grammar.block.doctest },
        // optionMarker
        //{ name: 'fieldMarker',      pattern: Grammar.block.fieldMarker },
        // enumerator:
        //{ name: 'bullet',           pattern: Grammar.block.bullet },
        { name: 'blank',            pattern: Grammar.block.blank}
    ];
    BodyState.prototype = Object.create(State.prototype);
    // noinspection JSUnusedGlobalSymbols
    BodyState.prototype.constructor = BodyState;
    BodyState.prototype.text = function() {
        return [this.lineReader.current()];
    };
    stateRegistry.registerState('Body', BodyState);

    function TextState() {
        State.call(this);
    }
    TextState.TRANSITIONS = [
        { name: 'text',      to: 'Body', pattern: Grammar.block.text },
        { name: 'underline', to: 'Body', pattern: Grammar.block.line }
    ];
    TextState.prototype = Object.create(State.prototype);
    // noinspection JSUnusedGlobalSymbols
    TextState.prototype.constructor = TextState;
    TextState.prototype.blank = function() {
        console.log(context);
    };
    TextState.prototype.text = function() {
        var lines = '';
        for (var i = context.length - 1; i >= 0; i--) {
            lines += context[i].rtrim();
        }
        lines += '\n' + this.lineReader.current().rtrim();

        while (this.lineReader.hasNext()) {
            var line = this.lineReader.next();
            if (!line.trim()) {
                break;
            }
            if (line[0] == ' ') {
                throw new ParserError('Unexpected indentation.', line, this.lineReader.getPosition() - 1);
            }
            lines += '\n' + line.rtrim();
        }

        inliner.parse(lines);

        // TODO: finish the function lol
        //lines;
        // paragraph(lines, lineno)

    };
    TextState.prototype.underline = function() {
        var title       = context[0],
            underline   = this.lineReader.current().rtrim(),
            source      = title + '\n' + underline;

        if (title.length > underline.length) {
            throw new ParserError('Title underline too short.', source , this.lineReader.getPosition());
        }

        this.createHeader(title, underline.charAt(0), source);
        return [];
    };
    stateRegistry.registerState('Text', TextState);

    function LineState() {
        State.call(this);
    }
    LineState.TRANSITIONS = [
        { name: 'text',      to: 'Body', pattern: Grammar.block.text },
        { name: 'underline', to: 'Body', pattern: Grammar.block.line }
    ];
    LineState.prototype = Object.create(State.prototype);
    // noinspection JSUnusedGlobalSymbols
    LineState.prototype.constructor = LineState;
    LineState.prototype.text = function() {
        var position    = this.lineReader.getPosition(),
            overline    = this.lineReader.get(position - 1).rtrim(),
            title       = this.lineReader.get(position).rtrim(),
            underline   = this.lineReader.next(),
            source      = overline + '\n' + title + '\n' + underline;

        if (!underline.match(Grammar.block.line)) {
            throw new ParserError('Missing matching underline for section title overline.', source , position);
        } else if (overline !== underline) {
            throw new ParserError('Title overline & underline mismatch.', source , position);
        }

        if (title.length > overline.length) {
            throw new ParserError('Title overline too short.', source , position);
        }

        this.createHeader(title, overline.charAt(0) + underline.charAt(0), source);
        return [];
    };
    stateRegistry.registerState('Line', LineState);

    //---------------------------------------------------------------------------

    // noinspection JSUnusedGlobalSymbols
    var fsm = StateMachine.create({
        initial: { state: 'Body', event: 'startup' },
        events: stateRegistry.getTransitions(),
        callbacks: {
            onafterevent: function(event, from, to, lineReader) {
                var state = stateRegistry.getState(from);
                if (state && typeof state[event] === 'function') {
                    state.setLineReader(lineReader);
                    context = state[event]();
                }
            }
        }
    });

    //---------------------------------------------------------------------------

    var run = function(self, lineReader) {
        while (lineReader.hasNext()) {
            var line = lineReader.next();
            var transitions = stateRegistry.getTransitionsOf(fsm.current);
            for (var i = transitions.length - 1; i >= 0; i--) {
                /*fsm.can(transitions[i].name) && */
                if (typeof fsm[transitions[i].name] === 'function' && line.match(transitions[i].pattern)) {
                    console.log(fsm.current.toString() + " => " + transitions[i].name + "\t\t" + line);
                    fsm[transitions[i].name](lineReader);
                    break;
                }
            }
        }
    };

    function Parser() {}
    Parser.prototype.parse = function(input) {
        run(this, new LineReader(input));
        return tree.toString();
    };

    return Parser;
});<|endoftext|>


<commit_before>// Karma configuration
// Generated on Thu Nov 05 2015 21:52:19 GMT-0300 (BRT)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'node_modules/angular/angular.js',
      'node_modules/angular-mocks/angular-mocks.js',
      'src/*.js',
      'tests/*.test.js'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress', 'coverage'],

    coverageReporter: {
      type : 'html',
      // output coverage reports
      dir : 'coverage/'
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultanous
    concurrency: Infinity
  })
}
<commit_msg>Configuring coverage to the project<commit_after>// Karma configuration
// Generated on Thu Nov 05 2015 21:52:19 GMT-0300 (BRT)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'node_modules/angular/angular.js',
      'node_modules/angular-mocks/angular-mocks.js',
      'src/*.js',
      'tests/*.test.js'
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'src/*.js': 'coverage'
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress', 'coverage'],

    coverageReporter: {
      type : 'html',
      // output coverage reports
      dir : 'coverage/'
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultanous
    concurrency: Infinity
  })
}
<|endoftext|>


<commit_before>var config = require('./config');

var path = require('path'),
  webpack = require('webpack'),
  devServer = config.ip + ':' + config.port;

var escapeRegExpString = function(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};

var pathToRegExp = function(p) {
  return new RegExp("^" + escapeRegExpString(p));
};

var fileNames = function(pathDir, paths) {
  return paths.map( function(stFileName) {
    return pathDir + stFileName;
  });
};

var getEntry = function(type) {
  var entry = {
    'vendor' : ['react', 'react-style', 'react-draggable', 'flux', 'page', 'object-assign', 'keymirror'],
    'app' : ['./app/index.jsx']
  };
  console.log(entry);
  return entry;
};

var getPlugins = function(type) {
  var arr = [];
  arr.push(new webpack.NoErrorsPlugin());
  arr.push(new webpack.optimize.DedupePlugin());
  arr.push(new webpack.optimize.OccurenceOrderPlugin());
  if ( type === 'production') {
    arr.push(new webpack.optimize.UglifyJsPlugin({ output : { comments : false } }));
  }
  arr.push(new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 20 }));
  arr.push(new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js", Infinity));
  return arr;
};

module.exports = {
  context : __dirname,
  entry : getEntry(config.env),
  devTool : 'eval',
  output : {
    path : __dirname + '/assets/',
    publicPath : '/assets/',
    filename : '[name].bundle.js',
    chunkFilename : '[hash]/js/[id].bundle.js'
  },
  module : {
    loaders : [
      { test: /\.jsx?$/, loaders: ['babel'], exclude: /node_modules/ },
      { test: /\.scss$/, loader: 'style!css!sass' }
    ],
    preloaders : [
      {
        test : /\.js$/,
        include : pathToRegExp(path.join(__dirname, "app")),
        loader : 'jshint-loader'
      }
    ]
  },
  resolve : {
    extensions : ['', '.js', '.jsx', '.css', '.scss'],
    modulesDirectories : ["web_loaders", "web_modules", "node_loaders", "node_modules"]
  },
  plugins : getPlugins(config.env)
};<commit_msg>Change specification of index file used by wepback<commit_after>var config = require('./config');

var path = require('path'),
  webpack = require('webpack'),
  devServer = config.ip + ':' + config.port;

var escapeRegExpString = function(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};

var pathToRegExp = function(p) {
  return new RegExp("^" + escapeRegExpString(p));
};

var fileNames = function(pathDir, paths) {
  return paths.map( function(stFileName) {
    return pathDir + stFileName;
  });
};

var getEntry = function(type) {
  var entry = {
    'vendor' : ['react', 'react-style', 'react-draggable', 'flux', 'page', 'object-assign', 'keymirror'],
    'app' : ['./index.jsx']
  };
  console.log(entry);
  return entry;
};

var getPlugins = function(type) {
  var arr = [];
  arr.push(new webpack.NoErrorsPlugin());
  arr.push(new webpack.optimize.DedupePlugin());
  arr.push(new webpack.optimize.OccurenceOrderPlugin());
  if ( type === 'production') {
    arr.push(new webpack.optimize.UglifyJsPlugin({ output : { comments : false } }));
  }
  arr.push(new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 20 }));
  arr.push(new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js", Infinity));
  return arr;
};

module.exports = {
  context : __dirname,
  entry : getEntry(config.env),
  devTool : 'eval',
  output : {
    path : __dirname + '/assets/',
    publicPath : '/assets/',
    filename : '[name].bundle.js',
    chunkFilename : '[hash]/js/[id].bundle.js'
  },
  module : {
    loaders : [
      { test: /\.jsx?$/, loaders: ['babel'], exclude: /node_modules/ },
      { test: /\.scss$/, loader: 'style!css!sass' }
    ],
    preloaders : [
      {
        test : /\.js$/,
        include : pathToRegExp(path.join(__dirname, "app")),
        loader : 'jshint-loader'
      }
    ]
  },
  resolve : {
    extensions : ['', '.js', '.jsx', '.css', '.scss'],
    modulesDirectories : ["web_loaders", "web_modules", "node_loaders", "node_modules"]
  },
  plugins : getPlugins(config.env)
};<|endoftext|>


<commit_before>/*
 Name    : style-switcher.js
 Author  : ono <http://onokumus.com />
 Version : 1.0
 */

// Load lesscss files
yepnope.addPrefix('less', function(resourceObj) {
    resourceObj.forceCSS = true;
    resourceObj.attrs = {
        'rel': 'stylesheet/less',
        'type': 'text/css'
    };
    return resourceObj;
});
var styleSwitcher = {
    init: function() {
        var $this = this;
        less = {env: "development"};

        // Style Switcher CSS
        yepnope([
            {load: 'assets/css/style-switcher.css'},
            {load: 'assets/css/colorpicker.css'},
            {load: 'assets/js/cssbeautify.js'},
            {load: 'assets/js/bootstrap-colorpicker.js',
                complete: function() {
                    yepnope([
                        {load: 'less!assets/less/theme.less'},
                        {load: 'assets/js/less-1.3.3.min.js',
                            complete: function() {

                                $this.build();

                                if (Modernizr.localstorage) {
                                    if (localStorage.color) {
                                        $this.colorSelectorA.css('background-color', localStorage.color);
                                    }
                                    if (localStorage.pattern) {
                                        $this.patternImage = localStorage.pattern;
                                    }
                                }
                            }
                        }
                    ]);

                }
            }
        ]);

    },
    build: function() {
        var $this = this;
        var localStor = false;
        if (Modernizr.localstorage) {
            localStor = true;
        }

        if (Modernizr.localstorage) {
            if (localStorage.layout) {
                $('body').addClass(localStorage.layout);
            }
            if (localStorage.color) {
                $this.setColor(localStorage.color);
            }
            if (localStorage.pattern) {
                $('body').css({
                    'background': 'url(assets/img/pattern/' + localStorage.pattern + '.png) repeat'
                });
            }
        }

        var modalHTML = '
'
                + '
'
                + '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>'
                + '
Theme CSS
'
                + '
'
                + '
'
                + '
'
                + 'Please add the "fixed" class to the <body> element.
'
                + '<textarea name="cssbeautify" id="cssbeautify" readonly></textarea>
'
                + '
'
                + '<button aria-hidden="true" data-dismiss="modal" class="btn">Close</button>'
                + '

';

        $("body").append(modalHTML);

        var switchDiv = $('
').attr('id', 'style-switcher').addClass('style-switcher hidden-phone');

        var h5Ai = $('').addClass('icon-cogs icon-2x');
        var h5A = $('')
                .attr({
            'href': '#',
            'id': 'switcher-link'
        })
                .on('click', function(e) {
            e.preventDefault();
            switchDiv.toggleClass('open');
        })
                .append(h5Ai);

        var h5 = $('
').html('Style Switcher').append(h5A);

        var colorList = $('
').addClass('options').attr('data-type', 'colors');
        var colors = [
            {"Hex": "#0088CC", "colorName": "Blue"},
            {"Hex": "#4EB25C", "colorName": "Green"},
            {"Hex": "#4A5B7D", "colorName": "Navy"},
            {"Hex": "#E05048", "colorName": "Red"},
            {"Hex": "#B8A279", "colorName": "Beige"},
            {"Hex": "#c71c77", "colorName": "Pink"},
            {"Hex": "#734BA9", "colorName": "Purple"},
            {"Hex": "#2BAAB1", "colorName": "Cyan"}
        ];
        $.each(colors, function(i) {
            var listElement = $('
')
                    .append(
                    $('')
                    .css("background-color", colors[i].Hex)
                    .attr({
                "data-color-hex": colors[i].Hex,
                "data-color-name": colors[i].colorName,
                "href": "#",
                "title": colors[i].colorName
            }).tooltip({'placement': 'bottom'})
                    );
            colorList.append(listElement);
        });

        colorList.find('a').on('click', function(e) {
            e.preventDefault();
            $this.setColor($(this).data('colorHex'));

            if (localStor) {
                localStorage.color = $(this).data('colorHex');
            }
        });
        var colorSelector = $('
')
                .addClass('color-picker')
                .attr({
            'id': 'colorSelector',
            'data-color': colors[0].Hex,
            'data-color-format': 'hex'
        })
                .append(
                $('')
                .css('background-color', colors[0].Hex)
                .attr({
            'href': '#',
            'id': 'colorSelectorA'
        }),
        $("")
                .addClass("color-picker-icon")
                );

        colorSelector.colorpicker().on('changeColor', function(ev) {
            colorSelector.find("a").css("background-color", ev.color.toHex());
            $this.setColor(ev.color.toHex());
            if (localStor) {
                localStorage.color = $(this).data('colorHex');
            }
        });

        var colorPicker = $('
').append(colorSelector);

        colorList.append(colorPicker);

        var styleSwitcherWrap = $('
')
                .addClass('style-switcher-wrap')
                .append(
                $('
').html('Colors'), colorList, $('
')
                );

        var boxLink = $('')
                .attr({
            'id': 'boxLink',
            'href': '#',
            'data-layout-type': 'fixed'
        })
                .html('Fixed')
                .on('click', function(e) {
            e.preventDefault();
            $(this).addClass('active').siblings('a').removeClass('active');
            $('body').removeClass('wide').addClass('fixed');
            if (localStor) {
                localStorage.layout = 'fixed';
            }
        });

        var wideLink = $('')
                .attr({
            'href': '#',
            'id': 'wideLink',
            'data-layout-type': 'wide'
        })
                .html('Wide')
                .on('click', function(e) {
            e.preventDefault();
            $(this).addClass('active').siblings('a').removeClass('active');
            $('body').removeClass('fixed').addClass('wide').removeAttr('style');
            if (localStor) {
                localStorage.layout = 'wide';
            }
        });
        if (localStor) {
            if (localStorage.layout === 'fixed') {
                boxLink.addClass('active');
            } else {
                wideLink.addClass('active');
            }
        }
        styleSwitcherWrap.append(
                $('
').addClass('options-link').append(
                $('
').html('Layout Style'),
                boxLink,
                wideLink
                ),
                $('
')
                );

        var patternList = $('
').addClass('options').attr('data-type', 'pattern');

        var patternImages = [
            {'image': 'brillant', 'title': 'Brillant'},
            {'image': 'always_grey', 'title': 'Always Grey'},
            {'image': 'retina_wood', 'title': 'Retina Wood'},
            {'image': 'low_contrast_linen', 'title': 'Low Constrat Linen'},
            {'image': 'egg_shell', 'title': 'Egg Shel'},
            {'image': 'cartographer', 'title': 'Cartographer'},
            {'image': 'batthern', 'title': 'Batthern'},
            {'image': 'noisy_grid', 'title': 'Noisy Grid'},
            {'image': 'diamond_upholstery', 'title': 'Diamond Upholstery'},
            {'image': 'greyfloral', 'title': 'Gray Floral'},
            {'image': 'white_tiles', 'title': 'White Tiles'},
            {'image': 'gplaypattern', 'title': 'GPlay'},
            {'image': 'arches', 'title': 'Arches'},
            {'image': 'purty_wood', 'title': 'Purty Wood'},
            {'image': 'diagonal_striped_brick', 'title': 'Diagonal Striped Brick'},
            {'image': 'large_leather', 'title': 'Large Leather'},
            {'image': 'bo_play_pattern', 'title': 'BO Play'},
            {'image': 'irongrip', 'title': 'Iron Grip'},
            {'image': 'wood_1', 'title': 'Dark Wood'},
            {'image': 'pool_table', 'title': 'Pool Table'},
            {'image': 'crissXcross', 'title': 'crissXcross'},
            {'image': 'rip_jobs', 'title': 'R.I.P Steve Jobs'},
            {'image': 'random_grey_variations', 'title': 'Random Grey Variations'},
            {'image': 'carbon_fibre', 'title': 'Carbon Fibre'},
        ];

        $.each(patternImages, function(i) {
            var listElement = $('
')
                    .append(
                    $('')
                    .css({
                'background': 'url(assets/img/pattern/' + patternImages[i].image + '.png) repeat'
            })
                    .attr({
                'href': '#',
                'title': patternImages[i].title,
                'data-pattern-image': patternImages[i].image
            }).tooltip({'placement': 'bottom'})
                    );
            patternList.append(listElement);
        });

        patternList.find('a').on('click', function(e) {
            e.preventDefault();
            $('body').css({
                'background-image': 'url(assets/img/pattern/' + $(this).data('patternImage') + '.png)',
                'background-repeat': ' repeat'
            });
            $this.patternImage = $(this).data('patternImage');
            if (localStor) {
                localStorage.pattern = $(this).data('patternImage');
            }
        });

        styleSwitcherWrap.append(
                $('
').addClass('pattern').append(
                $('
').html('Background Pattern'),
                patternList,
                $('
')
                )
                );

        var resetLink = $('')
                .html('Reset')
                .attr('href', '#')
                .on('click', function(e) {
            e.preventDefault();
            $this.reset();
        });

        var cssLink = $('')
                .html('Get CSS')
                .attr('href', '#').on('click', function(e) {
            e.preventDefault();
            $this.getCss();
        });

        styleSwitcherWrap.append(
                $('
').addClass('options-link').append(
                resetLink,
                cssLink
                )
                );

        switchDiv.append(h5, styleSwitcherWrap);
        $('body').append(switchDiv);

        $this.colorSelectorA = $('#colorSelectorA');
    },
    setColor: function(color) {
        $('#colorSelector').data('color', color);
        $('#colorSelectorA').css('background-color', color);
        less.modifyVars({'@baseColor': color});
        if (Modernizr.localstorage) {
            localStorage.color = color;
        }
    },
    reset: function() {
        if (Modernizr.localstorage) {
            localStorage.removeItem('color');
            localStorage.removeItem('layout');
            localStorage.removeItem('pattern');
        }
        $('#wideLink').click();
        window.location.reload();
        return false;
    },
    getCss: function() {
        var $this = this;
        var raw = "", options;
        var isBoxed = $('body').hasClass('fixed');

        var cssBeautify = $('#cssbeautify');
        if (isBoxed) {
            raw = 'body { background-image: url("../img/pattern/' + $this.patternImage + '.png"); }';
            $('#boxedBodyAlert').removeClass('hide');
        } else {
            $('#boxedBodyAlert').addClass('hide');
        }
        cssBeautify.text("");
        raw = raw + $('style[id^="less:"]').text();
        options = {
            indent: "\t",
            autosemicolon: true
        };
        cssBeautify.text(cssbeautify(raw, options));
        $("#getCSSModal").modal("show");
    }
};

styleSwitcher.init();
<commit_msg>update style-switcher.js<commit_after>/*
 Name    : style-switcher.js
 Author  : ono <http://onokumus.com />
 Version : 1.0
 */

// Load lesscss files
yepnope.addPrefix('less', function(resourceObj) {
    resourceObj.forceCSS = true;
    resourceObj.attrs = {
        'rel': 'stylesheet/less',
        'type': 'text/css'
    };
    return resourceObj;
});
var styleSwitcher = {
    init: function() {
        var $this = this;
        less = {env: "development"};

        // Style Switcher CSS
        yepnope([
            {load: 'assets/css/style-switcher.css'},
            {load: 'assets/css/colorpicker.css'},
            {load: 'assets/js/cssbeautify.js'},
            {load: 'assets/js/bootstrap-colorpicker.js',
                complete: function() {
                    yepnope([
                        {load: 'less!assets/less/theme.less'},
                        {load: 'assets/js/vendor/less-1.3.3.min.js',
                            complete: function() {

                                $this.build();

                                if (Modernizr.localstorage) {
                                    if (localStorage.color) {
                                        $this.colorSelectorA.css('background-color', localStorage.color);
                                    }
                                    if (localStorage.pattern) {
                                        $this.patternImage = localStorage.pattern;
                                    }
                                }
                            }
                        }
                    ]);

                }
            }
        ]);

    },
    build: function() {
        var $this = this;
        var localStor = false;
        if (Modernizr.localstorage) {
            localStor = true;
        }

        if (Modernizr.localstorage) {
            if (localStorage.layout) {
                $('body').addClass(localStorage.layout);
            }
            if (localStorage.color) {
                $this.setColor(localStorage.color);
            }
            if (localStorage.pattern) {
                $('body').css({
                    'background': 'url(assets/img/pattern/' + localStorage.pattern + '.png) repeat'
                });
            }
        }

        var modalHTML = '
'
                + '
'
                + '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>'
                + '
Theme CSS
'
                + '
'
                + '
'
                + '
'
                + 'Please add the "fixed" class to the <body> element.
'
                + '<textarea name="cssbeautify" id="cssbeautify" readonly></textarea>
'
                + '
'
                + '<button aria-hidden="true" data-dismiss="modal" class="btn">Close</button>'
                + '

';

        $("body").append(modalHTML);

        var switchDiv = $('
').attr('id', 'style-switcher').addClass('style-switcher hidden-phone');

        var h5Ai = $('').addClass('icon-cogs icon-2x');
        var h5A = $('')
                .attr({
            'href': '#',
            'id': 'switcher-link'
        })
                .on('click', function(e) {
            e.preventDefault();
            switchDiv.toggleClass('open');
        })
                .append(h5Ai);

        var h5 = $('
').html('Style Switcher').append(h5A);

        var colorList = $('
').addClass('options').attr('data-type', 'colors');
        var colors = [
            {"Hex": "#0088CC", "colorName": "Blue"},
            {"Hex": "#4EB25C", "colorName": "Green"},
            {"Hex": "#4A5B7D", "colorName": "Navy"},
            {"Hex": "#E05048", "colorName": "Red"},
            {"Hex": "#B8A279", "colorName": "Beige"},
            {"Hex": "#c71c77", "colorName": "Pink"},
            {"Hex": "#734BA9", "colorName": "Purple"},
            {"Hex": "#2BAAB1", "colorName": "Cyan"}
        ];
        $.each(colors, function(i) {
            var listElement = $('
')
                    .append(
                    $('')
                    .css("background-color", colors[i].Hex)
                    .attr({
                "data-color-hex": colors[i].Hex,
                "data-color-name": colors[i].colorName,
                "href": "#",
                "title": colors[i].colorName
            }).tooltip({'placement': 'bottom'})
                    );
            colorList.append(listElement);
        });

        colorList.find('a').on('click', function(e) {
            e.preventDefault();
            $this.setColor($(this).data('colorHex'));

            if (localStor) {
                localStorage.color = $(this).data('colorHex');
            }
        });
        var colorSelector = $('
')
                .addClass('color-picker')
                .attr({
            'id': 'colorSelector',
            'data-color': colors[0].Hex,
            'data-color-format': 'hex'
        })
                .append(
                $('')
                .css('background-color', colors[0].Hex)
                .attr({
            'href': '#',
            'id': 'colorSelectorA'
        }),
        $("")
                .addClass("color-picker-icon")
                );

        colorSelector.colorpicker().on('changeColor', function(ev) {
            colorSelector.find("a").css("background-color", ev.color.toHex());
            $this.setColor(ev.color.toHex());
            if (localStor) {
                localStorage.color = $(this).data('colorHex');
            }
        });

        var colorPicker = $('
').append(colorSelector);

        colorList.append(colorPicker);

        var styleSwitcherWrap = $('
')
                .addClass('style-switcher-wrap')
                .append(
                $('
').html('Colors'), colorList, $('
')
                );

        var boxLink = $('')
                .attr({
            'id': 'boxLink',
            'href': '#',
            'data-layout-type': 'fixed'
        })
                .html('Fixed')
                .on('click', function(e) {
            e.preventDefault();
            $(this).addClass('active').siblings('a').removeClass('active');
            $('body').removeClass('wide').addClass('fixed');
            if (localStor) {
                localStorage.layout = 'fixed';
            }
        });

        var wideLink = $('')
                .attr({
            'href': '#',
            'id': 'wideLink',
            'data-layout-type': 'wide'
        })
                .html('Wide')
                .on('click', function(e) {
            e.preventDefault();
            $(this).addClass('active').siblings('a').removeClass('active');
            $('body').removeClass('fixed').addClass('wide').removeAttr('style');
            if (localStor) {
                localStorage.layout = 'wide';
            }
        });
        if (localStor) {
            if (localStorage.layout === 'fixed') {
                boxLink.addClass('active');
            } else {
                wideLink.addClass('active');
            }
        }
        styleSwitcherWrap.append(
                $('
').addClass('options-link').append(
                $('
').html('Layout Style'),
                boxLink,
                wideLink
                ),
                $('
')
                );

        var patternList = $('
').addClass('options').attr('data-type', 'pattern');

        var patternImages = [
            {'image': 'brillant', 'title': 'Brillant'},
            {'image': 'always_grey', 'title': 'Always Grey'},
            {'image': 'retina_wood', 'title': 'Retina Wood'},
            {'image': 'low_contrast_linen', 'title': 'Low Constrat Linen'},
            {'image': 'egg_shell', 'title': 'Egg Shel'},
            {'image': 'cartographer', 'title': 'Cartographer'},
            {'image': 'batthern', 'title': 'Batthern'},
            {'image': 'noisy_grid', 'title': 'Noisy Grid'},
            {'image': 'diamond_upholstery', 'title': 'Diamond Upholstery'},
            {'image': 'greyfloral', 'title': 'Gray Floral'},
            {'image': 'white_tiles', 'title': 'White Tiles'},
            {'image': 'gplaypattern', 'title': 'GPlay'},
            {'image': 'arches', 'title': 'Arches'},
            {'image': 'purty_wood', 'title': 'Purty Wood'},
            {'image': 'diagonal_striped_brick', 'title': 'Diagonal Striped Brick'},
            {'image': 'large_leather', 'title': 'Large Leather'},
            {'image': 'bo_play_pattern', 'title': 'BO Play'},
            {'image': 'irongrip', 'title': 'Iron Grip'},
            {'image': 'wood_1', 'title': 'Dark Wood'},
            {'image': 'pool_table', 'title': 'Pool Table'},
            {'image': 'crissXcross', 'title': 'crissXcross'},
            {'image': 'rip_jobs', 'title': 'R.I.P Steve Jobs'},
            {'image': 'random_grey_variations', 'title': 'Random Grey Variations'},
            {'image': 'carbon_fibre', 'title': 'Carbon Fibre'},
        ];

        $.each(patternImages, function(i) {
            var listElement = $('
')
                    .append(
                    $('')
                    .css({
                'background': 'url(assets/img/pattern/' + patternImages[i].image + '.png) repeat'
            })
                    .attr({
                'href': '#',
                'title': patternImages[i].title,
                'data-pattern-image': patternImages[i].image
            }).tooltip({'placement': 'bottom'})
                    );
            patternList.append(listElement);
        });

        patternList.find('a').on('click', function(e) {
            e.preventDefault();
            $('body').css({
                'background-image': 'url(assets/img/pattern/' + $(this).data('patternImage') + '.png)',
                'background-repeat': ' repeat'
            });
            $this.patternImage = $(this).data('patternImage');
            if (localStor) {
                localStorage.pattern = $(this).data('patternImage');
            }
        });

        styleSwitcherWrap.append(
                $('
').addClass('pattern').append(
                $('
').html('Background Pattern'),
                patternList,
                $('
')
                )
                );

        var resetLink = $('')
                .html('Reset')
                .attr('href', '#')
                .on('click', function(e) {
            e.preventDefault();
            $this.reset();
        });

        var cssLink = $('')
                .html('Get CSS')
                .attr('href', '#').on('click', function(e) {
            e.preventDefault();
            $this.getCss();
        });

        styleSwitcherWrap.append(
                $('
').addClass('options-link').append(
                resetLink,
                cssLink
                )
                );

        switchDiv.append(h5, styleSwitcherWrap);
        $('body').append(switchDiv);

        $this.colorSelectorA = $('#colorSelectorA');
    },
    setColor: function(color) {
        $('#colorSelector').data('color', color);
        $('#colorSelectorA').css('background-color', color);
        less.modifyVars({'@baseColor': color});
        if (Modernizr.localstorage) {
            localStorage.color = color;
        }
    },
    reset: function() {
        if (Modernizr.localstorage) {
            localStorage.removeItem('color');
            localStorage.removeItem('layout');
            localStorage.removeItem('pattern');
        }
        $('#wideLink').click();
        window.location.reload();
        return false;
    },
    getCss: function() {
        var $this = this;
        var raw = "", options;
        var isBoxed = $('body').hasClass('fixed');

        var cssBeautify = $('#cssbeautify');
        if (isBoxed) {
            raw = 'body { background-image: url("../img/pattern/' + $this.patternImage + '.png"); }';
            $('#boxedBodyAlert').removeClass('hide');
        } else {
            $('#boxedBodyAlert').addClass('hide');
        }
        cssBeautify.text("");
        raw = raw + $('style[id^="less:"]').text();
        options = {
            indent: "\t",
            autosemicolon: true
        };
        cssBeautify.text(cssbeautify(raw, options));
        $("#getCSSModal").modal("show");
    }
};

styleSwitcher.init();
<|endoftext|>


<commit_before>'use strict';

// Rooms controller
angular.module('rooms').controller('RoomsController', ['$scope', '$stateParams', '$location', '$http', 'Authentication', 'Rooms', 'Upload', function ($scope, $stateParams, $location, $http, Authentication, Rooms, Upload) {
	$scope.authentication = Authentication;
	$scope.uploading = false;
	$scope.path = null;
	$scope.progressValue = null;
	$scope.map = null;
	$scope.configuration = -1;

	// Create new room
	$scope.create = function() {
		// Create new room object
		var room = new Rooms({
			ID: this.ID,
			name: this.name,
			seats: this.seats,
			path: $scope.path
		});

		// Redirect after save
		room.$save(function(response) {
			$location.path('rooms/' + response.ID);
		}, function(errorResponse) {
			$scope.error = errorResponse.data.message;
		});
	};

	// Remove existing Room
	$scope.remove = function(room) {
		if (room) {
			room.$remove();
			for (var i in $scope.rooms) {
				if ($scope.rooms[i] === room) {
					$scope.rooms.splice(i, 1);
				}
			}
		} else {
			$scope.room.$remove(function() {
				$location.path('rooms');
			});
		}
	};

	// Update existing Room
	$scope.update = function() {
		var room = $scope.room;
		room.$update(function() {
			$location.path('rooms/' + room.ID);
		}, function(errorResponse) {
			$scope.error = errorResponse.data.message;
		});
	};

	// Find a list of Rooms
	$scope.find = function() {
		$scope.rooms = Rooms.query();
	};

    // Find existing Room
    $scope.findOne = function() {
		$scope.room = Rooms.get({
			roomId: $stateParams.roomId
		});
	};

	// For the file upload
	$scope.upload = function(files) {
		if (! $scope.uploading && files && files.length === 1) {
			// Reset form
			$scope.uploading = true;
			$scope.path = null;
			$scope.progressValue = 0;
			// Launch the upload
			Upload.upload({
				url: 'upload/room',
				fields: {'username': $scope.authentication.user._id},
				file: files[0]
			}).progress(function(evt) {
				$scope.progressValue = parseInt(100.0 * evt.loaded / evt.total);
			}).success(function(data, status, headers, config) {
				$scope.progressValue = null;
				$scope.path = 'images/uploads/' + data;
				$scope.uploading = false;
			});
		}
	};

	// For the room map
	function drawMap() {
		var map = $scope.map;
		// Set up canvas
		var canvas = document.getElementById('roomplaces');
		canvas.width = map.width;
		canvas.height = map.height;
		// Initialise context
		var context = canvas.getContext('2d');
		context.clearRect(0, 0, map.width, map.height);
		context.strokeRect(0, 0, map.width, map.height);
		context.scale(1, 1);
		// Draw all shapes
		map.shapes.forEach (function(shape) {
			var attr = shape.attr;
			switch (shape.type) {
				case 'rectangle':
					context.strokeRect(attr.x, attr.y, attr.width, attr.height);
				break;

				case 'text':
					context.fillText(attr.value, attr.x, attr.y);
				break;
			}
		});
		// Draw configuration
		if ($scope.configuration !== -1) {
			$scope.room.configuration[$scope.configuration].seats.forEach(function(seat) {
				var seatcoord = $scope.map.seats[seat.seat];
				context.fillText('X', seatcoord.x, seatcoord.y);
			});
		}
	}

	$scope.loadMap = function() {
		if ($scope.map === null) {
			$http.get('images/rooms/' + $scope.room._id + '/map.json').success(function(data, status, headers, config) {
				$scope.map = data;
				drawMap();
			});
		}
	};

	$scope.getNumber = function(n) {
		var tab = [];
		for (var i = 0; i < n; i++) {
			tab.push(i);
		}
		return tab;
	};

	// Change room configuration
	$scope.changeConfiguration = function(conf) {
		$scope.configuration = conf;
		drawMap();
	};
}]);
<commit_msg>Update map drawing on room detail page<commit_after>'use strict';

// Rooms controller
angular.module('rooms').controller('RoomsController', ['$scope', '$stateParams', '$location', '$http', 'Authentication', 'Rooms', 'Upload', function ($scope, $stateParams, $location, $http, Authentication, Rooms, Upload) {
	$scope.authentication = Authentication;
	$scope.uploading = false;
	$scope.path = null;
	$scope.progressValue = null;
	$scope.map = null;
	$scope.configuration = -1;

	// Create new room
	$scope.create = function() {
		// Create new room object
		var room = new Rooms({
			ID: this.ID,
			name: this.name,
			seats: this.seats,
			path: $scope.path
		});

		// Redirect after save
		room.$save(function(response) {
			$location.path('rooms/' + response.ID);
		}, function(errorResponse) {
			$scope.error = errorResponse.data.message;
		});
	};

	// Remove existing Room
	$scope.remove = function(room) {
		if (room) {
			room.$remove();
			for (var i in $scope.rooms) {
				if ($scope.rooms[i] === room) {
					$scope.rooms.splice(i, 1);
				}
			}
		} else {
			$scope.room.$remove(function() {
				$location.path('rooms');
			});
		}
	};

	// Update existing Room
	$scope.update = function() {
		var room = $scope.room;
		room.$update(function() {
			$location.path('rooms/' + room.ID);
		}, function(errorResponse) {
			$scope.error = errorResponse.data.message;
		});
	};

	// Find a list of Rooms
	$scope.find = function() {
		$scope.rooms = Rooms.query();
	};

    // Find existing Room
    $scope.findOne = function() {
		$scope.room = Rooms.get({
			roomId: $stateParams.roomId
		});
	};

	// For the file upload
	$scope.upload = function(files) {
		if (! $scope.uploading && files && files.length === 1) {
			// Reset form
			$scope.uploading = true;
			$scope.path = null;
			$scope.progressValue = 0;
			// Launch the upload
			Upload.upload({
				url: 'upload/room',
				fields: {'username': $scope.authentication.user._id},
				file: files[0]
			}).progress(function(evt) {
				$scope.progressValue = parseInt(100.0 * evt.loaded / evt.total);
			}).success(function(data, status, headers, config) {
				$scope.progressValue = null;
				$scope.path = 'images/uploads/' + data;
				$scope.uploading = false;
			});
		}
	};

	// For the room map
	function drawMap() {
		var map = $scope.map;
		// Set up canvas
		var canvas = document.getElementById('roomplaces');
		canvas.width = map.width;
		canvas.height = map.height;
		// Initialise context
		var context = canvas.getContext('2d');
		context.clearRect(0, 0, map.width, map.height);
		context.strokeRect(0, 0, map.width, map.height);
		context.scale(1, 1);
		// Draw all shapes
		map.shapes.forEach (function(shape) {
			var attr = shape.attr;
			switch (shape.type) {
				case 'rectangle':
					context.strokeRect(attr.x, attr.y, attr.width, attr.height);
				break;

				case 'text':
					context.fillText(attr.value, attr.x, attr.y);
				break;
			}
		});
		// Draw configuration
		if ($scope.configuration !== -1) {
			context.textAlign = 'center';
			var seats = $scope.room.configuration[$scope.configuration].seats;
			for (var i = 0; i < seats.length; i++) {
				var seatcoord = $scope.map.seats[seats[i].seat];
				context.fillText('#' + (i + 1), seatcoord.x, seatcoord.y);
			}
		}
	}

	$scope.loadMap = function() {
		if ($scope.map === null) {
			$http.get('images/rooms/' + $scope.room._id + '/map.json').success(function(data, status, headers, config) {
				$scope.map = data;
				drawMap();
			});
		}
	};

	$scope.getNumber = function(n) {
		var tab = [];
		for (var i = 0; i < n; i++) {
			tab.push(i);
		}
		return tab;
	};

	// Change room configuration
	$scope.changeConfiguration = function(conf) {
		$scope.configuration = conf;
		drawMap();
	};
}]);
<|endoftext|>


<commit_before>var webpack = require('webpack');

module.exports = function(config) {
  config.set({

    browsers: ['PhantomJS'],

    singleRun: !!process.env.CI,

    frameworks: ['mocha'],

    files: [
      './node_modules/phantomjs-polyfill/bind-polyfill.js',
      process.env.WEBPACK_DLLS === '1' && './static/dist/dlls/dll__vendor.js',
      'tests.webpack.js'
    ].filter(function(x) { return !!x; }),

    preprocessors: {
      'tests.webpack.js': ['webpack', 'sourcemap']
    },

    reporters: ['mocha'],

    plugins: [
      require("karma-webpack"),
      require("karma-mocha"),
      require("karma-mocha-reporter"),
      require("karma-phantomjs-launcher"),
      require("karma-sourcemap-loader")
    ],

    webpack: {
      devtool: 'inline-source-map',
      module: {
        loaders: [
          { test: /\.(jpe?g|png|gif|svg)$/, loader: 'url', query: { limit: 10240 } },
          { test: /\.js$/, exclude: /node_modules/, loaders: ['babel'] },
          { test: /\.json$/, loader: 'json-loader' },
          { test: /\.less$/, loader: 'style!css!less' },
          {
            test: /\.scss$/,
            loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
          }
        ]
      },
      resolve: {
        modulesDirectories: [
          'src',
          'node_modules'
        ],
        extensions: ['', '.json', '.js']
      },
      plugins: [
        new webpack.IgnorePlugin(/\.json$/),
        new webpack.NoErrorsPlugin(),
        new webpack.DefinePlugin({
          __CLIENT__: true,
          __SERVER__: false,
          __DEVELOPMENT__: true,
          __DEVTOOLS__: false,  // <-------- DISABLE redux-devtools HERE
          __DLLS__: process.env.WEBPACK_DLLS === '1'
        })
      ]
    },

    webpackServer: {
      noInfo: true
    }

  });
};
<commit_msg>update karma conf for webpack 2<commit_after>var webpack = require('webpack');

module.exports = function (config) {
  config.set({

    browsers: ['PhantomJS'],

    singleRun: !!process.env.CI,

    frameworks: ['mocha'],

    files: [
      './node_modules/phantomjs-polyfill/bind-polyfill.js',
      process.env.WEBPACK_DLLS === '1' && './static/dist/dlls/dll__vendor.js',
      'tests.webpack.js'
    ].filter(function (x) { return !!x; }),

    preprocessors: {
      'tests.webpack.js': ['webpack', 'sourcemap']
    },

    reporters: ['mocha'],

    plugins: [
      require("karma-webpack"),
      require("karma-mocha"),
      require("karma-mocha-reporter"),
      require("karma-phantomjs-launcher"),
      require("karma-sourcemap-loader")
    ],

    webpack: {
      devtool: 'inline-source-map',
      module: {
        loaders: [
          { test: /\.(jpe?g|png|gif|svg)$/, loader: 'url', options: { limit: 10240 } },
          { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
          { test: /\.json$/, loader: 'json-loader' },
          { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' },
          {
            test: /\.scss$/,
            loader: 'style-loader!css-loader?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer-loader?browsers=last 2 version!sass-loader?outputStyle=expanded&sourceMap'
          }
        ]
      },
      resolve: {
        modules: [
          'src',
          'node_modules'
        ],
        extensions: ['.json', '.js']
      },
      plugins: [
        new webpack.IgnorePlugin(/\.json$/),
        new webpack.NoErrorsPlugin(),
        new webpack.DefinePlugin({
          __CLIENT__: true,
          __SERVER__: false,
          __DEVELOPMENT__: true,
          __DEVTOOLS__: false,  // <-------- DISABLE redux-devtools HERE
          __DLLS__: process.env.WEBPACK_DLLS === '1'
        })
      ]
    },

    webpackServer: {
      noInfo: true
    }

  });
};
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var elInput;
document.body.addEventListener("keydown", function(e){

    elInput = null;

    if(document.activeElement && document.activeElement.tagName.toUpperCase() === 'INPUT' && (document.activeElement.type === 'text' || document.activeElement.type === 'password')) {
        var event = document.createEvent('Event');
        switch(e.keyCode) {
            case 65376: // Done
                elInput = document.activeElement;
                event.initEvent('submit', true, true);
                elInput.dispatchEvent(event);
                elInput.setAttribute('data-toast-ime-shown', 'false');
                elInput.blur();
                break;
            case 65385: // Cancel
                elInput = document.activeElement;
                event.initEvent('cancel', true, true);
                elInput.dispatchEvent(event);
                elInput.setAttribute('data-toast-ime-shown', 'false');
                elInput.value = "";
                elInput.blur();
                break;
        }
    }
});

document.body.addEventListener('focus', function (e) {
    if(document.activeElement && document.activeElement.tagName.toUpperCase() === 'INPUT' && (document.activeElement.type === 'text' || document.activeElement.type === 'password')) {
        document.activeElement.setAttribute('data-toast-ime-shown', 'true');
    }
}, true);
<commit_msg>Fix coding style warnings<commit_after>/*
 * Copyright 2015 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var elInput;
document.body.addEventListener('keydown', function(e) {

    elInput = null;

    if(document.activeElement && document.activeElement.tagName.toUpperCase() === 'INPUT' && (document.activeElement.type === 'text' || document.activeElement.type === 'password')) {
        var event = document.createEvent('Event');
        switch(e.keyCode) {
            case 65376: // Done
                elInput = document.activeElement;
                event.initEvent('submit', true, true);
                elInput.dispatchEvent(event);
                elInput.setAttribute('data-toast-ime-shown', 'false');
                elInput.blur();
                break;
            case 65385: // Cancel
                elInput = document.activeElement;
                event.initEvent('cancel', true, true);
                elInput.dispatchEvent(event);
                elInput.setAttribute('data-toast-ime-shown', 'false');
                elInput.value = '';
                elInput.blur();
                break;
        }
    }
});

document.body.addEventListener('focus', function (e) {
    if(document.activeElement && document.activeElement.tagName.toUpperCase() === 'INPUT' && (document.activeElement.type === 'text' || document.activeElement.type === 'password')) {
        document.activeElement.setAttribute('data-toast-ime-shown', 'true');
    }
}, true);
<|endoftext|>


<commit_before>/**
 * State:
 */
var CONDITION = 0;
var STREAM = 1;
var SUCCESS = 2;
var FAIL = 3;

var log = console.log.bind(console);

// state = [ p, ps, success-state, fail-state ]

/** String PStream **/
var StringPS = {
  create: function(str) {
    return {
      __proto__: this,
      pos:   0,
      str_:  [str],
      tail_: []
    };
  },
  set str(str) { this.str_[0] = str; },
  get head() { return this.pos >= this.str_[0].length ? null : this.str_[0].charAt(this.pos); },
  get value() { return this.hasOwnProperty('value_') ? this.value_ : this.str_[0].charAt(this.pos-1); },
  get tail() { return /*this.pos >= this.str_[0].length ? this : */this.tail_[0] || ( this.tail_[0] = { __proto__: this.__proto__, str_: this.str_, pos: this.pos+1, tail_: [] } ); },
  setValue: function(value) { return { __proto__: this.__proto__, str_: this.str_, pos: this.pos, tail_: this.tail_, value_: value }; }
};

function prep(arg) {
  if ( typeof arg === 'string' ) return literal(arg);

  return arg;
}

function prepArgs(args) {
  for ( var i = 0 ; i < args.length ; i++ ) {
    args[i] = prep(args[i]);
  }

  return args;
}

function literal(c, opt_value) {
  return function(state) {
    var ps = state[STREAM]
    for ( var i = 0; i < c.length; i++ ) {
      if ( ps.head === null ) {
        return [literal(c.substring(i), opt_value || c), ps, state[SUCCESS], state[FAIL]];
      }

      if ( ps.head === c[i] )
        ps = ps.tail;
      else
        break;
    }
    if ( i === c.length ) {
      state[SUCCESS][STREAM] = ps.setValue(opt_value || c);
      return state[SUCCESS]
    }
    state[FAIL][STREAM] = state[STREAM];
    return state[FAIL];
  }
}

function seq(a, b) {
  var args = prepArgs(arguments);
  return function(state) {
    return [args[0], state[STREAM], [args[1], undefined, state[SUCCESS], state[FAIL]], state[FAIL]];
  }
}

function optional(a) {
  var args = prepArgs(arguments);
  return function(state) {
    return [args[0], state[STREAM], state[SUCCESS], state[SUCCESS]];
  }
}

function sym(name) {
  return function(state) {
    return this[name](state);
  }
}

function alt(a, b) {
  var args = prepArgs(arguments);
  return function(state) {
    return [args[0], state[STREAM], state[SUCCESS], [args[1], undefined, state[SUCCESS], state[FAIL]]];
  }
}

// TODO: Resuming in the middle of a literal

var grammar = {
  // Special end state indicator
  END: [],

  parseMore: function(str) {
    var ps = StringPS.create(str);
    this.state[STREAM] = ps;
    return this.parse();
  },
  parseString: function(str) {
    var ps = StringPS.create(str);
    this.state = [this.START, ps, this.END, this.END];
    return this.parse();
  },
  // Pumps the state machine until termination or more data needed.
  parse: function() {
    while (this.state) {
      if ( this.state === this.END ) {
        break;
      }

      if ( this.state[STREAM].head === null ) {
        return;
      }

      this.state = this.state[CONDITION].call(this, this.state);
    }
    return this.state[STREAM].value;
  },
  addAction: function(sym, action) {
    var old = this[sym];
    var wrapper = function(state) {
      action(state[STREAM].value);
      state[SUCCESS][STREAM] = state[STREAM];
      return state[SUCCESS];
    };

    this[sym] = function(state) {
      return [old, state[STREAM], [wrapper, undefined, state[SUCCESS], undefined], [state[FAIL]]];
    }
    return this;
  },
  addActions: function(map) {
    for ( var key in map ) this.addAction(key, map[key]);
    return this;
  }
};

var TestGrammar = {
  __proto__: grammar,

  START: seq("aaaa", seq(sym('middle'), sym('end'))),
  middle: alt("b", "c"),
  end: literal("dddd")
}.addActions({
  middle: function(value) {
    console.log("Middle is: ", value);
  }
});

//log(TestGrammar.parseString("aaaabdddd"));

TestGrammar.parseString("aa");
TestGrammar.parseMore("aa");
TestGrammar.parseMore("bd");
TestGrammar.parseMore("dd");
log(TestGrammar.parseMore("d"));
<commit_msg>Add some primitives to parse2.js<commit_after>/**
 * State:
 */
var CONDITION = 0;
var STREAM = 1;
var SUCCESS = 2;
var FAIL = 3;

var log = console.log.bind(console);

// state = [ p, ps, success-state, fail-state ]

/** String PStream **/
var StringPS = {
  create: function(str) {
    return {
      __proto__: this,
      pos:   0,
      str_:  [str],
      tail_: []
    };
  },
  set str(str) { this.str_[0] = str; },
  get head() { return this.pos >= this.str_[0].length ? null : this.str_[0].charAt(this.pos); },
  get value() { return this.hasOwnProperty('value_') ? this.value_ : this.str_[0].charAt(this.pos-1); },
  get tail() { return /*this.pos >= this.str_[0].length ? this : */this.tail_[0] || ( this.tail_[0] = { __proto__: this.__proto__, str_: this.str_, pos: this.pos+1, tail_: [] } ); },
  setValue: function(value) { return { __proto__: this.__proto__, str_: this.str_, pos: this.pos, tail_: this.tail_, value_: value }; }
};

function prep(arg) {
  if ( typeof arg === 'string' ) return literal(arg);

  return arg;
}

function prepArgs(args) {
  for ( var i = 0 ; i < args.length ; i++ ) {
    args[i] = prep(args[i]);
  }

  return args;
}

function literal(c, opt_value) {
  return function(state) {
    var ps = state[STREAM]
    for ( var i = 0; i < c.length; i++ ) {
      if ( ps.head === null ) {
        return [literal(c.substring(i), opt_value || c), ps, state[SUCCESS], state[FAIL]];
      }

      if ( ps.head === c[i] )
        ps = ps.tail;
      else
        break;
    }
    if ( i === c.length ) {
      state[SUCCESS][STREAM] = ps.setValue(opt_value || c);
      return state[SUCCESS]
    }
    state[FAIL][STREAM] = state[STREAM];
    return state[FAIL];
  }
}

function literal_ic(c, opt_value) {
  c = c.toLowerCase();
  return function(state) {
    var ps = state[STREAM]
    for ( var i = 0; i < c.length; i++ ) {
      if ( ps.head === null ) {
        return [literal(c.substring(i), opt_value || c), ps, state[SUCCESS], state[FAIL]];
      }

      if ( ps.head.toLowerCase() === c[i] )
        ps = ps.tail;
      else
        break;
    }
    if ( i === c.length ) {
      state[SUCCESS][STREAM] = ps.setValue(opt_value || c);
      return state[SUCCESS]
    }
    state[FAIL][STREAM] = state[STREAM];
    return state[FAIL];
  }
}

function anyChar(state) {
  state[SUCCESS][STREAM] = state[STREAM].tail.setValue(state[STREAM].head);
  return state[SUCCESS];
}

function notChar(c) {
  return function(state) {
    var next = state[STREAM].head !== c ? state[SUCCESS] : state[FAIL];
    next[STREAM] = state[STREAM].tail.setValue(c);
  }
}

function seq(a, b) {
  var args = prepArgs(arguments);
  return function(state) {
    return [args[0], state[STREAM], [args[1], undefined, state[SUCCESS], state[FAIL]], state[FAIL]];
  }
}

function optional(a) {
  var args = prepArgs(arguments);
  return function(state) {
    return [args[0], state[STREAM], state[SUCCESS], state[SUCCESS]];
  }
}

function sym(name) {
  return function(state) {
    return this[name](state);
  }
}

function alt(a, b) {
  var args = prepArgs(arguments);
  return function(state) {
    return [args[0], state[STREAM], state[SUCCESS], [args[1], undefined, state[SUCCESS], state[FAIL]]];
  }
}

// TODO: Resuming in the middle of a literal

var grammar = {
  // Special end state indicator
  END: [],

  parseMore: function(str) {
    var ps = StringPS.create(str);
    this.state[STREAM] = ps;
    return this.parse();
  },
  parseString: function(str) {
    var ps = StringPS.create(str);
    this.state = [this.START, ps, this.END, this.END];
    return this.parse();
  },
  // Pumps the state machine until termination or more data needed.
  parse: function() {
    while (this.state) {
      if ( this.state === this.END ) {
        break;
      }

      if ( this.state[STREAM].head === null ) {
        return;
      }

      this.state = this.state[CONDITION].call(this, this.state);
    }
    return this.state[STREAM].value;
  },
  addAction: function(sym, action) {
    var old = this[sym];
    var wrapper = function(state) {
      action(state[STREAM].value);
      state[SUCCESS][STREAM] = state[STREAM];
      return state[SUCCESS];
    };

    this[sym] = function(state) {
      return [old, state[STREAM], [wrapper, undefined, state[SUCCESS], undefined], [state[FAIL]]];
    }
    return this;
  },
  addActions: function(map) {
    for ( var key in map ) this.addAction(key, map[key]);
    return this;
  }
};

var TestGrammar = {
  __proto__: grammar,

  START: seq("aaaa", seq(sym('middle'), sym('end'))),
  middle: alt("b", "c"),
  end: literal("dddd")
}.addActions({
  middle: function(value) {
    console.log("Middle is: ", value);
  }
});

//log(TestGrammar.parseString("aaaabdddd"));

TestGrammar.parseString("aa");
TestGrammar.parseMore("aa");
TestGrammar.parseMore("bd");
TestGrammar.parseMore("dd");
log(TestGrammar.parseMore("d"));
<|endoftext|>