<commit_before>'use strict';

Entry.STATEMENT = 0;
Entry.PARAM = -1;
Entry.Code = class Code {
    schema = {
        view: null,
        board: null,
    };

    constructor(code, object) {
        Entry.Model(this, false);
        this.id = Entry.generateHash();
        if (object) {
            this.object = object;
        }

        this._data = new Entry.Collection();

        this._eventMap = {};
        this._blockMap = {};

        this.executors = [];
        this.watchEvent = new Entry.Event(this);
        this.executeEndEvent = new Entry.Event(this);
        this.changeEvent = new Entry.Event(this);
        this.changeEvent.attach(this, this._handleChange);

        this._maxZIndex = 0;

        this.load(code);
    }

    load(code) {
        if (Entry.engine && Entry.engine.isState('run')) {
            return;
        }

        this.clear();

        const parseCode = Array.isArray(code) ? code : JSON.parse(code);
        parseCode.forEach((t) => {
            const thread = new Entry.Thread(t, this);
            if (thread.hasData()) {
                this._data.push(thread);
            }
        });

        return this;
    }

    clear(isNotForce = false) {
        for (let i = this._data.length - 1; i >= 0; i--) {
            this._data[i].destroy(false, isNotForce);
        }

        this.clearExecutors();
    }

    createView(board) {
        if (this.view === null) {
            this.set({
                view: new Entry.CodeView(this, board),
                board,
            });
        } else {
            this.set({ board });
            board.bindCodeView(this.view);
        }
    }

    destroyView() {
        if (!this.view) {
            return;
        }
        this.view.destroy();
        this.set({ view: null });
    }

    recreateView() {
        if (!this.view) {
            return;
        }
        this.destroyView();
        this.set({
            view: new Entry.CodeView(this, this.board),
            board: this.board,
        });
    }

    registerEvent(block, eventType) {
        const eventMap = this._eventMap;
        if (!eventMap[eventType]) {
            eventMap[eventType] = [];
        }

        eventMap[eventType].push(block);
    }

    unregisterEvent(block, eventType) {
        const blocks = this._eventMap[eventType];
        if (_.isEmpty(blocks)) {
            return;
        }

        const index = blocks.indexOf(block);
        if (index < 0) {
            return;
        }
        blocks.splice(index, 1);
    }

    raiseEvent(eventType, entity, value) {
        const blocks = this._eventMap[eventType];
        if (blocks === undefined) {
            return;
        }

        const executors = [];

        for (let i = 0; i < blocks.length; i++) {
            const block = blocks[i];
            const pointer = block.pointer();
            if (pointer[3] !== 0 || pointer.length !== 4) {
                continue;
            }
            if (value === undefined || block.params.indexOf(value) > -1) {
                const executor = new Entry.Executor(blocks[i], entity, this);
                this.executors.push(executor);
                executors.push(executor);
            }
        }
        return executors;
    }

    getEventMap(eventType) {
        return this._eventMap[eventType];
    }

    map(func) {
        this._data.map(func);
    }

    tick() {
        if (Entry.isTurbo && !this.isUpdateTime) {
            this.isUpdateTime = performance.now();
        }
        const executors = this.executors;
        const watchEvent = this.watchEvent;
        const shouldNotifyWatch = watchEvent.hasListeners();
        let result;
        let executedBlocks = [];
        const loopExecutor = [];

        const _executeEvent = _.partial(Entry.dispatchEvent, 'blockExecute');
        const _executeEndEvent = _.partial(Entry.dispatchEvent, 'blockExecuteEnd');

        for (let i = 0; i < executors.length; i++) {
            const executor = executors[i];
            if (executor.isPause()) {
                continue;
            } else if (!executor.isEnd()) {
                const { view } = executor.scope.block || {};
                _executeEvent(view);
                result = executor.execute(true);
                if (executor.isLooped) {
                    loopExecutor.push(executor);
                }
                if (shouldNotifyWatch) {
                    const { blocks } = result;
                    executedBlocks = executedBlocks.concat(blocks);
                }
            } else if (executor.isEnd()) {
                _executeEndEvent(this.board);
                executors.splice(i--, 1);
                if (_.isEmpty(executors)) {
                    this.executeEndEvent.notify();
                }
            }
        }

        if (Entry.isTurbo) {
            for (let i = 0; i < loopExecutor.length; i++) {
                const executor = loopExecutor[i];
                if (executor.isPause()) {
                    continue;
                } else if (!executor.isEnd()) {
                    const { view } = executor.scope.block || {};
                    _executeEvent(view);
                    result = executor.execute(true);
                    if (shouldNotifyWatch) {
                        const { blocks } = result;
                        executedBlocks = executedBlocks.concat(blocks);
                    }
                } else if (executor.isEnd()) {
                    _executeEndEvent(this.board);
                    loopExecutor.splice(i--, 1);
                    if (_.isEmpty(loopExecutor)) {
                        this.executeEndEvent.notify();
                    }
                }

                if (
                    i === loopExecutor.length - 1 &&
                    Entry.tickTime > performance.now() - this.isUpdateTime
                ) {
                    i = -1;
                }
            }
        }

        this.isUpdateTime = 0;
        shouldNotifyWatch && watchEvent.notify(executedBlocks);
        if (result && result.promises) {
            Entry.engine.addPromiseExecutor(result.promises);
        }
    }

    removeExecutor(executor) {
        const index = this.executors.indexOf(executor);
        if (index > -1) {
            this.executors.splice(index, 1);
        }
    }

    clearExecutors() {
        this.executors.forEach((e) => e.end());
        Entry.dispatchEvent('blockExecuteEnd');
        this.executors = [];
    }

    clearExecutorsByEntity(entity) {
        this.executors.forEach((executor) => {
            if (executor.entity === entity) {
                executor.end();
            }
        });
    }

    addExecutor(executor) {
        this.executors.push(executor);
    }

    createThread(blocks, index) {
        if (!Array.isArray(blocks)) {
            return console.error('blocks must be array');
        }

        const thread = new Entry.Thread(blocks, this);
        if (index === undefined || index === null) {
            this._data.push(thread);
        } else {
            this._data.insert(thread, index);
        }

        this.changeEvent.notify();
        return thread;
    }

    getThreadIndex(thread) {
        return this._data.indexOf(thread);
    }

    getThreadCount() {
        return this._data.length;
    }

    cloneThread(thread, mode) {
        const newThread = thread.clone(this, mode);
        this._data.push(newThread);
        return newThread;
    }

    destroyThread(thread) {
        const data = this._data;
        const index = data.indexOf(thread);
        // case of statement thread
        if (~index) {
            data.splice(index, 1);
        }
    }

    pushBackThread(thread) {
        this._data.splice(this.getThreadIndex(thread), 1);
        this._data.push(thread);
    }

    doDestroyThread = this.destroyThread;

    getThread(index) {
        return this._data[index];
    }

    getThreads() {
        return this._data.slice();
    }

    getThreadsByCategory(categoryName) {
        if (!categoryName) {
            return [];
        }

        return this.getThreads().filter(
            (t) => _.result(t.getFirstBlock(), 'category') === categoryName
        );
    }

    toJSON(excludeData, option) {
        const params = [false, undefined, excludeData, option];
        return this.getThreads().map((t) => t.toJSON(...params));
    }

    countBlock() {
        return this.getThreads().reduce((cnt, thread) => cnt + thread.countBlock(), 0);
    }

    moveBy(x, y) {
        this.getThreads().forEach((thread) => {
            const { view = {} } = thread.getFirstBlock() || {};
            if (view && view.display) {
                view.moveBy(x, y, false);
            }
        });
        const { board } = this;
        if (board instanceof Entry.BlockMenu) {
            board.updateSplitters(y);
        }
    }

    stringify(excludeData) {
        return JSON.stringify(this.toJSON(excludeData));
    }

    dominate(thread) {
        thread.view.setZIndex(this._maxZIndex++);
    }

    getMaxZIndex() {
        return this._maxZIndex;
    }

    indexOf(thread) {
        return this._data.indexOf(thread);
    }

    _handleChange() {
        const board = _.result(this.view, 'board');
        const event = Entry.creationChangedEvent;
        if (board && event && board.constructor !== Entry.BlockMenu) {
            event.notify();
        }
    }

    hasBlockType(type) {
        return this.getThreads().some((thread) => thread.hasBlockType(type));
    }

    findById(id) {
        return this._blockMap[id];
    }

    registerBlock(block) {
        this._blockMap[block.id] = block;
    }

    unregisterBlock({ id }) {
        delete this._blockMap[id];
    }

    getByPointer([, , ...pointer]) {
        const thread = this._data[pointer.shift()];
        let block = thread.getBlock(pointer.shift());
        while (pointer.length) {
            if (!(block instanceof Entry.Block)) {
                if (!block || !block.getValueBlock) {
                    console.error("can't get valueBlock", block);
                    return block;
                }
                block = block.getValueBlock();
            }
            const type = pointer.shift();
            const index = pointer.shift();
            if (type > -1) {
                const statement = block.statements[type];
                if (index === undefined) {
                    return statement;
                } else {
                    block = statement.getBlock(index);
                }
            } else if (type === -1) {
                block = block.view.getParam(index);
            }
        }
        return block;
    }

    getTargetByPointer([, , ...pointer]) {
        const thread = this._data[pointer.shift()];
        let block;

        if (pointer.length === 1) {
            block = thread.getBlock(pointer.shift() - 1);
        } else {
            block = thread.getBlock(pointer.shift());
            while (pointer.length) {
                if (!(block instanceof Entry.Block)) {
                    block = block.getValueBlock();
                }
                const type = pointer.shift();
                const index = pointer.shift();
                if (type > -1) {
                    const statement = block.statements[type];
                    if (!pointer.length) {
                        if (index === 0) {
                            block = statement.view.getParent();
                        } else if (index === undefined) {
                            block = statement;
                        } else {
                            block = statement.getBlock(index - 1);
                        }
                    } else {
                        if (index < 0) {
                            block = statement;
                        } else {
                            block = statement.getBlock(index);
                        }
                    }
                } else if (type === -1) {
                    block = block.view.getParam(index);
                }
            }
        }
        return block;
    }

    getBlockList(excludePrimitive, type) {
        return _.chain(this.getThreads())
            .map((t) => t.getBlockList(excludePrimitive, type))
            .flatten(true)
            .value();
    }

    removeBlocksByType(type) {
        this.getBlockList(false, type).forEach((b) => b.doDestroy());
    }

    isAllThreadsInOrigin() {
        return this.getThreads().every((thread) => thread.isInOrigin());
    }

    destroy() {
        this.clear();
        this.destroyView();
    }

    static funcAsyncExecute = async (funcCode, funcExecutor, _promises = []) => {
        await Promise.all(_promises);
        if (Entry.engine.isState('pause')) {
            return this.funcAsyncExecute(funcCode, funcExecutor, _promises);
        } else if (!Entry.engine.isState('run')) {
            funcCode.removeExecutor(funcExecutor);
            return Entry.STATIC.BREAK;
        }

        return new Promise((resolve, reject) => {
            requestAnimationFrame(async () => {
                const result = funcExecutor.execute();
                const { promises = [] } = result || {};

                if (!funcExecutor.isEnd()) {
                    if (promises.length) {
                        try {
                            return resolve(
                                await this.funcAsyncExecute(funcCode, funcExecutor, promises)
                            );
                        } catch (e) {
                            return reject(e);
                        }
                    } else {
                        funcCode.callStackLength--;
                        funcCode.removeExecutor(funcExecutor);
                    }
                }
                return resolve(Entry.STATIC.BREAK);
            });
        });
    };
};
<commit_msg>add case<commit_after>'use strict';

