<commit_before>/*

index.js - "tart-PEG": Parsing Expression Grammar (PEG) tools (tart module)

The MIT License (MIT)

Copyright (c) 2015 Dale Schumacher

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

*/
"use strict";

var PEG = module.exports;

//var log = console.log;
var log = function () {};
var defaultLog = log;

var error = function error(m, e) {
    console.log('error', m, e);
    m.fail({
        start: m.input,
        end: m.input,
        error: e
    });
};

PEG.fail = function failBeh(m) {
    log('failBeh'+this.self+':', m);
    m.fail({
        start: m.input,
        end: m.input
    });
};

PEG.empty = function emptyBeh(m) {
    log('emptyBeh'+this.self+':', m);
    m.ok({
        start: m.input,
        end: m.input,
        value: []
    });
};

PEG.predicate = function predicatePtrn(predicate) {
    return function predicateBeh(m) {
        log('predicateBeh'+this.self+':', m);
        try {
            var token = m.input.value;
            if (token !== undefined) {
                if (predicate(token)) {
                    m.input.next(this.sponsor(function readBeh(input) {
                        m.ok({
                            start: m.input,
                            end: input,
                            value: token
                        });
                    }));
                    return;
                }
            }
            m.fail({
                start: m.input,
                end: m.input
            });
        } catch (e) {
            error(m, e);
        }
    };
};

PEG.dot = PEG.anything = PEG.predicate(function isTrue(token) {
    return true;
});

PEG.terminal = function terminalPtrn(expect) {
    return PEG.predicate(function isEqual(actual) {
        return (expect == actual);
    });
}

PEG.not = function notPtrn(pattern) {
    return function notBeh(m) {
        log('notBeh'+this.self+':', m);
        try {
            var result = {
                start: m.input,
                end: m.input
            };
            pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    m.fail(result);
                }),
                fail: this.sponsor(function failBeh(r) {
                    m.ok(result);
                })
            });
        } catch (e) {
            error(m, e);
        }
    };
};

PEG.follow = function followPtrn(pattern) {
    return function followBeh(m) {
        log('followBeh'+this.self+':', m);
        try {
            var result = {
                start: m.input,
                end: m.input
            };
            pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    m.ok(result);
                }),
                fail: this.sponsor(function failBeh(r) {
                    m.fail(result);
                })
            });
        } catch (e) {
            error(m, e);
        }
    };
};

var andThen = function andPtrn(first, rest) {
    return function andBeh(m) {
        log('andBeh'+this.self+':', m);
        var failure = this.sponsor(function failBeh(r) {
//            log('failBeh'+this.self+':', r, m);
            m.fail({
                start: m.input,
                end: r.end
            });
        });
        var next = this.sponsor(function nextBeh(r) {
            log('nextBeh'+this.self+':', r, m);
            var success = this.sponsor(function okBeh(rr) {
//                log('okBeh'+this.self+':', rr, r, m);
                rr.value.unshift(r.value);  // mutate rr.value
                m.ok({
                    start: m.input,
                    end: rr.end,
                    value: rr.value
                });
            });
            rest({
                input: r.end,
                ok: success,
                fail: failure
            });
        });
        first({
            input: m.input,
            ok: next,
            fail: failure
        });
    };
};
PEG.sequence = function sequencePtrn(list) {
    return function sequenceBeh(m) {
        if (list.length > 0) {
            var pattern = list.shift();
            this.behavior = andThen(
                pattern,
                this.sponsor(PEG.sequence(list))
            );
        } else {
            this.behavior = PEG.empty;
        }
        this.self(m);
    };
};

var orElse = function orPtrn(first, rest) {
    return function orBeh(m) {
        log('orBeh'+this.self+':', m);
        var next = this.sponsor(function nextBeh(r) {
            log('nextBeh'+this.self+':', r, m);
            rest({
                input: m.input,
                ok: m.ok,
                fail: m.fail
            });
        });
        first({
            input: m.input,
            ok: m.ok,
            fail: next
        });
    };
};
PEG.choice = function choicePtrn(list) {
    return function choiceBeh(m) {
        if (list.length > 0) {
            var pattern = list.shift();
            this.behavior = orElse(
                pattern,
                this.sponsor(PEG.choice(list))
            );
        } else {
            this.behavior = PEG.fail;
        }
        this.self(m);
    };
};

PEG.star = PEG.zeroOrMore = function zeroOrMorePtrn(pattern) {
    return function zeroOrMoreBeh(m) {
        log('zeroOrMoreBeh'+this.self+':', m);
        var list = [];
        var more = this.sponsor(function moreBeh(r) {
            list.push(r.value);  // mutate list
            pattern({
                input: r.end,
                ok: more,
                fail: done
            });
        });
        var done = this.sponsor(function doneBeh(r) {
            m.ok({
                start: m.input,
                end: r.end,
                value: list
            });
        });
        pattern({
            input: m.input,
            ok: more,
            fail: done
        });
    };
};

PEG.plus = PEG.oneOrMore = function oneOrMorePtrn(pattern) {
    return function oneOrMoreBeh(m) {
        log('oneOrMoreBeh'+this.self+':', m);
        var list = [];
        var more = this.sponsor(function moreBeh(r) {
            list.push(r.value);  // mutate list
            pattern({
                input: r.end,
                ok: more,
                fail: done
            });
        });
        var done = this.sponsor(function doneBeh(r) {
            m.ok({
                start: m.input,
                end: r.end,
                value: list
            });
        });
        pattern({
            input: m.input,
            ok: more,
            fail: m.fail
        });
    };
};

PEG.question = PEG.optional = PEG.zeroOrOne = function zeroOrOnePtrn(pattern) {
    return function zeroOrOneBeh(m) {
        log('zeroOrOneBeh'+this.self+':', m);
        pattern({
            input: m.input,
            ok: this.sponsor(function oneBeh(r) {
                m.ok({
                    start: m.input,
                    end: r.end,
                    value: [ r.value ]
                });
            }),
            fail: this.sponsor(function zeroBeh(r) {
                m.ok({
                    start: m.input,
                    end: m.input,
                    value: []
                });
            })
        });
    };
};

PEG.object = function objectPtrn(expect) {
    return PEG.predicate(function matchObject(actual) {
        for (var name in expect) {
            if (expect.hasOwnProperty(name)) {
                if (expect[name] !== actual[name]) {
                    return false;
                }
            }
        }
        return true;
    });
}

PEG.memoize = PEG.packrat = function packratPtrn(pattern, name, log) {
    var results = [];
    name = name || '';
    log = log || defaultLog;
    return function packratBeh(m) {
//        log('packratBeh:', name, m);
        try {
            var at = m.input.pos;
            var r = results[at];
            if (r) {
                log('used:', name, at, r);
                m.ok(r);
            } else {
                var memo = this.sponsor(function memo(r) {
                    results[at] = r;
                    log('memo:', name, at, r);
                    m.ok(r);
                });
                pattern({
                    input: m.input,
                    ok: memo,
                    fail: m.fail
                });
            }
        } catch (e) {
            error(m, e);
        }
    };
};

PEG.namespace = function namespace(log) {
    var ns = {};
    var ruleNamed = {};
    log = log || defaultLog;

    var defaultTransform = function ruleValue(name, value, r) {
        return {
            name: name,
            start: r.start,
            end: r.end,
            value: value
        };
    };
    ns.define = function setRule(name, pattern) {
        if (ruleNamed[name]) {
            throw Error('Redefined rule: ' + name);
        }
//        log('setRule:', name);
        var rule = {
            name: name,
            pattern: pattern,
            transform: defaultTransform
        };
        ruleNamed[name] = rule;
    };

    ns.lookup = function getRule(name) {
        // delay name lookup until rule is invoked
//        log('getRule:', name);
        return function callBeh(m) {
//            log('callBeh:', name, m);
            var rule = ruleNamed[name];
            if (!rule) {
                throw Error('Undefined rule: ' + name);
            }
            if (!rule.wrapped) {
                rule.wrapped = this.sponsor(ns.wrapper(rule));
            }
            rule.wrapped(m);
        };
    };

    ns.transform = function setTransform(name, transform) {
        var rule = ruleNamed[name];
        if (!rule) {
            throw Error('Undefined rule: ' + name);
        }
        rule.transform = transform;
    };

    ns.transformWrapper = function transformWrapper(rule) {
        return function transformBeh(m) {
//            log('transformBeh:', rule, m);
            rule.pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    try {
                        r.value = rule.transform(rule.name, r.value, r);
                    } catch (e) {
                        r.value = undefined;
                        r.error = e;
                    }
                    m.ok(r);
                }),
                fail: this.sponsor(function failBeh(r) {
                    m.fail(r);
                })
            });
        };
    };

    var ruleStack = [];
    var isRecursive = function isRecursive(rule, m) {
        var i = ruleStack.length;
        while (i > 0) {
            i -= 1;
            if (ruleStack[i].pos < m.input.pos) {
                return false;  // safe
            }
            if (ruleStack[i].rule === rule) {
                return true;  // RECURSIVE
            }
        }
        return false;  // safe
    };
    ns.stackingWrapper = function stackingWrapper(pattern, rule) {
        return function stackingBeh(m) {
            if (isRecursive(rule, m)) {
                log('RECURSIVE:', rule, m);
                m.fail({
                    start: m.input,
                    end: m.input
                });
                return;
            }
//            log('stackingBeh:', rule, m);
            ruleStack.push({
                rule: rule,
                pos: m.input.pos
            });
//            log('ruleStack.push:', ruleStack);
            pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    ruleStack.pop();
//                    log('ruleStack.ok:', ruleStack);
                    m.ok(r);
                }),
                fail: this.sponsor(function failBeh(r) {
                    ruleStack.pop();
//                    log('ruleStack.fail:', ruleStack);
                    m.fail(r);
                })
            });
        };
    };

    ns.wrapper = function wrapRule(rule) {
        return function wrapBeh(m) {
            log('wrapBeh:', rule, m);
            var transform = this.sponsor(ns.transformWrapper(rule));
            var stacking = this.sponsor(ns.stackingWrapper(transform, rule));
            this.behavior = PEG.memoize(stacking, rule.name, log);
            this.self(m);
        }
    };

    return ns;
};

