<commit_before>import {ParentContext} from '../ParentContext';
import MemberAvatar from '../common/MemberGravatar';
import ActionButton from '../common/ActionButton';
import InputField from '../common/InputField';
import PlansSection from '../common/PlansSection';
import Switch from '../common/Switch';

const React = require('react');

export default class AccountPlanPage extends React.Component {
    static contextType = ParentContext;

    constructor(props, context) {
        super(props, context);
        this.state = {
            plan: 'Monthly'
        };
    }

    handleSignout(e) {
        e.preventDefault();
        this.context.onAction('signout');
    }

    onBack(e) {
        this.context.onAction('back');
    }

    renderHeader() {
        return (

 this.onBack(e)}> < Back

 Choose Plan

        );
    }

    onPlanCheckout(e) {
        e.preventDefault();
        const {onAction} = this.context;
        const plan = this.state.plan;
        onAction('checkoutPlan', {plan});
    }

    onPlanSelect(e, name) {
        e.preventDefault();
        // Hack: React checkbox gets out of sync with dom state with instant update
        setTimeout(() => {
            this.setState({
                plan: name
            });
        }, 5);
    }

    renderPlanChooser() {
        const {plans} = this.context.site;
        const plansData = [
            {type: 'month', price: plans.monthly, currency: plans.currency_symbol, name: 'Monthly'},
            {type: 'year', price: plans.yearly, currency: plans.currency_symbol, name: 'Yearly'}
        ];
        return (

                <PlansSection
                    showLabel={false}
                    plans={plansData}
                    selectedPlan={this.state.plan}
                    onPlanSelect={(e, name) => this.onPlanSelect(e, name)}
                />
                <ActionButton
                    label="Continue"
                    onClick={e => this.onPlanCheckout(e)}
                    brandColor={this.context.brandColor}
                    style={{button: {marginTop: '12px'}}}
                />

        );
    }

    render() {
        return (

                {this.renderHeader()}
                {this.renderPlanChooser()}

        );
    }
}<commit_msg>Fixed lint<commit_after>import {ParentContext} from '../ParentContext';
import ActionButton from '../common/ActionButton';
import PlansSection from '../common/PlansSection';

const React = require('react');

export default class AccountPlanPage extends React.Component {
    static contextType = ParentContext;

    constructor(props, context) {
        super(props, context);
        this.state = {
            plan: 'Monthly'
        };
    }

    handleSignout(e) {
        e.preventDefault();
        this.context.onAction('signout');
    }

    onBack(e) {
        this.context.onAction('back');
    }

    renderHeader() {
        return (

 this.onBack(e)}> < Back

 Choose Plan

        );
    }

    onPlanCheckout(e) {
        e.preventDefault();
        const {onAction} = this.context;
        const plan = this.state.plan;
        onAction('checkoutPlan', {plan});
    }

    onPlanSelect(e, name) {
        e.preventDefault();
        // Hack: React checkbox gets out of sync with dom state with instant update
        setTimeout(() => {
            this.setState({
                plan: name
            });
        }, 5);
    }

    renderPlanChooser() {
        const {plans} = this.context.site;
        const plansData = [
            {type: 'month', price: plans.monthly, currency: plans.currency_symbol, name: 'Monthly'},
            {type: 'year', price: plans.yearly, currency: plans.currency_symbol, name: 'Yearly'}
        ];
        return (

                <PlansSection
                    showLabel={false}
                    plans={plansData}
                    selectedPlan={this.state.plan}
                    onPlanSelect={(e, name) => this.onPlanSelect(e, name)}
                />
                <ActionButton
                    label="Continue"
                    onClick={e => this.onPlanCheckout(e)}
                    brandColor={this.context.brandColor}
                    style={{button: {marginTop: '12px'}}}
                />

        );
    }

    render() {
        return (

                {this.renderHeader()}
                {this.renderPlanChooser()}

        );
    }
}<|endoftext|>


<commit_before>/*! Image Zoom - v1
 *  Copyright (c) 2016 Mattias Hinderson
 *  License: MIT
 */

(function (window, factory) {
    'use strict';

    if (typeof define == 'function' && define.amd) {
        // AMD
        define([
            './utils',
            './pubsub'
        ], function(utils, pubsub) {
            return factory(window, utils, pubsub);
        });
    } else if (typeof exports == 'object') {
        // CommonJS
        module.exports = factory(
            window,
            require('./utils'),
            require('./pubsub')
        );
    }

}(window, function factory (window, utils, pubsub) {
    'use strict';

    // Constants
    var OFFSET = 60;

    // Cached values
    var cache = {
        ticking: false,
        lastScrollY: window.pageYOffset,
        viewportWidth: window.innerWidth,
        viewportHeight: window.innerHeight
    };

    // Element states
    var activeElems = [];
    var currentlyZoomedIn = [];
    var loadedImages = [];

    // Window events
    var resizeEvent = utils.debounce(function ( ) {
    	cache.viewportWidth = window.innerWidth;
    	cache.viewportHeight = window.innerHeight;
        cache.lastScrollY = window.pageYOffset;
    }, 250);

    var scrollEvent = function ( ) {
    	var requestTick = function ( ) {
            cache.lastScrollY = window.pageYOffset;

    		// Stop ticking
    		cache.ticking = false;
    	};

    	if (!cache.ticking) {
    		utils.requestAnimFrame.call(window, requestTick);
    		cache.ticking = true;
    	}
    };

    window.addEventListener('resize', resizeEvent);
    window.addEventListener('scroll', scrollEvent);

    function keysPressed (e) {
        e = e || window.event;

        switch(e.which || e.keyCode) {
            // Esc
            case 27:
                var currentItem = currentlyZoomedIn[currentlyZoomedIn.length - 1];
                zoomOut(currentItem);
                break;

            // Left arrow
            case 37:
                e.preventDefault();
                togglePrevImage();
                break;

            // Right arrow
            case 39:
                e.preventDefault();
                toggleNextImage();
                break;

            default: return;
        }
    }

    // Performance helpers
    var hintBrowser = function ( ) {
        this.style.willChange = 'transform';
    };

    var removeHint = function ( ) {
        this.removeEventListener(transitionEvent, removeHint);
	    this.style.willChange = 'auto';
    };

    // Transition event helper
    var transitionEvent = utils.whichTransitionEvent();

    function calculateZoom (imageRect, thumbRect) {
        var highResImageWidth = imageRect.width;
        var highResImageHeight = imageRect.height;

        var viewportHeight = cache.viewportHeight - OFFSET;
        var viewportWidth  = cache.viewportWidth - OFFSET;

        var maxScaleFactor = highResImageWidth / thumbRect.width;

        var imageAspectRatio = thumbRect.width / thumbRect.height;
        var viewPortAspectRatio = viewportWidth / viewportHeight;

        var imgScaleFactor;
        if (highResImageWidth < viewportWidth && highResImageHeight < viewportHeight) {
            imgScaleFactor = maxScaleFactor;
        } else if (imageAspectRatio < viewPortAspectRatio) {
            imgScaleFactor = (viewportHeight / highResImageHeight) * maxScaleFactor;
        } else {
            imgScaleFactor = (viewportWidth / highResImageWidth) * maxScaleFactor;
        }

        return imgScaleFactor;
    }

    function loadHighResImage (container, src) {
        if (!(/\.(gif|jpg|jpeg|tiff|png)$/i).test(src)) {
            return;
        }

        var image = container.querySelector('img:last-of-type');

        if (loadedImages.indexOf(image) !== -1) {
            return;
        }

        // Load high-res image
        image.src = src;

        // Remove redundant attributes
        if (image.hasAttribute('srcset')) {
            image.removeAttribute('srcset');
        }
        if (image.hasAttribute('sizes')) {
            image.removeAttribute('sizes');
        }

        image.onload = function ( ) {
            loadedImages.push(image);
            pubsub.publish('imageLoaded', image);
        };
    }

    function zoomOut (container, callback) {
        pubsub.publish('zoomOutStart', container);

        // Remove keyboard commands
        window.removeEventListener('keydown', keysPressed);

        // Reset transforms
        utils.requestAnimFrame.call(window, function ( ) {
            container.classList.remove('is-zoomed');
            container.isAnimating = true;
            container.style.msTransform = '';
            container.style.webkitTransform = '';
            container.style.transform = '';
        });

        // Wait for transition to end
        container.addEventListener(transitionEvent, function resetImage ( ) {
            container.removeEventListener(transitionEvent, resetImage);
            container.classList.remove('is-active');
            container.isAnimating = false;
            pubsub.publish('zoomOutEnd', container);

            var i = currentlyZoomedIn.indexOf(container);
            if (i != -1) { currentlyZoomedIn.splice(i, 1); }
            if (callback) { callback(); }
        });

        container.addEventListener(transitionEvent, removeHint);
    }

    function zoomIn (container, callback) {
        var thumbRect = container.getBoundingClientRect();
        var imageRect = {
            width: container.getAttribute('data-width'),
            height: container.getAttribute('data-height'),
        };

        pubsub.publish('zoomInStart', container);

        container.classList.add('is-active');

        // Force repaint
        var repaint = container.offsetWidth;

        // Calculate offset
        var viewportY = cache.viewportHeight / 2;
        var viewportX = cache.viewportWidth / 2;
        var imageCenterY = thumbRect.top + (thumbRect.height / 2);
        var imageCenterX = thumbRect.left + (thumbRect.width / 2);
        var translate = 'translate3d(' + (viewportX - imageCenterX) + 'px, ' + (viewportY - imageCenterY) + 'px, 0)';

        // Calculate scale ratio
        var scale = 'scale(' + calculateZoom(imageRect, thumbRect) + ')';

        // Apply transforms
        utils.requestAnimFrame.call(window, function ( ) {
            container.classList.add('is-zooming');
            container.isAnimating = true;

            container.style.msTransform = translate + ' ' + scale;
            container.style.webkitTransform = translate + ' ' + scale;
            container.style.transform = translate + ' ' + scale;
        });

        // Events
        window.addEventListener('keydown', keysPressed);

        // Wait for transition to end
        container.addEventListener(transitionEvent, function activateImage ( ) {
            container.removeEventListener(transitionEvent, activateImage);

            container.classList.remove('is-zooming');
            container.classList.add('is-zoomed');
            container.isAnimating = false;
            currentlyZoomedIn.push(container);
            pubsub.publish('zoomInEnd', container);

            loadHighResImage(container, container.getAttribute('href'));

            if (callback) { callback(); }
        });
    }

    var toggleNextImage = function ( ) {
        var currentItem = currentlyZoomedIn[currentlyZoomedIn.length - 1];
        var currentIndex = activeElems.indexOf(currentItem);

        if ((currentIndex + 1) >= activeElems.length) {
            return;
        }

        zoomOut(currentItem, function ( ) {
            var nextItem = activeElems[currentIndex + 1];
            zoomIn(nextItem);
        });
    };

    var togglePrevImage = function ( ) {
        var currentItem = currentlyZoomedIn[currentlyZoomedIn.length - 1];
        var currentIndex = activeElems.indexOf(currentItem);

        if (currentIndex <= 0) {
            return;
        }

        zoomOut(currentItem, function ( ) {
            var prevItem = activeElems[currentIndex - 1];
            zoomIn(prevItem);
        });
    };

    var toggleZoom = function (event) {
        event.preventDefault();

        var container = event.delegateTarget;

        if (container.isAnimating) {
            return;
        }

        if (container.classList.contains('is-zoomed')) {
            zoomOut(container);
        } else {
            zoomIn(container);
        }
    };

    function ImageZoom (elems, options) {
        if (!elems) return;

        // Update default options
        if (options) {
            OFFSET = options.offset;
        }

        // Export event emitter
        this.on = pubsub.subscribe;

        // Export functions
        this.prev = togglePrevImage;
        this.next = toggleNextImage;

        // Attach click event listeners to all provided elems
        var bindElem = function (elem) {
            activeElems.push(elem);
            elem.addEventListener('click', utils.delegate(utils.criteria.hasAttribute('data-zoomable'), toggleZoom));
            elem.addEventListener('mouseenter', hintBrowser);
        };

        // Accepts both a single node and a NodeList
        if (utils.isNodeList(elems)) {
            utils.forEach(elems, function (index, elem) {
                bindElem(elem);
            });
        } else if (elems) {
            bindElem(elems);
        }
    }

	// Expose to interface
	if (typeof module === 'object' && typeof module.exports === 'object') {
		// CommonJS, just export
		module.exports = ImageZoom;
	} else if (typeof define === 'function' && define.amd) {
		// AMD support
		define('ImageZoom', function ( ) { return ImageZoom; } );
	}

}));
<commit_msg>Remove heavy will-change use<commit_after>/*! Image Zoom - v1
 *  Copyright (c) 2016 Mattias Hinderson
 *  License: MIT
 */