Entry.STATEMENT = 0;
Entry.PARAM = -1;
Entry.Code = class Code {
    schema = {
        view: null,
        board: null,
    };

    constructor(code, object) {
        Entry.Model(this, false);
        this.id = Entry.generateHash();
        if (object) {
            this.object = object;
        }

        this._data = new Entry.Collection();

        this._eventMap = {};
        this._blockMap = {};

        this.executors = [];
        this.watchEvent = new Entry.Event(this);
        this.executeEndEvent = new Entry.Event(this);
        this.changeEvent = new Entry.Event(this);
        this.changeEvent.attach(this, this._handleChange);

        this._maxZIndex = 0;

        this.load(code);
    }

    load(code) {
        if (Entry.engine && Entry.engine.isState('run')) {
            return;
        }

        this.clear();

        const parseCode = Array.isArray(code) ? code : JSON.parse(code);
        parseCode.forEach((t) => {
            const thread = new Entry.Thread(t, this);
            if (thread.hasData()) {
                this._data.push(thread);
            }
        });

        return this;
    }

    clear(isNotForce = false) {
        for (let i = this._data.length - 1; i >= 0; i--) {
            this._data[i].destroy(false, isNotForce);
        }

        this.clearExecutors();
    }

    createView(board) {
        if (this.view === null) {
            this.set({
                view: new Entry.CodeView(this, board),
                board,
            });
        } else {
            this.set({ board });
            board.bindCodeView(this.view);
        }
    }

    destroyView() {
        if (!this.view) {
            return;
        }
        this.view.destroy();
        this.set({ view: null });
    }

    recreateView() {
        if (!this.view) {
            return;
        }
        this.destroyView();
        this.set({
            view: new Entry.CodeView(this, this.board),
            board: this.board,
        });
    }

    registerEvent(block, eventType) {
        const eventMap = this._eventMap;
        if (!eventMap[eventType]) {
            eventMap[eventType] = [];
        }

        eventMap[eventType].push(block);
    }

    unregisterEvent(block, eventType) {
        const blocks = this._eventMap[eventType];
        if (_.isEmpty(blocks)) {
            return;
        }

        const index = blocks.indexOf(block);
        if (index < 0) {
            return;
        }
        blocks.splice(index, 1);
    }

    raiseEvent(eventType, entity, value) {
        const blocks = this._eventMap[eventType];
        if (blocks === undefined) {
            return;
        }

        const executors = [];

        for (let i = 0; i < blocks.length; i++) {
            const block = blocks[i];
            const pointer = block.pointer();
            if (pointer[3] !== 0 || pointer.length !== 4) {
                continue;
            }
            if (value === undefined || block.params.indexOf(value) > -1) {
                const executor = new Entry.Executor(blocks[i], entity, this);
                this.executors.push(executor);
                executors.push(executor);
            }
        }
        return executors;
    }

    getEventMap(eventType) {
        return this._eventMap[eventType];
    }

    map(func) {
        this._data.map(func);
    }

    tick() {
        if (Entry.isTurbo && !this.isUpdateTime) {
            this.isUpdateTime = performance.now();
        }
        const executors = this.executors;
        const watchEvent = this.watchEvent;
        const shouldNotifyWatch = watchEvent.hasListeners();
        let result;
        let executedBlocks = [];
        const loopExecutor = [];

        const _executeEvent = _.partial(Entry.dispatchEvent, 'blockExecute');
        const _executeEndEvent = _.partial(Entry.dispatchEvent, 'blockExecuteEnd');

        for (let i = 0; i < executors.length; i++) {
            const executor = executors[i];
            if (executor.isPause()) {
                continue;
            } else if (!executor.isEnd()) {
                const { view } = executor.scope.block || {};
                _executeEvent(view);
                result = executor.execute(true);
                if (executor.isLooped) {
                    loopExecutor.push(executor);
                }
                if (shouldNotifyWatch) {
                    const { blocks } = result;
                    executedBlocks = executedBlocks.concat(blocks);
                }
            } else if (executor.isEnd()) {
                _executeEndEvent(this.board);
                executors.splice(i--, 1);
                if (_.isEmpty(executors)) {
                    this.executeEndEvent.notify();
                }
            }
        }

        if (Entry.isTurbo) {
            for (let i = 0; i < loopExecutor.length; i++) {
                const executor = loopExecutor[i];
                if (executor.isPause()) {
                    continue;
                } else if (!executor.isEnd()) {
                    const { view } = executor.scope.block || {};
                    _executeEvent(view);
                    result = executor.execute(true);
                    if (shouldNotifyWatch) {
                        const { blocks } = result;
                        executedBlocks = executedBlocks.concat(blocks);
                    }
                } else if (executor.isEnd()) {
                    _executeEndEvent(this.board);
                    loopExecutor.splice(i--, 1);
                    if (_.isEmpty(loopExecutor)) {
                        this.executeEndEvent.notify();
                    }
                }

                if (
                    i === loopExecutor.length - 1 &&
                    Entry.tickTime > performance.now() - this.isUpdateTime
                ) {
                    i = -1;
                }
            }
        }

        this.isUpdateTime = 0;
        shouldNotifyWatch && watchEvent.notify(executedBlocks);
        if (result && result.promises) {
            Entry.engine.addPromiseExecutor(result.promises);
        }
    }

    removeExecutor(executor) {
        const index = this.executors.indexOf(executor);
        if (index > -1) {
            this.executors.splice(index, 1);
        }
    }

    clearExecutors() {
        this.executors.forEach((e) => e.end());
        Entry.dispatchEvent('blockExecuteEnd');
        this.executors = [];
    }

    clearExecutorsByEntity(entity) {
        this.executors.forEach((executor) => {
            if (executor.entity === entity) {
                executor.end();
            }
        });
    }

    addExecutor(executor) {
        this.executors.push(executor);
    }

    createThread(blocks, index) {
        if (!Array.isArray(blocks)) {
            return console.error('blocks must be array');
        }

        const thread = new Entry.Thread(blocks, this);
        if (index === undefined || index === null) {
            this._data.push(thread);
        } else {
            this._data.insert(thread, index);
        }

        this.changeEvent.notify();
        return thread;
    }

    getThreadIndex(thread) {
        return this._data.indexOf(thread);
    }

    getThreadCount() {
        return this._data.length;
    }

    cloneThread(thread, mode) {
        const newThread = thread.clone(this, mode);
        this._data.push(newThread);
        return newThread;
    }

    destroyThread(thread) {
        const data = this._data;
        const index = data.indexOf(thread);
        // case of statement thread
        if (~index) {
            data.splice(index, 1);
        }
    }

    pushBackThread(thread) {
        this._data.splice(this.getThreadIndex(thread), 1);
        this._data.push(thread);
    }

    doDestroyThread = this.destroyThread;

    getThread(index) {
        return this._data[index];
    }

    getThreads() {
        return this._data.slice();
    }

    getThreadsByCategory(categoryName) {
        if (!categoryName) {
            return [];
        }

        return this.getThreads().filter(
            (t) => _.result(t.getFirstBlock(), 'category') === categoryName
        );
    }

    toJSON(excludeData, option) {
        const params = [false, undefined, excludeData, option];
        return this.getThreads().map((t) => t.toJSON(...params));
    }

    countBlock() {
        return this.getThreads().reduce((cnt, thread) => cnt + thread.countBlock(), 0);
    }

    moveBy(x, y) {
        this.getThreads().forEach((thread) => {
            const { view = {} } = thread.getFirstBlock() || {};
            if (view && view.display) {
                view.moveBy(x, y, false);
            }
        });
        const { board } = this;
        if (board instanceof Entry.BlockMenu) {
            board.updateSplitters(y);
        }
    }

    stringify(excludeData) {
        return JSON.stringify(this.toJSON(excludeData));
    }

    dominate(thread) {
        thread.view.setZIndex(this._maxZIndex++);
    }

    getMaxZIndex() {
        return this._maxZIndex;
    }

    indexOf(thread) {
        return this._data.indexOf(thread);
    }

    _handleChange() {
        const board = _.result(this.view, 'board');
        const event = Entry.creationChangedEvent;
        if (board && event && board.constructor !== Entry.BlockMenu) {
            event.notify();
        }
    }

    hasBlockType(type) {
        return this.getThreads().some((thread) => thread.hasBlockType(type));
    }

    findById(id) {
        return this._blockMap[id];
    }

    registerBlock(block) {
        this._blockMap[block.id] = block;
    }

    unregisterBlock({ id }) {
        delete this._blockMap[id];
    }

    getByPointer([, , ...pointer]) {
        const thread = this._data[pointer.shift()];
        let block = thread.getBlock(pointer.shift());
        while (pointer.length) {
            if (!(block instanceof Entry.Block)) {
                if (!block || !block.getValueBlock) {
                    console.error("can't get valueBlock", block);
                    return block;
                }
                block = block.getValueBlock();
            }
            const type = pointer.shift();
            const index = pointer.shift();
            if (type > -1) {
                const statement = block.statements[type];
                if (index === undefined) {
                    return statement;
                } else {
                    block = statement.getBlock(index);
                }
            } else if (type === -1) {
                block = block.view.getParam(index);
            }
        }
        return block;
    }

    getTargetByPointer([, , ...pointer]) {
        const thread = this._data[pointer.shift()];
        let block;

        if (pointer.length === 1) {
            block = thread.getBlock(pointer.shift() - 1);
        } else {
            block = thread.getBlock(pointer.shift());
            while (pointer.length) {
                if (!(block instanceof Entry.Block)) {
                    block = block.getValueBlock();
                }
                const type = pointer.shift();
                const index = pointer.shift();
                if (type > -1) {
                    const statement = block.statements[type];
                    if (!pointer.length) {
                        if (index === 0) {
                            block = statement.view.getParent();
                        } else if (index === undefined) {
                            block = statement;
                        } else {
                            block = statement.getBlock(index - 1);
                        }
                    } else {
                        if (index < 0) {
                            block = statement;
                        } else {
                            block = statement.getBlock(index);
                        }
                    }
                } else if (type === -1) {
                    block = block.view.getParam(index);
                }
            }
        }
        return block;
    }

    getBlockList(excludePrimitive, type) {
        return _.chain(this.getThreads())
            .map((t) => t.getBlockList(excludePrimitive, type))
            .flatten(true)
            .value();
    }

    removeBlocksByType(type) {
        this.getBlockList(false, type).forEach((b) => b.doDestroy());
    }

    isAllThreadsInOrigin() {
        return this.getThreads().every((thread) => thread.isInOrigin());
    }

    destroy() {
        this.clear();
        this.destroyView();
    }

    static funcAsyncExecute = async (funcCode, funcExecutor, _promises = []) => {
        await Promise.all(_promises);
        if (Entry.engine.isState('pause')) {
            return this.funcAsyncExecute(funcCode, funcExecutor, _promises);
        } else if (!Entry.engine.isState('run')) {
            funcCode.removeExecutor(funcExecutor);
            return Entry.STATIC.BREAK;
        }

        return new Promise((resolve, reject) => {
            requestAnimationFrame(async () => {
                const result = funcExecutor.execute();
                const { promises = [] } = result || {};

                if (!funcExecutor.isEnd()) {
                    if (promises.length) {
                        try {
                            return resolve(
                                await this.funcAsyncExecute(funcCode, funcExecutor, promises)
                            );
                        } catch (e) {
                            return reject(e);
                        }
                    } else {
                        funcCode.callStackLength--;
                        funcCode.removeExecutor(funcExecutor);
                        return resolve(Entry.STATIC.BREAK);
                    }
                }
                return resolve();
            });
        });
    };
};
<|endoftext|>