PEG.start = function start(pattern, ok, fail) {
    return function startBeh(s) {
        pattern({
            input: s,
            ok: ok,
            fail: fail
        });
    };
};

PEG.factory = function factory(sponsor) {
    var kit = {
        fail: sponsor(PEG.fail),
        empty: sponsor(PEG.empty)
    };
    kit.dot = kit.any = kit.anything = sponsor(PEG.anything);
    kit.term = kit.terminal = function aTerminal(token) {
        return sponsor(PEG.terminal(token));
    };
    kit.if = kit.cond = kit.predicate = function aPredicate(predicate) {
        return sponsor(PEG.predicate(predicate));
    };
    kit.not = function aNot(pattern) {
        return sponsor(PEG.not(pattern));
    };
    kit.follow = function aFollow(pattern) {
        return sponsor(PEG.follow(pattern));
    };
    kit.seq = kit.sequence = function aSequence(list) {
        return sponsor(PEG.sequence(list));
    };
    kit.alt = kit.choice = function aChoice(list) {
        return sponsor(PEG.choice(list));
    };
    kit.star = kit.zeroOrMore = function aZeroOrMore(pattern) {
        return sponsor(PEG.zeroOrMore(pattern));
    };
    kit.plus = kit.oneOrMore = function aOneOrMore(pattern) {
        return sponsor(PEG.oneOrMore(pattern));
    };
    kit.opt = kit.optional = kit.question = kit.zeroOrOne = function aZeroOrOne(pattern) {
        return sponsor(PEG.zeroOrOne(pattern));
    };
    kit.like = kit.object = function anObject(expect) {
        return sponsor(PEG.object(expect));
    };
    kit.memo = kit.memoize = kit.packrat = function aPackrat(pattern, name, log) {
        return sponsor(PEG.packrat(pattern, name, log));
    };
    kit.scope = kit.namespace = function newNamespace(log) {
        var ns = PEG.namespace(log);
        ns.call = function aCall(name) {
            return sponsor(ns.lookup(name));
        };
        return ns;
    };
    kit.matcher = kit.match = kit.start = function aMatcher(pattern, ok, fail) {
        return sponsor(PEG.start(pattern, ok, fail));
    };
    return kit;
};
<commit_msg>Remember factory that created namespace<commit_after>/*

index.js - "tart-PEG": Parsing Expression Grammar (PEG) tools (tart module)

The MIT License (MIT)

Copyright (c) 2015 Dale Schumacher

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

*/
"use strict";

var PEG = module.exports;

//var log = console.log;
var log = function () {};
var defaultLog = log;

var error = function error(m, e) {
    console.log('error', m, e);
    m.fail({
        start: m.input,
        end: m.input,
        error: e
    });
};

PEG.fail = function failBeh(m) {
    log('failBeh'+this.self+':', m);
    m.fail({
        start: m.input,
        end: m.input
    });
};

PEG.empty = function emptyBeh(m) {
    log('emptyBeh'+this.self+':', m);
    m.ok({
        start: m.input,
        end: m.input,
        value: []
    });
};

PEG.predicate = function predicatePtrn(predicate) {
    return function predicateBeh(m) {
        log('predicateBeh'+this.self+':', m);
        try {
            var token = m.input.value;
            if (token !== undefined) {
                if (predicate(token)) {
                    m.input.next(this.sponsor(function readBeh(input) {
                        m.ok({
                            start: m.input,
                            end: input,
                            value: token
                        });
                    }));
                    return;
                }
            }
            m.fail({
                start: m.input,
                end: m.input
            });
        } catch (e) {
            error(m, e);
        }
    };
};

PEG.dot = PEG.anything = PEG.predicate(function isTrue(token) {
    return true;
});

PEG.terminal = function terminalPtrn(expect) {
    return PEG.predicate(function isEqual(actual) {
        return (expect == actual);
    });
}

PEG.not = function notPtrn(pattern) {
    return function notBeh(m) {
        log('notBeh'+this.self+':', m);
        try {
            var result = {
                start: m.input,
                end: m.input
            };
            pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    m.fail(result);
                }),
                fail: this.sponsor(function failBeh(r) {
                    m.ok(result);
                })
            });
        } catch (e) {
            error(m, e);
        }
    };
};

PEG.follow = function followPtrn(pattern) {
    return function followBeh(m) {
        log('followBeh'+this.self+':', m);
        try {
            var result = {
                start: m.input,
                end: m.input
            };
            pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    m.ok(result);
                }),
                fail: this.sponsor(function failBeh(r) {
                    m.fail(result);
                })
            });
        } catch (e) {
            error(m, e);
        }
    };
};

var andThen = function andPtrn(first, rest) {
    return function andBeh(m) {
        log('andBeh'+this.self+':', m);
        var failure = this.sponsor(function failBeh(r) {
//            log('failBeh'+this.self+':', r, m);
            m.fail({
                start: m.input,
                end: r.end
            });
        });
        var next = this.sponsor(function nextBeh(r) {
            log('nextBeh'+this.self+':', r, m);
            var success = this.sponsor(function okBeh(rr) {
//                log('okBeh'+this.self+':', rr, r, m);
                rr.value.unshift(r.value);  // mutate rr.value
                m.ok({
                    start: m.input,
                    end: rr.end,
                    value: rr.value
                });
            });
            rest({
                input: r.end,
                ok: success,
                fail: failure
            });
        });
        first({
            input: m.input,
            ok: next,
            fail: failure
        });
    };
};
PEG.sequence = function sequencePtrn(list) {
    return function sequenceBeh(m) {
        if (list.length > 0) {
            var pattern = list.shift();
            this.behavior = andThen(
                pattern,
                this.sponsor(PEG.sequence(list))
            );
        } else {
            this.behavior = PEG.empty;
        }
        this.self(m);
    };
};

var orElse = function orPtrn(first, rest) {
    return function orBeh(m) {
        log('orBeh'+this.self+':', m);
        var next = this.sponsor(function nextBeh(r) {
            log('nextBeh'+this.self+':', r, m);
            rest({
                input: m.input,
                ok: m.ok,
                fail: m.fail
            });
        });
        first({
            input: m.input,
            ok: m.ok,
            fail: next
        });
    };
};
PEG.choice = function choicePtrn(list) {
    return function choiceBeh(m) {
        if (list.length > 0) {
            var pattern = list.shift();
            this.behavior = orElse(
                pattern,
                this.sponsor(PEG.choice(list))
            );
        } else {
            this.behavior = PEG.fail;
        }
        this.self(m);
    };
};

PEG.star = PEG.zeroOrMore = function zeroOrMorePtrn(pattern) {
    return function zeroOrMoreBeh(m) {
        log('zeroOrMoreBeh'+this.self+':', m);
        var list = [];
        var more = this.sponsor(function moreBeh(r) {
            list.push(r.value);  // mutate list
            pattern({
                input: r.end,
                ok: more,
                fail: done
            });
        });
        var done = this.sponsor(function doneBeh(r) {
            m.ok({
                start: m.input,
                end: r.end,
                value: list
            });
        });
        pattern({
            input: m.input,
            ok: more,
            fail: done
        });
    };
};

PEG.plus = PEG.oneOrMore = function oneOrMorePtrn(pattern) {
    return function oneOrMoreBeh(m) {
        log('oneOrMoreBeh'+this.self+':', m);
        var list = [];
        var more = this.sponsor(function moreBeh(r) {
            list.push(r.value);  // mutate list
            pattern({
                input: r.end,
                ok: more,
                fail: done
            });
        });
        var done = this.sponsor(function doneBeh(r) {
            m.ok({
                start: m.input,
                end: r.end,
                value: list
            });
        });
        pattern({
            input: m.input,
            ok: more,
            fail: m.fail
        });
    };
};

PEG.question = PEG.optional = PEG.zeroOrOne = function zeroOrOnePtrn(pattern) {
    return function zeroOrOneBeh(m) {
        log('zeroOrOneBeh'+this.self+':', m);
        pattern({
            input: m.input,
            ok: this.sponsor(function oneBeh(r) {
                m.ok({
                    start: m.input,
                    end: r.end,
                    value: [ r.value ]
                });
            }),
            fail: this.sponsor(function zeroBeh(r) {
                m.ok({
                    start: m.input,
                    end: m.input,
                    value: []
                });
            })
        });
    };
};

