<commit_before>"use strict"

const width = 500, height = 500

let white = new TGAColor(255, 255, 255, 255)
let red = new TGAColor(255, 0, 0, 255)
let green = new TGAColor(0, 255, 0, 255)
let model, image

main()

async function main() {
	image = new TGAImage(width, height, TGAImage.RGB)

	// await drawModel()
	drawTriangles()

	image.flip_vertically()

	console.log('finish')
}

function drawTriangles() {
	let t0 = [new Vec2i(10, 70), new Vec2i(50, 160), new Vec2i(70, 80)]
	let t1 = [new Vec2i(180, 50), new Vec2i(150, 1), new Vec2i(70, 180)]
	let t2 = [new Vec2i(180, 150), new Vec2i(120, 160), new Vec2i(130, 180)]

	triangle(t0[0], t0[1], t0[2], image, red)
	triangle(t1[0], t1[1], t1[2], image, white)
	triangle(t2[0], t2[1], t2[2], image, green)
}

async function drawModel() {
	let obj = await axios.get('obj/african_head.obj');
	model = new Model(obj.data)

	for(let i=0; i<model.nfaces(); i++) {
		let face = model.face(i)
		for(let j=0;j<3;j++) {
			let v0 = model.vert(face[j])
			let v1 = model.vert(face[(j+1)%3])

			let x0 = ((v0.x+1)*width/2)|0
			let y0 = ((v0.y+1)*height/2)|0
			let x1 = ((v1.x+1)*width/2)|0
			let y1 = ((v1.y+1)*height/2)|0

			line(x0, y0, x1, y1, image, white)
		}
	}
}

function line(x0, y0, x1, y1, image, color) {
	let steep = false

	if(Math.abs(x0-x1) < Math.abs(y0-y1)) {
		[x0, y0, x1, y1] = [y0, x0, y1, x1];
		steep = true
	}
	if(x0>x1) {
		[x0, x1, y0, y1] = [x1, x0, y1, y0];
	}

	let dx = x1-x0
	let dy = y1-y0
	let derror2 = Math.abs(dy)*2
	let error2 = 0
	let y = y0

	for(let x=x0;x<x1;x++) {
		if(steep)
			image.set(y, x, color)
		else
			image.set(x, y, color)
		error2 += derror2
		if(error2 > dx) {
			y += y1 > y0 ? 1 : -1
			error2 -= dx*2
		}
	}
}

function triangle(t0, t1, t2, image, color) {
	// line(t0.x, t0.y, t1.x, t1.y, image, color)
	// line(t2.x, t2.y, t1.x, t1.y, image, color)
	// line(t0.x, t0.y, t2.x, t2.y, image, color)

	const minX = Math.min(t0.x, t1.x, t2.x)
	const maxX = Math.max(t0.x, t1.x, t2.x)
	const minY = Math.min(t0.y, t1.y, t2.y)
	const maxY = Math.max(t0.y, t1.y, t2.y)

	for(let x=minX;x<maxX;x++) {
		for(let y=minY;y<maxY;y++) {
			if(!isPointInsideOfTriangle(new Vec2i(x, y), t0, t1, t2)) continue
			image.set(x, y, color)
		}
	}
}

function isPointInsideOfTriangle(targetPoint, p1, p2, p3) {
	let b1, b2, b3

	b1 = sign(targetPoint, p1, p2) < 0.
	b2 = sign(targetPoint, p2, p3) < 0.
	b3 = sign(targetPoint, p3, p1) < 0.

	return ((b1 == b2) && (b2 == b3))

	function sign(p1, p2, p3) {
		return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)
	}
}<commit_msg>[=] line function works with Vec2i now<commit_after>"use strict"

const width = 500, height = 500

let white = new TGAColor(255, 255, 255, 255)
let red = new TGAColor(255, 0, 0, 255)
let green = new TGAColor(0, 255, 0, 255)
let model, image

main()

async function main() {
	image = new TGAImage(width, height, TGAImage.RGB)

	// await drawModel()
	drawTriangles()

	image.flip_vertically()

	console.log('finish')
}

function drawTriangles() {
	let t0 = [new Vec2i(10, 70), new Vec2i(50, 160), new Vec2i(70, 80)]
	let t1 = [new Vec2i(180, 50), new Vec2i(150, 1), new Vec2i(70, 180)]
	let t2 = [new Vec2i(180, 150), new Vec2i(120, 160), new Vec2i(130, 180)]

	triangle(t0[0], t0[1], t0[2], image, red)
	triangle(t1[0], t1[1], t1[2], image, white)
	triangle(t2[0], t2[1], t2[2], image, green)
}

async function drawModel() {
	let obj = await axios.get('obj/african_head.obj');
	model = new Model(obj.data)

	for(let i=0; i<model.nfaces(); i++) {
		let face = model.face(i)
		for(let j=0;j<3;j++) {
			let v0 = model.vert(face[j])
			let v1 = model.vert(face[(j+1)%3])

			let x0 = ((v0.x+1)*width/2)|0
			let y0 = ((v0.y+1)*height/2)|0
			let x1 = ((v1.x+1)*width/2)|0
			let y1 = ((v1.y+1)*height/2)|0

			line(new Vec2i(x0, y0), new Vec2i(x1, y1), image, white)
		}
	}
}

function line(v0, v1, image, color) {
	if(arguments.length !== 4) throw new Error("Wrong arguments length")
	let [x0, y0, x1, y1] = [v0.x, v0.y, v1.x, v1.y]
	let steep = false

	if(Math.abs(x0-x1) < Math.abs(y0-y1)) {
		[x0, y0, x1, y1] = [y0, x0, y1, x1];
		steep = true
	}
	if(x0>x1) {
		[x0, x1, y0, y1] = [x1, x0, y1, y0];
	}

	let dx = x1-x0
	let dy = y1-y0
	let derror2 = Math.abs(dy)*2
	let error2 = 0
	let y = y0

	for(let x=x0;x<x1;x++) {
		if(steep)
			image.set(y, x, color)
		else
			image.set(x, y, color)
		error2 += derror2
		if(error2 > dx) {
			y += y1 > y0 ? 1 : -1
			error2 -= dx*2
		}
	}
}

function triangle(t0, t1, t2, image, color) {
	// line(t0, t1, image, color)
	// line(t2, t1, image, color)
	// line(t0, t2, image, color)

	const minX = Math.min(t0.x, t1.x, t2.x)
	const maxX = Math.max(t0.x, t1.x, t2.x)
	const minY = Math.min(t0.y, t1.y, t2.y)
	const maxY = Math.max(t0.y, t1.y, t2.y)

	for(let x=minX;x<maxX;x++) {
		for(let y=minY;y<maxY;y++) {
			if(!isPointInsideOfTriangle(new Vec2i(x, y), t0, t1, t2)) continue
			image.set(x, y, color)
		}
	}
}

function isPointInsideOfTriangle(targetPoint, p1, p2, p3) {
	let b1, b2, b3

	b1 = sign(targetPoint, p1, p2) < 0.
	b2 = sign(targetPoint, p2, p3) < 0.
	b3 = sign(targetPoint, p3, p1) < 0.

	return ((b1 == b2) && (b2 == b3))

	function sign(p1, p2, p3) {
		return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)
	}
}<|endoftext|>