<commit_before>"use strict";

// Takes a string and produces an escaped Turtle String production but without quotes
module.exports = function encodeString(str) {
	var out = "";
	for(var i=0; i<str.length; i++) {
		var code = str.charCodeAt(i);
		if(0xD800<=code && code<=0xDBFF) {
			var low = str.charCodeAt(i + 1);
			if(low>=0xDC00 && low<=0xDFFF){
				code = (code - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000;
				++i;
			}
		}
		if(code > 0x10FFFF) { throw new Error("Char out of range"); }
		var hex = "00000000".concat((new Number(code)).toString(16).toUpperCase());
		if(code >= 0x10000) {
			out += "\\U" + hex.slice(-8);
		} else {
			if(code >= 0x7F || code <= 31) {
				switch(code) {
					case 0x09:	out += "\\t"; break;
					case 0x0A: out += "\\n"; break;
					case 0x0D: out += "\\r"; break;
					default: out += "\\u" + hex.slice(-4); break;
				}
			} else {
				switch(code) {
					case 0x22: out += '\\"'; break;
					case 0x5C: out += "\\\\"; break;
					default: out += str.charAt(i); break;
				}
			}
		}
	}
	return out;
}
<commit_msg>Performance improvement for encodeString<commit_after>"use strict";

// #x22#x5C#xA#xD
var encodeMap = {
	'"': '\\"',
	'\\': '\\\\',
	"\r": '\\r',
	"\n": '\\n',
	"\t": '\\t',
};

// Takes a string and produces an escaped Turtle String production but without quotes
module.exports = encodeASCIIString;

// Use this to output the unicode character whenever it's legal in N-Triples
// var encodeSearch = /["\r\n\\]/g;
// function encodeString(str) {
// 	return str.replace(encodeSearch, function(a, b){
// 		return encodeMap[b];
// 	});
// }

var encodeASCIIStringSearch = /(["\r\n\t\\])|([\u0080-\uD7FF\uE000-\uFFFF])|([\uD800-\uDBFF][\uDC00-\uDFFF])/g;
function encodeASCIIStringReplace(a, b, c, d){
	if(b){
		return encodeMap[b];
	}
	if(c){
		return '\\u'+('0000'+c.charCodeAt(0).toString(16).toUpperCase()).substr(-4);
	}
	if(d){
		var hig = d.charCodeAt(0);
		var low = d.charCodeAt(1);
		var code = (hig - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000;
		return '\\U'+('00000000'+code.toString(16).toUpperCase()).substr(-8);
	}
}

// Return a Turtle string with backslash escapes for all non-7-bit characters
function encodeASCIIString(str){
	return str.replace(encodeASCIIStringSearch, encodeASCIIStringReplace);
}
<|endoftext|>


<commit_before>"use strict";

// Takes a string and produces an escaped Turtle String production but without quotes
module.exports = function encodeString(str) {
	var out = "";
	for(var i=0; i<str.length; i++) {
		var code = str.charCodeAt(i);
		if(0xD800<=code && code<=0xDBFF) {
			var low = str.charCodeAt(i + 1);
			if(low>=DC00 && low<=DFFF){
				code = (code - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000;
				++i;
			}
		}
		if(code > 0x10FFFF) { throw new Error("Char out of range"); }
		var hex = "00000000".concat((new Number(code)).toString(16).toUpperCase());
		if(code >= 0x10000) {
			out += "\\U" + hex.slice(-8);
		} else {
			if(code >= 0x7F || code <= 31) {
				switch(code) {
					case 0x09:	out += "\\t"; break;
					case 0x0A: out += "\\n"; break;
					case 0x0D: out += "\\r"; break;
					default: out += "\\u" + hex.slice(-4); break;
				}
			} else {
				switch(code) {
					case 0x22: out += '\\"'; break;
					case 0x5C: out += "\\\\"; break;
					default: out += str.charAt(i); break;
				}
			}
		}
	}
	return out;
}
<commit_msg>Fix encodeString<commit_after>"use strict";

// Takes a string and produces an escaped Turtle String production but without quotes
module.exports = function encodeString(str) {
	var out = "";
	for(var i=0; i<str.length; i++) {
		var code = str.charCodeAt(i);
		if(0xD800<=code && code<=0xDBFF) {
			var low = str.charCodeAt(i + 1);
			if(low>=0xDC00 && low<=0xDFFF){
				code = (code - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000;
				++i;
			}
		}
		if(code > 0x10FFFF) { throw new Error("Char out of range"); }
		var hex = "00000000".concat((new Number(code)).toString(16).toUpperCase());
		if(code >= 0x10000) {
			out += "\\U" + hex.slice(-8);
		} else {
			if(code >= 0x7F || code <= 31) {
				switch(code) {
					case 0x09:	out += "\\t"; break;
					case 0x0A: out += "\\n"; break;
					case 0x0D: out += "\\r"; break;
					default: out += "\\u" + hex.slice(-4); break;
				}
			} else {
				switch(code) {
					case 0x22: out += '\\"'; break;
					case 0x5C: out += "\\\\"; break;
					default: out += str.charAt(i); break;
				}
			}
		}
	}
	return out;
}
<|endoftext|>


<commit_before>import Plugin from './Plugin';

export default class Formtag extends Plugin {
  constructor(core, opts) {
    super(core, opts);
    this.type = 'selecter';
  }

  run(results) {
    console.log({
      class  : 'Formtag',
      method : 'run',
      results: results
    });

    this.setProgress(0);

    const button = document.querySelector(this.opts.doneButtonSelector);
    var self     = this;

    return new Promise((resolve, reject) => {
      button.addEventListener('click', (e) => {
        var fields   = document.querySelectorAll(self.opts.selector);
        var files    = [];
        var selected = [];

        [].forEach.call(fields, function(field, i) {
          [].forEach.call(field.files, function(file, j) {
            selected.push({
              from: 'Formtag',
              file: file
            })
          })
        });

        // console.log(fields.length);
        // for (var i in fields) {
        //   console.log('i');
        //   // console.log('i: ', i);
        //   for (var j in fields[i].files) {
        //     console.log('j');
        //     // console.log('i, j', i, j);
        //     console.log(fields[i].files);
        //     var file = fields[i].files.item(j);
        //     if (file) {
        //       selected.push({
        //         from: 'Formtag',
        //         file: fields[i].files.item(j)
        //       });
        //     }
        //   }
        // }
        self.setProgress(100);
        console.log({
          selected:selected,
          fields  :fields
        })
        resolve(selected);
      });
    });
  }
}
<commit_msg>changed callbacks to arrow expressions<commit_after>import Plugin from './Plugin';

export default class Formtag extends Plugin {
  constructor(core, opts) {
    super(core, opts);
    this.type = 'selecter';
  }

  run(results) {
    console.log({
      class  : 'Formtag',
      method : 'run',
      results: results
    });

    this.setProgress(0);

    const button = document.querySelector(this.opts.doneButtonSelector);
    var self     = this;

    return new Promise((resolve, reject) => {
      button.addEventListener('click', (e) => {
        var fields   = document.querySelectorAll(self.opts.selector);
        var files    = [];
        var selected = [];

        [].forEach.call(fields, (field, i) => {
          [].forEach.call(field.files, (file, j) => {
            selected.push({
              from: 'Formtag',
              file: file
            })
          })
        });

        // console.log(fields.length);
        // for (var i in fields) {
        //   console.log('i');
        //   // console.log('i: ', i);
        //   for (var j in fields[i].files) {
        //     console.log('j');
        //     // console.log('i, j', i, j);
        //     console.log(fields[i].files);
        //     var file = fields[i].files.item(j);
        //     if (file) {
        //       selected.push({
        //         from: 'Formtag',
        //         file: fields[i].files.item(j)
        //       });
        //     }
        //   }
        // }
        self.setProgress(100);
        console.log({
          selected:selected,
          fields  :fields
        })
        resolve(selected);
      });
    });
  }
}
<|endoftext|>


<commit_before>'use strict';

var logger = require('../thaliLogger')('thaliManager');

var thaliConfig = require('./thaliConfig');
var ThaliMobile = require('./thaliMobile');
var ThaliSendNotificationBasedOnReplication =
  require('./replication/thaliSendNotificationBasedOnReplication');
var ThaliPullReplicationFromNotification =
  require('./replication/thaliPullReplicationFromNotification');

var express = require('express');
var salti = require('salti');
var path = require('path');
var Promise = require('lie');
var assert = require('assert');

/** @module thaliManager */

/**
 * @classdesc This may look like a class but it really should only have one
 * instance or bad stuff can happen.
 *
 * @public
 * @param {expressPouchdb} expressPouchDB The express-pouchdb object we are
 * supposed to use to create the router.
 * @param {PouchDB} PouchDB PouchDB object we are supposed to use to create
 * dbs. Typically this should have PouchDB.defaults set with db to
 * require('leveldown-mobile') and prefix to the path where the application
 * wishes to store the DB.
 * @param {string} dbName Name of the db, both locally and remotely that we are
 * interacting with.
 * @param {Crypto.ECDH} ecdhForLocalDevice A Crypto.ECDH object initialized with
 * the local device's public and private keys.
 * @param {module:thaliPeerPoolInterface~ThaliPeerPoolInterface} [thaliPeerPoolInterface]
 * If your app doesn't specify its own pool interface you will seriously
 * regret it as the default one has awful behavior. Building your own
 * thaliPeerPoolInterface is pretty much a requirement for a decent Thali app.
 *
 * @constructor
 */
function ThaliManager(expressPouchDB,
                      PouchDB,
                      dbName,
                      ecdhForLocalDevice,
                      thaliPeerPoolInterface) {
  var self = this;

  this._router = express.Router();
  this._router.all('*', this._connectionFilter.bind(this));

  this._router.all('*', salti(
    dbName,
    ThaliManager._acl,
    this._resolveThaliId.bind(this),
    { dbPrefix: thaliConfig.BASE_DB_PATH }
  ));

  logger.debug('creating ThaliSendNotificationBasedOnReplication instance');

  this._thaliSendNotificationBasedOnReplication =
    new ThaliSendNotificationBasedOnReplication(
        this._router,
        ecdhForLocalDevice,
        thaliConfig.BEACON_MILLISECONDS_TO_EXPIRE,
        new PouchDB(dbName));
  this._getPskIdToSecret =
    self._thaliSendNotificationBasedOnReplication.getPskIdToSecret();
  this._getPskIdToPublicKey =
    self._thaliSendNotificationBasedOnReplication.getPskIdToPublicKey();

  logger.debug('creating ThaliPullReplicationFromNotification instance');

  this._thaliPullReplicationFromNotification =
    new ThaliPullReplicationFromNotification(
        PouchDB,
        dbName,
        thaliPeerPoolInterface,
        ecdhForLocalDevice);
  this._thaliPeerPoolInterface = thaliPeerPoolInterface;

  logger.debug('creating express pouchdb instance');

  this._router.use(thaliConfig.BASE_DB_PATH, expressPouchDB(PouchDB, {
    mode: 'minimumForPouchDB'
  }));

  this.state = ThaliManager.STATES.CREATED;
}

/**
 * This is a list of states for ThaliManager.
 * @public
 * @readonly
 * @enum {string}
 */
ThaliManager.STATES = {
  CREATED: 'created',
  STARTING: 'starting',
  STARTED: 'started',
  STOPPING: 'stopping',
  STOPPED: 'stopped'
};

/**
 * Starts up everything including listening for advertisements, sending out
 * our advertisements, generating beacons to notify peers that we have data
 * for them as well as running pull replication jobs to pull data from other
 * peers who have data for us.
 *
 * This method is not idempotent as each call to start with different arguments
 * will cause the related states to be changed.
 *
 * @param {Buffer[]} [arrayOfRemoteKeys] This is the list of ECDH public keys
 * that we should be willing to send notifications of our changes to and receive
 * notifications of changes from.
 * @returns {Promise<?Error>}
 */
ThaliManager.prototype.start = function (arrayOfRemoteKeys) {
  var self = this;

  // Can we start now?
  var args = arguments;
  switch (this.state) {
    case ThaliManager.STATES.STARTING: {
      return this._startingPromise;
    }
    case ThaliManager.STATES.STARTED: {
      return Promise.resolve();
    }
    case ThaliManager.STATES.STOPPING: {
      return this._stoppingPromise
        .then(function () {
          return self.start.apply(self, args);
        });
    }
  }
  assert(
    this.state === ThaliManager.STATES.CREATED ||
    this.state === ThaliManager.STATES.STOPPED,
    'ThaliManager state should be \'CREATED\' or \'STOPPED\' for start'
  );
  this.state = ThaliManager.STATES.STARTING;

  logger.debug('starting thaliPullReplicationFromNotification');
  this._thaliPullReplicationFromNotification.start(arrayOfRemoteKeys);

  logger.debug('starting ThaliMobile');
  this._startingPromise = ThaliMobile.start(self._router, self._getPskIdToSecret)

  .then(function () {
    /*
    Ideally we could call startListening and startUpdateAdvertising separately
    but this causes problems in iOS. The issue is that we deal with the
    restriction that there can only be one MCSession between two devices by
    having a leader election where one device will always form the session.
    Imagine that there is device A and B. B is advertising. A hears the
    advertisement and wants to connect but it can't start the session. So what
    it has to do is send an invite to B, who will reject the invite but then
    respond with its own invite to A. For this to work however B has to be
    listening for advertisements (not just making them) because otherwise
    there is no way in iOS for A to ask B for a session (that will be
    refused). Simultaneously A must be listening for advertisements (or it
    wouldn't have heard B) and it must be advertising itself or B couldn't
    establish the MCSession with it. So in practice this means that in iOS
    everyone has to be both listening and advertising at the same time.
    */
    logger.debug('start listening for advertisements');
    return ThaliMobile.startListeningForAdvertisements();
  })

  .then(function () {
    logger.debug('start update advertising and listening');
    return ThaliMobile.startUpdateAdvertisingAndListening();
  })

  .then(function () {
    logger.debug('starting thaliSendNotificationBasedOnReplication');
    return self._thaliSendNotificationBasedOnReplication.start(arrayOfRemoteKeys);
  })

  .then(function () {
    self.state = ThaliManager.STATES.STARTED;
    self._startingPromise = undefined;
  });

  return this._startingPromise;
};

/**
 * Shuts down the radios and deactivates all replications.
 * @public
 * @returns {Promise<?Error>}
 */
ThaliManager.prototype.stop = function () {
  var self = this;

  // Can we stop now?
  var args = arguments;
  switch (this.state) {
    case ThaliManager.STATES.CREATED:
    case ThaliManager.STATES.STOPPED: {
      return Promise.resolve();
    }
    case ThaliManager.STATES.STOPPING: {
      return this._stoppingPromise;
    }
    case ThaliManager.STATES.STARTING: {
      return this._startingPromise
        .then(function () {
          return self.stop.apply(self, args);
        });
    }
  }
  assert(
    this.state === ThaliManager.STATES.STARTED,
    'ThaliManager state should be \'STARTED\' for stop'
  );
  this.state = ThaliManager.STATES.STOPPING;

  logger.debug('stopping thaliPullReplicationFromNotification');
  this._thaliPullReplicationFromNotification.stop();

  logger.debug('stopping thaliSendNotificationBasedOnReplication');
  this._stoppingPromise = this._thaliSendNotificationBasedOnReplication.stop()

  .then(function () {
    logger.debug('stopping thaliPeerPoolInterface');
    return self._thaliPeerPoolInterface.stop();
  })

  .then(function () {
    logger.debug('stopping advertising and listening');
    return ThaliMobile.stopAdvertisingAndListening();
  })

  .then(function () {
    logger.debug('stopping listening for advertisements');
    return ThaliMobile.stopListeningForAdvertisements();
  })

  .then(function () {
    logger.debug('stopping ThaliMobile');
    return ThaliMobile.stop();
  })

  .then(function () {
    self.state = ThaliManager.STATES.STOPPED;
    self._stoppingPromise = undefined;
  });

  return this._stoppingPromise;
};

/**
 * This is connection filter. What role we can assign to request.connection?
 * @private
 * @param {object} request
 * @param {object} response
 * @param {Function} nextHandler
 * @returns {boolean}
 */
ThaliManager.prototype._connectionFilter = function (request, response, nextHandler) {
  logger.debug(
    'connected pskIdentity', request.connection.pskIdentity,
    'for path', request.path
  );

  // We need to let connections passing through the connection filter
  // in starting, started and stopping state in order to let peer actions be
  // properly started and stopped.
  assert(
    this.state === ThaliManager.STATES.STARTING ||
    this.state === ThaliManager.STATES.STARTED ||
    this.state === ThaliManager.STATES.STOPPING,
    'ThaliManager is not ready to accept any connection when state is ' + this.state
  );

  if (request.connection.authorized) {
    var secret = this._getPskIdToSecret(request.connection.pskIdentity);
    if (secret === thaliConfig.BEACON_KEY) {
      /*
        * When folks want to access the beacon they need to connect via TLS with a
        * predefined PSK. So we need to check for the magic PSK and if used then the
        * caller will only be allowed to make a GET request to the beacon path and
        * nothing else.
        * The current magic PSK identity value is 'beacons' and the secret is a binary
        * array consisting of 16 zero bytes in a row.
        */
      request.connection.pskRole = 'beacon';
    } else if (secret) {
      /*
        * In this role the user connected over TLS using a PSK that we can associate
        * with an identity (this is generated as part of beacon generation). We would
        * then surface the public key for the identity to the router who would check
        * that the path for the request is from our white list. The white list will
        * contain Express-Pouch DB paths and methods that the caller can get to. These
        * will include paths/methods needed for pull replication as well as the ability
        * to get to _Local.
        */
      request.connection.pskRole = 'replication';
    } else {
      // Default role. It is usually unused.
      request.connection.pskRole = 'public';
    }
  } else {
    logger.debug('connected pskIdentity is not authorized');
    return response.status(401).send({
      success: false,
      message: 'Unauthorized'
    });
  }

  nextHandler();
}

/**
 * This is thali id callback. Is thali id valid?
 * @private
 * @param {string} thaliId
 * @param {object} request
 * @returns {boolean}
 */
ThaliManager.prototype._resolveThaliId = function (thaliId, request) {
  // In the case of an id that begins with the string [LOCAL_SEQ_POINT_PREFIX]
  // we MUST enforce that the value of the :id EXACTLY matches the hashed
  // public key of the caller as generated by thaliNotificationBeacons.createPublicKeyHash.

  var publicKey = this._getPskIdToPublicKey(request.connection.pskIdentity);
  assert(Buffer.isBuffer(publicKey), 'publicKey should be a buffer');
  return Buffer.compare(new Buffer(thaliId, 'base64'), publicKey) === 0;
}

/**
 * This method will provide the actual state of ThaliManager
 * @public
 */
ThaliManager.prototype.getState = function () {
  return this.state;
}

/**
 * ACL data for roles.
 * @private
 * @type {Object}
 * @readonly
 */
ThaliManager._acl = [
  {
    'role': 'replication',
    'paths': [
      {
        'path': thaliConfig.BASE_DB_PATH,
        'verbs': ['GET']
      },
      {
        'path': '/{:db}',
        'verbs': ['GET']
      },
      {
        'path': '/{:db}/_all_docs',
        'verbs': ['GET', 'HEAD', 'POST']
      },
      {
        'path': '/{:db}/_bulk_docs',
        'verbs': ['GET', 'HEAD', 'POST']
      },
      {
        'path': '/{:db}/_bulk_get',
        'verbs': ['POST']
      },
      {
        'path': '/{:db}/_changes',
        'verbs': ['GET', 'POST']
      },
      {
        'path': '/{:db}/_revs_diff',
        'verbs': ['POST']
      },
      {
        'path': '/{:db}/:id',
        'verbs': ['GET']
      },
      {
        'path': '/{:db}/:id/attachment',
        'verbs': ['GET']
      },
      {
        'path': '/{:db}/_local/{:id}',
        'verbs': ['GET', 'PUT', 'DELETE']
      },
      {
        'path': '/{:db}/_local/' + thaliConfig.LOCAL_SEQ_POINT_PREFIX + '{:id}',
        'verbs': ['GET', 'PUT', 'DELETE']
      }
    ]
  },
  {
    'role': 'beacon',
    'paths': [
      {
        'path': '/NotificationBeacons',
        'verbs': ['GET']
      }
    ]
  }
];

module.exports = ThaliManager;
<commit_msg>cosmetics<commit_after>'use strict';

var logger = require('../ThaliLogger')('thaliManager');

var thaliConfig = require('./thaliConfig');
var ThaliMobile = require('./thaliMobile');
var ThaliSendNotificationBasedOnReplication =
  require('./replication/thaliSendNotificationBasedOnReplication');
var ThaliPullReplicationFromNotification =
  require('./replication/thaliPullReplicationFromNotification');

var express = require('express');
var salti = require('salti');
var path = require('path');
var Promise = require('lie');
var assert = require('assert');

/** @module thaliManager */

/**
 * @classdesc This may look like a class but it really should only have one
 * instance or bad stuff can happen.
 *
 * @public
 * @param {expressPouchdb} expressPouchDB The express-pouchdb object we are
 * supposed to use to create the router.
 * @param {PouchDB} PouchDB PouchDB object we are supposed to use to create
 * dbs. Typically this should have PouchDB.defaults set with db to
 * require('leveldown-mobile') and prefix to the path where the application
 * wishes to store the DB.
 * @param {string} dbName Name of the db, both locally and remotely that we are
 * interacting with.
 * @param {Crypto.ECDH} ecdhForLocalDevice A Crypto.ECDH object initialized with
 * the local device's public and private keys.
 * @param {module:thaliPeerPoolInterface~ThaliPeerPoolInterface} [thaliPeerPoolInterface]
 * If your app doesn't specify its own pool interface you will seriously
 * regret it as the default one has awful behavior. Building your own
 * thaliPeerPoolInterface is pretty much a requirement for a decent Thali app.
 *
 * @constructor
 */
function ThaliManager(expressPouchDB,
                      PouchDB,
                      dbName,
                      ecdhForLocalDevice,
                      thaliPeerPoolInterface) {
  var self = this;

  this._router = express.Router();
  this._router.all('*', this._connectionFilter.bind(this));

  this._router.all('*', salti(
    dbName,
    ThaliManager._acl,
    this._resolveThaliId.bind(this),
    { dbPrefix: thaliConfig.BASE_DB_PATH }
  ));

  logger.debug('creating ThaliSendNotificationBasedOnReplication instance');

  this._thaliSendNotificationBasedOnReplication =
    new ThaliSendNotificationBasedOnReplication(
        this._router,
        ecdhForLocalDevice,
        thaliConfig.BEACON_MILLISECONDS_TO_EXPIRE,
        new PouchDB(dbName));
  this._getPskIdToSecret =
    self._thaliSendNotificationBasedOnReplication.getPskIdToSecret();
  this._getPskIdToPublicKey =
    self._thaliSendNotificationBasedOnReplication.getPskIdToPublicKey();

  logger.debug('creating ThaliPullReplicationFromNotification instance');

  this._thaliPullReplicationFromNotification =
    new ThaliPullReplicationFromNotification(
        PouchDB,
        dbName,
        thaliPeerPoolInterface,
        ecdhForLocalDevice);
  this._thaliPeerPoolInterface = thaliPeerPoolInterface;

  logger.debug('creating express pouchdb instance');

  this._router.use(thaliConfig.BASE_DB_PATH, expressPouchDB(PouchDB, {
    mode: 'minimumForPouchDB'
  }));

  this.state = ThaliManager.STATES.CREATED;
}

/**
 * This is a list of states for ThaliManager.
 * @public
 * @readonly
 * @enum {string}
 */
ThaliManager.STATES = {
  CREATED: 'created',
  STARTING: 'starting',
  STARTED: 'started',
  STOPPING: 'stopping',
  STOPPED: 'stopped'
};

/**
 * Starts up everything including listening for advertisements, sending out
 * our advertisements, generating beacons to notify peers that we have data
 * for them as well as running pull replication jobs to pull data from other
 * peers who have data for us.
 *
 * This method is not idempotent as each call to start with different arguments
 * will cause the related states to be changed.
 *
 * @param {Buffer[]} [arrayOfRemoteKeys] This is the list of ECDH public keys
 * that we should be willing to send notifications of our changes to and receive
 * notifications of changes from.
 * @returns {Promise<?Error>}
 */
ThaliManager.prototype.start = function (arrayOfRemoteKeys) {
  var self = this;

  // Can we start now?
  var args = arguments;
  switch (this.state) {
    case ThaliManager.STATES.STARTING: {
      return this._startingPromise;
    }
    case ThaliManager.STATES.STARTED: {
      return Promise.resolve();
    }
    case ThaliManager.STATES.STOPPING: {
      return this._stoppingPromise
        .then(function () {
          return self.start.apply(self, args);
        });
    }
  }
  assert(
    this.state === ThaliManager.STATES.CREATED ||
    this.state === ThaliManager.STATES.STOPPED,
    'ThaliManager state should be \'CREATED\' or \'STOPPED\' for start'
  );
  this.state = ThaliManager.STATES.STARTING;

  logger.debug('starting thaliPullReplicationFromNotification');
  this._thaliPullReplicationFromNotification.start(arrayOfRemoteKeys);

  logger.debug('starting ThaliMobile');
  this._startingPromise = ThaliMobile.start(self._router, self._getPskIdToSecret)

  .then(function () {
    /*
    Ideally we could call startListening and startUpdateAdvertising separately
    but this causes problems in iOS. The issue is that we deal with the
    restriction that there can only be one MCSession between two devices by
    having a leader election where one device will always form the session.
    Imagine that there is device A and B. B is advertising. A hears the
    advertisement and wants to connect but it can't start the session. So what
    it has to do is send an invite to B, who will reject the invite but then
    respond with its own invite to A. For this to work however B has to be
    listening for advertisements (not just making them) because otherwise
    there is no way in iOS for A to ask B for a session (that will be
    refused). Simultaneously A must be listening for advertisements (or it
    wouldn't have heard B) and it must be advertising itself or B couldn't
    establish the MCSession with it. So in practice this means that in iOS
    everyone has to be both listening and advertising at the same time.
    */
    logger.debug('start listening for advertisements');
    return ThaliMobile.startListeningForAdvertisements();
  })

  .then(function () {
    logger.debug('start update advertising and listening');
    return ThaliMobile.startUpdateAdvertisingAndListening();
  })

  .then(function () {
    logger.debug('starting thaliSendNotificationBasedOnReplication');
    return self._thaliSendNotificationBasedOnReplication.start(arrayOfRemoteKeys);
  })

  .then(function () {
    self.state = ThaliManager.STATES.STARTED;
    self._startingPromise = undefined;
  });

  return this._startingPromise;
};

/**
 * Shuts down the radios and deactivates all replications.
 * @public
 * @returns {Promise<?Error>}
 */
ThaliManager.prototype.stop = function () {
  var self = this;

  // Can we stop now?
  var args = arguments;
  switch (this.state) {
    case ThaliManager.STATES.CREATED:
    case ThaliManager.STATES.STOPPED: {
      return Promise.resolve();
    }
    case ThaliManager.STATES.STOPPING: {
      return this._stoppingPromise;
    }
    case ThaliManager.STATES.STARTING: {
      return this._startingPromise
        .then(function () {
          return self.stop.apply(self, args);
        });
    }
  }
  assert(
    this.state === ThaliManager.STATES.STARTED,
    'ThaliManager state should be \'STARTED\' for stop'
  );
  this.state = ThaliManager.STATES.STOPPING;

  logger.debug('stopping thaliPullReplicationFromNotification');
  this._thaliPullReplicationFromNotification.stop();

  logger.debug('stopping thaliSendNotificationBasedOnReplication');
  this._stoppingPromise = this._thaliSendNotificationBasedOnReplication.stop()

  .then(function () {
    logger.debug('stopping thaliPeerPoolInterface');
    return self._thaliPeerPoolInterface.stop();
  })

  .then(function () {
    logger.debug('stopping advertising and listening');
    return ThaliMobile.stopAdvertisingAndListening();
  })

  .then(function () {
    logger.debug('stopping listening for advertisements');
    return ThaliMobile.stopListeningForAdvertisements();
  })

  .then(function () {
    logger.debug('stopping ThaliMobile');
    return ThaliMobile.stop();
  })

  .then(function () {
    self.state = ThaliManager.STATES.STOPPED;
    self._stoppingPromise = undefined;
  });

  return this._stoppingPromise;
};

/**
 * This is connection filter. What role we can assign to request.connection?
 * @private
 * @param {object} request
 * @param {object} response
 * @param {Function} nextHandler
 * @returns {boolean}
 */
ThaliManager.prototype._connectionFilter = function (request, response, nextHandler) {
  logger.debug(
    'connected pskIdentity', request.connection.pskIdentity,
    'for path', request.path
  );

  // We need to let connections passing through the connection filter
  // in starting, started and stopping state in order to let peer actions be
  // properly started and stopped.
  assert(
    this.state === ThaliManager.STATES.STARTING ||
    this.state === ThaliManager.STATES.STARTED ||
    this.state === ThaliManager.STATES.STOPPING,
    'ThaliManager is not ready to accept any connection when state is ' + this.state
  );

  if (request.connection.authorized) {
    var secret = this._getPskIdToSecret(request.connection.pskIdentity);
    if (secret === thaliConfig.BEACON_KEY) {
      /*
        * When folks want to access the beacon they need to connect via TLS with a
        * predefined PSK. So we need to check for the magic PSK and if used then the
        * caller will only be allowed to make a GET request to the beacon path and
        * nothing else.
        * The current magic PSK identity value is 'beacons' and the secret is a binary
        * array consisting of 16 zero bytes in a row.
        */
      request.connection.pskRole = 'beacon';
    } else if (secret) {
      /*
        * In this role the user connected over TLS using a PSK that we can associate
        * with an identity (this is generated as part of beacon generation). We would
        * then surface the public key for the identity to the router who would check
        * that the path for the request is from our white list. The white list will
        * contain Express-Pouch DB paths and methods that the caller can get to. These
        * will include paths/methods needed for pull replication as well as the ability
        * to get to _Local.
        */
      request.connection.pskRole = 'replication';
    } else {
      // Default role. It is usually unused.
      request.connection.pskRole = 'public';
    }
  } else {
    logger.debug('connected pskIdentity is not authorized');
    return response.status(401).send({
      success: false,
      message: 'Unauthorized'
    });
  }

  nextHandler();
}

/**
 * This is thali id callback. Is thali id valid?
 * @private
 * @param {string} thaliId
 * @param {object} request
 * @returns {boolean}
 */
ThaliManager.prototype._resolveThaliId = function (thaliId, request) {
  // In the case of an id that begins with the string [LOCAL_SEQ_POINT_PREFIX]
  // we MUST enforce that the value of the :id EXACTLY matches the hashed
  // public key of the caller as generated by thaliNotificationBeacons.createPublicKeyHash.

  var publicKey = this._getPskIdToPublicKey(request.connection.pskIdentity);
  assert(Buffer.isBuffer(publicKey), 'publicKey should be a buffer');
  return Buffer.compare(new Buffer(thaliId, 'base64'), publicKey) === 0;
}

/**
 * This method will provide the actual state of ThaliManager
 * @public
 */
ThaliManager.prototype.getState = function () {
  return this.state;
}

/**
 * ACL data for roles.
 * @private
 * @type {Object}
 * @readonly
 */
ThaliManager._acl = [
  {
    'role': 'replication',
    'paths': [
      {
        'path': thaliConfig.BASE_DB_PATH,
        'verbs': ['GET']
      },
      {
        'path': '/{:db}',
        'verbs': ['GET']
      },
      {
        'path': '/{:db}/_all_docs',
        'verbs': ['GET', 'HEAD', 'POST']
      },
      {
        'path': '/{:db}/_bulk_docs',
        'verbs': ['GET', 'HEAD', 'POST']
      },
      {
        'path': '/{:db}/_bulk_get',
        'verbs': ['POST']
      },
      {
        'path': '/{:db}/_changes',
        'verbs': ['GET', 'POST']
      },
      {
        'path': '/{:db}/_revs_diff',
        'verbs': ['POST']
      },
      {
        'path': '/{:db}/:id',
        'verbs': ['GET']
      },
      {
        'path': '/{:db}/:id/attachment',
        'verbs': ['GET']
      },
      {
        'path': '/{:db}/_local/{:id}',
        'verbs': ['GET', 'PUT', 'DELETE']
      },
      {
        'path': '/{:db}/_local/' + thaliConfig.LOCAL_SEQ_POINT_PREFIX + '{:id}',
        'verbs': ['GET', 'PUT', 'DELETE']
      }
    ]
  },
  {
    'role': 'beacon',
    'paths': [
      {
        'path': '/NotificationBeacons',
        'verbs': ['GET']
      }
    ]
  }
];

module.exports = ThaliManager;
<|endoftext|>


<commit_before>"use strict";

const pos = require('pos');

const KEYPHRASES = [
  "error",
  "stacktrace",
  "exception"
];

const NOUNS_TO_KEEP = [
  'variable',
  'method',
  'function',
  'class'
];

const BLACKLISTED_COMMANDS = [
  'ls'
];

/**
 * This receives all terminal input and output, for this reason
 * it's assumed that the first line is an input line. This is used to then
 * determine the username and later input lines
 */
class ErrorParser {
  constructor() {
    // Used to identify input lines from terminal output
    this._username = null;

    // Used to indicate whether or not we're watching input
    this._shouldParseOutput = true;
  }
  /**
   * @param str - a new line of input
   * @returns parsed error - this may be multiple lines from previously
   * received input
   */
  parse(str) {
    if (str.length === 0) return null;
    // if this line is an input line, we should check if the command is a command to ignore, and start or stop tracking as appropriate
    if (this.isInputLine(str)) {
      let command = this.getCommandForInputLine(str);
      this._shouldParseOutput = !this.isBlackListed(command);
      return null;
    }
    // ignore if we're currently not tracking output because of a blacklisted command
    if (!this._shouldParseOutput) return null;
    // keep a copy of the string before lowercase, so we can keep the parsed
    // string with its capitalisation
    var rtn = str;
    var parsedString = str.toLowerCase();
    if (!this.isError(parsedString)) return null;
    // Use POS tagging to find nouns which should equate to variable
    // or file names
    var words = new pos.Lexer().lex(parsedString);
    var tagger = new pos.Tagger();
    var taggedWords = tagger.tag(words);
    // Go through each word and remove names so that we can then search
    // using a generic error
    for (var i in taggedWords) {
      var taggedWord = taggedWords[i];
      var word = taggedWord[0];
      var tag = taggedWord[1];
      // If we've found a noun that isn't an error name
      if ((tag == 'NN') && (word.length > 0) && (!this.isWhiteListed(word))) {
        // Remove it from the string. We remove the following space as well
        // for readability
        // TODO: figure out how to match boundary as well, so we don't end up
        // with loose punctuation in return value
        try {
          // We call replace on the original string to maintain case
          rtn = rtn.replace(new RegExp('\\b'+word+'\\b',"i"), '');
        } catch (e) {
          // There are cases where the parsed words return invalid regex. In
          // this case we'll ignore those words
        }
      }
    }
    // remove empty quotes since the variable names may be in quotes
    rtn = rtn.replace(new RegExp("\'\'", 'g'), '');
    // remove unnecessary spaces that were left during replace
    rtn = rtn.replace(/\s\s+/g, ' ');
    return rtn;
  }

  isError(str) {
    if (str.length == 0) return false;
    // split on all punctuation
    let words = str.split(/[^\w\s]|_/g);
    for (var i in KEYPHRASES) {
      var substr = KEYPHRASES[i];
      for (var j in words) {
        let word = words[j];
        // only looking for words that end in error
        if (word.endsWith(substr)) return true;
      }
    }
    return false;
  }

  /**
   * Will return true if the phrase contains any words or phrases that
   * we expected to be useful in the message
   */
  isWhiteListed(phrase) {
    for (var i in KEYPHRASES) {
      if (phrase.indexOf(KEYPHRASES[i]) > -1) return true;
    }
    for (var i in NOUNS_TO_KEEP) {
      if (phrase == NOUNS_TO_KEEP[i]) return true;
    }
    return false;
  }

  /**
   * TODO: should the error parser be filtering this or should we also
   * have a `script` parser that determines legitimate output and filters
   * out backspaces etc.?
   */
  isInputLine(command) {
    // We assume that the first line with a dollar sign in it is an input
    // line. Therefore we can get the username
    if (this._username === null) {
      this._username = command.substring(0, command.indexOf("$") + 1);
      return true;
    }
    // If it starts with the stored username then its an input line
    return command.indexOf(this._username) == 0;
  }

  /**
   * Will return true if the command matches any of the blacklisted commands
   * to ignore
   */
  isBlackListed(command) {
    if (BLACKLISTED_COMMANDS.indexOf(command) !== -1) return true;
    return false;
  }

  /**
   * Returns the command given of an input line, e.g. "username$ ls -la" -> "ls -la"
   * Optionally return the whole command or just the base command
   */
  getCommandForInputLine(line, getBaseCommand = true) {
    // We assume that the first line with a dollar sign in it is an input
    // line. Therefore we can get the username
    let wholeCommand = line.substring(line.indexOf("$") + 1).trim();

    return getBaseCommand ? wholeCommand.split(" ")[0] : wholeCommand;
  }
}

module.exports = ErrorParser;
<commit_msg>Fix edge case where username isnt in first line<commit_after>"use strict";

const pos = require('pos');

const KEYPHRASES = [
  "error",
  "stacktrace",
  "exception"
];

const NOUNS_TO_KEEP = [
  'variable',
  'method',
  'function',
  'class'
];

const BLACKLISTED_COMMANDS = [
  'ls'
];

/**
 * This receives all terminal input and output, for this reason
 * it's assumed that the first line is an input line. This is used to then
 * determine the username and later input lines
 */
class ErrorParser {
  constructor() {
    // Used to identify input lines from terminal output
    this._username = null;

    // Used to indicate whether or not we're watching input
    this._shouldParseOutput = true;
  }
  /**
   * @param str - a new line of input
   * @returns parsed error - this may be multiple lines from previously
   * received input
   */
  parse(str) {
    if (str.length === 0) return null;
    // if this line is an input line, we should check if the command is a command to ignore, and start or stop tracking as appropriate
    if (this.isInputLine(str)) {
      let command = this.getCommandForInputLine(str);
      this._shouldParseOutput = !this.isBlackListed(command);
      return null;
    }
    // ignore if we're currently not tracking output because of a blacklisted command
    if (!this._shouldParseOutput) return null;
    // keep a copy of the string before lowercase, so we can keep the parsed
    // string with its capitalisation
    var rtn = str;
    var parsedString = str.toLowerCase();
    if (!this.isError(parsedString)) return null;
    // Use POS tagging to find nouns which should equate to variable
    // or file names
    var words = new pos.Lexer().lex(parsedString);
    var tagger = new pos.Tagger();
    var taggedWords = tagger.tag(words);
    // Go through each word and remove names so that we can then search
    // using a generic error
    for (var i in taggedWords) {
      var taggedWord = taggedWords[i];
      var word = taggedWord[0];
      var tag = taggedWord[1];
      // If we've found a noun that isn't an error name
      if ((tag == 'NN') && (word.length > 0) && (!this.isWhiteListed(word))) {
        // Remove it from the string. We remove the following space as well
        // for readability
        // TODO: figure out how to match boundary as well, so we don't end up
        // with loose punctuation in return value
        try {
          // We call replace on the original string to maintain case
          rtn = rtn.replace(new RegExp('\\b'+word+'\\b',"i"), '');
        } catch (e) {
          // There are cases where the parsed words return invalid regex. In
          // this case we'll ignore those words
        }
      }
    }
    // remove empty quotes since the variable names may be in quotes
    rtn = rtn.replace(new RegExp("\'\'", 'g'), '');
    // remove unnecessary spaces that were left during replace
    rtn = rtn.replace(/\s\s+/g, ' ');
    return rtn;
  }

  isError(str) {
    if (str.length == 0) return false;
    // split on all punctuation
    let words = str.split(/[^\w\s]|_/g);
    for (var i in KEYPHRASES) {
      var substr = KEYPHRASES[i];
      for (var j in words) {
        let word = words[j];
        // only looking for words that end in error
        if (word.endsWith(substr)) return true;
      }
    }
    return false;
  }

  /**
   * Will return true if the phrase contains any words or phrases that
   * we expected to be useful in the message
   */
  isWhiteListed(phrase) {
    for (var i in KEYPHRASES) {
      if (phrase.indexOf(KEYPHRASES[i]) > -1) return true;
    }
    for (var i in NOUNS_TO_KEEP) {
      if (phrase == NOUNS_TO_KEEP[i]) return true;
    }
    return false;
  }

  /**
   * TODO: should the error parser be filtering this or should we also
   * have a `script` parser that determines legitimate output and filters
   * out backspaces etc.?
   */
  isInputLine(command) {
    // We assume that the first line with a dollar sign in it is an input
    // line. Therefore we can get the username
    if (this._username === null) {
      if (command.indexOf("$") === -1) return false;
      this._username = command.substring(0, command.indexOf("$") + 1);
      return true;
    }
    // If it starts with the stored username then its an input line
    return command.indexOf(this._username) == 0;
  }

  /**
   * Will return true if the command matches any of the blacklisted commands
   * to ignore
   */
  isBlackListed(command) {
    if (BLACKLISTED_COMMANDS.indexOf(command) !== -1) return true;
    return false;
  }

  /**
   * Returns the command given of an input line, e.g. "username$ ls -la" -> "ls -la"
   * Optionally return the whole command or just the base command
   */
  getCommandForInputLine(line, getBaseCommand = true) {
    // We assume that the first line with a dollar sign in it is an input
    // line. Therefore we can get the username
    let wholeCommand = line.substring(line.indexOf("$") + 1).trim();

    return getBaseCommand ? wholeCommand.split(" ")[0] : wholeCommand;
  }
}

module.exports = ErrorParser;
<|endoftext|>


<commit_before>var uuid = require('uuid'),
    util = require('util'),
    each = require('lodash/each'),
    utils = require('./utils'),
    merge = require('lodash/merge'),
    isString = require('lodash/isString');

/**
 * @description Ignition Error Prototype.
 *
 * Ignition offers a set of general & pre-configured error definitions you can use in your project.
 * If you instantiate an error, Ignition will try to set up all error properties based on your input.
 * Ignition errors stick to the format of native errors + add's more custom attributes.
 *
 * @TODO: Move this code into errors.js.
 * @TODO: Re-write and use ES6 class.
 *
 * @param {Object} options
 * @constructor
 */
function IgnitionError(options) {
    options = options || {};
    var self = this;

    if (isString(options)) {
        throw new Error('Please instantiate Errors with the option pattern. e.g. new errors.IgnitionError({message: ...})');
    }

    Error.call(this);
    Error.captureStackTrace(this, IgnitionError);

    /**
     * defaults
     */
    this.statusCode = 500;
    this.errorType = 'InternalServerError';
    this.level = 'normal';
    this.message = 'The server has encountered an error.';
    this.id = uuid.v1();

    /**
     * custom overrides
     */
    this.id = options.id || this.id;
    this.statusCode = options.statusCode || this.statusCode;
    this.level = options.level || this.level;
    this.context = options.context || this.context;
    this.help = options.help || this.help;
    this.errorType = this.name = options.errorType || this.errorType;
    this.errorDetails = options.errorDetails;
    this.code = options.code || null;
    this.property = options.property || null;
    this.redirect = options.redirect || null;

    this.message = options.message || this.message;
    this.hideStack = options.hideStack;

    // NOTE: Error to inherit from, override!
    //       Nested objects are getting copied over in one piece (can be changed, but not needed right now)
    if (options.err) {
        // CASE: Support err as string (it happens that third party libs return a string instead of an error instance)
        if (isString(options.err)) {
            options.err = new Error(options.err);
        }

        Object.getOwnPropertyNames(options.err).forEach(function (property) {
            if (['errorType', 'name', 'statusCode', 'message', 'level'].indexOf(property) !== -1) {
                return;
            }

            // CASE: `code` should put options as priority over err
            if (property === 'code') {
                self[property] = self[property] || options.err[property];
                return;
            }

            if (property === 'stack') {
                self[property] += '\n\n' + options.err[property];
                return;
            }

            self[property] = options.err[property] || self[property];
        });
    }
}

// jscs:disable
var errors = {
    InternalServerError: function InternalServerError(options) {
        IgnitionError.call(this, merge({
            statusCode: 500,
            level: 'critical',
            errorType: 'InternalServerError',
            message: 'The server has encountered an error.'
        }, options));
    },
    IncorrectUsageError: function IncorrectUsageError(options) {
        IgnitionError.call(this, merge({
            statusCode: 400,
            level: 'critical',
            errorType: 'IncorrectUsageError',
            message: 'We detected a misuse. Please read the stack trace.'
        }, options));
    },
    NotFoundError: function NotFoundError(options) {
        IgnitionError.call(this, merge({
            statusCode: 404,
            errorType: 'NotFoundError',
            message: 'Resource could not be found.'
        }, options));
    },
    BadRequestError: function BadRequestError(options) {
        IgnitionError.call(this, merge({
            statusCode: 400,
            errorType: 'BadRequestError',
            message: 'The request could not be understood.'
        }, options));
    },
    UnauthorizedError: function UnauthorizedError(options) {
        IgnitionError.call(this, merge({
            statusCode: 401,
            errorType: 'UnauthorizedError',
            message: 'You are not authorised to make this request.'
        }, options));
    },
    PasswordResetRequiredError: function PasswordResetRequiredError(options) {
        IgnitionError.call(this, merge({
            statusCode: 401,
            errorType: 'PasswordResetRequiredError',
            message: 'Your password has been reset for security. Please follow the forgotten password flow to set a new password.'
        }, options));
    },
    NoPermissionError: function NoPermissionError(options) {
        IgnitionError.call(this, merge({
            statusCode: 403,
            errorType: 'NoPermissionError',
            message: 'You do not have permission to perform this request.'
        }, options));
    },
    ValidationError: function ValidationError(options) {
        IgnitionError.call(this, merge({
            statusCode: 422,
            errorType: 'ValidationError',
            message: 'The request failed validation.'
        }, options));
    },
    UnsupportedMediaTypeError: function UnsupportedMediaTypeError(options) {
        IgnitionError.call(this, merge({
            statusCode: 415,
            errorType: 'UnsupportedMediaTypeError',
            message: 'The media in the request is not supported by the server.'
        }, options));
    },
    TooManyRequestsError: function TooManyRequestsError(options) {
        IgnitionError.call(this, merge({
            statusCode: 429,
            errorType: 'TooManyRequestsError',
            message: 'Server has received too many similar requests in a short space of time.'
        }, options));
    },
    MaintenanceError: function MaintenanceError(options) {
        IgnitionError.call(this, merge({
            statusCode: 503,
            errorType: 'MaintenanceError',
            message: 'The server is temporarily down for maintenance.'
        }, options));
    },
    MethodNotAllowedError: function MethodNotAllowedError(options) {
        IgnitionError.call(this, merge({
            statusCode: 405,
            errorType: 'MethodNotAllowedError',
            message: 'Method not allowed for resource.'
        }, options));
    },
    RequestEntityTooLargeError: function RequestEntityTooLargeError(options) {
        IgnitionError.call(this, merge({
            statusCode: 413,
            errorType: 'RequestEntityTooLargeError',
            message: 'Request was too big for the server to handle.'
        }, options));
    },
    TokenRevocationError: function TokenRevocationError(options) {
        IgnitionError.call(this, merge({
            statusCode: 503,
            errorType: 'TokenRevocationError',
            message: 'Token is no longer available.'
        }, options));
    },
    VersionMismatchError: function VersionMismatchError(options) {
        IgnitionError.call(this, merge({
            statusCode: 400,
            errorType: 'VersionMismatchError',
            message: 'Requested version does not match server version.'
        }, options));
    }
};

util.inherits(IgnitionError, Error);
each(errors, function (error) {
    util.inherits(error, IgnitionError);
});

module.exports = errors;
module.exports.IgnitionError = IgnitionError;
module.exports.utils = {
    serialize: utils.serialize.bind(errors),
    deserialize: utils.deserialize.bind(errors),
    isIgnitionError: utils.isIgnitionError.bind(errors)
};

<commit_msg>Updated `PasswordResetRequiredError` message text<commit_after>var uuid = require('uuid'),
    util = require('util'),
    each = require('lodash/each'),
    utils = require('./utils'),
    merge = require('lodash/merge'),
    isString = require('lodash/isString');

/**
 * @description Ignition Error Prototype.
 *
 * Ignition offers a set of general & pre-configured error definitions you can use in your project.
 * If you instantiate an error, Ignition will try to set up all error properties based on your input.
 * Ignition errors stick to the format of native errors + add's more custom attributes.
 *
 * @TODO: Move this code into errors.js.
 * @TODO: Re-write and use ES6 class.
 *
 * @param {Object} options
 * @constructor
 */
function IgnitionError(options) {
    options = options || {};
    var self = this;

    if (isString(options)) {
        throw new Error('Please instantiate Errors with the option pattern. e.g. new errors.IgnitionError({message: ...})');
    }

    Error.call(this);
    Error.captureStackTrace(this, IgnitionError);

    /**
     * defaults
     */
    this.statusCode = 500;
    this.errorType = 'InternalServerError';
    this.level = 'normal';
    this.message = 'The server has encountered an error.';
    this.id = uuid.v1();

    /**
     * custom overrides
     */
    this.id = options.id || this.id;
    this.statusCode = options.statusCode || this.statusCode;
    this.level = options.level || this.level;
    this.context = options.context || this.context;
    this.help = options.help || this.help;
    this.errorType = this.name = options.errorType || this.errorType;
    this.errorDetails = options.errorDetails;
    this.code = options.code || null;
    this.property = options.property || null;
    this.redirect = options.redirect || null;

    this.message = options.message || this.message;
    this.hideStack = options.hideStack;

    // NOTE: Error to inherit from, override!
    //       Nested objects are getting copied over in one piece (can be changed, but not needed right now)
    if (options.err) {
        // CASE: Support err as string (it happens that third party libs return a string instead of an error instance)
        if (isString(options.err)) {
            options.err = new Error(options.err);
        }

        Object.getOwnPropertyNames(options.err).forEach(function (property) {
            if (['errorType', 'name', 'statusCode', 'message', 'level'].indexOf(property) !== -1) {
                return;
            }

            // CASE: `code` should put options as priority over err
            if (property === 'code') {
                self[property] = self[property] || options.err[property];
                return;
            }

            if (property === 'stack') {
                self[property] += '\n\n' + options.err[property];
                return;
            }

            self[property] = options.err[property] || self[property];
        });
    }
}

// jscs:disable
var errors = {
    InternalServerError: function InternalServerError(options) {
        IgnitionError.call(this, merge({
            statusCode: 500,
            level: 'critical',
            errorType: 'InternalServerError',
            message: 'The server has encountered an error.'
        }, options));
    },
    IncorrectUsageError: function IncorrectUsageError(options) {
        IgnitionError.call(this, merge({
            statusCode: 400,
            level: 'critical',
            errorType: 'IncorrectUsageError',
            message: 'We detected a misuse. Please read the stack trace.'
        }, options));
    },
    NotFoundError: function NotFoundError(options) {
        IgnitionError.call(this, merge({
            statusCode: 404,
            errorType: 'NotFoundError',
            message: 'Resource could not be found.'
        }, options));
    },
    BadRequestError: function BadRequestError(options) {
        IgnitionError.call(this, merge({
            statusCode: 400,
            errorType: 'BadRequestError',
            message: 'The request could not be understood.'
        }, options));
    },
    UnauthorizedError: function UnauthorizedError(options) {
        IgnitionError.call(this, merge({
            statusCode: 401,
            errorType: 'UnauthorizedError',
            message: 'You are not authorised to make this request.'
        }, options));
    },
    PasswordResetRequiredError: function PasswordResetRequiredError(options) {
        IgnitionError.call(this, merge({
            statusCode: 401,
            errorType: 'PasswordResetRequiredError',
            message: 'As a security precaution, your password must be reset. Click "Forgot?" to receive an email with instructions.'
        }, options));
    },
    NoPermissionError: function NoPermissionError(options) {
        IgnitionError.call(this, merge({
            statusCode: 403,
            errorType: 'NoPermissionError',
            message: 'You do not have permission to perform this request.'
        }, options));
    },
    ValidationError: function ValidationError(options) {
        IgnitionError.call(this, merge({
            statusCode: 422,
            errorType: 'ValidationError',
            message: 'The request failed validation.'
        }, options));
    },
    UnsupportedMediaTypeError: function UnsupportedMediaTypeError(options) {
        IgnitionError.call(this, merge({
            statusCode: 415,
            errorType: 'UnsupportedMediaTypeError',
            message: 'The media in the request is not supported by the server.'
        }, options));
    },
    TooManyRequestsError: function TooManyRequestsError(options) {
        IgnitionError.call(this, merge({
            statusCode: 429,
            errorType: 'TooManyRequestsError',
            message: 'Server has received too many similar requests in a short space of time.'
        }, options));
    },
    MaintenanceError: function MaintenanceError(options) {
        IgnitionError.call(this, merge({
            statusCode: 503,
            errorType: 'MaintenanceError',
            message: 'The server is temporarily down for maintenance.'
        }, options));
    },
    MethodNotAllowedError: function MethodNotAllowedError(options) {
        IgnitionError.call(this, merge({
            statusCode: 405,
            errorType: 'MethodNotAllowedError',
            message: 'Method not allowed for resource.'
        }, options));
    },
    RequestEntityTooLargeError: function RequestEntityTooLargeError(options) {
        IgnitionError.call(this, merge({
            statusCode: 413,
            errorType: 'RequestEntityTooLargeError',
            message: 'Request was too big for the server to handle.'
        }, options));
    },
    TokenRevocationError: function TokenRevocationError(options) {
        IgnitionError.call(this, merge({
            statusCode: 503,
            errorType: 'TokenRevocationError',
            message: 'Token is no longer available.'
        }, options));
    },
    VersionMismatchError: function VersionMismatchError(options) {
        IgnitionError.call(this, merge({
            statusCode: 400,
            errorType: 'VersionMismatchError',
            message: 'Requested version does not match server version.'
        }, options));
    }
};

util.inherits(IgnitionError, Error);
each(errors, function (error) {
    util.inherits(error, IgnitionError);
});

module.exports = errors;
module.exports.IgnitionError = IgnitionError;
module.exports.utils = {
    serialize: utils.serialize.bind(errors),
    deserialize: utils.deserialize.bind(errors),
    isIgnitionError: utils.isIgnitionError.bind(errors)
};

<|endoftext|>


<commit_before>module.exports = function(grunt) {

	//Loads all grunt tasks matching the ['grunt-*', '@*/grunt-*'] patterns.
	require('load-grunt-tasks')(grunt);

	grunt.initConfig({

		pkg: grunt.file.readJSON('package.json'),

		watch: {
			options: {
				livereload: true,
			},
			scss: {
				files: ['css/sass/*.scss', 'css/sass/**/*.scss'],
				tasks: ['compass', 'combine_mq', 'cssmin', 'gitadd', 'gitcommit'],
				options: {
					spawn: false
				}
			},
			scripts: {
				files: ['js/config.js', 'js/modules/**/*.js', 'Gruntfile.js'],
				tasks: ['jshint', 'requirejs', 'gitadd', 'gitcommit']
			},
			images: {
				files: ['images/**/*.{png,jpg,gif}'],
				tasks: ['gitadd', 'gitcommit']
			},
			src: {
				files: [
					'!node_modules/*',
					'package.json',
					'**/*.php',
					'screenshot.png'
				],
				tasks: ['gitadd', 'gitcommit']
			}
		},

		gitadd: {
			task: {
				options: {
					all: true,
					force: true
				},
				files: {
					src: [
					'*.{php,png,css,rb,json,js}',
					'js/**/*.{js,htc}',
					'css/*.css',
					'css/sass/**/*.{scss,sass}',
					'page_templates/*.php',
					'images/*.{png,jpg,gif}'
					]
				}
			}
		},

		gitcommit: {
			your_target: {
				options: {
					cwd: '../../',
					message: 'Repo updated on: ' + grunt.template.today()
				},
				files: [{
					src: ['*'],
					expand: true,
					cwd: 'themes/digitalportfolio/'
				}]
			}
		},

		compass: {
			dist: {
				options: {
					config: 'config.rb',
					sassDir: 'css/sass',
					cssDir: 'css',
					environment: 'development'
				}
			}
		},

		combine_mq: {
			options: {
				beautify: true
			},
			main: {
				src: 'style.css',
				dest: 'style.css'
			}
		},

		cssmin: {
			target: {
				files: [{
					expand: true,
					cwd: 'css/sass',
					src: ['*.css']
				}]
			}
		},

		jshint: {
			all: ['Gruntfile.js']
		},

		requirejs: {
			compile: {
				options: {
					baseUrl: 'js',
					name: 'config',
					optomize: 'none',
					paths: {
						jquery: 'libraries/jquery-1.11.3.min',
						app: 'modules/app'
					},
					out: 'js/optimize.min.js'
				}
			}
		}
	});
	grunt.registerTask('default', [
		'grunt-contrib-grunt-git',
		'grunt-contrib-cssmin',
		'grunt-contrib-combine-mq',
		'grunt-contrib-compass',
		'grunt-contrib-jshint',
		'grunt-contrib-requirejs'
	]);
};<commit_msg>Repo updated on: Sun Dec 20 2015 17:30:24<commit_after>module.exports = function(grunt) {

	//Loads all grunt tasks matching the ['grunt-*', '@*/grunt-*'] patterns.
	require('load-grunt-tasks')(grunt);

	grunt.initConfig({

		pkg: grunt.file.readJSON('package.json'),

		watch: {
			options: {
				livereload: true,
			},
			config: {
				files: ['package.json', 'Gruntfile.js'],
				tasks: ['jshint', 'gitadd', 'gitcommit']
			},
			scss: {
				files: ['css/sass/*.scss', 'css/sass/**/*.scss'],
				tasks: ['compass', 'combine_mq', 'cssmin', 'gitadd', 'gitcommit'],
				options: {
					spawn: false
				}
			},
			scripts: {
				files: ['js/config.js', 'js/modules/**/*.js'],
				tasks: ['jshint', 'requirejs', 'gitadd', 'gitcommit']
			},
			images: {
				files: ['images/**/*.{png,jpg,gif}'],
				tasks: ['gitadd', 'gitcommit']
			},
			src: {
				files: [
					'**/*.php',
					'screenshot.png'
				],
				tasks: ['gitadd', 'gitcommit']
			}
		},

		gitadd: {
			task: {
				options: {
					all: true,
					force: true
				},
				files: {
					src: [
					'*.{php,png,css,rb,json,js}',
					'js/**/*.{js,htc}',
					'css/*.css',
					'css/sass/**/*.{scss,sass}',
					'page_templates/*.php',
					'images/*.{png,jpg,gif}'
					]
				}
			}
		},

		gitcommit: {
			your_target: {
				options: {
					cwd: '../../',
					message: 'Repo updated on: ' + grunt.template.today()
				},
				files: [{
					src: ['*'],
					expand: true,
					cwd: 'themes/digitalportfolio/'
				}]
			}
		},

		compass: {
			dist: {
				options: {
					config: 'config.rb',
					sassDir: 'css/sass',
					cssDir: 'css',
					environment: 'development'
				}
			}
		},

		combine_mq: {
			options: {
				beautify: true
			},
			main: {
				src: 'style.css',
				dest: 'style.css'
			}
		},

		cssmin: {
			target: {
				files: [{
					expand: true,
					cwd: 'css/sass',
					src: ['*.css']
				}]
			}
		},

		jshint: {
			all: ['Gruntfile.js']
		},

		requirejs: {
			compile: {
				options: {
					baseUrl: 'js',
					name: 'config',
					optomize: 'none',
					paths: {
						jquery: 'libraries/jquery-1.11.3.min',
						app: 'modules/app'
					},
					out: 'js/optimize.min.js'
				}
			}
		}
	});
	grunt.registerTask('default', [
		'grunt-contrib-grunt-git',
		'grunt-contrib-cssmin',
		'grunt-contrib-combine-mq',
		'grunt-contrib-compass',
		'grunt-contrib-jshint',
		'grunt-contrib-requirejs'
	]);
};<|endoftext|>


<commit_before>Rye.define('evententEmitter', function(){

    var util = Rye.require('util')

    function evententEmitter () {
        this.eventents = {}
    }

    function parseeventent (event) {
        var i = event.lastIndexOf('.')
        return {
            name      : (i < 0 ? event : event.substring(0, event.lastIndexOf('.')))
          , namespace : (i < 0 ? '' : event.substring(event.lastIndexOf('.')+1))
        }
    }

    evententEmitter.prototype.on = function (event, handler) {
        ;(this.eventents[event] || (this.eventents[event] = [])).push(handler)
    }

    evententEmitter.prototype.removeListener = function (event, handler) {
        var eventents = this.eventents
          , p = parseeventent(event)

        if (handler){
            var arr = eventents[event]
            arr.splice(arr.indexOf(handler), 1)
            if (arr.length === 0) {
                delete this.eventents[event]
            }

        } else if (p.name && p.namespace) {
            delete this.eventents[event]

        } else {
            var part = p.namespace ? 'namespace' : 'name'
            for (var e in eventents) {
                if (parseeventent(e)[part] === p[part]) {
                    delete this.eventents[e]
                }
            }
        }
    }

    function fire (arr, context, args) {
        for (var i = 0, ln = arr.length; i < ln; i++) {
            arr[i].apply(context, args)
        }
    }

    evententEmitter.prototype.emit = function (event) {
        var eventents = this.eventents
          , p = parseeventent(event)
          , args = [].slice.call(arguments, 1)
          , matches = []

        if (p.name && p.namespace) {
            fire(eventents[event], this, args)
        } else {
            var part = p.namespace ? 'namespace' : 'name'
            for (var e in eventents) {
                if (parseeventent(e)[part] === p[part]) {
                    fire(eventents[e], this, args)
                }
            }
        }
    }

    evententEmitter.prototype.once = function (event, handler) {
        function suicide () {
            handler.apply(this, arguments)
            this.removeListener(event, remover)
        }
        this.on(event, suicide)
    }

    return evententEmitter

})
<commit_msg>Mega replace fail<commit_after>Rye.define('EventEmitter', function(){

    var util = Rye.require('util')

    function EventEmitter () {
        this.events = {}
    }

    function parseEvent (ev) {
        var i = ev.lastIndexOf('.')
        return {
            name      : (i < 0 ? ev : ev.substring(0, ev.lastIndexOf('.')))
          , namespace : (i < 0 ? '' : ev.substring(ev.lastIndexOf('.')+1))
        }
    }

    EventEmitter.prototype.on = function (ev, handler) {
        ;(this.events[ev] || (this.events[ev] = [])).push(handler)
    }

    EventEmitter.prototype.removeListener = function (ev, handler) {
        var events = this.events
          , p = parseEvent(ev)

        if (handler){
            var arr = events[ev]
            arr.splice(arr.indexOf(handler), 1)
            if (arr.length === 0) {
                delete this.events[ev]
            }

        } else if (p.name && p.namespace) {
            delete this.events[ev]

        } else {
            var part = p.namespace ? 'namespace' : 'name'
            for (var e in events) {
                if (parseEvent(e)[part] === p[part]) {
                    delete this.events[e]
                }
            }
        }
    }

    function fire (arr, context, args) {
        for (var i = 0, ln = arr.length; i < ln; i++) {
            arr[i].apply(context, args)
        }
    }

    EventEmitter.prototype.emit = function (ev) {
        var events = this.events
          , p = parseEvent(ev)
          , args = [].slice.call(arguments, 1)
          , matches = []

        if (p.name && p.namespace) {
            fire(events[ev], this, args)
        } else {
            var part = p.namespace ? 'namespace' : 'name'
            for (var e in events) {
                if (parseEvent(e)[part] === p[part]) {
                    fire(events[e], this, args)
                }
            }
        }
    }

    EventEmitter.prototype.once = function (ev, handler) {
        function suicide () {
            handler.apply(this, arguments)
            this.removeListener(ev, remover)
        }
        this.on(ev, suicide)
    }

    return EventEmitter

})
<|endoftext|>


<commit_before>import { defineProtoFunc } from "./defineProtoFunc.js";

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill
defineProtoFunc(String, 'endsWith', function(search, this_len) {
    if (this_len === undefined || this_len > this.length) {
        this_len = this.length;
    }
    return this.substring(this_len - search.length, this_len) === search;
});

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Polyfill
defineProtoFunc(String, 'includes', function(search, start) {
    'use strict';
    if (typeof start !== 'number') {
        start = 0;
    }

    if (start + search.length > this.length) {
        return false;
    } else {
        return this.indexOf(search, start) !== -1;
    }
});

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill
defineProtoFunc(String, 'startsWith', function(search, rawPos) {
    var pos = rawPos > 0 ? rawPos|0 : 0;
    return this.substring(pos, pos + search.length) === search;
});
<commit_msg>Polyfill for String.trimEnd (#4288)<commit_after>import { defineProtoFunc } from "./defineProtoFunc.js";

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill
defineProtoFunc(String, 'endsWith', function (search, this_len) {
    if (this_len === undefined || this_len > this.length) {
        this_len = this.length;
    }
    return this.substring(this_len - search.length, this_len) === search;
});

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Polyfill
defineProtoFunc(String, 'includes', function (search, start) {
    'use strict';
    if (typeof start !== 'number') {
        start = 0;
    }

    if (start + search.length > this.length) {
        return false;
    } else {
        return this.indexOf(search, start) !== -1;
    }
});

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill
defineProtoFunc(String, 'startsWith', function(search, rawPos) {
    var pos = rawPos > 0 ? rawPos|0 : 0;
    return this.substring(pos, pos + search.length) === search;
});

// https://vanillajstoolkit.com/polyfills/stringtrimend/
defineProtoFunc(String, 'trimEnd', function () {
    return this.replace(new RegExp(/[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/.source + '$', 'g'), '');
});
<|endoftext|>