PEG.object = function objectPtrn(expect) {
    return PEG.predicate(function matchObject(actual) {
        for (var name in expect) {
            if (expect.hasOwnProperty(name)) {
                if (expect[name] !== actual[name]) {
                    return false;
                }
            }
        }
        return true;
    });
}

PEG.memoize = PEG.packrat = function packratPtrn(pattern, name, log) {
    var results = [];
    name = name || '';
    log = log || defaultLog;
    return function packratBeh(m) {
//        log('packratBeh:', name, m);
        try {
            var at = m.input.pos;
            var r = results[at];
            if (r) {
                log('used:', name, at, r);
                m.ok(r);
            } else {
                var memo = this.sponsor(function memo(r) {
                    results[at] = r;
                    log('memo:', name, at, r);
                    m.ok(r);
                });
                pattern({
                    input: m.input,
                    ok: memo,
                    fail: m.fail
                });
            }
        } catch (e) {
            error(m, e);
        }
    };
};

PEG.namespace = function namespace(log) {
    var ns = {};
    var ruleNamed = {};
    log = log || defaultLog;

    var defaultTransform = function ruleValue(name, value, r) {
        return {
            name: name,
            start: r.start,
            end: r.end,
            value: value
        };
    };
    ns.define = function setRule(name, pattern) {
        if (ruleNamed[name]) {
            throw Error('Redefined rule: ' + name);
        }
//        log('setRule:', name);
        var rule = {
            name: name,
            pattern: pattern,
            transform: defaultTransform
        };
        ruleNamed[name] = rule;
    };

    ns.lookup = function getRule(name) {
        // delay name lookup until rule is invoked
//        log('getRule:', name);
        return function callBeh(m) {
//            log('callBeh:', name, m);
            var rule = ruleNamed[name];
            if (!rule) {
                throw Error('Undefined rule: ' + name);
            }
            if (!rule.wrapped) {
                rule.wrapped = this.sponsor(ns.wrapper(rule));
            }
            rule.wrapped(m);
        };
    };

    ns.transform = function setTransform(name, transform) {
        var rule = ruleNamed[name];
        if (!rule) {
            throw Error('Undefined rule: ' + name);
        }
        rule.transform = transform;
    };

    ns.transformWrapper = function transformWrapper(rule) {
        return function transformBeh(m) {
//            log('transformBeh:', rule, m);
            rule.pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    try {
                        r.value = rule.transform(rule.name, r.value, r);
                    } catch (e) {
                        r.value = undefined;
                        r.error = e;
                    }
                    m.ok(r);
                }),
                fail: this.sponsor(function failBeh(r) {
                    m.fail(r);
                })
            });
        };
    };

    var ruleStack = [];
    var isRecursive = function isRecursive(rule, m) {
        var i = ruleStack.length;
        while (i > 0) {
            i -= 1;
            if (ruleStack[i].pos < m.input.pos) {
                return false;  // safe
            }
            if (ruleStack[i].rule === rule) {
                return true;  // RECURSIVE
            }
        }
        return false;  // safe
    };
    ns.stackingWrapper = function stackingWrapper(pattern, rule) {
        return function stackingBeh(m) {
            if (isRecursive(rule, m)) {
                log('RECURSIVE:', rule, m);
                m.fail({
                    start: m.input,
                    end: m.input
                });
                return;
            }
//            log('stackingBeh:', rule, m);
            ruleStack.push({
                rule: rule,
                pos: m.input.pos
            });
//            log('ruleStack.push:', ruleStack);
            pattern({
                input: m.input,
                ok: this.sponsor(function okBeh(r) {
                    ruleStack.pop();
//                    log('ruleStack.ok:', ruleStack);
                    m.ok(r);
                }),
                fail: this.sponsor(function failBeh(r) {
                    ruleStack.pop();
//                    log('ruleStack.fail:', ruleStack);
                    m.fail(r);
                })
            });
        };
    };

    ns.wrapper = function wrapRule(rule) {
        return function wrapBeh(m) {
            log('wrapBeh:', rule, m);
            var transform = this.sponsor(ns.transformWrapper(rule));
            var stacking = this.sponsor(ns.stackingWrapper(transform, rule));
            this.behavior = PEG.memoize(stacking, rule.name, log);
            this.self(m);
        }
    };

    return ns;
};

PEG.start = function start(pattern, ok, fail) {
    return function startBeh(s) {
        pattern({
            input: s,
            ok: ok,
            fail: fail
        });
    };
};

PEG.factory = function factory(sponsor) {
    var kit = {
        fail: sponsor(PEG.fail),
        empty: sponsor(PEG.empty)
    };
    kit.dot = kit.any = kit.anything = sponsor(PEG.anything);
    kit.term = kit.terminal = function aTerminal(token) {
        return sponsor(PEG.terminal(token));
    };
    kit.if = kit.cond = kit.predicate = function aPredicate(predicate) {
        return sponsor(PEG.predicate(predicate));
    };
    kit.not = function aNot(pattern) {
        return sponsor(PEG.not(pattern));
    };
    kit.follow = function aFollow(pattern) {
        return sponsor(PEG.follow(pattern));
    };
    kit.seq = kit.sequence = function aSequence(list) {
        return sponsor(PEG.sequence(list));
    };
    kit.alt = kit.choice = function aChoice(list) {
        return sponsor(PEG.choice(list));
    };
    kit.star = kit.zeroOrMore = function aZeroOrMore(pattern) {
        return sponsor(PEG.zeroOrMore(pattern));
    };
    kit.plus = kit.oneOrMore = function aOneOrMore(pattern) {
        return sponsor(PEG.oneOrMore(pattern));
    };
    kit.opt = kit.optional = kit.question = kit.zeroOrOne = function aZeroOrOne(pattern) {
        return sponsor(PEG.zeroOrOne(pattern));
    };
    kit.like = kit.object = function anObject(expect) {
        return sponsor(PEG.object(expect));
    };
    kit.memo = kit.memoize = kit.packrat = function aPackrat(pattern, name, log) {
        return sponsor(PEG.packrat(pattern, name, log));
    };
    kit.scope = kit.namespace = function newNamespace(log) {
        var ns = PEG.namespace(log);
        ns.factory = kit;
        ns.call = function aCall(name) {
            return sponsor(ns.lookup(name));
        };
        return ns;
    };
    kit.matcher = kit.match = kit.start = function aMatcher(pattern, ok, fail) {
        return sponsor(PEG.start(pattern, ok, fail));
    };
    return kit;
};
<|endoftext|>


<commit_before>'use strict'

var fb    = new Firebase ('https://ticytacytoey.firebaseio.com/'),
    piece = 'x',
    board = {a1:'', a2:'', a3:'', b1:'', b2:'', b3:'', c1:'', c2:'', c3:''},
    winConditions;

$('tbody').on('click','td', function(event){
	var $td = $(this).closest("td");
	$td.text(piece);
	if(piece === 'x') {
		piece = 'o';
	} else {
		piece = 'x';
	}
board.a1 = $('#one').text();
board.a2 = $('#two').text();
board.a3 = $('#three').text();
board.b1 = $('#four').text();
board.b2 = $('#five').text();
board.b3 = $('#six').text();
board.c1 = $('#seven').text();
board.c2 = $('#eight').text();
board.c3 = $('#nine').text();
});
winConditions = [
    [board.a1, board.a2, board.a3],
    [board.b1, board.b2, board.b3],
    [board.c1, board.c2, board.c3],
    [board.a1, board.b1, board.c1],
    [board.a2, board.b2, board.c2],
    [board.a3, board.b3, board.c3],
    [board.a1, board.b2, board.c3],
    [board.a3, board.b2, board.c1],
    ];

//check td #id for value
//store value in board array

<commit_msg>add commented code for create table function in js<commit_after>'use strict'

var fb    = new Firebase ('https://ticytacytoey.firebaseio.com/'),
    piece = 'x',
    board = {a1:'', a2:'', a3:'', b1:'', b2:'', b3:'', c1:'', c2:'', c3:''},
    winConditions;

$('tbody').on('click','td', function(event){
	var $td = $(this).closest("td");
	$td.text(piece);
	if(piece === 'x') {
		piece = 'o';
	} else {
		piece = 'x';
	}
board.a1 = $('#one').text();
board.a2 = $('#two').text();
board.a3 = $('#three').text();
board.b1 = $('#four').text();
board.b2 = $('#five').text();
board.b3 = $('#six').text();
board.c1 = $('#seven').text();
board.c2 = $('#eight').text();
board.c3 = $('#nine').text();
winConditions = [
    [board.a1, board.a2, board.a3],
    [board.b1, board.b2, board.b3],
    [board.c1, board.c2, board.c3],
    [board.a1, board.b1, board.c1],
    [board.a2, board.b2, board.c2],
    [board.a3, board.b3, board.c3],
    [board.a1, board.b2, board.c3],
    [board.a3, board.b2, board.c1],
    ];
});

//var b = [['','',''],['','',''],['','','']];

// function render(b){
// 	var $table = $('

');

// b.forEach(function(row){
// 	var $tr = $('

');

// 		row.forEach(function(cell){
// 			$tr.append($(''+ cell +'	'));
// 		})
// 		$table.append($tr);
// 	})
// 	return $table;
// 	console.log('yup');
// };