<commit_before>// ==UserScript==
// @name         GitHub 汉化插件
// @description  汉化 GitHub 界面的部分菜单及内容。
// @copyright    2016, 楼教主 (http://www.52cik.com/)
// @icon         https://assets-cdn.github.com/pinned-octocat.svg
// @version      1.3.2
// @author       楼教主
// @license      MIT
// @homepageURL  https://github.com/52cik/github-hans
// @match        http://*.github.com/*
// @match        https://*.github.com/*
// @require      http://www.52cik.com/github-hans/locals.js?v1.3.2
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function (window, document, undefined) {
    'use strict';

    // 要翻译的页面正则
    var page = document.body.className.match(I18N.conf.rePageClass);

    if (!page) { // 扩展 pathname 匹配
        page = location.pathname.match(I18N.conf.rePagePath);
    }

    if (!page) { // 扩展 url 匹配
        page = location.href.match(I18N.conf.rePageUrl);
    }

    page = page ? page[1] : false;

    timeElement(); // 时间节点翻译
    walk(document.body); // 立即翻译
    contributions(); // // 贡献日历 基于事件翻译

    $(document).ajaxComplete(function () {
        walk(document.body); // ajax 请求后再次翻译
    });

    function walk(node) {
        var nodes = node.childNodes;

        var i = 0;
        var len = nodes.length;
        var el = null; // 遍历元素用
        var attr; // 元素属性

        for (; i < len; i++) {
            el = nodes[i];

            if (el.nodeType === 1) {
                if (el.tagName === "INPUT") { // 输入框 按钮 处理
                    if (el.type === "button" || el.type === "submit") {
                        el.value = translate(el.value);
                    } else {
                        el.placeholder = translate(el.placeholder);
                    }
                } else if (attr = el.getAttribute('aria-label')) { // 带提示的元素，类似 tooltip 效果的
                    el.setAttribute('aria-label', translate(attr));

                    if (attr = el.getAttribute('data-copied-hint')) { // 复制成功提示
                        el.setAttribute('data-copied-hint', translate(attr));
                    }
                }

                // todo 的跳过 readme, 文件列表, 代码显示
                if (el.id !== 'readme' && !I18N.conf.reIgnore.test(el.className)) {
                    walk(el);
                }
            } else if (el.nodeType === 3) { // 文本节点处理
                el.data = translate(el.data);
            }
        }
    }

    function translate(data) { // 翻译
        var str;
        var _key = data.trim();

        if (_key === '') { return data; } // 空字符返回原始数据

        str = transPage('pubilc', _key); // 公共翻译
        if (str !== _key) { return str; } // 已公共翻译

        if (page === false) { return data; } // 未知页面不翻译

        str = transPage(page, _key); // 翻译已知页面
        return str === _key ? data : str; // 未翻译返回原始数据
    }

    function transPage(page, key) {
        var str, res, len, i;

        // 静态翻译
        str = I18N['zh'][page]['static'][key];
        if (str) { return str; }

        // 正则翻译
        if (res = I18N['zh'][page]['regexp']) {
            for (i = 0, len = res.length; i < len; i++) {
                str = key.replace(res[i][0], res[i][1]);
                if (str !== key) { return str; }
            }
        }

        return key; // 没有翻译条目
    }

    function timeElement () { // 时间节点翻译
        var RelativeTimeElement$getFormattedDate = RelativeTimeElement.prototype.getFormattedDate;
        var TimeAgoElement$getFormattedDate = TimeAgoElement.prototype.getFormattedDate;
        var LocalTimeElement$getFormattedDate = LocalTimeElement.prototype.getFormattedDate;

        var RelativeTime = function(str, el) { // 相对时间解析
            if (/^on ([\w ]+)$/.test(str)) {
                return '于 ' + el.title.replace(/ .+$/, '');
            }

            return str.replace(/just now|(an?|\d+) (second|minute|hour|day|month|year)s? ago/, function(m, d, t) {
                if (m === 'just now') { return '刚刚'; }

                if (d[0] === 'a') { d = '1'; } // a, an 修改为 1

                var dt = {second: '秒', minute: '分钟', hour: '小时', day: '天', month: '个月', year: '年'};

                return d + ' ' + dt[t] + '之前';
            });
        };

        RelativeTimeElement.prototype.getFormattedDate = function() {
            var str = RelativeTimeElement$getFormattedDate.call(this);
            return RelativeTime(str, this);
        };

        TimeAgoElement.prototype.getFormattedDate = function() {
            var str = TimeAgoElement$getFormattedDate.call(this);
            return RelativeTime(str, this);
        };

        LocalTimeElement.prototype.getFormattedDate = function() {
            return this.title.replace(/ .+$/, '');
        };

        // 遍历 time 元素进行翻译
        $('time').each(function (i, el) {
            if (el.getFormattedDate) { // 跳过未注册的 time 元素
                el.textContent = el.getFormattedDate();
            }
        });
    }

    function contributions() { // 贡献日历 基于事件翻译
        var tip = document.getElementsByClassName('svg-tip-one-line');

        setTimeout(function () {
            $('.js-calendar-graph').on('mouseover', '.day', function() {
                var $tip = $(tip);

                var str = $tip.text().trim().replace(/^(No|\d+) contributions? on (.+)$/, function(m, i, d) {
                    var str = '';
                    str += i === 'No' ? '无贡献' : (i + ' 次贡献');
                    str += ' ';

                    var dt = new Date(d);
                    dt.setHours(dt.getHours() + 8); // 为了获取 +8 时区的 ISO 时间。
                    str += dt.toISOString().split('T')[0]; // 得到 yyyy-mm-dd 这样的格式

                    return str;
                });

                $tip.html(str);
                $tip.css('left', $(this).offset().left - tip[0].offsetWidth / 2 + 5.5);
            });
        }, 99);
    }

})(window, document);
<commit_msg>修复贡献日历提示问题<commit_after>// ==UserScript==
// @name         GitHub 汉化插件
// @description  汉化 GitHub 界面的部分菜单及内容。
// @copyright    2016, 楼教主 (http://www.52cik.com/)
// @icon         https://assets-cdn.github.com/pinned-octocat.svg
// @version      1.3.3
// @author       楼教主
// @license      MIT
// @homepageURL  https://github.com/52cik/github-hans
// @match        http://*.github.com/*
// @match        https://*.github.com/*
// @require      http://www.52cik.com/github-hans/locals.js?v1.3.3
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function (window, document, undefined) {
    'use strict';

    // 要翻译的页面正则
    var page = document.body.className.match(I18N.conf.rePageClass);

    if (!page) { // 扩展 pathname 匹配
        page = location.pathname.match(I18N.conf.rePagePath);
    }

    if (!page) { // 扩展 url 匹配
        page = location.href.match(I18N.conf.rePageUrl);
    }

    page = page ? page[1] : false;

    timeElement(); // 时间节点翻译
    walk(document.body); // 立即翻译
    contributions(); // // 贡献日历 基于事件翻译

    $(document).ajaxComplete(function (event, xhr, settings) {
        // console.log(settings.url);
        walk(document.body); // ajax 请求后再次翻译
    });

    function walk(node) {
        var nodes = node.childNodes;

        var i = 0;
        var len = nodes.length;
        var el = null; // 遍历元素用
        var attr; // 元素属性

        for (; i < len; i++) {
            el = nodes[i];

            if (el.nodeType === 1) {
                if (el.tagName === "INPUT") { // 输入框 按钮 处理
                    if (el.type === "button" || el.type === "submit") {
                        el.value = translate(el.value);
                    } else {
                        el.placeholder = translate(el.placeholder);
                    }
                } else if (attr = el.getAttribute('aria-label')) { // 带提示的元素，类似 tooltip 效果的
                    el.setAttribute('aria-label', translate(attr));

                    if (attr = el.getAttribute('data-copied-hint')) { // 复制成功提示
                        el.setAttribute('data-copied-hint', translate(attr));
                    }
                }

                // todo 的跳过 readme, 文件列表, 代码显示
                if (el.id !== 'readme' && !I18N.conf.reIgnore.test(el.className)) {
                    walk(el);
                }
            } else if (el.nodeType === 3) { // 文本节点处理
                el.data = translate(el.data);
            }
        }
    }

    function translate(data) { // 翻译
        var str;
        var _key = data.trim();

        if (_key === '') { return data; } // 空字符返回原始数据

        str = transPage('pubilc', _key); // 公共翻译
        if (str !== _key) { return str; } // 已公共翻译

        if (page === false) { return data; } // 未知页面不翻译

        str = transPage(page, _key); // 翻译已知页面
        return str === _key ? data : str; // 未翻译返回原始数据
    }

    function transPage(page, key) {
        var str, res, len, i;

        // 静态翻译
        str = I18N['zh'][page]['static'][key];
        if (str) { return str; }

        // 正则翻译
        if (res = I18N['zh'][page]['regexp']) {
            for (i = 0, len = res.length; i < len; i++) {
                str = key.replace(res[i][0], res[i][1]);
                if (str !== key) { return str; }
            }
        }

        return key; // 没有翻译条目
    }

    function timeElement() { // 时间节点翻译
        var RelativeTimeElement$getFormattedDate = RelativeTimeElement.prototype.getFormattedDate;
        var TimeAgoElement$getFormattedDate = TimeAgoElement.prototype.getFormattedDate;
        var LocalTimeElement$getFormattedDate = LocalTimeElement.prototype.getFormattedDate;

        var RelativeTime = function (str, el) { // 相对时间解析
            if (/^on ([\w ]+)$/.test(str)) {
                return '于 ' + el.title.replace(/ .+$/, '');
            }

            return str.replace(/just now|(an?|\d+) (second|minute|hour|day|month|year)s? ago/, function (m, d, t) {
                if (m === 'just now') { return '刚刚'; }

                if (d[0] === 'a') { d = '1'; } // a, an 修改为 1

                var dt = {second: '秒', minute: '分钟', hour: '小时', day: '天', month: '个月', year: '年'};

                return d + ' ' + dt[t] + '之前';
            });
        };

        RelativeTimeElement.prototype.getFormattedDate = function () {
            var str = RelativeTimeElement$getFormattedDate.call(this);
            return RelativeTime(str, this);
        };

        TimeAgoElement.prototype.getFormattedDate = function () {
            var str = TimeAgoElement$getFormattedDate.call(this);
            return RelativeTime(str, this);
        };

        LocalTimeElement.prototype.getFormattedDate = function () {
            return this.title.replace(/ .+$/, '');
        };

        // 遍历 time 元素进行翻译
        $('time').each(function (i, el) {
            if (el.getFormattedDate) { // 跳过未注册的 time 元素
                el.textContent = el.getFormattedDate();
            }
        });
    }

    function contributions() { // 贡献日历 基于事件翻译
        var tip = document.getElementsByClassName('svg-tip-one-line');

        /* 调试用
         var $includeFragment = $('include-fragment'); // IncludeFragmentElement 元素
         console.log($includeFragment.length ? '回调' : '直接加载');
         */

        // 等待 IncludeFragmentElement 元素加载完毕后绑定事件, 类似 jq 的 live 事件
        $.observe(".js-calendar-graph-svg", function () {
            setTimeout(function mouseover() {
                $('.js-calendar-graph').on('mouseover', '.day', function () {
                    if (tip.length === 0) { // 没有 tip 元素时推出防止报错
                        return true;
                    }

                    var $tip = $(tip);

                    var str = $tip.text().trim().replace(/^(No|\d+) contributions? on (.+)$/, function (m, i, d) {
                        var str = '';
                        str += i === 'No' ? '无贡献' : (i + ' 次贡献');
                        str += ' ';

                        var dt = new Date(d);
                        dt.setHours(dt.getHours() + 8); // 为了获取 +8 时区的 ISO 时间。
                        str += dt.toISOString().split('T')[0]; // 得到 yyyy-mm-dd 这样的格式

                        return str;
                    });

                    $tip.html(str);
                    $tip.css('left', $(this).offset().left - tip[0].offsetWidth / 2 + 5.5);
                });
            }, 999);
        });
    }

})(window, document);
<|endoftext|>