(function (window, factory) {
    'use strict';

    if (typeof define == 'function' && define.amd) {
        // AMD
        define([
            './utils',
            './pubsub'
        ], function(utils, pubsub) {
            return factory(window, utils, pubsub);
        });
    } else if (typeof exports == 'object') {
        // CommonJS
        module.exports = factory(
            window,
            require('./utils'),
            require('./pubsub')
        );
    }

}(window, function factory (window, utils, pubsub) {
    'use strict';

    // Constants
    var OFFSET = 60;

    // Cached values
    var cache = {
        ticking: false,
        lastScrollY: window.pageYOffset,
        viewportWidth: window.innerWidth,
        viewportHeight: window.innerHeight
    };

    // Element states
    var activeElems = [];
    var currentlyZoomedIn = [];
    var loadedImages = [];

    // Window events
    var resizeEvent = utils.debounce(function ( ) {
    	cache.viewportWidth = window.innerWidth;
    	cache.viewportHeight = window.innerHeight;
        cache.lastScrollY = window.pageYOffset;
    }, 250);

    var scrollEvent = function ( ) {
    	var requestTick = function ( ) {
            cache.lastScrollY = window.pageYOffset;

    		// Stop ticking
    		cache.ticking = false;
    	};

    	if (!cache.ticking) {
    		utils.requestAnimFrame.call(window, requestTick);
    		cache.ticking = true;
    	}
    };

    window.addEventListener('resize', resizeEvent);
    window.addEventListener('scroll', scrollEvent);

    function keysPressed (e) {
        e = e || window.event;

        switch(e.which || e.keyCode) {
            // Esc
            case 27:
                var currentItem = currentlyZoomedIn[currentlyZoomedIn.length - 1];
                zoomOut(currentItem);
                break;

            // Left arrow
            case 37:
                e.preventDefault();
                togglePrevImage();
                break;

            // Right arrow
            case 39:
                e.preventDefault();
                toggleNextImage();
                break;

            default: return;
        }
    }

    // Transition event helper
    var transitionEvent = utils.whichTransitionEvent();

    function calculateZoom (imageRect, thumbRect) {
        var highResImageWidth = imageRect.width;
        var highResImageHeight = imageRect.height;

        var viewportHeight = cache.viewportHeight - OFFSET;
        var viewportWidth  = cache.viewportWidth - OFFSET;

        var maxScaleFactor = highResImageWidth / thumbRect.width;

        var imageAspectRatio = thumbRect.width / thumbRect.height;
        var viewPortAspectRatio = viewportWidth / viewportHeight;

        var imgScaleFactor;
        if (highResImageWidth < viewportWidth && highResImageHeight < viewportHeight) {
            imgScaleFactor = maxScaleFactor;
        } else if (imageAspectRatio < viewPortAspectRatio) {
            imgScaleFactor = (viewportHeight / highResImageHeight) * maxScaleFactor;
        } else {
            imgScaleFactor = (viewportWidth / highResImageWidth) * maxScaleFactor;
        }

        return imgScaleFactor;
    }

    function loadHighResImage (container, src) {
        if (!(/\.(gif|jpg|jpeg|tiff|png)$/i).test(src)) {
            return;
        }

        var image = container.querySelector('img:last-of-type');

        if (loadedImages.indexOf(image) !== -1) {
            return;
        }

        // Load high-res image
        image.src = src;

        // Remove redundant attributes
        if (image.hasAttribute('srcset')) {
            image.removeAttribute('srcset');
        }
        if (image.hasAttribute('sizes')) {
            image.removeAttribute('sizes');
        }

        image.onload = function ( ) {
            loadedImages.push(image);
            pubsub.publish('imageLoaded', image);
        };
    }

    function zoomOut (container, callback) {
        pubsub.publish('zoomOutStart', container);

        // Remove keyboard commands
        window.removeEventListener('keydown', keysPressed);

        // Reset transforms
        utils.requestAnimFrame.call(window, function ( ) {
            container.classList.remove('is-zoomed');
            container.isAnimating = true;
            container.style.msTransform = '';
            container.style.webkitTransform = '';
            container.style.transform = '';
        });

        // Wait for transition to end
        container.addEventListener(transitionEvent, function resetImage ( ) {
            container.removeEventListener(transitionEvent, resetImage);
            container.classList.remove('is-active');
            container.isAnimating = false;
            pubsub.publish('zoomOutEnd', container);

            var i = currentlyZoomedIn.indexOf(container);
            if (i != -1) { currentlyZoomedIn.splice(i, 1); }
            if (callback) { callback(); }
        });
    }

    function zoomIn (container, callback) {
        var thumbRect = container.getBoundingClientRect();
        var imageRect = {
            width: container.getAttribute('data-width'),
            height: container.getAttribute('data-height'),
        };

        pubsub.publish('zoomInStart', container);

        container.classList.add('is-active');

        // Force repaint
        var repaint = container.offsetWidth;

        // Calculate offset
        var viewportY = cache.viewportHeight / 2;
        var viewportX = cache.viewportWidth / 2;
        var imageCenterY = thumbRect.top + (thumbRect.height / 2);
        var imageCenterX = thumbRect.left + (thumbRect.width / 2);
        var translate = 'translate3d(' + (viewportX - imageCenterX) + 'px, ' + (viewportY - imageCenterY) + 'px, 0)';

        // Calculate scale ratio
        var scale = 'scale(' + calculateZoom(imageRect, thumbRect) + ')';

        // Apply transforms
        utils.requestAnimFrame.call(window, function ( ) {
            container.classList.add('is-zooming');
            container.isAnimating = true;

            container.style.msTransform = translate + ' ' + scale;
            container.style.webkitTransform = translate + ' ' + scale;
            container.style.transform = translate + ' ' + scale;
        });

        // Events
        window.addEventListener('keydown', keysPressed);

        // Wait for transition to end
        container.addEventListener(transitionEvent, function activateImage ( ) {
            container.removeEventListener(transitionEvent, activateImage);

            container.classList.remove('is-zooming');
            container.classList.add('is-zoomed');
            container.isAnimating = false;
            currentlyZoomedIn.push(container);
            pubsub.publish('zoomInEnd', container);

            loadHighResImage(container, container.getAttribute('href'));

            if (callback) { callback(); }
        });
    }

    var toggleNextImage = function ( ) {
        var currentItem = currentlyZoomedIn[currentlyZoomedIn.length - 1];
        var currentIndex = activeElems.indexOf(currentItem);

        if ((currentIndex + 1) >= activeElems.length) {
            return;
        }

        zoomOut(currentItem, function ( ) {
            var nextItem = activeElems[currentIndex + 1];
            zoomIn(nextItem);
        });
    };

    var togglePrevImage = function ( ) {
        var currentItem = currentlyZoomedIn[currentlyZoomedIn.length - 1];
        var currentIndex = activeElems.indexOf(currentItem);

        if (currentIndex <= 0) {
            return;
        }

        zoomOut(currentItem, function ( ) {
            var prevItem = activeElems[currentIndex - 1];
            zoomIn(prevItem);
        });
    };

    var toggleZoom = function (event) {
        event.preventDefault();

        var container = event.delegateTarget;

        if (container.isAnimating) {
            return;
        }

        if (container.classList.contains('is-zoomed')) {
            zoomOut(container);
        } else {
            zoomIn(container);
        }
    };

    function ImageZoom (elems, options) {
        if (!elems) return;

        // Update default options
        if (options) {
            OFFSET = options.offset;
        }

        // Export event emitter
        this.on = pubsub.subscribe;

        // Export functions
        this.prev = togglePrevImage;
        this.next = toggleNextImage;

        // Attach click event listeners to all provided elems
        var bindElem = function (elem) {
            activeElems.push(elem);
            elem.addEventListener('click', utils.delegate(utils.criteria.hasAttribute('data-zoomable'), toggleZoom));
        };

        // Accepts both a single node and a NodeList
        if (utils.isNodeList(elems)) {
            utils.forEach(elems, function (index, elem) {
                bindElem(elem);
            });
        } else if (elems) {
            bindElem(elems);
        }
    }

	// Expose to interface
	if (typeof module === 'object' && typeof module.exports === 'object') {
		// CommonJS, just export
		module.exports = ImageZoom;
	} else if (typeof define === 'function' && define.amd) {
		// AMD support
		define('ImageZoom', function ( ) { return ImageZoom; } );
	}

}));
<|endoftext|>