// b[0][0] = $('#one').text();
// render(b);

//check td #id for value
//store value in board array

<|endoftext|>


<commit_before>/* global d3:true */
'use strict';

// Set chart dimensions, radius of chart based on smaller of two dimensions
var width = 360,
    height = 360,
    radius = Math.min(width, height) / 2,
    donutWidth = 75;

// Set legend variables
var legendRectSize = 18,
    legendSpacing = 4;

// Set color scale from D3
var color = d3.scale.category20b();
// Alternative: Set our own color scale
// var color = d3.scale.ordinal()
//               .range(['#hex1'..'#hex5']);

var svg = d3.select('#chart') // get DOM element with chart ID
            .append('svg')    // add an SVG to its end
            .attr('width', width) // set width...
            .attr('height', height) // ...and height
            .append('g') // append a 'g' element to the SVG and then center it
            .attr('transform', 'translate(' + (width / 2) + ',' + (height / 2) + ')');

// to define the chart's outer radius
var arc = d3.svg
            .arc()
            .innerRadius(radius - donutWidth)
            .outerRadius(radius);

// starting and ending angles of the segments - function to be called later
// return d.count to get the number from the dataset object
// disable sorting to prevent unintended consequences in the animation
var pie = d3.layout.pie()
            .value(function (d) { return d.count; })
            .sort(null);

var tooltip = d3.select('#chart')
                .append('div')
                .attr('class', 'd3-tooltip');

tooltip.append('div')
       .attr('class', 'label');

tooltip.append('div')
       .attr('class', 'count');

tooltip.append('div')
       .attr('class', 'percent');

// load data from a CSV file
var url = 'https://gist.githubusercontent.com/chrisbodhi/1670837485e27e6ec5d7/raw/7c4ab29f18f66ab7a7dd35e2958beba84849bbf3/parkingData.csv';
// var url = 'data.json' // ticket info
/*
d3.json(url, function(error, data){
  // set d.count to total number of tickets per user
  // set d.label to ticket.assignee.first_name
});
*/

d3.csv(url, function(error, dataset){
  dataset.forEach(function(d){
    d.count = +d.count;
    d.enabled = true;
  });

  // create the chart
  var path = svg.selectAll('path') // select all 'path' in g in the svg, but they don't exist yet
                .data(pie(dataset)) // associate dataset with path elements
                .enter() // creates a placeholder node for each dataset value
                .append('path') // replace placeholder with 'path' element
                .attr('d', arc) // define a d attribute for each path element
                .attr('fill', function(d, i){ // use the colorscale to fill each path
                  return color(d.data.label);
                })
                .each(function(d){ this._current = d; });

  // mouse event handlers for the tooltips
  path.on('mouseover', function(d){
    var total = d3.sum(dataset.map(function(d){
      return (d.enabled) ? d.count : 0;
    }));
    var percent = Math.round(1000 * d.data.count / total) / 10;
    tooltip.select('.label').html(d.data.label);
    tooltip.select('.count').html(d.data.count);
    tooltip.select('.percent').html(percent + '%');
    tooltip.style('display', 'block');
  });

  path.on('mouseout', function(d){
    tooltip.style('display', 'none');
  });

  // path.on('mousemove', function(d){
  //   tooltip.style('top', (d3.event.pageY + 10) + 'px')
  //          .style('left', (d3.event.pageX + 10) + 'px');
  // });

  // define and add the legend for the chart
  var legend = svg.selectAll('.legend') // select elements with legend class, but they don't exist yet
                  .data(color.domain()) // call data with arrays of labels from the dataset
                  .enter() // creates the placeholders
                  .append('g') // replace placeholders with the g elements
                  .attr('class', 'legend') // give each g element the legend class
                  .attr('transform', function(d, i){ // centers the legend
                    var height = legendRectSize + legendSpacing,
                        offset = height * color.domain().length / 2,
                        horz = -2 * legendRectSize, // shifts left of center
                        vert = i * height - offset;
                    return 'translate(' + horz + ',' + vert + ')';
                  });

  // Add the square and label for the legend
  legend.append('rect')
        .attr('width', legendRectSize)
        .attr('height', legendRectSize)
        .style('fill', color) // color('Abulia') returns '#393b79'
        .style('stroke', color)
        .on('click', function(label) {
          var rect = d3.select(this);
          var enabled = true;
          var totalEnabled = d3.sum(dataset.map(function(d) {
            return (d.enabled) ? 1 : 0;
          }));

          if (rect.attr('class') === 'disabled') {
            rect.attr('class', '');
          } else {
            if (totalEnabled < 2) return;
            rect.attr('class', 'disabled');
            enabled = false;
          }

          pie.value(function(d) {
            if (d.label === label) d.enabled = enabled;
            return (d.enabled) ? d.count : 0;
          });

          path = path.data(pie(dataset));

          path.transition()
            .duration(750)
            .attrTween('d', function(d) {
              var interpolate = d3.interpolate(this._current, d);
              this._current = interpolate(0);
              return function(t) {
                return arc(interpolate(t));
              };
            });
        });

  // Add the text to the legend
  legend.append('text')
        .attr('x', legendRectSize + legendSpacing)
        .attr('y', legendRectSize - legendSpacing)
        .text(function(d) { return d; });

});<commit_msg>Add call for JSON file that's holding ticket data.<commit_after>/* global d3:true */
'use strict';

// Set chart dimensions, radius of chart based on smaller of two dimensions
var width = 360,
    height = 360,
    radius = Math.min(width, height) / 2,
    donutWidth = 75;

// Set legend variables
var legendRectSize = 18,
    legendSpacing = 4;

// Set color scale from D3
var color = d3.scale.category20b();
// Alternative: Set our own color scale
// var color = d3.scale.ordinal()
//               .range(['#hex1'..'#hex5']);

var svg = d3.select('#chart') // get DOM element with chart ID
            .append('svg')    // add an SVG to its end
            .attr('width', width) // set width...
            .attr('height', height) // ...and height
            .append('g') // append a 'g' element to the SVG and then center it
            .attr('transform', 'translate(' + (width / 2) + ',' + (height / 2) + ')');

// to define the chart's outer radius
var arc = d3.svg
            .arc()
            .innerRadius(radius - donutWidth)
            .outerRadius(radius);

// starting and ending angles of the segments - function to be called later
// return d.count to get the number from the dataset object
// disable sorting to prevent unintended consequences in the animation
var pie = d3.layout.pie()
            .value(function (d) { return d.count; })
            .sort(null);

var tooltip = d3.select('#chart')
                .append('div')
                .attr('class', 'd3-tooltip');

tooltip.append('div')
       .attr('class', 'label');

tooltip.append('div')
       .attr('class', 'count');

tooltip.append('div')
       .attr('class', 'percent');

// load data from a CSV file
// var url = 'https://gist.githubusercontent.com/chrisbodhi/1670837485e27e6ec5d7/raw/7c4ab29f18f66ab7a7dd35e2958beba84849bbf3/parkingData.csv';
var url = 'scripts/tickets.json'; // ticket info
/*
d3.json(url, function(error, data){
  // set d.count to total number of tickets per user
  // set d.label to ticket.assignee.first_name
});
*/
$.get(url).then(function(dataset){

// d3.json(data, function(error, dataset){
  dataset.forEach(function(d){
    d.count = +d.count;
    d.enabled = true;
  });

  // create the chart
  var path = svg.selectAll('path') // select all 'path' in g in the svg, but they don't exist yet
                .data(pie(dataset)) // associate dataset with path elements
                .enter() // creates a placeholder node for each dataset value
                .append('path') // replace placeholder with 'path' element
                .attr('d', arc) // define a d attribute for each path element
                .attr('fill', function(d, i){ // use the colorscale to fill each path
                  return color(d.data.label);
                })
                .each(function(d){ this._current = d; });

  // mouse event handlers for the tooltips
  path.on('mouseover', function(d){
    var total = d3.sum(dataset.map(function(d){
      return (d.enabled) ? d.count : 0;
    }));
    var percent = Math.round(1000 * d.data.count / total) / 10;
    tooltip.select('.label').html(d.data.label);
    tooltip.select('.count').html(d.data.count);
    tooltip.select('.percent').html(percent + '%');
    tooltip.style('display', 'block');
  });

  path.on('mouseout', function(d){
    tooltip.style('display', 'none');
  });

  // path.on('mousemove', function(d){
  //   tooltip.style('top', (d3.event.pageY + 10) + 'px')
  //          .style('left', (d3.event.pageX + 10) + 'px');
  // });

  // define and add the legend for the chart
  var legend = svg.selectAll('.legend') // select elements with legend class, but they don't exist yet
                  .data(color.domain()) // call data with arrays of labels from the dataset
                  .enter() // creates the placeholders
                  .append('g') // replace placeholders with the g elements
                  .attr('class', 'legend') // give each g element the legend class
                  .attr('transform', function(d, i){ // centers the legend
                    var height = legendRectSize + legendSpacing,
                        offset = height * color.domain().length / 2,
                        horz = -2 * legendRectSize, // shifts left of center
                        vert = i * height - offset;
                    return 'translate(' + horz + ',' + vert + ')';
                  });

  // Add the square and label for the legend
  legend.append('rect')
        .attr('width', legendRectSize)
        .attr('height', legendRectSize)
        .style('fill', color) // color('Abulia') returns '#393b79'
        .style('stroke', color)
        .on('click', function(label) {
          var rect = d3.select(this);
          var enabled = true;
          var totalEnabled = d3.sum(dataset.map(function(d) {
            return (d.enabled) ? 1 : 0;
          }));

          if (rect.attr('class') === 'disabled') {
            rect.attr('class', '');
          } else {
            if (totalEnabled < 2) {return;}
            rect.attr('class', 'disabled');
            enabled = false;
          }

          pie.value(function(d) {
            if (d.label === label) {d.enabled = enabled;}
            return (d.enabled) ? d.count : 0;
          });

          path = path.data(pie(dataset));

          path.transition()
            .duration(750)
            .attrTween('d', function(d) {
              var interpolate = d3.interpolate(this._current, d);
              this._current = interpolate(0);
              return function(t) {
                return arc(interpolate(t));
              };
            });
        });

  // Add the text to the legend
  legend.append('text')
        .attr('x', legendRectSize + legendSpacing)
        .attr('y', legendRectSize - legendSpacing)
        .text(function(d) { return d; });

});<|endoftext|>