<commit_before>const rootVm = new Vue({
    el: '#app-sudoku',
    template: `

 event.target.focus()"
    >

                        {{ cell.value }}
                        {{ cell.value }}

 set ? i + 1 : ''), 3)">
                            {{ n }}

        <historical-event :event="command" :key="index" :active="history.commands.length - index === history.current"
        v-for="(command, index) in Array.from(history.commands).reverse()" />

initial

`,
    components: {
        'historical-event': {
            props: { event: Object, active: Boolean, },
            template: '
{{ where + " " + what }}
',
            computed: {
                where: function() {
                    const where = this.event.where;
                    return '(' + (~~(where / 9) + 1) + ',' + (where % 9 + 1) + ')';
                },
                what: function() {
                    switch(this.event.type) {
                    case 'erase': return 'erase';
                    default: return this.event.type + ' ' + this.event.value;
                    }
                },
            },
        }
    },
    computed: {
        affectedIndices: function() { return this.affectedIndicesBy(this.pointed); },
        boxes: function() {
            return this.slice(this.indices.box.map(index => this.cells[index]), 9);
        },
        cells: function() {
            /* manage each number cell by the object: {
                {Boolean} given, -- true if the number is given for clue, otherwise false.
                {Number} value, -- a number between 0 to 9.
                {Array} memo, -- array of Boolean, each element represent the number those of which can be placed, user considers.
            } */
            const initial = Array.from(
                '060003001200500600007090500000400090800000006010005000002010700004009003700200040' // 朝日新聞beパズル 2017/10/07 掲載分
            ).map(Number).map(n => new Object({given: Boolean(n), value: n, memo: Array(9), }));
            const commands = this.history.commands.slice(0, this.history.current);
            return commands.reduce((board, command) => {
                const target = board[command.where];
                switch(command.type) {
                case 'place':
                case 'erase':
                    target.value = command.value;
                    break;
                case 'remark':
                case 'unmark':
                    target.memo[command.value - 1] = command.type[0] === 'r';
                    break;
                case 'flush':
                    this.affectedIndicesBy(command.where).forEach(index => board[index].memo[command.value - 1] = false);
                    break;
                }
                return board;
            }, initial);
        },
        missPlacedIndices: function() {
            const unique = (value, index, array) => array.indexOf(value) === index;
            const indices = [this.indices.row, this.indices.col, this.indices.box].reduce((a, b) => a.concat(b));
            const dupOrNot = this.slice(indices.map(index => this.cells[index].value), 9) // for each 9...
            .map(vs => vs.map((v, i, self) => v && self.slice(0, i).concat(self.slice(i+1)).some(x => x === v))) // flag non-zero and duplicates
            .reduce((a, b) => a.concat(b));
            return dupOrNot.map((v, i) => v ? indices[i] : NaN).filter(unique); // NaN will be removed by unique.
        },
        indices: (() => {
            const colNr = index => index % 9;
            const boxNr = index => 3 * ~~(index / 27) + ~~((index % 9) / 3);
            const row = Array.from({length: 81, }).map((_, index) => index);
            const col = Array.from(row).sort((a, b) => colNr(a) - colNr(b));
            const box = Array.from(row).sort((a, b) => boxNr(a) - boxNr(b));
            const indices = { row: row, col: col, box: box, };
            return () => indices;
        })(),
        pointedCell: function() { return this.cells[this.pointed] || {given: true, }; },
    },
    data: () => new Object({
        pointed: -1,
        /* user operations. this backs undo/redo up.
        `current` points `commands` array index where new command to be inserted into. */
        history: {commands: [], current: 0, },
    }),
    methods: {
        slice: (() => {
            const splitAt = (array, n) => [array.slice(0, n), array.slice(n)];
            const reduceConcat = a => a.length ? a.reduce((a, b) => [a].concat(reduceConcat(b))) : [];

            return (array, n) => {
                const splitted = splitAt(array, n);
                var p = splitted;
                while (p[1].length !== 0) {
                    p[1] = splitAt(p[1], n);
                    p = p[1];
                }
                return reduceConcat(splitted);
            };
        })(),
        affectedIndicesBy: function(cellIndex) {
            const get = array => {
                const index = array.findIndex(x => x === cellIndex);
                const start = 9 * ~~(index / 9);
                return array.slice(start, start + (index !== -1 ? 9 : 0));
            };
            return [get(this.indices.row), get(this.indices.col), get(this.indices.box)]
            .reduce((a, b) => a.concat(b)) // flatten array
            .filter(value => value !== cellIndex) // remove cellIndex itself
            .filter((value, index, array) => array.indexOf(value) === index); // remove duplicates
        },
        onKey: function(event) {
            const ALT = event.altKey;
            const SHIFT = event.shiftKey;
            const NUMBER = Number((/^Digit([1-9])$/.exec(event.code) || [])[1]);
            const UNDO = event.code === 'KeyZ' && ALT && !SHIFT;
            const REDO = (event.code === 'KeyZ' && ALT && SHIFT) || (event.code === 'KeyY' && ALT && !SHIFT);
            if (ALT && NUMBER && this.pointed !== -1) {
                this.mark(NUMBER, !SHIFT);
            } else if (!ALT && NUMBER && !this.pointedCell.given) {
                this.place(NUMBER);
            } else if (['Digit0', 'Backspace'].includes(event.code) && !this.pointedCell.given) {
                this.erase();
            } else if (UNDO && this.history.current !== 0) {
                this.history.current -= 1;
            } else if (REDO && this.history.current != this.history.commands.length) {
                this.history.current += 1;
            }
        },
        place: function(number) {
            this.push({value: number, where: this.pointed, type: 'place', });
        },
        erase: function() {
            this.push({value: 0, where: this.pointed, type: 'erase', });
        },
        mark: function(number, mark) {
            this.push({value: number, where: this.pointed, type: mark ? 'remark' : 'unmark', });
        },
        flush: function() {
            this.push({value: this.pointedCell.value, where: this.pointed, type: 'flush', });
        },
        push: function(command) {
            this.history.commands.splice(this.history.current, Infinity, Object.assign({when: new Date(), }, command));
            this.history.current = this.history.commands.length;
        },
    },
});
<commit_msg>Gather command's `where` definition into push method.<commit_after>const rootVm = new Vue({
    el: '#app-sudoku',
    template: `

 event.target.focus()"
    >

                        {{ cell.value }}
                        {{ cell.value }}

 set ? i + 1 : ''), 3)">
                            {{ n }}

        <historical-event :event="command" :key="index" :active="history.commands.length - index === history.current"
        v-for="(command, index) in Array.from(history.commands).reverse()" />

initial

`,
    components: {
        'historical-event': {
            props: { event: Object, active: Boolean, },
            template: '
{{ where + " " + what }}
',
            computed: {
                where: function() {
                    const where = this.event.where;
                    return '(' + (~~(where / 9) + 1) + ',' + (where % 9 + 1) + ')';
                },
                what: function() {
                    switch(this.event.type) {
                    case 'erase': return 'erase';
                    default: return this.event.type + ' ' + this.event.value;
                    }
                },
            },
        }
    },
    computed: {
        affectedIndices: function() { return this.affectedIndicesBy(this.pointed); },
        boxes: function() {
            return this.slice(this.indices.box.map(index => this.cells[index]), 9);
        },
        cells: function() {
            /* manage each number cell by the object: {
                {Boolean} given, -- true if the number is given for clue, otherwise false.
                {Number} value, -- a number between 0 to 9.
                {Array} memo, -- array of Boolean, each element represent the number those of which can be placed, user considers.
            } */
            const initial = Array.from(
                '060003001200500600007090500000400090800000006010005000002010700004009003700200040' // 朝日新聞beパズル 2017/10/07 掲載分
            ).map(Number).map(n => new Object({given: Boolean(n), value: n, memo: Array(9), }));
            const commands = this.history.commands.slice(0, this.history.current);
            return commands.reduce((board, command) => {
                const target = board[command.where];
                switch(command.type) {
                case 'place':
                case 'erase':
                    target.value = command.value;
                    break;
                case 'remark':
                case 'unmark':
                    target.memo[command.value - 1] = command.type[0] === 'r';
                    break;
                case 'flush':
                    this.affectedIndicesBy(command.where).forEach(index => board[index].memo[command.value - 1] = false);
                    break;
                }
                return board;
            }, initial);
        },
        missPlacedIndices: function() {
            const unique = (value, index, array) => array.indexOf(value) === index;
            const indices = [this.indices.row, this.indices.col, this.indices.box].reduce((a, b) => a.concat(b));
            const dupOrNot = this.slice(indices.map(index => this.cells[index].value), 9) // for each 9...
            .map(vs => vs.map((v, i, self) => v && self.slice(0, i).concat(self.slice(i+1)).some(x => x === v))) // flag non-zero and duplicates
            .reduce((a, b) => a.concat(b));
            return dupOrNot.map((v, i) => v ? indices[i] : NaN).filter(unique); // NaN will be removed by unique.
        },
        indices: (() => {
            const colNr = index => index % 9;
            const boxNr = index => 3 * ~~(index / 27) + ~~((index % 9) / 3);
            const row = Array.from({length: 81, }).map((_, index) => index);
            const col = Array.from(row).sort((a, b) => colNr(a) - colNr(b));
            const box = Array.from(row).sort((a, b) => boxNr(a) - boxNr(b));
            const indices = { row: row, col: col, box: box, };
            return () => indices;
        })(),
        pointedCell: function() { return this.cells[this.pointed] || {given: true, }; },
    },
    data: () => new Object({
        pointed: -1,
        /* user operations. this backs undo/redo up.
        `current` points `commands` array index where new command to be inserted into. */
        history: {commands: [], current: 0, },
    }),
    methods: {
        slice: (() => {
            const splitAt = (array, n) => [array.slice(0, n), array.slice(n)];
            const reduceConcat = a => a.length ? a.reduce((a, b) => [a].concat(reduceConcat(b))) : [];

            return (array, n) => {
                const splitted = splitAt(array, n);
                var p = splitted;
                while (p[1].length !== 0) {
                    p[1] = splitAt(p[1], n);
                    p = p[1];
                }
                return reduceConcat(splitted);
            };
        })(),
        affectedIndicesBy: function(cellIndex) {
            const get = array => {
                const index = array.findIndex(x => x === cellIndex);
                const start = 9 * ~~(index / 9);
                return array.slice(start, start + (index !== -1 ? 9 : 0));
            };
            return [get(this.indices.row), get(this.indices.col), get(this.indices.box)]
            .reduce((a, b) => a.concat(b)) // flatten array
            .filter(value => value !== cellIndex) // remove cellIndex itself
            .filter((value, index, array) => array.indexOf(value) === index); // remove duplicates
        },
        onKey: function(event) {
            const ALT = event.altKey;
            const SHIFT = event.shiftKey;
            const NUMBER = Number((/^Digit([1-9])$/.exec(event.code) || [])[1]);
            const UNDO = event.code === 'KeyZ' && ALT && !SHIFT;
            const REDO = (event.code === 'KeyZ' && ALT && SHIFT) || (event.code === 'KeyY' && ALT && !SHIFT);
            if (ALT && NUMBER && this.pointed !== -1) {
                this.mark(NUMBER, !SHIFT);
            } else if (!ALT && NUMBER && !this.pointedCell.given) {
                this.place(NUMBER);
            } else if (['Digit0', 'Backspace'].includes(event.code) && !this.pointedCell.given) {
                this.erase();
            } else if (UNDO && this.history.current !== 0) {
                this.history.current -= 1;
            } else if (REDO && this.history.current != this.history.commands.length) {
                this.history.current += 1;
            }
        },
        place: function(number) {
            this.push({value: number, type: 'place', });
        },
        erase: function() {
            this.push({value: 0, type: 'erase', });
        },
        mark: function(number, mark) {
            this.push({value: number, type: mark ? 'remark' : 'unmark', });
        },
        flush: function() {
            this.push({value: this.pointedCell.value, type: 'flush', });
        },
        push: function(command) {
            const history = this.history, commands = this.history.commands;
            commands.splice(history.current, Infinity, Object.assign({when: new Date(), where: this.pointed, }, command));
            history.current += 1;
        },
    },
});
<|endoftext|>