<commit_before>// ==UserScript==
// @name        GitHub Code Folding
// @version     1.0.6
// @description A userscript that adds code folding to GitHub files
// @license     MIT
// @author      Rob Garrison
// @namespace   https://github.com/Mottie
// @include     https://github.com/*
// @run-at      document-idle
// @grant       GM_addStyle
// @require     https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=189706
// @icon        https://github.com/fluidicon.png
// @updateURL   https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-code-folding.user.js
// @downloadURL https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-code-folding.user.js
// ==/UserScript==
/**
 * This userscript has been heavily modified from the "github-code-folding"
 * Chrome extension Copyright 2016 by Noam Lustiger; under an MIT license
 * https://github.com/noam3127/github-code-folding
 */
(() => {
	"use strict";

	GM_addStyle(`
		td.blob-code.blob-code-inner { padding-left:13px; }
		.collapser { position:absolute; left:2px; width:22px; opacity:.5;
			transition:.15s; cursor:pointer; }
		.collapser:after { content:"\u25bc"; }
		.collapser:hover { opacity:1; }
		.sideways { transform:rotate(-90deg); transform-origin:16% 49%; opacity:.8; }
		.hidden-line { display:none; }
		.ellipsis { padding:1px 2px; margin-left:2px; cursor:pointer;
			background:rgba(255,235,59,.4); position:relative; z-index:1; }
		.ellipsis:hover { background:rgba(255,235,59,.7); }
	`);

	const pairs = new Map(),
		ellipsis = document.createElement("span"),
		triangle = document.createElement("span");

	triangle.className = "collapser";
	ellipsis.className = "pl-smi ellipsis";
	ellipsis.innerHTML = "…";

	function countInitialWhiteSpace(arr) {
		const getWhiteSpaceIndex = i => {
			if (arr[i] !== " " && arr[i] !== "\t") {
				return i;
			}
			i++;
			return getWhiteSpaceIndex(i);
		};
		return getWhiteSpaceIndex(0);
	}

	function getPreviousSpaces(map, lineNum) {
		let prev = map.get(lineNum - 1);
		return prev === -1 ?
			getPreviousSpaces(map, lineNum - 1) : {
				lineNum: lineNum - 1,
				count: prev
			};
	}

	function getLineNumber(el) {
		let elm = closest("td", el),
			index = elm ? elm.id : "";
		if (index) {
			return parseInt(index.slice(2), 10);
		}
		return "";
	}

	function toggleCode(action, index, depth) {
		let els, lineNums;
		const codeLines = $$(".file table.highlight .blob-code-inner");
		// depth is a string containing a specific depth number to toggle
		if (depth) {
			els = $$(`.collapser[data-depth="${depth}"]`);
			lineNums = els.map(el => {
				el.classList.toggle("sideways", action === "hide");
				return getLineNumber(el);
			});
		} else {
			lineNums = [index];
		}

		if (action === "hide") {
			lineNums.forEach(start => {
				let end = pairs.get(start - 1);
				codeLines.slice(start, end).forEach(el => {
					let elm = closest("tr", el);
					if (elm) {
						elm.classList.add("hidden-line");
					}
				});
				if (!$(".ellipsis", codeLines[start - 1])) {
					codeLines[start - 1].appendChild(ellipsis.cloneNode(true));
				}
			});
		} else if (action === "show") {
			lineNums.forEach(start => {
				let end = pairs.get(start - 1);
				codeLines.slice(start, end).forEach(el => {
					let elm = closest("tr", el);
					if (elm) {
						elm.classList.remove("hidden-line");
						remove(".ellipsis", elm);
					}
					elm = $(".sideways", elm);
					if (elm) {
						elm.classList.remove("sideways");
					}
				});
				remove(".ellipsis", codeLines[start - 1]);
			});
		}
		// shift ends up selecting text on the page, so clear it
		if (lineNums.length > 1) {
			removeSelection();
		}
	}

	function addBindings() {
		document.addEventListener("click", event => {
			let index, elm, isCollapsed;
			const el = event.target;

			// click on collapser
			if (el && el.classList.contains("collapser")) {
				isCollapsed = el.classList.contains("sideways");
				index = getLineNumber(el);
				// Shift + click to toggle them all
				if (index && event.getModifierState("Shift")) {
					return toggleCode(
						isCollapsed ? "show" : "hide",
						index,
						el.getAttribute("data-depth")
					);
				}
				if (index) {
					if (isCollapsed) {
						el.classList.remove("sideways");
						toggleCode("show", index);
					} else {
						el.classList.add("sideways");
						toggleCode("hide", index);
					}
				}
				return;
			}

			// click on ellipsis
			if (el && el.classList.contains("ellipsis")) {
				elm = $(".sideways", el.parentNode);
				if (elm) {
					elm.classList.remove("sideways");
				}
				index = getLineNumber(el);
				if (index) {
					toggleCode("show", index);
				}
			}
		});
	}

	function addCodeFolding() {
		if ($(".file table.highlight")) {
			// In case this script has already been run and modified the DOM on a
			// previous page in github, make sure to reset it.
			remove("span.collapser");
			pairs.clear();

			const codeLines = $$(".file table.highlight .blob-code-inner"),
				spaceMap = new Map(),
				stack = [];

			codeLines.forEach((el, lineNum) => {
				let prevSpaces,
					line = el.textContent,
					count = line.trim().length ?
						countInitialWhiteSpace(line.split("")) :
						-1;
				spaceMap.set(lineNum, count);

				function tryPair() {
					let el,
						top = stack[stack.length - 1];
					if (count !== -1 && count <= spaceMap.get(top)) {
						pairs.set(top, lineNum);
						// prepend triangle
						el = triangle.cloneNode();
						el.setAttribute("data-depth", count + 1);
						codeLines[top].insertBefore(el, codeLines[top].childNodes[0]);
						stack.pop();
						return tryPair();
					}
				}
				tryPair();

				prevSpaces = getPreviousSpaces(spaceMap, lineNum);
				if (count > prevSpaces.count) {
					stack.push(prevSpaces.lineNum);
				}
			});
		}
	}

	function $(selector, el) {
		return (el || document).querySelector(selector);
	}

	function $$(selector, el) {
		return Array.from((el || document).querySelectorAll(selector));
	}

	function closest(selector, el) {
		while (el && el.nodeType === 1) {
			if (el.matches(selector)) {
				return el;
			}
			el = el.parentNode;
		}
		return null;
	}

	function remove(selector, el) {
		let els = $$(selector, el),
			index = els.length;
		while (index--) {
			els[index].parentNode.removeChild(els[index]);
		}
	}

	function removeSelection() {
		// remove text selection - https://stackoverflow.com/a/3171348/145346
		const sel = window.getSelection ?
			window.getSelection() :
			document.selection;
		if (sel) {
			if (sel.removeAllRanges) {
				sel.removeAllRanges();
			} else if (sel.empty) {
				sel.empty();
			}
		}
	}

	document.addEventListener("ghmo:container", addCodeFolding);
	addCodeFolding();
	addBindings();

})();
<commit_msg>Code-folding: Append collapse arrow<commit_after>// ==UserScript==
// @name        GitHub Code Folding
// @version     1.0.6
// @description A userscript that adds code folding to GitHub files
// @license     MIT
// @author      Rob Garrison
// @namespace   https://github.com/Mottie
// @include     https://github.com/*
// @run-at      document-idle
// @grant       GM_addStyle
// @require     https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=189706
// @icon        https://github.com/fluidicon.png
// @updateURL   https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-code-folding.user.js
// @downloadURL https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-code-folding.user.js
// ==/UserScript==
/**
 * This userscript has been heavily modified from the "github-code-folding"
 * Chrome extension Copyright 2016 by Noam Lustiger; under an MIT license
 * https://github.com/noam3127/github-code-folding
 */