<commit_before>/* global bible */
/* global Spinner */
/* global planner */
/* global saveAs */

'use strict';

// tests
console.groupCollapsed('App tests');
console.log('Running jQuery %s', $().jquery);
console.log(bible);
var ref = bible.parseReference('rom 1:4');
console.log(bible.add(ref, 10).toString());
console.groupEnd();

/**
 * Contants
 */
var READING_PLANS = '../bower_components/readingplans';
var FILENAME = 'BibleReadingPlan';

/**
 * Helper functions
 */

/**
 * Get skipped days checked
 * @return {array} Array of skipped days
 */
function getSkippedDays () {
    var opts = [];
    $('#skip-checkboxes input:checked').each(function (i, input) {
        opts.push(input.value);
    });
    return opts;
}

/**
 * Gets name from each plan and add to list
 * @param {string} plan Filename of plan to load
 */
function setSequences (sequence) {
    $.getJSON(READING_PLANS + '/' + sequence)
    .done(function(json) {
        var plan = '' + json.name + '';
        $('#sequence').append(plan);

        // select functionality
        $('.list-group-item').click(function () {
            $('.list-group-item').each(function () {
                $(this).removeClass('active');
            });

            $(this).addClass('active');
        });
    });
}

/**
 * Shows error message
 * @param  {string} message Error message
 */
function showError(message) {
    var errorMessage = '
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + message + '
';
    $('#wait').hide();
    $('div .alert').remove();
    $('#wait').parent().append(errorMessage);
    document.getElementById('wait').scrollIntoView() ;
}

/**
 * Get data from page elements
 * @return {array} Array of the user data
 */
function getPlannerData () {
    var data = {};

    // sequence name
    data.sequenceName = $('.list-group-item.active').attr('name');

    // beginning
    data.begin = $('#calendar-start').datepicker('getDate');

    // end
    data.end = $('#calendar-end').datepicker('getDate');

    // days to skip
    var opts = [];
    $('#skip-checkboxes input:checked').each(function (i, input) {
        opts.push(Number(input.value));
    });

    data.skip = opts;

    // type
    data.type = $('#type :radio:checked').attr('id');

    // amount
    data.amount = (data.type === 'specified') ? $('#amountSpecified :radio:checked').attr('id') : $('#amountNumber').val();

    console.info('Data ' + JSON.stringify(data));
    return data;
}

/**
 * Creates output of plan
 * @param  {object} plan        Bible reading plan
 * @param  {string} destination Type of destination to create output for
 * @return {string}             Formated bible reading plan
 */
function output (plan, destination) {
    switch (destination) {
    case 'pdf':
    case 'text':
    case 'markdown':
    case 'ical':
        console.error('Not implemented yet.');
        break;
    case 'dom':
        var rows = '';
        for (var i = 0; i < plan.length; i++) {
            rows = rows + '
' + plan[i].day + '	';
            for(var n = 0; n < plan[i].refs.length; n++) {
                rows = rows + plan[i].refs[n];
                // rows = rows + plan[i].refs[n].toString();

                // don't put a comma after the last element
                if( n < plan[i].refs.length - 1) {
                    rows = rows + ', ';
                }
            }

            rows = rows + '
';
        }
        return rows;
    default:
        break;
    }
}

/**
 * UI construct
 */

// Load plans
$.ajax({
    url: READING_PLANS,
    type: 'GET',
})
.done(function(data) {
    var plans = [];

    $(data).find('a:contains(.json)').each(function() {
        plans.push($(this).attr('title'));
    });

    for (var i = 0; i < plans.length; i++) {
        setSequences(plans[i]);
    }
})
.fail(function() {
    console.error('error loading bible reading plan');
    var plan = 'Error Loading Plans';
    $('#sequence').append(plan);
});

// calendars
$('#calendar-start').datepicker({
    'todayHighlight': true,
    'startDate': new Date()
});

$('#calendar-start').datepicker('update', new Date());

$('#calendar-end').datepicker({
    'todayHighlight': true,
    'startDate': new Date()
});

var initEndDate = new Date();
initEndDate.setDate(initEndDate.getDate() + 30);
$('#calendar-end').datepicker('update', initEndDate);

// the end cannot be before the start
$('#calendar-start').change(function() {
    $('#calendar-end').datepicker('setStartDate', $('#calendar-start').datepicker('getDate'));
});

// the start cannot be after the end
$('#calendar-end').change(function() {
    $('#calendar-start').datepicker('setEndDate', $('#calendar-end').datepicker('getDate'));
});

// disable days
$('#skip-checkboxes').change(function () {
    $('#calendar-start').datepicker('setDaysOfWeekDisabled', getSkippedDays());
    $('#calendar-end').datepicker('setDaysOfWeekDisabled', getSkippedDays());
});

// radio buttons
$('#type input[type=radio]').change(function () {
    if ( this.id === 'specified' ) {
        $('#amountNumber').hide();
        $('#amountSpecified').show();
    }
    else {
        $('#amountNumber').show();
        $('#amountSpecified').hide();
    }
});

/**
 * User actions
 */

$('#sequence').click(function (e) {
    e.preventDefault();
});

$('#legal').click(function (e) {
    e.preventDefault();
    $('.legal').show();
});

// create plan
$('#create').click(function() {
    $('#wait').show();
    // Show spinner while waiting
    var opts = {
        lines: 13,
        length: 15,
        width: 5,
        radius: 15,
        corners: 1,
        rotate: 0,
        direction: 1,
        color: '#000',
        speed: 1,
        trail: 40,
        shadow: false,
        hwaccel: false,
        className: 'spinner'
    };
    var wait = document.getElementById('wait');
    var spinner;
    // don't add another spiner if one exists
    if (!wait.firstElementChild) {
        spinner = new Spinner(opts).spin(wait);
    }

    try {
        $('.alert').remove();

        var data = getPlannerData();
        planner.set(data);
        planner.create();
        var rows = output(planner.plan, 'dom');

        spinner.stop();
        $('#wait').hide();

        if (rows) {
            $('tbody').children().remove();
        }
        $('tbody').append(rows);
        $('.plan').addClass('fade');

        document.getElementById('plan').scrollIntoView();
    }
    catch(err) {
        console.error(err);
        spinner.stop();
        showError(err);
    }
});

// download as text
$('#downloadText').click(function(event) {
    event.preventDefault();
    var text = '';
    $('tbody td').each(function( index ) {
        text = (index%2 === 0) ? text + $(this).text().trim() : text + ': ' + $(this).text().trim() + '\n';
    });
    var blob = new Blob([text], {type: 'text/plain;charset=utf-8'});
    saveAs(blob, FILENAME + '.txt');
});

// download as markdown
$('#downloadMarkdown').click(function(event) {
    event.preventDefault();
    var text = '';
    $('tbody td').each(function( index ) {
        text = (index%2 === 0) ? text + '**' + $(this).text().trim() + '**' : text + ': ' + $(this).text().trim() + '  \n';
    });
    var blob = new Blob([text], {type: 'text/plain;charset=utf-8'});
    saveAs(blob, FILENAME + '.md');
});

// download as ics
$('#downloadIcs').click(function(event) {
    event.preventDefault();
    $.getScript('/scripts/ics.js')
        .done(function() {
            var cal = ics();
            $('tbody tr').each(function (index, el) {
                var day = moment(el.cells[0].innerText, 'MMMM DD, YYYY');
                var start = moment(day).format('YYYY/MM/DD');
                var end = moment(day).add('d', 1).format('YYYY/MM/DD');
                var description = el.cells[1].innerText;
                var subject = 'Bible Reading';
                var location = 'Your Bible';
                cal.addEvent(subject, description, location, start, end);
            });
            cal.download(FILENAME);
        })
        .fail(function(err) {
            showError(err);
            console.log(err);
        });
});

//sdg
<commit_msg>refactor downloads<commit_after>/* global bible */
/* global Spinner */
/* global planner */
/* global saveAs */
/* global moment */
/* global ics */

'use strict';