<commit_before>'use strict';

const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

var options = {
    client_id: 'zjdmn6jek8xd5v6yz9eptc8m',
    redirect_uri: "https://localhost/main.js",
    response_type: 'code'
};
var isUrl = 'https://signin.infusionsoft.com/app/oauth/authorize?';
var authUrl = isUrl + 'client_id=' + options.client_id + '&redirect_uri=' + options.redirect_uri + '&response_type=' + options.response_type;

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600, 'nodeIntegration':false });

  mainWindow.$ = require('jQuery');
  mainWindow.jQuery = require('jQuery');

  // and load the index.html of the app.
  mainWindow.loadURL(authUrl);

  // Open the DevTools.
  mainWindow.webContents.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', createWindow);

// listening for the access_token redirect, but nothing is logged except a load error containing the access token
app.on('did-get-redirect-request', function () {
  var addr = window.location.href;
  console.log(addr);
})

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }

  function handleCallback (url) {
    var raw_code = /code=([^&]*)/.exec(url) || null;
    var code = (raw_code && raw_code.length > 1) ? raw_code[1] : null;
    var error = /\?error=(.+)$/.exec(url);

    if (code || error) {
      // Close the browser if code found or error
      console.log('code or error')
      authWindow.destroy();
    }

    // If there is a code, proceed to get token from IS
    if (code) {
      //self.requestGithubToken(options, code);
      console.log(code);
    } else if (error) {
      alert('Oops! Something went wrong and we couldn\'t' +
        'log you into Infusionsoft. Please try again.');
    }
  }

  mainWindow.webContents.on('will-navigate', function (event, url) {
    handleCallback(url);
  });

  mainWindow.webContents.on('did-get-redirect-request', function (event, oldUrl, newUrl) {
    handleCallback(newUrl);
  });

  // Reset the authWindow on close
  mainWindow.on('close', function() {
      mainWindow = null;
  }, false);
});
<commit_msg>editing createWindow() function<commit_after>'use strict';

const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

var options = {
    client_id: 'zjdmn6jek8xd5v6yz9eptc8m',
    // redirect_uri: "http://localhost/main.js",
    redirect_uri: "http://localhost/notifusion/index.html",
    response_type: 'code'
};
var isUrl = 'https://signin.infusionsoft.com/app/oauth/authorize?';
var authUrl = isUrl + 'client_id=' + options.client_id + '&redirect_uri=' + options.redirect_uri + '&response_type=' + options.response_type;

function createWindow () {
    // Create the browser window.
    mainWindow = new BrowserWindow({
        width: 960,
        height: 960,
        'webPreferences': {
          'nodeIntegration': false,
          'webSecurity': false
        }
    });

    mainWindow.$ = require('jQuery');
    mainWindow.jQuery = require('jQuery');

    // and load the index.html of the app.
    mainWindow.loadURL(authUrl);

    // Open the DevTools.
    mainWindow.webContents.openDevTools();

    // listen for the access token
    mainWindow.webContents.on('did-get-redirect-request', function (event, arg) {
      console.log(event);
      console.log(arg);
    });

    function handleCallback (url) {
      var raw_code = /code=([^&]*)/.exec(url) || null;
      var code = (raw_code && raw_code.length > 1) ? raw_code[1] : null;
      var error = /\?error=(.+)$/.exec(url);

      if (code || error) {
          // Close the browser if code found or error
          console.log('code or error')
          //authWindow.destroy();
      }

      // If there is a code, proceed to get token from IS
      if (code) {
          //self.requestGithubToken(options, code);
          console.log(code);
      } else if (error) {
          alert('Oops! Something went wrong and we couldn\'t' +
          'log you into Infusionsoft. Please try again.');
      }
    }

    mainWindow.webContents.on('will-navigate', function (event, url) {
      handleCallback(url);
    });

    mainWindow.webContents.on('did-get-redirect-request', function (event, oldUrl, newUrl) {
      handleCallback(newUrl);
    });

    // Emitted when the window is closed.
    mainWindow.on('closed', function() {
        // Dereference the window object, usually you would store windows
        // in an array if your app supports multi windows, this is the time
        // when you should delete the corresponding element.
        mainWindow = null;
    });
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', function () {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.on('activate', function () {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (mainWindow === null) {
        createWindow();
    }

  // Reset the authWindow on close
  mainWindow.on('close', function() {
      mainWindow = null;
  }, false);
});
<|endoftext|>


<commit_before>"use strict";

/*global module, require*/

var d3 = require("d3"),
    iframeNoScroll = require("./iframe-noscroll"),
    backendFactory = require("./backend.js"),
    storeFactory = require("./store.js"),
    queryStringFactory = require("./query-string.js"),
    menuStateFactory = require("./menu-state.js"),
    menuContainerFactory = require("./menu-container.js"),
    menuContentsFactory = require("./menu-contents.js"),
    buttonSpecFactory = require("./buttons/specify-buttons.js"),
    standardButtonFactory = require("./buttons/standard-buttons.js"),

    defaultUrl = function() {
	var a = document.createElement("a");
	a.href = "/";
	return a.href + "channel";
    }(),

    isEmbedded = function() {
	try {
	    return window.self !== window.top;
	} catch (e) {
	    return true;
	}
    };

module.exports = function(collection, friendlyName, serialize, deserialize, getModel, setModel, freshModel, url, helpURL) {
    var embedded = isEmbedded();

    if (embedded) {
	iframeNoScroll();

	d3.select('body').classed('embedded', true);
    }

    var backend = backendFactory(!embedded, url ? url : defaultUrl),
	buttonSpec = buttonSpecFactory(collection),

	store = storeFactory(!embedded, collection, backend, serialize, deserialize, getModel, setModel, freshModel),
	queryString = queryStringFactory(
	    collection,
	    store
	),
	menuState = menuStateFactory(
	    embedded,
	    backend.onUp, backend.onDown, backend.isUp,
	    store.getAutosave, store.onAutosaveChanged,
	    store.getTitle, store.getVersion, store.onNavigate
	);

    queryString.param(
	"debug",
	backend.setDebug,
	function() {
	    return backend.isDebugging() ? true : null;
	}
    );

    return {
	backend: backend,
	store: store,
	queryString: queryString,
	spec: buttonSpec,
	buildMenu: function(container) {
	    var menuContainer = menuContainerFactory(container, helpURL),
		menuContents = menuContentsFactory(
		    menuContainer,
		    store.getTitle,
		    menuState
		);

	    var standardButtons = standardButtonFactory(
		buttonSpec,
		store,
		backend.search,
		backend.getProjectsList,
		menuContainer,
		collection,
		friendlyName
	    );

	    return {
		container: menuContainer,
		contents: menuContents,

		standardButtons: standardButtons,
		setButtons: menuContents.setButtons
	    };
	}
    };
};

<commit_msg>Exposed button processes so that they may be used by custom buttons.<commit_after>"use strict";

/*global module, require*/

var d3 = require("d3"),
    iframeNoScroll = require("./iframe-noscroll"),
    backendFactory = require("./backend.js"),
    storeFactory = require("./store.js"),
    queryStringFactory = require("./query-string.js"),
    menuStateFactory = require("./menu-state.js"),
    menuContainerFactory = require("./menu-container.js"),
    menuContentsFactory = require("./menu-contents.js"),
    buttonSpecFactory = require("./buttons/specify-buttons.js"),
    standardButtonFactory = require("./buttons/standard-buttons.js"),

    modalDialogueProcess = require("./buttons/processes/modal-dialogue.js"),
    searchProcess = require("./buttons/processes/search.js"),
    submenuProcess = require("./buttons/processes/sub-menu.js"),

    defaultUrl = function() {
	var a = document.createElement("a");
	a.href = "/";
	return a.href + "channel";
    }(),

    isEmbedded = function() {
	try {
	    return window.self !== window.top;
	} catch (e) {
	    return true;
	}
    };

module.exports = function(collection, friendlyName, serialize, deserialize, getModel, setModel, freshModel, url, helpURL) {
    var embedded = isEmbedded();

    if (embedded) {
	iframeNoScroll();

	d3.select('body').classed('embedded', true);
    }

    var backend = backendFactory(!embedded, url ? url : defaultUrl),
	buttonSpec = buttonSpecFactory(collection),

	store = storeFactory(!embedded, collection, backend, serialize, deserialize, getModel, setModel, freshModel),
	queryString = queryStringFactory(
	    collection,
	    store
	),
	menuState = menuStateFactory(
	    embedded,
	    backend.onUp, backend.onDown, backend.isUp,
	    store.getAutosave, store.onAutosaveChanged,
	    store.getTitle, store.getVersion, store.onNavigate
	);

    queryString.param(
	"debug",
	backend.setDebug,
	function() {
	    return backend.isDebugging() ? true : null;
	}
    );

    return {
	backend: backend,
	store: store,
	queryString: queryString,
	spec: buttonSpec,
	buttonProcesses: {
	    modalDialogue: modalDialogueProcess,
	    subMenu: submenuProcess,
	    search: searchProcess
	},
	buildMenu: function(container) {
	    var menuContainer = menuContainerFactory(container, helpURL),
		menuContents = menuContentsFactory(
		    menuContainer,
		    store.getTitle,
		    menuState
		);

	    var standardButtons = standardButtonFactory(
		buttonSpec,
		store,
		backend.search,
		backend.getProjectsList,
		menuContainer,
		collection,
		friendlyName
	    );

	    return {
		container: menuContainer,
		contents: menuContents,

		standardButtons: standardButtons,
		setButtons: menuContents.setButtons
	    };
	}
    };
};