(() => {
	"use strict";

	GM_addStyle(`
		td.blob-code.blob-code-inner { padding-left:13px; }
		.collapser { position:absolute; left:2px; width:22px; opacity:.5;
			transition:.15s; cursor:pointer; }
		.collapser:after { content:"\u25bc"; }
		.collapser:hover { opacity:1; }
		.sideways { transform:rotate(-90deg); transform-origin:16% 49%; opacity:.8; }
		.hidden-line { display:none; }
		.ellipsis { padding:1px 2px; margin-left:2px; cursor:pointer;
			background:rgba(255,235,59,.4); position:relative; z-index:1; }
		.ellipsis:hover { background:rgba(255,235,59,.7); }
	`);

	const pairs = new Map(),
		ellipsis = document.createElement("span"),
		triangle = document.createElement("span");

	triangle.className = "collapser";
	ellipsis.className = "pl-smi ellipsis";
	ellipsis.innerHTML = "…";

	function countInitialWhiteSpace(arr) {
		const getWhiteSpaceIndex = i => {
			if (arr[i] !== " " && arr[i] !== "\t") {
				return i;
			}
			i++;
			return getWhiteSpaceIndex(i);
		};
		return getWhiteSpaceIndex(0);
	}

	function getPreviousSpaces(map, lineNum) {
		let prev = map.get(lineNum - 1);
		return prev === -1 ?
			getPreviousSpaces(map, lineNum - 1) : {
				lineNum: lineNum - 1,
				count: prev
			};
	}

	function getLineNumber(el) {
		let elm = closest("td", el),
			index = elm ? elm.id : "";
		if (index) {
			return parseInt(index.slice(2), 10);
		}
		return "";
	}

	function toggleCode(action, index, depth) {
		let els, lineNums;
		const codeLines = $$(".file table.highlight .blob-code-inner");
		// depth is a string containing a specific depth number to toggle
		if (depth) {
			els = $$(`.collapser[data-depth="${depth}"]`);
			lineNums = els.map(el => {
				el.classList.toggle("sideways", action === "hide");
				return getLineNumber(el);
			});
		} else {
			lineNums = [index];
		}

		if (action === "hide") {
			lineNums.forEach(start => {
				let elm,
					end = pairs.get(start - 1);
				codeLines.slice(start, end).forEach(el => {
					elm = closest("tr", el);
					if (elm) {
						elm.classList.add("hidden-line");
					}
				});
				if (!$(".ellipsis", codeLines[start - 1])) {
					elm = $(".collapser", codeLines[start - 1]);
					elm.parentNode.insertBefore(
						ellipsis.cloneNode(true),
						elm.nextSibling
					);
				}
			});
		} else if (action === "show") {
			lineNums.forEach(start => {
				let end = pairs.get(start - 1);
				codeLines.slice(start, end).forEach(el => {
					let elm = closest("tr", el);
					if (elm) {
						elm.classList.remove("hidden-line");
						remove(".ellipsis", elm);
					}
					elm = $(".sideways", elm);
					if (elm) {
						elm.classList.remove("sideways");
					}
				});
				remove(".ellipsis", codeLines[start - 1]);
			});
		}
		// shift ends up selecting text on the page, so clear it
		if (lineNums.length > 1) {
			removeSelection();
		}
	}

	function addBindings() {
		document.addEventListener("click", event => {
			let index, elm, isCollapsed;
			const el = event.target;

			// click on collapser
			if (el && el.classList.contains("collapser")) {
				isCollapsed = el.classList.contains("sideways");
				index = getLineNumber(el);
				// Shift + click to toggle them all
				if (index && event.getModifierState("Shift")) {
					return toggleCode(
						isCollapsed ? "show" : "hide",
						index,
						el.getAttribute("data-depth")
					);
				}
				if (index) {
					if (isCollapsed) {
						el.classList.remove("sideways");
						toggleCode("show", index);
					} else {
						el.classList.add("sideways");
						toggleCode("hide", index);
					}
				}
				return;
			}

			// click on ellipsis
			if (el && el.classList.contains("ellipsis")) {
				elm = $(".sideways", el.parentNode);
				if (elm) {
					elm.classList.remove("sideways");
				}
				index = getLineNumber(el);
				if (index) {
					toggleCode("show", index);
				}
			}
		});
	}

	function addCodeFolding() {
		if ($(".file table.highlight")) {
			// In case this script has already been run and modified the DOM on a
			// previous page in github, make sure to reset it.
			remove("span.collapser");
			pairs.clear();

			const codeLines = $$(".file table.highlight .blob-code-inner"),
				spaceMap = new Map(),
				stack = [];

			codeLines.forEach((el, lineNum) => {
				let prevSpaces,
					line = el.textContent,
					count = line.trim().length ?
						countInitialWhiteSpace(line.split("")) :
						-1;
				spaceMap.set(lineNum, count);

				function tryPair() {
					let el,
						top = stack[stack.length - 1];
					if (count !== -1 && count <= spaceMap.get(top)) {
						pairs.set(top, lineNum);
						// prepend triangle
						el = triangle.cloneNode();
						el.setAttribute("data-depth", count + 1);
						codeLines[top].appendChild(el, codeLines[top].childNodes[0]);
						stack.pop();
						return tryPair();
					}
				}
				tryPair();

				prevSpaces = getPreviousSpaces(spaceMap, lineNum);
				if (count > prevSpaces.count) {
					stack.push(prevSpaces.lineNum);
				}
			});
		}
	}

	function $(selector, el) {
		return (el || document).querySelector(selector);
	}

	function $$(selector, el) {
		return Array.from((el || document).querySelectorAll(selector));
	}

	function closest(selector, el) {
		while (el && el.nodeType === 1) {
			if (el.matches(selector)) {
				return el;
			}
			el = el.parentNode;
		}
		return null;
	}

	function remove(selector, el) {
		let els = $$(selector, el),
			index = els.length;
		while (index--) {
			els[index].parentNode.removeChild(els[index]);
		}
	}

	function removeSelection() {
		// remove text selection - https://stackoverflow.com/a/3171348/145346
		const sel = window.getSelection ?
			window.getSelection() :
			document.selection;
		if (sel) {
			if (sel.removeAllRanges) {
				sel.removeAllRanges();
			} else if (sel.empty) {
				sel.empty();
			}
		}
	}

	document.addEventListener("ghmo:container", addCodeFolding);
	addCodeFolding();
	addBindings();

})();
<|endoftext|>


<commit_before>'use strict';

var superagent = require('superagent');

module.exports = function(file, callback) {

    superagent.get( window.location.origin +  file )
    .end(function(err, res) {
        if(res.ok) {
            callback(null, res.text); // passing null error param to keep same interface as fs.readfile.
        }else {
            callback(err || res.body);
        }
    });
};
<commit_msg>handle error in superagent readfile<commit_after>'use strict';

var superagent = require('superagent');