// tests
console.groupCollapsed('App tests');
console.log('Running jQuery %s', $().jquery);
console.log(bible);
var ref = bible.parseReference('rom 1:4');
console.log(bible.add(ref, 10).toString());
console.groupEnd();

/**
 * Contants
 */
var READING_PLANS = '../bower_components/readingplans';
var FILENAME = 'BibleReadingPlan';
var SEPARATOR = (navigator.appVersion.indexOf('Win') !== -1) ? '\r\n' : '\n';

/**
 * Helper functions
 */

/**
 * Get skipped days checked
 * @return {array} Array of skipped days
 */
function getSkippedDays () {
    var opts = [];
    $('#skip-checkboxes input:checked').each(function (i, input) {
        opts.push(input.value);
    });
    return opts;
}

/**
 * Gets name from each plan and add to list
 * @param {string} plan Filename of plan to load
 */
function setSequences (sequence) {
    $.getJSON(READING_PLANS + '/' + sequence)
    .done(function(json) {
        var plan = '' + json.name + '';
        $('#sequence').append(plan);

        // select functionality
        $('.list-group-item').click(function () {
            $('.list-group-item').each(function () {
                $(this).removeClass('active');
            });

            $(this).addClass('active');
        });
    });
}

/**
 * Shows error message
 * @param  {string} message Error message
 */
function showError(message) {
    var errorMessage = '
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + message + '
';
    $('#wait').hide();
    $('div .alert').remove();
    $('#wait').parent().append(errorMessage);
    document.getElementById('wait').scrollIntoView() ;
}

/**
 * Get data from page elements
 * @return {array} Array of the user data
 */
function getPlannerData () {
    var data = {};

    // sequence name
    data.sequenceName = $('.list-group-item.active').attr('name');

    // beginning
    data.begin = $('#calendar-start').datepicker('getDate');

    // end
    data.end = $('#calendar-end').datepicker('getDate');

    // days to skip
    var opts = [];
    $('#skip-checkboxes input:checked').each(function (i, input) {
        opts.push(Number(input.value));
    });

    data.skip = opts;

    // type
    data.type = $('#type :radio:checked').attr('id');

    // amount
    data.amount = (data.type === 'specified') ? $('#amountSpecified :radio:checked').attr('id') : $('#amountNumber').val();

    console.info('Data ' + JSON.stringify(data));
    return data;
}

/**
 * Creates output of plan
 * @param  {object} plan        Bible reading plan
 * @param  {string} destination Type of destination to create output for
 * @return {string}             Formated bible reading plan
 */
function output (plan, destination) {
    switch (destination) {
    case 'pdf':
    case 'text':
    case 'markdown':
    case 'ical':
        console.error('Not implemented yet.');
        break;
    case 'dom':
        var rows = '';
        for (var i = 0; i < plan.length; i++) {
            rows = rows + '
' + plan[i].day + '	';
            for(var n = 0; n < plan[i].refs.length; n++) {
                rows = rows + plan[i].refs[n];
                // rows = rows + plan[i].refs[n].toString();

                // don't put a comma after the last element
                if( n < plan[i].refs.length - 1) {
                    rows = rows + ', ';
                }
            }

            rows = rows + '
';
        }
        return rows;
    default:
        break;
    }
}

/**
 * UI construct
 */

// Load plans
$.ajax({
    url: READING_PLANS,
    type: 'GET',
})
.done(function(data) {
    var plans = [];

    $(data).find('a:contains(.json)').each(function() {
        plans.push($(this).attr('title'));
    });

    for (var i = 0; i < plans.length; i++) {
        setSequences(plans[i]);
    }
})
.fail(function() {
    console.error('error loading bible reading plan');
    var plan = 'Error Loading Plans';
    $('#sequence').append(plan);
});

// calendars
$('#calendar-start').datepicker({
    'todayHighlight': true,
    'startDate': new Date()
});

$('#calendar-start').datepicker('update', new Date());

$('#calendar-end').datepicker({
    'todayHighlight': true,
    'startDate': new Date()
});

var initEndDate = new Date();
initEndDate.setDate(initEndDate.getDate() + 30);
$('#calendar-end').datepicker('update', initEndDate);

// the end cannot be before the start
$('#calendar-start').change(function() {
    $('#calendar-end').datepicker('setStartDate', $('#calendar-start').datepicker('getDate'));
});

// the start cannot be after the end
$('#calendar-end').change(function() {
    $('#calendar-start').datepicker('setEndDate', $('#calendar-end').datepicker('getDate'));
});

// disable days
$('#skip-checkboxes').change(function () {
    $('#calendar-start').datepicker('setDaysOfWeekDisabled', getSkippedDays());
    $('#calendar-end').datepicker('setDaysOfWeekDisabled', getSkippedDays());
});

// radio buttons
$('#type input[type=radio]').change(function () {
    if ( this.id === 'specified' ) {
        $('#amountNumber').hide();
        $('#amountSpecified').show();
    }
    else {
        $('#amountNumber').show();
        $('#amountSpecified').hide();
    }
});

/**
 * User actions
 */

$('#sequence').click(function (e) {
    e.preventDefault();
});

$('#legal').click(function (e) {
    e.preventDefault();
    $('.legal').show();
});

// create plan
$('#create').click(function() {
    $('#wait').show();
    // Show spinner while waiting
    var opts = {
        lines: 13,
        length: 15,
        width: 5,
        radius: 15,
        corners: 1,
        rotate: 0,
        direction: 1,
        color: '#000',
        speed: 1,
        trail: 40,
        shadow: false,
        hwaccel: false,
        className: 'spinner'
    };
    var wait = document.getElementById('wait');
    var spinner;
    // don't add another spiner if one exists
    if (!wait.firstElementChild) {
        spinner = new Spinner(opts).spin(wait);
    }

    try {
        $('.alert').remove();

        var data = getPlannerData();
        planner.set(data);
        planner.create();
        var rows = output(planner.plan, 'dom');

        spinner.stop();
        $('#wait').hide();

        if (rows) {
            $('tbody').children().remove();
        }
        $('tbody').append(rows);
        $('.plan').addClass('fade');

        document.getElementById('plan').scrollIntoView();
    }
    catch(err) {
        console.error(err);
        spinner.stop();
        showError(err);
    }
});

// download as text
$('#downloadText').click(function(event) {
    event.preventDefault();
    var text = '';
    $('tbody tr').each(function( index, el ) {
        text += el.cells[0].innerText + ': ' + el.cells[1].innerText + SEPARATOR;
    });
    var blob = new Blob([text], {type: 'text/plain;charset=utf-8'});
    saveAs(blob, FILENAME + '.txt');
});

// download as markdown
$('#downloadMarkdown').click(function(event) {
    event.preventDefault();
    var text = '';
    $('tbody tr').each(function( index, el ) {
        text += '**' + el.cells[0].innerText + '**: ' + el.cells[1].innerText + SEPARATOR;
    });
    var blob = new Blob([text], {type: 'text/plain;charset=utf-8'});
    saveAs(blob, FILENAME + '.md');
});

// download as ics
$('#downloadIcs').click(function(event) {
    event.preventDefault();
    $.getScript('/scripts/ics.js')
        .done(function() {
            var cal = ics();
            $('tbody tr').each(function (index, el) {
                var day = moment(el.cells[0].innerText, 'MMMM DD, YYYY');
                var start = moment(day).format('YYYY/MM/DD');
                var end = moment(day).add('d', 1).format('YYYY/MM/DD');
                var description = el.cells[1].innerText;
                var subject = 'Bible Reading';
                var location = 'Your Bible';
                cal.addEvent(subject, description, location, start, end);
            });
            cal.download(FILENAME);
        })
        .fail(function(err) {
            showError(err);
            console.log(err);
        });
});

//sdg
<|endoftext|>


<commit_before>/*
 * name: main.js
 * Authors: Tanner Garrett, Brandon Thepvongsa
 * Discription: JavaScript used to create the functionality of FolderDocs
*/

$(document).ready(function() {
	$("#dboxButton").on("click", connectDropbox);
	if(getClient()) {
		$(".jumbotron").hide();
	}
});

var
	im,
	associations,
	dropboxClientCredentials,
	dropboxClient;

dropboxClientCredentials = {
	key: config.key,
	secret: config.secret
};

dropboxClient = new Dropbox.Client(dropboxClientCredentials);

dropboxClient.authDriver(new Dropbox.AuthDriver.Redirect({
	rememberUser: true
}));

var authenticatedClient = null;

function getClient() {
	return authenticatedClient;
}

// Constructs the root ItemMirror object from the root of the Dropbox.
function constructIMObject() {
	dropboxXooMLUtility = {
		fragmentURI: '/XooML2.xml',
		driverURI: 'DropboxXooMLUtility',
		dropboxClient: dropboxClient
	};
	dropboxItemUtility = {
		driverURI: 'DropboxItemUtility',
		dropboxClient: dropboxClient
	};
	mirrorSyncUtility = {
		utilityURI: 'MirrorSyncUtility'
	};
	var options = {
		groupingItemURI: "/",
		xooMLDriver: dropboxXooMLUtility,
		itemDriver: dropboxItemUtility,
		syncDriver: mirrorSyncUtility
	};
	var im = new ItemMirror(options, function(error, newMirror) {
		if(error) {
			console.log(error);
		} else {
			im = newMirror
			console.log(im);
		}
	});
}