<|endoftext|>


<commit_before>//Modules
var modSpawning = require('module.spawning');
var modCommon = require('module.common');
var modStructures = require('module.structures');
var modMemory = require('module.memory');
var modAssist = require('module.assist');

//main loop
module.exports.loop = function () {

  //Only initialize if it hasnt been done (or it was manually set to false)
  if(Memory.initialized!==true){
    modMemory.init();
  }

  //Loop to check each room that is visible to the script
  for(var roomName in Memory.rooms){
    var room = Game.rooms[roomName];

    //Creep lists in each room, comparing lengths shows if there are 'others'
    var allCreepList = room.find(FIND_CREEPS);
    var myCreepList = _.filter(allCreepList, (creep) => (creep.owner && creep.owner.username ==="PCarton"));
    var enemyPresent = allCreepList.length>myCreepList.length;

    //Al the structures in the room that are controlled by the player
    var allStructs = room.find(FIND_MY_STRUCTURES);
    var towers = _.filter(allStructs, (struct) => struct.structureType === STRUCTURE_TOWER);

    if(allStructs.lenth <=0){
      //Find the nearest room to this new one and spawn an assist builder and upgrader
      var dist = -1;
      var otherRoom = null;
      for(var roomNameClose in Game.rooms){
        if(roomNameClose !== roomName){
          var tempDist = Game.map.getResourceType(roomName, roomNameClose);
          if(dist === -1 || tempDist < dist){
            dist = tempDist;
            otherRoom = roomNameClose;
          }
        }
      }
      if(otherRoom !== null){
        modSpawning.enqueueAssist(otherRoom, 'builder', roomName);
        modSpawning.enqueueAssist(otherRoom, 'upgrader', roomName);
      }
    }

    for(var tower in towers){
      if(Memory.rooms[roomName].towers[tower.id] === null){
        modMemory.initTower(tower);
      }
    }

    //Clear dead creeps from memory
    modCommon.clearDead();

    //assign the right run method to each creep based on its role
    for(var name in myCreepList) {
        var creep = myCreepList[name];

        //Has the non-military creeps retreat
        //Mining creeps are considered military - like the supply line
        if(!room.controller.safeMode && enemyPresent && creep.memory.military !== true){
          modCommon.retreat(creep);
        }
        //if the creep is to assist
        else if(creep.memory.assist){
          modAssist.run(creep);
        }
        //If there are no enemies, run the appropriate role method
        else{
          modCommon.runCreep(creep);
        }
    }

    //determine if new creeps need to be spawned and pick an appropriate spawner
    //Spawn logic is in a seperate module
    if(Memory.rooms[roomName].roles.numCreeps < modSpawning.maxCreeps){
      if(Game.time%modConstants.spawnFrequency===0)
        modSpawning.enqueueAllNeeded(roomName);
      modSpawning.spawn(roomName);
    }

    var control = room.controller;

    if(enemyPresent && modCommon.playerAttack(allCreepList) && !(control.safeMode || control.safeModeCooldown) && control.safeModeAvailable > 0 ){
      control.activateSafeMode();
      Game.notify(modCommon.linkRoomAtTick(room,Game.time,"Activated Safe Mode"),0);
    }

    var newEnemy = true;

    for(var towerId in Memory.rooms[roomName].towers){
      if(Memory.rooms[roomName].towers[towerId].mode === "attack")
        newEnemy = false;
      var towerObj = Game.getObjectById(towerId);
      if(enemyPresent){
        Memory.rooms[roomName].towers[towerId].mode = "attack";
        var targetID =   Memory.rooms[roomName].towers[towerId].target;
        var target = null;
        try{
          target = Game.getObjectById(targetID);
        }catch(err){
          console.log(err.name + "\n" + err.message);
        }
        if(!target){
          modStructures.pickTargets(room.controller, allCreepList);
        }
      }else{ //TODO check for injured creeps and set to heal, maybe room variable that triggers on hit
        Memory.rooms[roomName].towers[towerId].mode = "repair";
      }
      modStructures.runTower(towerObj,allCreepList);
    }

    if(enemyPresent && newEnemy)
      Game.notify(modCommon.linkRoomAtTick(room, Game.time, "EnemyFound"),60);
  }
};
<commit_msg>added check for construction sites so rooms traveled through dont get assist<commit_after>//Modules
var modSpawning = require('module.spawning');
var modCommon = require('module.common');
var modStructures = require('module.structures');
var modMemory = require('module.memory');
var modAssist = require('module.assist');

//main loop
module.exports.loop = function () {

  //Only initialize if it hasnt been done (or it was manually set to false)
  if(Memory.initialized!==true){
    modMemory.init();
  }

  //Loop to check each room that is visible to the script
  for(var roomName in Memory.rooms){
    var room = Game.rooms[roomName];

    //Creep lists in each room, comparing lengths shows if there are 'others'
    var allCreepList = room.find(FIND_CREEPS);
    var myCreepList = _.filter(allCreepList, (creep) => (creep.owner && creep.owner.username ==="PCarton"));
    var enemyPresent = allCreepList.length>myCreepList.length;

    //Al the structures in the room that are controlled by the player
    var allStructs = room.find(FIND_MY_STRUCTURES);
    var allConstruct = room.find(FIND_MY_CONSTRUCTION_SITES);
    var towers = _.filter(allStructs, (struct) => struct.structureType === STRUCTURE_TOWER);

    if(allStructs.length <=0 && allConstruct.length<=0){
      //Find the nearest room to this new one and spawn an assist builder and upgrader
      var dist = -1;
      var otherRoom = null;
      for(var roomNameClose in Game.rooms){
        if(roomNameClose !== roomName){
          var tempDist = Game.map.getResourceType(roomName, roomNameClose);
          if(dist === -1 || tempDist < dist){
            dist = tempDist;
            otherRoom = roomNameClose;
          }
        }
      }
      if(otherRoom !== null){
        modSpawning.enqueueAssist(otherRoom, 'builder', roomName);
        modSpawning.enqueueAssist(otherRoom, 'upgrader', roomName);
      }
    }

    for(var tower in towers){
      if(Memory.rooms[roomName].towers[tower.id] === null){
        modMemory.initTower(tower);
      }
    }

    //Clear dead creeps from memory
    modCommon.clearDead();

    //assign the right run method to each creep based on its role
    for(var name in myCreepList) {
        var creep = myCreepList[name];

        //Has the non-military creeps retreat
        //Mining creeps are considered military - like the supply line
        if(!room.controller.safeMode && enemyPresent && creep.memory.military !== true){
          modCommon.retreat(creep);
        }
        //if the creep is to assist
        else if(creep.memory.assist){
          modAssist.run(creep);
        }
        //If there are no enemies, run the appropriate role method
        else{
          modCommon.runCreep(creep);
        }
    }

    //determine if new creeps need to be spawned and pick an appropriate spawner
    //Spawn logic is in a seperate module
    if(Memory.rooms[roomName].roles.numCreeps < modSpawning.maxCreeps){
      if(Game.time%modConstants.spawnFrequency===0)
        modSpawning.enqueueAllNeeded(roomName);
      modSpawning.spawn(roomName);
    }

    var control = room.controller;

    if(enemyPresent && modCommon.playerAttack(allCreepList) && !(control.safeMode || control.safeModeCooldown) && control.safeModeAvailable > 0 ){
      control.activateSafeMode();
      Game.notify(modCommon.linkRoomAtTick(room,Game.time,"Activated Safe Mode"),0);
    }

    var newEnemy = true;

    for(var towerId in Memory.rooms[roomName].towers){
      if(Memory.rooms[roomName].towers[towerId].mode === "attack")
        newEnemy = false;
      var towerObj = Game.getObjectById(towerId);
      if(enemyPresent){
        Memory.rooms[roomName].towers[towerId].mode = "attack";
        var targetID =   Memory.rooms[roomName].towers[towerId].target;
        var target = null;
        try{
          target = Game.getObjectById(targetID);
        }catch(err){
          console.log(err.name + "\n" + err.message);
        }
        if(!target){
          modStructures.pickTargets(room.controller, allCreepList);
        }
      }else{ //TODO check for injured creeps and set to heal, maybe room variable that triggers on hit
        Memory.rooms[roomName].towers[towerId].mode = "repair";
      }
      modStructures.runTower(towerObj,allCreepList);
    }

    if(enemyPresent && newEnemy)
      Game.notify(modCommon.linkRoomAtTick(room, Game.time, "EnemyFound"),60);
  }
};
<|endoftext|>


<commit_before>'use strict';

var self;

var Bind = require('github/jillix/bind');
var Events = require('github/jillix/events');

module.exports = function (config) {

    self = this;

    Events.call(self, config);

    var container = $(config.container, self.dom);

    // On tab click
    $(config.tabs, self.dom).on('click', function() {

        // Change the hash in URL
        if (config.options.hash) {
            if (!$(this).attr('data-hash')) {
                return;
            }

            window.location.hash = $(this).attr('data-hash');
        } else {
            activateTab(config, $(this));
        }

        return false;
    });

    // hashchange handler
    $(window).on('hashchange', function () {
        var tab = $('[data-hash=' + window.location.hash.substring(1) +  ']');
        activateTab(config, tab);
    })

    // Load first content
    if ((config.options.first) && (!window.location.hash)) {
        M(config.container, config.options.first, function () {
            self.emit('tabActivated', config.options.first);
        });
        return;
    }

    // Load the right content for hash
    if ((window.location.hash) && (config.options.hash)) {
        var tab = $('[data-hash=' + window.location.hash.substring(1) +  ']');
        activateTab(config, tab);
        return;
    }

    if (typeof window[config.onInitEnd] === 'function') {
        window[config.onInitEnd].apply(self);
    }
}

function activateTab(config, tab) {

    if (!tab.length) {
        return;
    }

    // TODO we cannot rely that the selected class exists and based on this
    // to test the current tab. The current miid should be buffered
    var active = $(config.tabs).parent().find('.' + config.options.classes.selected);
    if (tab.attr('data-miid') === active.attr('data-miid')) {
        return;
    }

    // Removes the active class
    $(config.tabs).removeClass(config.options.classes.selected);

    // Removes the content of container
    $(config.container).html('');

    // Adds active class
    tab.addClass(config.options.classes.selected);

    var miid = tab.attr('data-miid');

    // Sets the content in container
    M(config.container, miid, function () {
        self.emit('tabActivated', miid);
    });
}
<commit_msg>Added the resue option.<commit_after>'use strict';