module.exports = function(file, callback) {

    superagent.get( window.location.origin +  file )
    .end(function(err, res) {

        if(err) {
            return callback(err)
        }
        if(res.ok) {
            callback(null, res.text); // passing null error param to keep same interface as fs.readfile.
        }else {
            callback(res.body);
        }
    });
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name          GitHub Show Repo Issues
// @version       3.0.1
// @description   A userscript that adds a repo issues count to the repository tab & organization page (https://github.com/:user)
// @license       https://creativecommons.org/licenses/by-sa/4.0/
// @namespace     http://github.com/Mottie
// @include       https://github.com/*
// @grant         GM_addStyle
// @grant         GM_xmlhttpRequest
// @connect       api.github.com
// @run-at        document-idle
// @author        Rob Garrison
// @updateURL     https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-issue-counts.user.js
// @downloadURL   https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-issue-counts.user.js
// ==/UserScript==
/* global GM_addStyle, GM_xmlhttpRequest */
/* jshint esnext:true, unused:true */
(() => {
	"use strict";
	let busy = false;

	// issue count = get all repos from user => api v3
	// https://api.github.com/users/:user/repos
	// then look for "open_issues_count" in the named repos
	const api = "https://api.github.com/users",
		// bug icon
		icon = `<svg class="octicon octicon-repo-issues" xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 53 53">
				<path d="m39.2 0c2 0 3.7 1.5 3.7 3.4 0 1.9-1.7 3.4-3.7 3.4l-0.9-0.1-3.4 4c2.3 1.6 4.4 3.8 6 6.4-4 1.2-8.9 1.9-14.2 1.9-5.3 0-10.1-0.7-14.2-1.9 1.5-2.6 3.5-4.7 5.7-6.3l-3.5-4.1c-0.2 0-0.4 0.1-0.6 0.1-2 0-3.7-1.5-3.7-3.4 0-1.9 1.7-3.4 3.7-3.4 2 0 3.7 1.5 3.7 3.4 0 0.7-0.2 1.3-0.6 1.8l3.5 4.2c1.8-0.8 3.8-1.3 5.9-1.3 2 0 3.9 0.4 5.6 1.2l3.7-4.3c-0.3-0.5-0.4-1-0.4-1.6 0-1.9 1.6-3.4 3.7-3.4zm11.8 28.5c1.2 0 2.2 0.9 2.2 2 0 1.1-1 2-2.2 2l-6.7 0c-0.1 1.5-0.3 2.9-0.6 4.3l7.8 3.4c1.1 0.5 1.6 1.7 1.1 2.7-0.5 1-1.8 1.5-2.9 1l-7.2-3.1c-2.7 6.7-8 11.4-14.3 12.1l0-31.2c5.2-0.1 10-1 13.9-2.3l0.3 0.7 7.5-2.7c1.1-0.4 2.4 0.1 2.9 1.2 0.4 1.1-0.1 2.2-1.3 2.6l-7.9 2.8c0.3 1.4 0.6 2.9 0.7 4.5l6.7 0 0 0zm-48.7 0 6.7 0c0.1-1.5 0.3-3.1 0.7-4.5l-7.9-2.8c-1.1-0.4-1.7-1.6-1.3-2.6 0.4-1 1.7-1.6 2.9-1.2l7.5 2.7 0.3-0.7c3.9 1.3 8.7 2.1 13.9 2.3l0 31.2c-6.2-0.7-11.5-5.4-14.3-12.1l-7.2 3.1c-1.1 0.5-2.4 0-2.9-1-0.5-1 0-2.2 1.1-2.7l7.8-3.4c-0.3-1.4-0.5-2.8-0.6-4.3l-6.7 0c-1.2 0-2.2-0.9-2.2-2 0-1.1 1-2 2.2-2z" />
			</svg>`,

		repoSelectors = "#user-repositories-list, #org-repositories, ol.pinned-repos-list";

	// add bug image styling
	GM_addStyle(`
		.repo-list-stats a.issues svg {
			position: relative;
			top: 2px;
			fill: #888;
		}
		.repo-list-stats a.issues:hover svg {
			fill: #4078C0;
		}
	`);

	/*
	 * Org repos
	 *   container = div#org-repositories > div > div.org-repos.repo-list > li
	 * User repos
	 *   container = div#user-repositories-list > div.js-repo-list > li
	 * Common org/user
	 *   repo url = container h3 a (first a)
	 *   issue link location = container div[3] a[last]:after
	 *   fork link HTML - both user/org (Dec 2016)
	 *
	 *       <svg class="octicon octicon-repo-forked">...</svg> :fork-count
	 *
	 *
	 * Pinned repos
	 *   container = ol.pinned-repos-list li.pinned-repo-item
	 *   repo url = container span span a (first a)
	 *   issue link location = container > span.pinned-repo-item-content p[last] a[last]:after
	 *   fork link HTML
	 *
	 *       <svg aria-label="forks" class="octicon octicon-repo-forked">...</svg> :fork-count
	 *
	*/
	function addLinks(data, repos) {
		repos.forEach(repo => {
			let wrapper, el, html, setClass;
			const url = ($("a", repo).getAttribute("href") || "").slice(1),
				result = url && data.find(item => {
					return item.full_name === url;
				});
			// pinned
			if (repo.classList.contains("pinned-repo-item")) {
				el = $$(".pinned-repo-item-content p:last-child", repo);
				setClass = "muted-link ghic2-issue-link";
			} else {
				// user/org list = third div in repo list contains links
				wrapper = $$("div", repo)[3];
				el = wrapper && $$("a", wrapper);
				setClass = "muted-link tooltipped tooltipped-s mr-3 ghic2-issue-link";
			}
			if (el) {
				if (result && typeof result.open_issues_count === "number") {
					html = `
							${icon} ${result.open_issues_count}
						`;
					// target the last "a"
					el = el[el.length - 1];
					// add after last link, sometimes there is no fork
					if (el) {
						if (el.tagName === "P") {
							wrapper = document.createElement("span");
							wrapper.className = "ghic-link pinned-repo-meta";
							el.appendChild(wrapper);
							el.querySelector(".ghic-link").innerHTML = html;
						} else {
							el.insertAdjacentHTML("afterend", html);
						}
					}
				}
			}
		});
		busy = false;
	}

	function addIssues() {
		let user, url,
			repos = $$(repoSelectors);
		if (
			// look for user overview, user repositories & organization repo page
			repos.length &&
			// and not already applied
			!$$(".ghic2-issue-link").length
		) {
			busy = true;
			// no issue count for non-public & forks
			repos = $$("li", repos[0]).filter(repo => {
				let list = repo.classList;
				return list.contains("public") && !list.contains("fork");
			});
			if (repos.length) {
				url = $("a", repos[ 0 ]).getAttribute("href");
				user = (url || "").match(/^\/[^/]+/);

				if (user && user.length) {
					GM_xmlhttpRequest({
						method : "GET",
						url : api + user[0] + "/repos",
						onload : function(response) {
							const data = JSON.parse(response.responseText || "null");
							if (data) {
								addLinks(data, repos);
							}
						}
					});
				}
			} else {
				busy = false;
			}
		} else {
			busy = false;
		}
	}

	function $(str, el) {
		return (el || document).querySelector(str);
	}

	function $$(str, el) {
		return Array.from((el || document).querySelectorAll(str));
	}

	Array.from(
		document.querySelectorAll(
			"#js-repo-pjax-container, #js-pjax-container, .js-contribution-activity"
		)
	).forEach(
		target => {
			new MutationObserver(mutations => {
				mutations.forEach(mutation => {
					// preform checks before adding code wrap to minimize function calls
					if (!busy && mutation.target === target) {
						addIssues();
					}
				});
			}).observe(target, {
				childList: true,
				subtree: true
			});
		});

	addIssues();

})();
<commit_msg>Issue-counts: Use pjax & fix linting<commit_after>// ==UserScript==
// @name          GitHub Show Repo Issues
// @version       3.0.2
// @description   A userscript that adds a repo issues count to the repository tab & organization page (https://github.com/:user)
// @license       https://creativecommons.org/licenses/by-sa/4.0/
// @namespace     https://github.com/Mottie
// @include       https://github.com/*
// @grant         GM_addStyle
// @grant         GM_xmlhttpRequest
// @connect       api.github.com
// @run-at        document-idle
// @author        Rob Garrison
// @updateURL     https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-issue-counts.user.js
// @downloadURL   https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-issue-counts.user.js
// ==/UserScript==
(() => {
	"use strict";

	// issue count = get all repos from user => api v3
	// https://api.github.com/users/:user/repos
	// then look for "open_issues_count" in the named repos
	const api = "https://api.github.com/users",
		// bug icon
		icon = `<svg class="octicon octicon-repo-issues" xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 53 53">
				<path d="m39.2 0c2 0 3.7 1.5 3.7 3.4 0 1.9-1.7 3.4-3.7 3.4l-0.9-0.1-3.4 4c2.3 1.6 4.4 3.8 6 6.4-4 1.2-8.9 1.9-14.2 1.9-5.3 0-10.1-0.7-14.2-1.9 1.5-2.6 3.5-4.7 5.7-6.3l-3.5-4.1c-0.2 0-0.4 0.1-0.6 0.1-2 0-3.7-1.5-3.7-3.4 0-1.9 1.7-3.4 3.7-3.4 2 0 3.7 1.5 3.7 3.4 0 0.7-0.2 1.3-0.6 1.8l3.5 4.2c1.8-0.8 3.8-1.3 5.9-1.3 2 0 3.9 0.4 5.6 1.2l3.7-4.3c-0.3-0.5-0.4-1-0.4-1.6 0-1.9 1.6-3.4 3.7-3.4zm11.8 28.5c1.2 0 2.2 0.9 2.2 2 0 1.1-1 2-2.2 2l-6.7 0c-0.1 1.5-0.3 2.9-0.6 4.3l7.8 3.4c1.1 0.5 1.6 1.7 1.1 2.7-0.5 1-1.8 1.5-2.9 1l-7.2-3.1c-2.7 6.7-8 11.4-14.3 12.1l0-31.2c5.2-0.1 10-1 13.9-2.3l0.3 0.7 7.5-2.7c1.1-0.4 2.4 0.1 2.9 1.2 0.4 1.1-0.1 2.2-1.3 2.6l-7.9 2.8c0.3 1.4 0.6 2.9 0.7 4.5l6.7 0 0 0zm-48.7 0 6.7 0c0.1-1.5 0.3-3.1 0.7-4.5l-7.9-2.8c-1.1-0.4-1.7-1.6-1.3-2.6 0.4-1 1.7-1.6 2.9-1.2l7.5 2.7 0.3-0.7c3.9 1.3 8.7 2.1 13.9 2.3l0 31.2c-6.2-0.7-11.5-5.4-14.3-12.1l-7.2 3.1c-1.1 0.5-2.4 0-2.9-1-0.5-1 0-2.2 1.1-2.7l7.8-3.4c-0.3-1.4-0.5-2.8-0.6-4.3l-6.7 0c-1.2 0-2.2-0.9-2.2-2 0-1.1 1-2 2.2-2z" />
			</svg>`,

		repoSelectors = "#user-repositories-list, #org-repositories, ol.pinned-repos-list";

	// add bug image styling
	GM_addStyle(`
		.repo-list-stats a.issues svg {
			position: relative;
			top: 2px;
			fill: #888;
		}
		.repo-list-stats a.issues:hover svg {
			fill: #4078C0;
		}
	`);

	/*
	 * Org repos
	 *   container = div#org-repositories > div > div.org-repos.repo-list > li
	 * User repos
	 *   container = div#user-repositories-list > div.js-repo-list > li
	 * Common org/user
	 *   repo url = container h3 a (first a)
	 *   issue link location = container div[3] a[last]:after
	 *   fork link HTML - both user/org (Dec 2016)
	 *
	 *       <svg class="octicon octicon-repo-forked">...</svg> :fork-count
	 *
	 *
	 * Pinned repos
	 *   container = ol.pinned-repos-list li.pinned-repo-item
	 *   repo url = container span span a (first a)
	 *   issue link location = container > span.pinned-repo-item-content p[last] a[last]:after
	 *   fork link HTML
	 *
	 *       <svg aria-label="forks" class="octicon octicon-repo-forked">...</svg> :fork-count
	 *
	*/
	function addLinks(data, repos) {
		repos.forEach(repo => {
			let wrapper, el, html, setClass;
			const url = ($("a", repo).getAttribute("href") || "").slice(1),
				result = url && data.find(item => {
					return item.full_name === url;
				});
			// pinned
			if (repo.classList.contains("pinned-repo-item")) {
				el = $$(".pinned-repo-item-content p:last-child", repo);
				setClass = "muted-link ghic2-issue-link";
			} else {
				// user/org list = third div in repo list contains links
				wrapper = $$("div", repo)[3];
				el = wrapper && $$("a", wrapper);
				setClass = "muted-link tooltipped tooltipped-s mr-3 ghic2-issue-link";
			}
			if (el) {
				if (result && typeof result.open_issues_count === "number") {
					html = `
							${icon} ${result.open_issues_count}
						`;
					// target the last "a"
					el = el[el.length - 1];
					// add after last link, sometimes there is no fork
					if (el) {
						if (el.tagName === "P") {
							wrapper = document.createElement("span");
							wrapper.className = "ghic-link pinned-repo-meta";
							el.appendChild(wrapper);
							el.querySelector(".ghic-link").innerHTML = html;
						} else {
							el.insertAdjacentHTML("afterend", html);
						}
					}
				}
			}
		});
	}

	function addIssues() {
		let user, url,
			repos = $$(repoSelectors);
		if (
			// look for user overview, user repositories & organization repo page
			repos.length &&
			// and not already applied
			!$$(".ghic2-issue-link").length
		) {
			// no issue count for non-public & forks
			repos = $$("li", repos[0]).filter(repo => {
				let list = repo.classList;
				return list.contains("public") && !list.contains("fork");
			});
			if (repos.length) {
				url = $("a", repos[ 0 ]).getAttribute("href");
				user = (url || "").match(/^\/[^/]+/);

				if (user && user.length) {
					GM_xmlhttpRequest({
						method : "GET",
						url : api + user[0] + "/repos",
						onload : response => {
							const data = JSON.parse(response.responseText || "null");
							if (data) {
								addLinks(data, repos);
							}
						}
					});
				}
			} else {
			}
		}
	}

	function $(str, el) {
		return (el || document).querySelector(str);
	}

	function $$(str, el) {
		return Array.from((el || document).querySelectorAll(str));
	}

	document.addEventListener("pjax:end", addIssues);
	addIssues();

})();
<|endoftext|>


<commit_before>
/**
  @class

  `XT.Model` is an abstract class designed to operate with `XT.DataSource`.
  It should be subclassed for any specific implentation. Subtypes should
  include a `recordType` the data source will use to retreive the record.

  To create a new model include `isNew` in the options like so:
    XM.Contact = XT.Model.extend({recordType: 'XM.Contact'});
    m = new XM.Contact({firstName: 'Randy'}, {isNew: true});

  To load an existing record include a guid in the options like so:
    XM.Contact = XT.Model.extend({recordType: 'XM.Contact'});
    m = new XM.Contact({guid: 1});
    m.fetch();

    OR

    XM.Contact = XT.Model.extend({recordType: 'XM.Contact'});
    m = XM.Contact();
    m.fetch({id: 1});

  @extends Backbone.RelationalModel
  @param {Object} attributes
  @param {Object} options
*/
XT.Model = Backbone.RelationalModel.extend(
  /** @scope XT.Model.prototype */ {

  idAttribute: "guid",

  /**
  Set to true if you want an id fetched from the server when the `isNew` option
  is passed on a new model.

  @type {Boolean}
  */
  autoFetchId: true,

  /**
  Specify the name of a data source model here.

  @type {String}
  */
  recordType: null,

  /**
  A hash structure that defines data access.

  @property
  @type {Hash}
  */
  privileges: {},

  /**
  An array of required attributes. A validate on the entire model will fail
  until all the required attributes have values.

  @type {Array}
  */
  required: [],

  /**
  An array of attribute names designating attributes that are not editable.
  Use `setReadOnly` to edit this array.

  @seealso `setReadOnly`
  @seealso `isReadOnly`
  @type {Array}
  */
  readOnly: [],

  // ..........................................................
  // METHODS
  //

  /**
    Returns whether the current record can be updated based on privilege
    settings.

    @returns {Boolean}
  */
  canUpdate: function() {
    var obj = Backbone.Relational.store.getObjectByName(this.recordType);
    return obj.canUpdate(this);
  },

  /**
    Returns whether the current record can be deleted based on privilege
    settings.

    @returns {Boolean}
  */
  canDelete: function() {
    var obj = Backbone.Relational.store.getObjectByName(this.recordType);
    return obj.canDelete(this);
  },

  /**
  Set the entire model, or a specific model attribute to readOnly. Privilege
  enforcement supercedes read-only settings.

  Examples:

  model.setReadOnly() // sets model to read only
  model.setReadOnly(false) // sets model to be editable
  model.setReadOnly('name') // sets 'name' attribute to read-only
  model.setReadOnly('name', false) // sets 'name' attribute to be editable

  @seealso `isReadOnly`
  @seealso `readOnly`
  @param {String|Boolean} Attribute to set, or boolean if setting the model
  @param {Boolean} boolean - default = true.
  */
  setReadOnly: function(key, value) {
    // handle attribute
    if (_.isString(key)) {
      value = _.isBoolean(value) ? value : true;
      if (value && !_.contains(this.readOnly, key)) {
        this.readOnly.push(key);
      } else if (!value && _.contains(this.readOnly, key)) {
        this.readOnly = _.without(this.readOnly, key);
      }
      return;
    }

    // handle model
    key = _.isBoolean(key) ? key : true;
    this._readOnly = key;
  },

  /**
  Return whether the model is in a read-only state. If an attribute name
  is passed, returns whether that attribute is read-only.

  @seealso `setReadOnly`
  @seealso `readOnly`
  @param {String} attribute
  */
  isReadOnly: function(attr) {
    var canNotUpdate = !this.canUpdate();
    if (!_.isString(attr) || this._readOnly || canNotUpdate) {
      return this._readOnly || canNotUpdate;
    }
    return _.contains(this.readOnly, attr);
  },

  initialize: function() {
    var options = arguments[1];

    // set data source
    this._dataSource = XT.dataSource;

    // initialize for new record
    if (options && options.isNew) {
      this.attributes.dataState = 'create';
      if (this.autoFetchId) this._fetchId();
    }

    // set id to read only
    if (this.idAttribute && !_.contains(this.readOnly, this.idAttribute)) {
      this.readOnly.push(this.idAttribute);
    }

    // set id as required
    if (this.idAttribute && !_.contains(this.required, this.idAttribute)) {
      this.required.push(this.idAttribute);
    }

    // set up state change handler
    this.on('change', this._changed);
  },

  /**
  Reimplemented. A model is new if the dataState is `create`.
  */
  isNew: function() {
    return this.get('dataState') === 'create';
  },

  /**
  Returns true when dataState is `create` or `update`.
  */
  isDirty: function() {
    var dataState = this.get('dataState');
    return dataState === 'create' || dataState === 'update';
  },

  /**
  Reimplemented to handle state change.
  */
  fetch: function(options) {
    options = options ? _.clone(options) : {};
    var that = this;
    var success = options.success;

    // flip sync flag back on success
    options.success = function(resp, status, xhr) {
      that._sync = false;
      that._attrCache = _.clone(that.attributes);
      if (success) success(model, resp, options);
    };

    return Backbone.Model.prototype.fetch.call(this, options);
  },

  /**
  Reimplemented to handle state change.
  */
  save: function(key, value, options) {
    // Handle both `("key", value)` and `({key: value})` -style calls.
    if (_.isObject(key) || key === null || key === undefined) options = value;
    options = options ? _.clone(options) : {};

    var that = this;
    var success = options.success;

    // flip sync flag back on success
    options.success = function(resp, status, xhr) {
      that._sync = false;
      that._attrCache = _.clone(that.attributes);
      if (success) success(model, resp, options);
    };

    // Handle both `("key", value)` and `({key: value})` -style calls.
    if (_.isObject(key) || key === null || key === undefined) value = options;

    return Backbone.Model.prototype.save.call(this, key, value, options);
  },

  /**
  Reimplemented.
  */
  destroy: function(options) {
    options = options ? _.clone(options) : {};
    var that = this;
    var success = options.success;

    // clear on success
    options.success = function(resp, status, xhr) {
      that.clear({silent: true});
      that._attrCache = null;
      if (success) success(model, resp, options);
    };

    this.set('dataState', 'delete');
    return Backbone.Model.prototype.destroy.call(this, options);
  },

  /**
  Overload: sync to xtuple datasource.
  */
  sync: function(method, model, options) {
    var recordType = model.recordType;
    var id = options.id || this.id;
    var success = options.success;

    if (options === undefined) options = {};
    this._sync = true;

    // read
    if (method === 'read' && recordType && id && success) {
      return this._dataSource.retrieveRecord(recordType, id, options);

    // write
    } else if (method === 'create' || method === 'update' || method === 'delete') {
      var ret = this._dataSource.commitRecord(model, options);
      this.set('dataState', 'busy');
      return ret;
    }

    return false;
  },

  /**
  Default validation checks required fields and read-only.
  Reimplement your own custom validation code here, but make sure
  to call back to the superclass at the top of your function using:

  return XT.Model.prototype.validate.call(this, attributes, options);

  @param {Object} attributes
  @param {Object} options
  */
  validate: function(attributes, options) {
    // if we're syncing, bail out
    if (this._sync) return;

    var prop;
    var val;
    var attr;

    //check required
    if (!attributes) {
      for (i = 0; i < this.required.length; i++) {
        if (!this.has(this.required[i])) {
          return "'" + this.required[i] + "' is required.";
        }
      }
    }

    //check read-only
    if (attributes) {
      if (this.isReadOnly()) {
        return "Record is in a read only state.";
      } else {
        for (attr in attributes) {
          if (this.isReadOnly(attr)) {
            return "Can not edit read only attribute " + attr + ".";
          }
        }
      }
    }
  },

  // ..........................................................
  // PRIVATE
  //

  /** @private */
  _attrCache: null,

  /** @private */
  _dataSource: null,

  /** @private */
  _readOnly: false,

  /** @private */
  _sync: false,

  /** @private */
  _changed: function() {
    if (this.get('dataState') === 'read' && !this._sync) {
      this.set('dataState', 'update');
    }
  },

  /** @private */
  _fetchId: function() {
    var that = this;
    var options = {};

    // callback
    options.success = function(resp, status, xhr) {
      var attr = that.idAttribute;

      // set the id
      that.setReadOnly(attr, false);
      that.set(attr, resp);
      that.setReadOnly(attr, true);
    };

    // fetch id
    this._dataSource.dispatch('XT.Record', 'fetchId', this.recordType, options);
  }

});

// ..........................................................
// CLASS METHODS
//

enyo.mixin( /** @scope XT.Model */ XT.Model, {

  /**
    Use this function to find out whether a user can create records before
    instantiating one.

    @returns {Boolean}
  */
  canCreate: function() {
    var privileges = this.prototype.privileges,
        sessionPrivs = XT.session.getPrivileges(),
        isGranted = false;

    if (sessionPrivs && sessionPrivs.get) {
      // check global
      isGranted = privileges.all && privileges.all.create &&
                  sessionPrivs.get(privileges.all.create) === true;

      // check personal
      if (!isGranted) {
        isGranted = privileges.personal && privileges.personal.create &&
                    sessionPrivs.get(privileges.personal.create) === true;
      }
    }

    return isGranted;
  },

  /**
    Use this function to find out whether a user can read this record type
    before any have been loaded.

    @returns {Boolean}
  */
  canRead: function() {
    var privileges = this.prototype.privileges,
        sessionPrivs = XT.session.privileges,
        isGranted = false;

    if (sessionPrivs && sessionPrivs.get) {
      // check global read privilege
      isGranted = privileges.all && privileges.all.read &&
                  sessionPrivs.get(privileges.all.read) === true;

      // check global update privilege
      if (!isGranted) {
        isGranted = privileges.all && privileges.all.update &&
                    sessionPrivs.get(privileges.all.update) === true;
      }

      // check personal view privilege
      if (!isGranted) {
        isGranted = privileges.personal && privileges.personal.read &&
                    sessionPrivs.get(privileges.personal.read) === true;
      }

      // check personal update privilege
      if (!isGranted) {
        isGranted = privileges.personal && privileges.personal.update &&
                    sessionPrivs.get(privileges.personal.update) === true;
      }
    }

    return isGranted;
  },

  /**
    Returns whether a user has access to update a record of this type. If a
    record is passed that involves personal privileges, it will validate
    whether that particular record is updatable.

    @returns {Boolean}
  */
  canUpdate: function(record) {
    return XT.Model._canDo.call(this, 'update', record);
  },

  /**
    Returns whether a user has access to delete a record of this type. If a
    record is passed that involves personal privileges, it will validate
    whether that particular record is deletable.

    @returns {Boolean}
  */
  canDelete: function(record) {
    return XT.Model._canDo.call(this, 'delete', record);
  },

  /** @private */
  _canDo: function(action, record) {
    var privileges = this.prototype.privileges,
        sessionPrivs = XT.session.privileges,
        isGrantedAll = false,
        isGrantedPersonal = false,
        userName = XT.session.details.username;

    if (sessionPrivs && sessionPrivs.get) {
      // check global privileges
      if (privileges.all && privileges.all[action]) {
        isGrantedAll = sessionPrivs.get(privileges.all[action]) === true;
      }

      // check personal privileges
      if (!isGrantedAll && privileges.personal && privileges.personal[action]) {
        isGrantedPersonal = sessionPrivs.get(privileges.personal[action]) === true;
      }
    }

    // If only personal privileges, check the original attribute cache against
    // the personal attribute list to see if we can update
    if (!isGrantedAll && isGrantedPersonal) {
      var i = 0;
      var username = XT.session.details.username;
      var props = privileges.personal && privileges.personal.properties ?
                  privileges.personal.properties : [];

      isGrantedPersonal = false;
      if (record && record._attrCache) {
        while (!isGrantedPersonal && i < props.length) {
          isGrantedPersonal = m._attrCache[props[i]].get('username') === username;
          i++;
        }
      }
    }

    return isGrantedAll || isGrantedPersonal;
  }

});

<commit_msg>switch to xt.model<commit_after>
/**
  @class

  `XT.Model` is an abstract class designed to operate with `XT.DataSource`.
  It should be subclassed for any specific implentation. Subtypes should
  include a `recordType` the data source will use to retreive the record.

  To create a new model include `isNew` in the options like so:
    XM.Contact = XT.Model.extend({recordType: 'XM.Contact'});
    m = new XM.Contact({firstName: 'Randy'}, {isNew: true});

  To load an existing record include a guid in the options like so:
    XM.Contact = XT.Model.extend({recordType: 'XM.Contact'});
    m = new XM.Contact({guid: 1});
    m.fetch();

    OR

    XM.Contact = XT.Model.extend({recordType: 'XM.Contact'});
    m = XM.Contact();
    m.fetch({id: 1});

  @extends Backbone.RelationalModel
  @param {Object} attributes
  @param {Object} options
*/
XT.Model = Backbone.RelationalModel.extend(
  /** @scope XT.Model.prototype */ {

  idAttribute: "guid",

  /**
  Set to true if you want an id fetched from the server when the `isNew` option
  is passed on a new model.

  @type {Boolean}
  */
  autoFetchId: true,

  /**
  Specify the name of a data source model here.

  @type {String}
  */
  recordType: null,

  /**
  A hash structure that defines data access.

  @property
  @type {Hash}
  */
  privileges: {},

  /**
  An array of required attributes. A validate on the entire model will fail
  until all the required attributes have values.

  @type {Array}
  */
  required: [],

  /**
  An array of attribute names designating attributes that are not editable.
  Use `setReadOnly` to edit this array.

  @seealso `setReadOnly`
  @seealso `isReadOnly`
  @type {Array}
  */
  readOnly: [],

  // ..........................................................
  // METHODS
  //

  /**
    Returns whether the current record can be updated based on privilege
    settings.

    @returns {Boolean}
  */
  canUpdate: function() {
    var obj = Backbone.Relational.store.getObjectByName(this.recordType);
    return obj.canUpdate(this);
  },

  /**
    Returns whether the current record can be deleted based on privilege
    settings.

    @returns {Boolean}
  */
  canDelete: function() {
    var obj = Backbone.Relational.store.getObjectByName(this.recordType);
    return obj.canDelete(this);
  },

  /**
  Set the entire model, or a specific model attribute to readOnly. Privilege
  enforcement supercedes read-only settings.

  Examples:

  model.setReadOnly() // sets model to read only
  model.setReadOnly(false) // sets model to be editable
  model.setReadOnly('name') // sets 'name' attribute to read-only
  model.setReadOnly('name', false) // sets 'name' attribute to be editable

  @seealso `isReadOnly`
  @seealso `readOnly`
  @param {String|Boolean} Attribute to set, or boolean if setting the model
  @param {Boolean} boolean - default = true.
  */
  setReadOnly: function(key, value) {
    // handle attribute
    if (_.isString(key)) {
      value = _.isBoolean(value) ? value : true;
      if (value && !_.contains(this.readOnly, key)) {
        this.readOnly.push(key);
      } else if (!value && _.contains(this.readOnly, key)) {
        this.readOnly = _.without(this.readOnly, key);
      }
      return;
    }

    // handle model
    key = _.isBoolean(key) ? key : true;
    this._readOnly = key;
  },

  /**
  Return whether the model is in a read-only state. If an attribute name
  is passed, returns whether that attribute is read-only.

  @seealso `setReadOnly`
  @seealso `readOnly`
  @param {String} attribute
  */
  isReadOnly: function(attr) {
    var canNotUpdate = !this.canUpdate();
    if (!_.isString(attr) || this._readOnly || canNotUpdate) {
      return this._readOnly || canNotUpdate;
    }
    return _.contains(this.readOnly, attr);
  },

  initialize: function() {
    var options = arguments[1];

    // set data source
    this._dataSource = XT.dataSource;

    // initialize for new record
    if (options && options.isNew) {
      this.attributes.dataState = 'create';
      if (this.autoFetchId) this._fetchId();
    }

    // set id to read only
    if (this.idAttribute && !_.contains(this.readOnly, this.idAttribute)) {
      this.readOnly.push(this.idAttribute);
    }

    // set id as required
    if (this.idAttribute && !_.contains(this.required, this.idAttribute)) {
      this.required.push(this.idAttribute);
    }

    // set up state change handler
    this.on('change', this._changed);
  },

  /**
  Reimplemented. A model is new if the dataState is `create`.
  */
  isNew: function() {
    return this.get('dataState') === 'create';
  },

  /**
  Returns true when dataState is `create` or `update`.
  */
  isDirty: function() {
    var dataState = this.get('dataState');
    return dataState === 'create' || dataState === 'update';
  },

  /**
  Reimplemented to handle state change.
  */
  fetch: function(options) {
    options = options ? _.clone(options) : {};
    var that = this;
    var success = options.success;

    // flip sync flag back on success
    options.success = function(resp, status, xhr) {
      that._sync = false;
      that._attrCache = _.clone(that.attributes);
      if (success) success(model, resp, options);
    };

    return Backbone.Model.prototype.fetch.call(this, options);
  },

  /**
  Reimplemented to handle state change.
  */
  save: function(key, value, options) {
    // Handle both `("key", value)` and `({key: value})` -style calls.
    if (_.isObject(key) || key === null || key === undefined) options = value;
    options = options ? _.clone(options) : {};

    var that = this;
    var success = options.success;

    // flip sync flag back on success
    options.success = function(resp, status, xhr) {
      that._sync = false;
      that._attrCache = _.clone(that.attributes);
      if (success) success(model, resp, options);
    };

    // Handle both `("key", value)` and `({key: value})` -style calls.
    if (_.isObject(key) || key === null || key === undefined) value = options;

    return Backbone.Model.prototype.save.call(this, key, value, options);
  },

  /**
  Reimplemented.
  */
  destroy: function(options) {
    options = options ? _.clone(options) : {};
    var that = this;
    var success = options.success;

    // clear on success
    options.success = function(resp, status, xhr) {
      that.clear({silent: true});
      that._attrCache = null;
      if (success) success(model, resp, options);
    };

    this.set('dataState', 'delete');
    return Backbone.Model.prototype.destroy.call(this, options);
  },

  /**
  Overload: sync to xtuple datasource.
  */
  sync: function(method, model, options) {
    var recordType = model.recordType;
    var id = options.id || this.id;
    var success = options.success;

    if (options === undefined) options = {};
    this._sync = true;

    // read
    if (method === 'read' && recordType && id && success) {
      return this._dataSource.retrieveRecord(recordType, id, options);

    // write
    } else if (method === 'create' || method === 'update' || method === 'delete') {
      var ret = this._dataSource.commitRecord(model, options);
      this.set('dataState', 'busy');
      return ret;
    }

    return false;
  },

  /**
  Default validation checks required fields and read-only.
  Reimplement your own custom validation code here, but make sure
  to call back to the superclass at the top of your function using:

  return XT.Model.prototype.validate.call(this, attributes, options);

  @param {Object} attributes
  @param {Object} options
  */
  validate: function(attributes, options) {
    // if we're syncing, bail out
    if (this._sync) return;

    var prop;
    var val;
    var attr;

    //check required
    if (!attributes) {
      for (i = 0; i < this.required.length; i++) {
        if (!this.has(this.required[i])) {
          return "'" + this.required[i] + "' is required.";
        }
      }
    }

    //check read-only
    if (attributes) {
      if (this.isReadOnly()) {
        return "Record is in a read only state.";
      } else {
        for (attr in attributes) {
          if (this.isReadOnly(attr)) {
            return "Can not edit read only attribute " + attr + ".";
          }
        }
      }
    }
  },

  // ..........................................................
  // PRIVATE
  //

  /** @private */
  _attrCache: null,

  /** @private */
  _dataSource: null,

  /** @private */
  _readOnly: false,

  /** @private */
  _sync: false,

  /** @private */
  _changed: function() {
    if (this.get('dataState') === 'read' && !this._sync) {
      this.set('dataState', 'update');
    }
  },

  /** @private */
  _fetchId: function() {
    var that = this;
    var options = {};

    // callback
    options.success = function(resp, status, xhr) {
      var attr = that.idAttribute;

      // set the id
      that.setReadOnly(attr, false);
      that.set(attr, resp);
      that.setReadOnly(attr, true);
    };

    // fetch id
    this._dataSource.dispatch('XT.Model', 'fetchId', this.recordType, options);
  }

});

// ..........................................................
// CLASS METHODS
//

enyo.mixin( /** @scope XT.Model */ XT.Model, {

  /**
    Use this function to find out whether a user can create records before
    instantiating one.

    @returns {Boolean}
  */
  canCreate: function() {
    var privileges = this.prototype.privileges,
        sessionPrivs = XT.session.getPrivileges(),
        isGranted = false;

    if (sessionPrivs && sessionPrivs.get) {
      // check global
      isGranted = privileges.all && privileges.all.create &&
                  sessionPrivs.get(privileges.all.create) === true;

      // check personal
      if (!isGranted) {
        isGranted = privileges.personal && privileges.personal.create &&
                    sessionPrivs.get(privileges.personal.create) === true;
      }
    }

    return isGranted;
  },

  /**
    Use this function to find out whether a user can read this record type
    before any have been loaded.

    @returns {Boolean}
  */
  canRead: function() {
    var privileges = this.prototype.privileges,
        sessionPrivs = XT.session.privileges,
        isGranted = false;

    if (sessionPrivs && sessionPrivs.get) {
      // check global read privilege
      isGranted = privileges.all && privileges.all.read &&
                  sessionPrivs.get(privileges.all.read) === true;

      // check global update privilege
      if (!isGranted) {
        isGranted = privileges.all && privileges.all.update &&
                    sessionPrivs.get(privileges.all.update) === true;
      }

      // check personal view privilege
      if (!isGranted) {
        isGranted = privileges.personal && privileges.personal.read &&
                    sessionPrivs.get(privileges.personal.read) === true;
      }

      // check personal update privilege
      if (!isGranted) {
        isGranted = privileges.personal && privileges.personal.update &&
                    sessionPrivs.get(privileges.personal.update) === true;
      }
    }

    return isGranted;
  },

  /**
    Returns whether a user has access to update a record of this type. If a
    record is passed that involves personal privileges, it will validate
    whether that particular record is updatable.

    @returns {Boolean}
  */
  canUpdate: function(record) {
    return XT.Model._canDo.call(this, 'update', record);
  },

  /**
    Returns whether a user has access to delete a record of this type. If a
    record is passed that involves personal privileges, it will validate
    whether that particular record is deletable.

    @returns {Boolean}
  */
  canDelete: function(record) {
    return XT.Model._canDo.call(this, 'delete', record);
  },

  /** @private */
  _canDo: function(action, record) {
    var privileges = this.prototype.privileges,
        sessionPrivs = XT.session.privileges,
        isGrantedAll = false,
        isGrantedPersonal = false,
        userName = XT.session.details.username;

    if (sessionPrivs && sessionPrivs.get) {
      // check global privileges
      if (privileges.all && privileges.all[action]) {
        isGrantedAll = sessionPrivs.get(privileges.all[action]) === true;
      }

      // check personal privileges
      if (!isGrantedAll && privileges.personal && privileges.personal[action]) {
        isGrantedPersonal = sessionPrivs.get(privileges.personal[action]) === true;
      }
    }

    // If only personal privileges, check the original attribute cache against
    // the personal attribute list to see if we can update
    if (!isGrantedAll && isGrantedPersonal) {
      var i = 0;
      var username = XT.session.details.username;
      var props = privileges.personal && privileges.personal.properties ?
                  privileges.personal.properties : [];

      isGrantedPersonal = false;
      if (record && record._attrCache) {
        while (!isGrantedPersonal && i < props.length) {
          isGrantedPersonal = m._attrCache[props[i]].get('username') === username;
          i++;
        }
      }
    }

    return isGrantedAll || isGrantedPersonal;
  }

});

<|endoftext|>


<commit_before>var SkirmishMap = (function () {

    var map;
    function initialize() {
        console.log("SkirmishMap initializing");
        var mapOptions;
        mapOptions = {
          center: new google.maps.LatLng(39.8282, 98.5795),
          zoom: 10
        };
        map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
    };

    var displayCity = function(city){
        var iconBase = 'http://www.gravatar.com/avatar/';
        new google.maps.Marker({
            position: new google.maps.LatLng(city.latLng[0], city.latLng[1]),
            map: map,
            title: city.name + ' ' + city.playerId,
            icon: iconBase + '205e460b479e2e5b48aec07710c08d50?s=50',
            playerId: city.playerId
        });
    };

    var displayCities = function(cities){
        for(var i = 0; i < cities.length; i++){
            var city = cities[i];
            SkirmishMap.displayCity(city);
        };
    };

    return  {
        displayCity: displayCity,
        displayCities: displayCities,
        initialize: initialize
    };

})();<commit_msg>Set starting view of map to USA<commit_after>var SkirmishMap = (function () {

    var map;
    function initialize() {
        console.log("SkirmishMap initializing");
        var mapOptions;
        mapOptions = {
          center: new google.maps.LatLng(39.8282, -98.5795),
          zoom: 5
        };
        map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
    };

    var displayCity = function(city){
        var iconBase = 'http://www.gravatar.com/avatar/';
        new google.maps.Marker({
            position: new google.maps.LatLng(city.latLng[0], city.latLng[1]),
            map: map,
            title: city.name + ' ' + city.playerId,
            icon: iconBase + '205e460b479e2e5b48aec07710c08d50?s=50',
            playerId: city.playerId
        });
    };

    var displayCities = function(cities){
        for(var i = 0; i < cities.length; i++){
            var city = cities[i];
            SkirmishMap.displayCity(city);
        };
    };

    return  {
        displayCity: displayCity,
        displayCities: displayCities,
        initialize: initialize
    };

})();<|endoftext|>