// Directs the client to Dropbox's authentication page to sign in.
function connectDropbox() {
	if(authenticatedClient) {
		console.log('Dropbox authenticated');
	} else {
		console.log('Dropbox authenticating...');
		dropboxClient.authenticate(function (error, client) {
			if(error) {
				console.log('Dropbox failed to authenticate');
			} else {
				authenticatedClient = client;
				console.log('Dropbox authenticated');
			}
		});
	}
}

// Signs current client out of Dropbox
function disconnectDropbox() {
	dropboxClient.signOut();
}

// Deletes all elements in the display, then populates the list with paragraphs for each
// association (WiP).
function refreshIMDisplay() {
	var entryDisplayName;
	$("#display").empty();
	im.listAssociations(function(GUIDs) {
		associations = GUIDs;
	});
	associations.forEach(function(entry) {
		im.getDisplayName(function(displayName) {
			entryDisplayName = displayName;
		});
		$("#display").append("
" + entryDisplayName + "
");
	});
}<commit_msg>Fetches associations and displays displaytext<commit_after>/*
 * name: main.js
 * Authors: Tanner Garrett, Brandon Thepvongsa
 * Discription: JavaScript used to create the functionality of FolderDocs
*/

$(document).ready(function() {
	$("#dboxButton").on("click", connectDropbox);
	if(getClient()) {
		$(".jumbotron").hide();
	}
});

var
	im,
	associations,
	dropboxClientCredentials,
	dropboxClient;

dropboxClientCredentials = {
	key: config.key,
	secret: config.secret
};

dropboxClient = new Dropbox.Client(dropboxClientCredentials);

dropboxClient.authDriver(new Dropbox.AuthDriver.Redirect({
	rememberUser: true
}));

var authenticatedClient = null;

function getClient() {
	return authenticatedClient;
}

// Constructs the root ItemMirror object from the root of the Dropbox.
function constructIMObject() {
	dropboxXooMLUtility = {
		fragmentURI: '/XooML2.xml',
		driverURI: 'DropboxXooMLUtility',
		dropboxClient: dropboxClient
	};
	dropboxItemUtility = {
		driverURI: 'DropboxItemUtility',
		dropboxClient: dropboxClient
	};
	mirrorSyncUtility = {
		utilityURI: 'MirrorSyncUtility'
	};
	var options = {
		groupingItemURI: "/",
		xooMLDriver: dropboxXooMLUtility,
		itemDriver: dropboxItemUtility,
		syncDriver: mirrorSyncUtility
	};
	im = new ItemMirror(options, function(error, newMirror) {
		if(error) {
			console.log(error);
		} else {
			im = newMirror
			console.log(im);
			refreshIMDisplay();
		}
	});
}

// Directs the client to Dropbox's authentication page to sign in.
function connectDropbox() {
	if(authenticatedClient) {
		console.log('Dropbox authenticated');
	} else {
		console.log('Dropbox authenticating...');
		dropboxClient.authenticate(function (error, client) {
			if(error) {
				console.log('Dropbox failed to authenticate');
			} else {
				authenticatedClient = client;
				console.log('Dropbox authenticated');
				constructIMObject();
			}
		});
	}
}

// Signs current client out of Dropbox
function disconnectDropbox() {
	dropboxClient.signOut();
}

// Deletes all elements in the display, then populates the list with paragraphs for each
// association (WiP).
function refreshIMDisplay() {
	var entryDisplayName;
	$("#display").empty();
	// im.listAssociations(function(GUIDs) {
	// 	associations = GUIDs;
	// });
	associations = im.listAssociations();
	var length = associations.length;

	for(var i = 0; i < length; i++) {
		var displayText = im.getAssociationDisplayText(associations[i]);
		$("#display").append("
" + displayText + "
");
	}

	// associations.forEach(function(entry) {
	// 	im.getDisplayName(function(displayName) {
	// 		entryDisplayName = displayName;
	// 	});
	// 	$("#display").append("
" + entryDisplayName + "
");
	// });
}<|endoftext|>


<commit_before>'use strict';

// Retrieve the main menu and its childern
$(function() {
  var $menu = $('.categories-menu .dropdown-menu-right');
  var slideDuration = 500;

  // Open / close main menu nav
  $('#heading-categories-menu, .gray-overlay').click(function() {
    $('body').toggleClass('categories-menu-open');
  });

  $.ajax({url: '/catalogs'}) // Append path to mark active
    .done(function(data) {
      $menu.html(data);

      // Expand menus
      $('.expand').on('click', function() {
        var $use = $(this).find('use');
        var $ul = $(this).closest('li').children('ul');
        if ($use.attr('xlink:href') === '#icon-plus') {
          $ul.slideDown(slideDuration, function() {
            $use.attr('xlink:href', '#icon-minus');
          });
        } else {
          $ul.slideUp(slideDuration, function() {
            $use.attr('xlink:href', '#icon-plus');
          });
        }
        return false;
      });
    })
    .fail(function() {
      var message =
        'Uups, der skete en fejl. Prøv at genindlæse siden.';
      $('.categories-menu .dropdown-menu-right').html(
        '
' + message + '
'
      );
    });
});
<commit_msg>faster slide<commit_after>'use strict';

// Retrieve the main menu and its childern
$(function() {
  var $menu = $('.categories-menu .dropdown-menu-right');
  var slideDuration = 200;

  // Open / close main menu nav
  $('#heading-categories-menu, .gray-overlay').click(function() {
    $('body').toggleClass('categories-menu-open');
  });

  $.ajax({url: '/catalogs'}) // Append path to mark active
    .done(function(data) {
      $menu.html(data);

      // Expand menus
      $('.expand').on('click', function() {
        var $use = $(this).find('use');
        var $ul = $(this).closest('li').children('ul');
        if ($use.attr('xlink:href') === '#icon-plus') {
          $ul.slideDown(slideDuration, function() {
            $use.attr('xlink:href', '#icon-minus');
          });
        } else {
          $ul.slideUp(slideDuration, function() {
            $use.attr('xlink:href', '#icon-plus');
          });
        }
        return false;
      });
    })
    .fail(function() {
      var message =
        'Uups, der skete en fejl. Prøv at genindlæse siden.';
      $('.categories-menu .dropdown-menu-right').html(
        '
' + message + '
'
      );
    });
});
<|endoftext|>


<commit_before>'use strict';

/**
 */
angular.module('openolitor-kundenportal')
  .controller('OpenOlitorRootController', ['$scope', '$rootScope',
    'ServerService', 'ProjektService', 'gettextCatalog', 'amMoment',
    '$location', 'msgBus', 'checkSize', '$window', '$timeout', 'BUILD_NR',
    'ENV', 'VERSION',
    'ooAuthService', 'API_URL', '$cookies', 'dialogService',
    function($scope, $rootScope, ServerService, ProjektService,
      gettextCatalog, amMoment, $location, msgBus, checkSize, $window,
      $timeout, BUILD_NR, ENV, VERSION, ooAuthService, API_URL,
      $cookies, dialogService) {
      angular.element($window).bind('resize', function() {
        checkSize();
      });

      $scope.welcomeDisplayed = false;

      $scope.currentPathContains = function(pathJunk) {
        return $location.url().indexOf(pathJunk) !== -1;
      };

      //initial launch
      checkSize();

      $scope.connected = false;

      var unwatchLoggedIn = $scope.$watch(function() {
        return ooAuthService.getUser();
      }, function(user) {
        $scope.loggedIn = ooAuthService.isUserLoggedIn(user);
        $scope.user = user;

        if ($scope.loggedIn) {
          ProjektService.resolveProjekt(false).then(function(projekt) {
            $scope.projekt = projekt;
            $rootScope.projekt = projekt;
            $scope.checkWelcomeMessage();
          });
        } else {
          ProjektService.resolveProjekt(true).then(function(projekt) {
            $scope.projekt = projekt;
            $rootScope.projekt = projekt;
          });
        }
      });

      var unwatchStaticServerInfo = $scope.$watch(ServerService.getStaticServerInfo,
        function(info) {
          if (!angular.isUndefined(info)) {
            $scope.serverInfo = info;
            $scope.connected = true;
          }
        });

      $scope.buildNr = BUILD_NR;
      $scope.env = ENV;
      $scope.version = VERSION;

      msgBus.onMsg('WebSocketClosed', $rootScope, function(event, msg) {
        $scope.connected = false;
        $scope.messagingSocketClosedReason = msg.reason;
        $timeout(function() {
          $scope.showConnectionErrorMessage = true;
        }, 30000);
        $scope.$apply();
      });

      msgBus.onMsg('WebSocketOpen', $rootScope, function() {
        $scope.connected = true;
        $scope.showConnectionErrorMessage = false;
        $scope.messagingSocketClosedReason = '';
        $scope.$apply();
      });

      $scope.changeLang = function(lang) {
        if (!angular.isUndefined(lang)) {

          msgBus.emitMsg({
            type: 'ChangeLang',
            reason: lang
          });
          $scope.storeActiveLang(lang);
          $scope.$emit('languageChanged');
        }
      };

      msgBus.onMsg('ChangeLang', $rootScope, function(event, msg) {
        gettextCatalog.setCurrentLanguage(msg.reason);
      });

      $scope.activeLang = function() {
        return gettextCatalog.getCurrentLanguage();
      };

      $scope.storedActiveLang = function() {
        return $cookies.get('activeLang');
      };

      $scope.storeActiveLang = function(lang) {
        $cookies.put('activeLang', lang);
      };

      if (angular.isUndefined($scope.storedActiveLang())) {
        var lang = $window.navigator.language || $window.navigator.userLanguage;
        if (lang.indexOf('de-') > 0) {
          $scope.changeLang('de');
        } else if (lang.indexOf('fr-') > 0) {
          $scope.changeLang('fr');
        } else if (lang.indexOf('en-') > 0) {
          $scope.changeLang('en');
        } else {
          $scope.changeLang('de');
        }
      } else {
        $scope.changeLang($scope.storedActiveLang());
      }

      $scope.checkWelcomeMessage = function() {
        if (!$scope.welcomeDisplayed) {
          $scope.welcomeDisplayed = true;
          if ($scope.projekt.welcomeMessage2) {
            dialogService.displayDialogOkAbort(
              $scope.projekt.welcomeMessage2,
              function() {},
              'Mitteilung',
              true,
              'Schliessen'
            );
          }
        }
      };

      $scope.$on('destroy', function() {
        unwatchLoggedIn();
        unwatchStaticServerInfo();
      });
    }
  ]);<commit_msg>fix/OO-#24_fixing_default_language<commit_after>'use strict';

/**
 */
angular.module('openolitor-kundenportal')
  .controller('OpenOlitorRootController', ['$scope', '$rootScope',
    'ServerService', 'ProjektService', 'gettextCatalog', 'amMoment',
    '$location', 'msgBus', 'checkSize', '$window', '$timeout', 'BUILD_NR',
    'ENV', 'VERSION',
    'ooAuthService', 'API_URL', '$cookies', 'dialogService',
    function($scope, $rootScope, ServerService, ProjektService,
      gettextCatalog, amMoment, $location, msgBus, checkSize, $window,
      $timeout, BUILD_NR, ENV, VERSION, ooAuthService, API_URL,
      $cookies, dialogService) {
      angular.element($window).bind('resize', function() {
        checkSize();
      });

      $scope.welcomeDisplayed = false;

      $scope.currentPathContains = function(pathJunk) {
        return $location.url().indexOf(pathJunk) !== -1;
      };

      //initial launch
      checkSize();

      $scope.connected = false;

      var unwatchLoggedIn = $scope.$watch(function() {
        return ooAuthService.getUser();
      }, function(user) {
        $scope.loggedIn = ooAuthService.isUserLoggedIn(user);
        $scope.user = user;

        if ($scope.loggedIn) {
          ProjektService.resolveProjekt(false).then(function(projekt) {
            $scope.projekt = projekt;
            $rootScope.projekt = projekt;
            $scope.checkWelcomeMessage();
          });
        } else {
          ProjektService.resolveProjekt(true).then(function(projekt) {
            $scope.projekt = projekt;
            $rootScope.projekt = projekt;
          });
        }
      });

      var unwatchStaticServerInfo = $scope.$watch(ServerService.getStaticServerInfo,
        function(info) {
          if (!angular.isUndefined(info)) {
            $scope.serverInfo = info;
            $scope.connected = true;
          }
        });

      $scope.buildNr = BUILD_NR;
      $scope.env = ENV;
      $scope.version = VERSION;

      msgBus.onMsg('WebSocketClosed', $rootScope, function(event, msg) {
        $scope.connected = false;
        $scope.messagingSocketClosedReason = msg.reason;
        $timeout(function() {
          $scope.showConnectionErrorMessage = true;
        }, 30000);
        $scope.$apply();
      });

      msgBus.onMsg('WebSocketOpen', $rootScope, function() {
        $scope.connected = true;
        $scope.showConnectionErrorMessage = false;
        $scope.messagingSocketClosedReason = '';
        $scope.$apply();
      });

      $scope.changeLang = function(lang) {
        if (!angular.isUndefined(lang)) {

          msgBus.emitMsg({
            type: 'ChangeLang',
            reason: lang
          });
          $scope.storeActiveLang(lang);
          $scope.$emit('languageChanged');
        }
      };

      msgBus.onMsg('ChangeLang', $rootScope, function(event, msg) {
        gettextCatalog.setCurrentLanguage(msg.reason);
      });

      $scope.activeLang = function() {
        return gettextCatalog.getCurrentLanguage();
      };

      $scope.storedActiveLang = function() {
        return $cookies.get('activeLang');
      };

      $scope.storeActiveLang = function(lang) {
        $cookies.put('activeLang', lang);
      };

      if (angular.isUndefined($scope.storedActiveLang())) {
        var lang = $window.navigator.language || $window.navigator.userLanguage;
        if (lang.indexOf('de-CH') >= 0) {
          $scope.changeLang('de_CH');
        } else if (lang.indexOf('de-DE') >= 0) {
          $scope.changeLang('de_DE');
        } else if (lang.indexOf('de-') >= 0) {
          $scope.changeLang('de_DE');
        } else if (lang.indexOf('fr-BE') >= 0) {
          $scope.changeLang('fr_BE');
        } else if (lang.indexOf('fr-CH') >= 0) {
          $scope.changeLang('fr_CH');
        } else if (lang.indexOf('fr-') >= 0) {
          $scope.changeLang('fr_CH');
        } else if (lang.indexOf('en-') >= 0) {
          $scope.changeLang('en');
        } else if (lang.indexOf('es-') >= 0) {
          $scope.changeLang('es');
        } else if (lang.indexOf('cs-') >= 0) {
          $scope.changeLang('cs');
        } else if (lang.indexOf('hu-') >= 0) {
          $scope.changeLang('hu');
        } else {
          $scope.changeLang('en');
        }
      } else {
        $scope.changeLang($scope.storedActiveLang());
      }

      $scope.checkWelcomeMessage = function() {
        if (!$scope.welcomeDisplayed) {
          $scope.welcomeDisplayed = true;
          if ($scope.projekt.welcomeMessage2) {
            dialogService.displayDialogOkAbort(
              $scope.projekt.welcomeMessage2,
              function() {},
              'Mitteilung',
              true,
              'Schliessen'
            );
          }
        }
      };

      $scope.$on('destroy', function() {
        unwatchLoggedIn();
        unwatchStaticServerInfo();
      });
    }
  ]);
<|endoftext|>


<commit_before>/**
 * Talisman stats/ngrams
 * ======================
 *
 * Functions related to ngrams' computation.
 */
import {seq} from '../helpers';

/**
 * Identity function used as placeholder.
 */
const identity = x => x;

/**
 * Function taking a sequence and computing its ngrams.
 *
 * @param  {number}  n         - Nb of elements in the subsequence.
 * @param  {mixed}   sequence  - The sequence to process.
 * @param  {function} [hasher] - A function optionally used to hash the ngrams.
 * @return {array}             - The array of resulting ngrams.
 *
 * @throws {Error} The function expects a positive n > 0.
 */
export default function ngrams(n, sequence, hasher) {
  if (n < 1)
    throw Error('talisman/stats/ngrams: first argument should be a positive integer > 0.');

  sequence = seq(sequence);
  hasher = typeof hasher === 'function' ? hasher : identity;

  const subsequences = [];

  for (let i = 0, l = sequence.length; i < l - n + 1; i++) {
    const subsequence = [];

    for (let j = 0; j < n; j++)
      subsequence.push(sequence[i + j]);

    subsequences.push(hasher(subsequence));
  }

  return subsequences;
}

/**
 * Creating popular aliases.
 */
const bigrams = ngrams.bind(null, 2),
      trigrams = ngrams.bind(null, 3),
      quadrigrams = ngrams.bind(null, 4);

export {bigrams, trigrams, quadrigrams};
<commit_msg>Fixing comments<commit_after>/**
 * Talisman stats/ngrams
 * ======================
 *
 * Functions related to ngrams' computation.
 */
import {seq} from '../helpers';

/**
 * Identity function used as placeholder.
 */
const identity = x => x;

/**
 * Function taking a sequence and computing its ngrams.
 *
 * @param  {number}   n         - Nb of elements in the subsequence.
 * @param  {mixed}    sequence  - The sequence to process.
 * @param  {function} [hasher]  - A function optionally used to hash the ngrams.
 * @return {array}              - The array of resulting ngrams.
 *
 * @throws {Error} The function expects a positive n > 0.
 */
export default function ngrams(n, sequence, hasher) {
  if (n < 1)
    throw Error('talisman/stats/ngrams: first argument should be a positive integer > 0.');

  sequence = seq(sequence);
  hasher = typeof hasher === 'function' ? hasher : identity;

  const subsequences = [];

  for (let i = 0, l = sequence.length; i < l - n + 1; i++) {
    const subsequence = [];

    for (let j = 0; j < n; j++)
      subsequence.push(sequence[i + j]);

    subsequences.push(hasher(subsequence));
  }

  return subsequences;
}

/**
 * Creating popular aliases.
 */
const bigrams = ngrams.bind(null, 2),
      trigrams = ngrams.bind(null, 3),
      quadrigrams = ngrams.bind(null, 4);

export {bigrams, trigrams, quadrigrams};
<|endoftext|>