var self;

var Bind = require('github/jillix/bind');
var Events = require('github/jillix/events');

module.exports = function (config) {

    self = this;

    Events.call(self, config);

    var container = $(config.container, self.dom);

    if (config.options.reuse) {
        self.tabs = {};
    }

    // On tab click
    $(config.tabs, self.dom).on('click', function() {

        // Change the hash in URL
        if (config.options.hash) {
            if (!$(this).attr('data-hash')) {
                return;
            }

            window.location.hash = $(this).attr('data-hash');
        } else {
            activateTab(config, $(this));
        }

        return false;
    });

    // hashchange handler
    $(window).on('hashchange', function () {
        var tab = $('[data-hash=' + window.location.hash.substring(1) +  ']', self.dom);
        activateTab(config, tab);
    })

    // Load first content
    if ((config.options.first) && (!window.location.hash)) {
        M(config.container, config.options.first, function () {
            self.emit('tabActivated', config.options.first);

            if (config.options.reuse) {
                self.tabs[config.options.first] = true;
            }
        });
        return;
    }

    // Load the right content for hash
    if ((window.location.hash) && (config.options.hash)) {
        var tab = $('[data-hash=' + window.location.hash.substring(1) +  ']', self.dom);
        activateTab(config, tab);
        return;
    }

    if (typeof window[config.onInitEnd] === 'function') {
        window[config.onInitEnd].apply(self);
    }
}

function activateTab(config, tab) {

    if (!tab.length) {
        return;
    }

    // TODO we cannot rely that the selected class exists and based on this
    // to test the current tab. The current miid should be buffered
    var active = $(config.tabs, self.dom).parent().find('.' + config.options.classes.selected);
    if (tab.attr('data-miid') === active.attr('data-miid')) {
        return;
    }

    // Removes the active class
    $(config.tabs, self.dom).removeClass(config.options.classes.selected);

    // Removes the content of container if reuse is false or undefined
    if (!config.options.reuse) {
        $(config.container, self.dom).html('');
    }

    // Adds active class
    tab.addClass(config.options.classes.selected);

    var miid = tab.attr('data-miid');

    // Sets the content in container
    // resue is true
    if (config.options.reuse) {

        // miid was NOT loaded
        if (!self.tabs[miid]) {
            M(config.container, miid, function () {
                self.emit('tabActivated', miid);

                if (config.options.reuse) {
                    self.tabs[miid] = true;
                }
            });
        }
        // miid was already loaded, show it!
        else {
            $(config.container).find("*").hide();
            $("#" + miid).show();
        }
    }
    // resue is false
    else {
        M(config.container, miid, function () {
            self.emit('tabActivated', miid);
        });
    }
}
<|endoftext|>


<commit_before>const electron = require('electron')
const ipcMain = electron.ipcMain
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')

let splashWindow
let editorWindow

function createSplash () {
  // Create the browser window.
  splashWindow = new BrowserWindow({width: 621, height: 421, frame: false})

  // and load the index.html of the app.
  splashWindow.loadURL(url.format({
    pathname: path.join(__dirname, "pages", "splash" , "splash.html"),
    protocol: 'file:',
    slashes: true
  }))

  // Emitted when the window is closed.
  splashWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    splashWindow = null
  })
}

function createEditor() {
  editorWindow = new BrowserWindow({width: 1280, height:720, frame: false})
  editorWindow.loadURL(url.format({
    pathname: path.join(__dirname, "pages", "editor-main" , "editor-main.html"),
    protocol: 'file:',
    slashes: true
  }))

  editorWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  editorWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    editorWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createSplash)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  createSplash()
})

ipcMain.on('splash-timeout', function() {
    createEditor()
    splashWindow.close()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg>Added dev check<commit_after>const electron = require('electron')
const ipcMain = electron.ipcMain
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')

let splashWindow
let editorWindow

function createSplash () {
  // Create the browser window.
  splashWindow = new BrowserWindow({width: 621, height: 421, frame: false})

  // and load the index.html of the app.
  splashWindow.loadURL(url.format({
    pathname: path.join(__dirname, "pages", "splash" , "splash.html"),
    protocol: 'file:',
    slashes: true
  }))

  // Emitted when the window is closed.
  splashWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    splashWindow = null
  })
}

function createEditor() {
  editorWindow = new BrowserWindow({width: 1280, height:720, frame: false})
  editorWindow.loadURL(url.format({
    pathname: path.join(__dirname, "pages", "editor-main" , "editor-main.html"),
    protocol: 'file:',
    slashes: true
  }))

  if (process.env.NODE_ENV === 'dev')
    editorWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  editorWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    editorWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createSplash)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  createSplash()
})

ipcMain.on('splash-timeout', function() {
    createEditor()
    splashWindow.close()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>


<commit_before>var startButton;
var time;
var timeInterval;
var clickedOnce = false;
var circle;
var currentuser;
var temprank;
var rank;
function setup(){
	$("#menuBar").hide();
	firebase.auth().onAuthStateChanged(function (user){
	 	if(user){
	 		currentuser = user;
	 		startButton = select("#StartButton");
			time= select("#time");
			circle = select('#circle1');
			userName = select('#userName');
			rank = select('#userRank');
			var name = user.displayName.split(" ");
			name = name[0];
			var temp = name[0].toUpperCase();
			for (var i = 1; i < name.length; i++) {
				temp += name[i];
			}
			userName.html("Welcome " + temp);

			firebase.database().ref("users/"+currentuser.uid+"/rank").once('value').then(function(snap){
				 temprank = snap.val();
				if(temprank != undefined && temprank != null){
					rank.html("Rank : #" + temprank);
					$("#menuBar").slideDown(1500);
				}
				else{
					rank.html(0);
					$("#menuBar").slideDown(1500);
				}
			})

			time.hide();
			if(!clickedOnce){
				startButton.mousePressed(hideStartButton);
			};
	 	}
	 	else{
	 		window.location.href = "index.html";
	 	}
	 });

	var signoutbutton = select("#signOut");
	signoutbutton.mousePressed(signout);

	var signoutbutton2 = select("#signOut2");
	signoutbutton2.mousePressed(signout);

}

function hideStartButton(){
	if (!clickedOnce === true) {
		clickedOnce = true;
		$('#StartButton').fadeOut({"duration":500,"complete":startcount});
		$('#userRank').slideUp(400);
		$('#userName').slideUp({'duration':400, 'complete':updateScoreandTime});

	}

}

var score = 0;
var highScorenum = 90;
var updateScoreandTime = function(){
	userName.html("Time Left : 30 seconds");
	rank.html("Score : 0");
		$("#userRank").slideDown(500);
		$('#userName').slideDown(500);
}
var startwatch;
var stopwatch = function(){
	startwatch = setInterval(count1,1000);
}
var counter1 = 30;
var count1 = function(){
		userName.html("Time Left : " + --counter1 + " seconds");
		if (counter1===0) {
			clearInterval(startwatch);
			circle.hide();
			gameOver();
		}
		if (counter1 <= 5 && counter1 != 0) {
			time.html(counter1);
			time.show();
		}

}

function startcount(){
	time.show();
	timeInterval = setInterval(count,1000);
}
var counter = 3 ;
var startgame = false;
var count = function(){
	if (counter == 0) {
		time.hide();
		clearInterval(timeInterval);
		startgame = true;
		stopwatch();
		countdown();

	}
	else{
		time.html(--counter +"");
	}
}

function countdown(){
	makenewcircle();
	circle.mousePressed(explode);
}

function explode(){
	dontBounce=false;

	if (startgame === true) {
		rank.html("Score : " + ++score);
		$('#circle1').effect('explode',{'duration':220,'complete': makenewcircle});
	}
	else{
		circle.hide();
	}

//	makenewcircle();
}
var dontBounce = false;
function makenewcircle(){
	var newcircle = new randomDot();
	circle.position(newcircle.x, newcircle.y);
	circle.style("background", newcircle.color);
	if(startgame===true){
		circle.style("width", newcircle.radius+'em');
		circle.style("height",newcircle.radius+'em');
		circle.show();
		if (! dontBounce) {
			$('#circle1').effect('bounce',200);
		}

	}
	else{
		circle.hide();
	}

}

function gameOver(){

	firebase.database().ref("users/"+currentuser.uid+"/highScore").once('value').then(function(snapshot){
		highScorenum = snapshot.val();
	//	console.log(highScorenum);
		if(highScorenum === undefined || highScorenum=== null){
		firebase.database().ref("users/"+currentuser.uid).set({
					name: currentuser.displayName,
					highScore: score
				});
		highScorenum = score;
	}
	else{
		if (score >= highScorenum) {
			firebase.database().ref("users/"+currentuser.uid).set({
				highScore: score
			});
			highScorenum = score;
		}
	}
	var currentScore = select("#currentScore");
	currentScore.html("Score : " + score);
	var highScore = select("#highScore");
	highScore.html("Highest Score : " + highScorenum);
	var gameover = select("#GameOver");
	var currentRank = select("#currentRank");
	currentRank.html(rank.html());
	gameover.show();
	firebase.database().ref("users/"+currentuser.uid+"/rank").on('value',function(snap){
				var tempscore = snap.val();
		//		console.log(tempscore);
				if (tempscore != undefined && tempscore != null){
					var currentRank = select("#currentRank");
					currentRank.html("Current Rank : " + tempscore);
				//	$("#currentRank").bounce();
				//	gameover.show();
				}
				else{
					var currentRank = select("#currentRank");
					currentRank.html("Current Rank : " + 0);
				//	gameover.show();
				}
			});

/*
			var currentRank = select("#currentRank");
	var temprank = snapshot.parent.child("rank").val();
	console.log("The rank is " + temprank);
	if (temprank != null && temprank != undefined) {
		currentRank.html("Current Rank : " + tempscore);
	}
	else{
		currentRank.html("Current Rank : " + 0);
	}

					gameover.show();*/
	});

	startgame = false;
	time.hide();

	circle.hide();
	var replay = select("#replay");
	replay.mousePressed(function(){
		window.location.href = "game.html";
	});
}

function windowResized(){
	if(startgame===true){
		dontBounce=true;
		makenewcircle();
	}
}

function signout(){
	firebase.auth().signOut().then(function(){
		window.location.href = "index.html";
	}, function(error){
		console.log('Sign Out error', error);
	});
}
<commit_msg>Removed some log statements<commit_after>var startButton;
var time;
var timeInterval;
var clickedOnce = false;
var circle;
var currentuser;
var temprank;
var rank;
function setup(){
//	$("#exit").hide();
	$("#menuBar").hide();
	$("#menuBar").slideDown(1500);
	firebase.auth().onAuthStateChanged(function (user){
	 	if(user){
	 		currentuser = user;
	 		startButton = select("#StartButton");
			time= select("#time");
			circle = select('#circle1');
			userName = select('#userName');
			rank = select('#userRank');
			var name = user.displayName.split(" ");
			name = name[0];
			var temp = name[0].toUpperCase();
			for (var i = 1; i < name.length; i++) {
				temp += name[i];
			}
			userName.html("Welcome " + temp);

			firebase.database().ref("users/"+currentuser.uid+"/rank").once('value').then(function(snap){
				 temprank = snap.val();
				if(temprank != undefined && temprank != null){
					rank.html("Rank : #" + temprank);
				}
				else{
					rank.html(0);
				}
			})

			time.hide();
			if(!clickedOnce){
				startButton.mousePressed(hideStartButton);
			};
	 	}
	 	else{
	 		window.location.href = "index.html";
	 	}
	 });

	var signoutbutton = select("#signOut");
	signoutbutton.mousePressed(signout);

	var signoutbutton2 = select("#signOut2");
	signoutbutton2.mousePressed(signout);

}

function hideStartButton(){
	if (!clickedOnce === true) {
		clickedOnce = true;
		$('#StartButton').fadeOut({"duration":500,"complete":startcount});
		$('#userRank').slideUp(400);
		$('#userName').slideUp({'duration':400, 'complete':updateScoreandTime});

	}

}

var score = 0;
var highScorenum = 90;
var updateScoreandTime = function(){
	userName.html("Time Left : 30 seconds");
	rank.html("Score : 0");
		$("#userRank").slideDown(500);
		$('#userName').slideDown(500);
}
var startwatch;
var stopwatch = function(){
	startwatch = setInterval(count1,1000);
}
var counter1 = 30;
var count1 = function(){
		userName.html("Time Left : " + --counter1 + " seconds");
		if (counter1===0) {
			clearInterval(startwatch);
			circle.hide();
			gameOver();
		}
		if (counter1 <= 5 && counter1 != 0 || counter1===25 || counter1 === 20 || counter1===15 || counter1 ===10) {
			time.html(counter1);
			time.show();
		}
		else{
			time.hide();
		}

}

function startcount(){
	time.show();
	timeInterval = setInterval(count,1000);
}
var counter = 3 ;
var startgame = false;
var count = function(){
	if (counter == 0) {
		time.hide();
		clearInterval(timeInterval);
		startgame = true;
		stopwatch();
		countdown();
		$("#exit").slideDown(1000);
		var exitButton = select("#exit");
		exitButton.mousePressed(function(){
			window.location.href= "game.html";
		});
	}
	else{
		time.html(--counter +"");
	}
}

function countdown(){
	makenewcircle();
	circle.mousePressed(explode);
}

function explode(){
	$("#circle1").stop();
	dontBounce=false;
	if (startgame === true) {
		rank.html("Score : " + ++score);
		$('#circle1').effect('explode',{'duration':220,'complete': makenewcircle});
	}
	else{
		circle.hide();
	}

//	makenewcircle();
}
var dontBounce = false;
function makenewcircle(){
	var newcircle = new randomDot();
	circle.position(newcircle.x, newcircle.y);
	circle.style("background", newcircle.color);
	if(startgame===true){
		circle.style("width", newcircle.radius+'em');
		circle.style("height",newcircle.radius+'em');
		circle.show();
		if (! dontBounce) {
			$('#circle1').effect('bounce',200);
		}

	}
	else{
		circle.hide();
	}

}

function gameOver(){

	firebase.database().ref("users/"+currentuser.uid+"/highScore").once('value').then(function(snapshot){
		highScorenum = snapshot.val();
	//	console.log(highScorenum);
		if(highScorenum === undefined || highScorenum=== null){
		firebase.database().ref("users/"+currentuser.uid).set({
					name: currentuser.displayName,
					highScore: score
				});
		highScorenum = score;
	}
	else{
		if (score >= highScorenum) {
			firebase.database().ref("users/"+currentuser.uid).set({
				highScore: score
			});
			highScorenum = score;
		}
	}
	var currentScore = select("#currentScore");
	currentScore.html("Score : " + score);
	var highScore = select("#highScore");
	highScore.html("Highest Score : " + highScorenum);
	var gameover = select("#GameOver");
	var currentRank = select("#currentRank");
	currentRank.html(rank.html());
	gameover.show();
	firebase.database().ref("users/"+currentuser.uid+"/rank").on('value',function(snap){
				var tempscore = snap.val();
		//		console.log(tempscore);
				if (tempscore != undefined && tempscore != null){
					var currentRank = select("#currentRank");
					currentRank.html("Current Rank : " + tempscore);
				//	$("#currentRank").bounce();
				//	gameover.show();
				}
				else{
					var currentRank = select("#currentRank");
					currentRank.html("Current Rank : " + 0);
				//	gameover.show();
				}
			});

/*
			var currentRank = select("#currentRank");
	var temprank = snapshot.parent.child("rank").val();
	console.log("The rank is " + temprank);
	if (temprank != null && temprank != undefined) {
		currentRank.html("Current Rank : " + tempscore);
	}
	else{
		currentRank.html("Current Rank : " + 0);
	}

					gameover.show();*/
	});

	startgame = false;
	time.hide();

	circle.hide();
	var replay = select("#replay");
	replay.mousePressed(function(){
		window.location.href = "game.html";
	});
}

function windowResized(){
	if(startgame===true){
		dontBounce=true;
		makenewcircle();
	}
}

function signout(){
	firebase.auth().signOut().then(function(){
		window.location.href = "index.html";
	}, function(error){
		console.log('Sign Out error', error);
	});
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Raymond Camden
 *
 * See the file LICENSE for copying permission.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window, JSHINT*/
define(function (require, exports, module) {
    "use strict";

    var CodeInspection          = brackets.getModule("language/CodeInspection"),
        FileSystem              = brackets.getModule("filesystem/FileSystem"),
        FileUtils               = brackets.getModule("file/FileUtils"),
        ProjectManager          = brackets.getModule("project/ProjectManager"),
        defaultConfig = {
            "options": {"undef": true},
            "globals": {}
        };

    require("jshint/jshint");

    /**
     * @private
     * @type {string}
     */
    var _configFileName = ".jshintrc";

    /**
     * Synchronous linting entry point.
     *
     * @param {string} text File contents.
     * @param {string} fullPath Absolute path to the file.
     * @param {object} config  JSHint configuration object.
     *
     * @return {object} Results of code inspection.
     */
    function handleHinter(text, fullPath, config) {

        // make sure that synchronous linter does not break
        if (!config) {
            config = defaultConfig;
        }

        var resultJH = JSHINT(text, config.options, config.globals);

        if (!resultJH) {
            var errors = JSHINT.errors,
                result = { errors: [] },
                i,
                len;
            for (i = 0, len = errors.length; i < len; i++) {
                var messageOb = errors[i],
                    //default
                    type = CodeInspection.Type.ERROR;

                // encountered an issue when jshint returned a null err
                if (messageOb) {
                    var message;
                    if (messageOb.type !== undefined) {
                        // default is ERROR, override only if it differs
                        if (messageOb.type === "warning") {
                            type = CodeInspection.Type.WARNING;
                        }
                    }

                    message = messageOb.reason;
                    if (messageOb.code) {
                        message += " (" + messageOb.code + ")";
                    }

                    result.errors.push({
                        pos: {line: messageOb.line - 1, ch: messageOb.character - 1},
                        message: message,
                        type: type
                    });
                }
            }
            return result;
        } else {
            return null;
        }

    }

    /**
     * Asynchronous linting entry point.
     *
     * @param {string} text File contents.
     * @param {string} fullPath Absolute path to the file.
     *
     * @return {$.Promise} Promise to return results of code inspection.
     */
    function handleHinterAsync(text, fullPath) {
        var deferred = new $.Deferred();
        _loadConfig(fullPath)
            .done(function (cfg) {
                deferred.resolve(handleHinter(text, fullPath, cfg));
            });
        return deferred.promise();
    }

    /**
     * Reads configuration file in the specified directory. Returns a promise for configuration object.
     *
     * @param {string} dir absolute path to a directory.
     *
     * @returns {$.Promise} a promise to return configuration object.
     */
    function _readConfig(dir) {
        var result = new $.Deferred(),
            file;
        file = FileSystem.getFileForPath(dir + _configFileName);
        file.read(function (err, content) {
            if (!err) {
                var cfg = {},
                    config;
                try {
                    config = JSON.parse(removeComments(content));
                } catch (e) {
                    console.error("JSHint: error parsing " + file.fullPath + ". Details: " + e);
                    result.reject(e);
                    return;
                }
                cfg.globals = config.globals || {};
                if (config.globals) { delete config.globals; }
                cfg.options = config;
                result.resolve(cfg);
            } else {
                result.reject(err);
            }
        });
        return result.promise();
    }

    /**
     * Looks up the configuration file in the filesystem hierarchy and loads it.
     *
     * @param {string} dir Relative path to directory to start with.
     * @param {function} proc Function to read and load configuration file.
     *
     * @returns {$.Promise} A promise for configuration.
     */
    function _lookupAndLoad(root, dir, readConfig) {
        var deferred = new $.Deferred(),
            done = false,
            cdir = dir,
            file,
            iter = {
                next: function () {
                    if (done) {
                        return;
                    }
                    readConfig(root + cdir)
                        .then(function (cfg) {
                            this.stop(cfg);
                        }.bind(this))
                        .fail(function () {
                            if (!cdir) {
                                this.stop(defaultConfig);
                            }
                            if (!done) {
                                cdir = FileUtils.getDirectoryPath(cdir.substring(0, cdir.length - 1));
                                this.next();
                            }
                        }.bind(this));
                },
                stop: function (cfg) {
                    deferred.resolve(cfg);
                    done = true;
                }
            };
        if (cdir === undefined || cdir === null) {
            deferred.resolve(defaultConfig);
        } else {
            iter.next();
        }
        return deferred.promise();
    }

    /**
     * Loads JSHint configuration for the specified file.
     *
     * The configuration file should have name .jshintrc. If the specified file is outside the
     * current project root, then defaultConfiguration is used. Otherwise, the configuration file
     * is looked up starting from the directory where the specified file is located, going up to
     * the project root, but no further.
     *
     * @param {string} fullPath Absolute path for the file linted.
     *
     * @return {$.Promise} Promise to return JSHint configuration object.
     *
     * @see JSHint option
     * reference.
     */
    function _loadConfig(fullPath) {

        var projectRootEntry = ProjectManager.getProjectRoot(),
            result = new $.Deferred(),
            relPath,
            file,
            config;

        if (!projectRootEntry) {
            return result.reject().promise();
        }

        // for files outside the project root, use default config
        if (!(relPath = FileUtils.getRelativeFilename(projectRootEntry.fullPath, fullPath))) {
            result.resolve(defaultConfig);
            return result.promise();
        }

        relPath = FileUtils.getDirectoryPath(relPath);

        _lookupAndLoad(projectRootEntry.fullPath, relPath, _readConfig)
            .done(function (cfg) {
                result.resolve(cfg);
            });
        return result.promise();
    }

    /**
     * Removes JavaScript comments from a string by replacing
     * everything between block comments and everything after
     * single-line comments in a non-greedy way.
     *
     * English version of the regex:
     *   match '/*'
     *   then match zero or more instances of any character (incl. \n)
     *   except for instances of '* /' (without a space, obv.)
     *   then match '* /' (again, without a space)
     *
     * @param {string} str a string with potential JavaScript comments.
     * @returns {string} a string without JavaScript comments.
     */
    function removeComments(str) {
        str = str || "";

        str = str.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\//g, "");
        str = str.replace(/\/\/[^\n\r]*/g, ""); // Everything after '//'

        return str;
    }

    CodeInspection.register("javascript", {
        name: "JSHint",
        scanFile: handleHinter,
        scanFileAsync: handleHinterAsync
    });

});
<commit_msg>Add support for per-file directive overrides.<commit_after>/*
 * Copyright (c) 2012 Raymond Camden
 *
 * See the file LICENSE for copying permission.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window, JSHINT*/
define(function (require, exports, module) {
    "use strict";

    var CodeInspection          = brackets.getModule("language/CodeInspection"),
        FileSystem              = brackets.getModule("filesystem/FileSystem"),
        FileUtils               = brackets.getModule("file/FileUtils"),
        ProjectManager          = brackets.getModule("project/ProjectManager"),
        defaultConfig = {
            "options": {"undef": true},
            "globals": {}
        };

    require("jshint/jshint");

    /**
     * @private
     * @type {string}
     */
    var _configFileName = ".jshintrc";

    /**
     * Synchronous linting entry point.
     *
     * @param {string} text File contents.
     * @param {string} fullPath Absolute path to the file.
     * @param {object} config  JSHint configuration object.
     *
     * @return {object} Results of code inspection.
     */
    function handleHinter(text, fullPath, config) {

        // make sure that synchronous linter does not break
        if (!config) {
            config = defaultConfig;
        }

        var resultJH = JSHINT(text, config.options, config.globals);

        if (!resultJH) {
            var errors = JSHINT.errors,
                result = { errors: [] },
                i,
                len;
            for (i = 0, len = errors.length; i < len; i++) {
                var messageOb = errors[i],
                    //default
                    type = CodeInspection.Type.ERROR;

                // encountered an issue when jshint returned a null err
                if (messageOb) {
                    var message;
                    if (messageOb.type !== undefined) {
                        // default is ERROR, override only if it differs
                        if (messageOb.type === "warning") {
                            type = CodeInspection.Type.WARNING;
                        }
                    }

                    message = messageOb.reason;
                    if (messageOb.code) {
                        message += " (" + messageOb.code + ")";
                    }

                    result.errors.push({
                        pos: {line: messageOb.line - 1, ch: messageOb.character - 1},
                        message: message,
                        type: type
                    });
                }
            }
            return result;
        } else {
            return null;
        }

    }

    /**
     * Asynchronous linting entry point.
     *
     * @param {string} text File contents.
     * @param {string} fullPath Absolute path to the file.
     *
     * @return {$.Promise} Promise to return results of code inspection.
     */
    function handleHinterAsync(text, fullPath) {
        var deferred = new $.Deferred();
        _loadConfig(fullPath)
            .then(_applyOverrides(fullPath))
            .done(function (cfg) {
                deferred.resolve(handleHinter(text, fullPath, cfg));
            });
        return deferred.promise();
    }

    /**
     * Reads configuration file in the specified directory. Returns a promise for configuration object.
     *
     * @param {string} dir absolute path to a directory.
     *
     * @returns {$.Promise} a promise to return configuration object.
     */
    function _readConfig(dir) {
        var result = new $.Deferred(),
            file;
        file = FileSystem.getFileForPath(dir + _configFileName);
        file.read(function (err, content) {
            if (!err) {
                var cfg = {},
                    config;
                try {
                    config = JSON.parse(removeComments(content));
                } catch (e) {
                    console.error("JSHint: error parsing " + file.fullPath + ". Details: " + e);
                    result.reject(e);
                    return;
                }
                cfg.globals = config.globals || {};
                if (config.globals) { delete config.globals; }
                cfg.options = config;
                result.resolve(cfg);
            } else {
                result.reject(err);
            }
        });
        return result.promise();
    }

    /**
     * Applies per-file overrides, if any were provided in the configuration.
     * Follows format supported in commit #df60b9c on JSHint repository:
     * https://github.com/jshint/jshint/commit/df60b9c75daa4321a4d064fcab04e14692c94039
     *
     * @param   {string} fullPath  absolute path to the processed file
     * @returns {Function}         function that returns a promise for configuration object with overrides applied
     */
    function _applyOverrides(fullPath) {

        var basePath = ProjectManager.getProjectRoot().fullPath,
            filePath = FileUtils.getRelativeFilename(basePath, fullPath);

        return function(cfg) {

            var bundle,
                has = Object.prototype.hasOwnProperty.call.bind(Object),
                overrides = cfg.options.overrides,
                pattern;

            if (overrides) {
                delete cfg.options.overrides;

                for (pattern in overrides) {
                    if (has(overrides, pattern) && (new RegExp(pattern)).test(filePath)) {
                        bundle = overrides[pattern];

                        if (bundle.globals) {
                            $.extend(true, cfg.globals, bundle.globals);
                            delete bundle.globals;
                        }
                        $.extend(true, cfg.options, bundle);

                    }
                }
            }

            return cfg;
        };
    }

    /**
     * Looks up the configuration file in the filesystem hierarchy and loads it.
     *
     * @param {string} dir Relative path to directory to start with.
     * @param {function} proc Function to read and load configuration file.
     *
     * @returns {$.Promise} A promise for configuration.
     */
    function _lookupAndLoad(root, dir, readConfig) {
        var deferred = new $.Deferred(),
            done = false,
            cdir = dir,
            file,
            iter = {
                next: function () {
                    if (done) {
                        return;
                    }
                    readConfig(root + cdir)
                        .then(function (cfg) {
                            this.stop(cfg);
                        }.bind(this))
                        .fail(function () {
                            if (!cdir) {
                                this.stop(defaultConfig);
                            }
                            if (!done) {
                                cdir = FileUtils.getDirectoryPath(cdir.substring(0, cdir.length - 1));
                                this.next();
                            }
                        }.bind(this));
                },
                stop: function (cfg) {
                    deferred.resolve(cfg);
                    done = true;
                }
            };
        if (cdir === undefined || cdir === null) {
            deferred.resolve(defaultConfig);
        } else {
            iter.next();
        }
        return deferred.promise();
    }

    /**
     * Loads JSHint configuration for the specified file.
     *
     * The configuration file should have name .jshintrc. If the specified file is outside the
     * current project root, then defaultConfiguration is used. Otherwise, the configuration file
     * is looked up starting from the directory where the specified file is located, going up to
     * the project root, but no further.
     *
     * @param {string} fullPath Absolute path for the file linted.
     *
     * @return {$.Promise} Promise to return JSHint configuration object.
     *
     * @see JSHint option
     * reference.
     */
    function _loadConfig(fullPath) {

        var projectRootEntry = ProjectManager.getProjectRoot(),
            result = new $.Deferred(),
            relPath,
            file,
            config;

        if (!projectRootEntry) {
            return result.reject().promise();
        }

        // for files outside the project root, use default config
        if (!(relPath = FileUtils.getRelativeFilename(projectRootEntry.fullPath, fullPath))) {
            result.resolve(defaultConfig);
            return result.promise();
        }

        relPath = FileUtils.getDirectoryPath(relPath);

        _lookupAndLoad(projectRootEntry.fullPath, relPath, _readConfig)
            .done(function (cfg) {
                result.resolve(cfg);
            });
        return result.promise();
    }

    /**
     * Removes JavaScript comments from a string by replacing
     * everything between block comments and everything after
     * single-line comments in a non-greedy way.
     *
     * English version of the regex:
     *   match '/*'
     *   then match zero or more instances of any character (incl. \n)
     *   except for instances of '* /' (without a space, obv.)
     *   then match '* /' (again, without a space)
     *
     * @param {string} str a string with potential JavaScript comments.
     * @returns {string} a string without JavaScript comments.
     */
    function removeComments(str) {
        str = str || "";

        str = str.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\//g, "");
        str = str.replace(/\/\/[^\n\r]*/g, ""); // Everything after '//'

        return str;
    }

    CodeInspection.register("javascript", {
        name: "JSHint",
        scanFile: handleHinter,
        scanFileAsync: handleHinterAsync
    });

});
<|endoftext|>