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

/**
 * External dependencies
 */
import invariant from 'invariant';
import { isPlainObject } from 'lodash';

/**
 * WordPress dependencies
 */
import { isURL } from '@wordpress/url';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import Data from 'googlesitekit-data';
import { STORE_NAME } from './constants';

// Actions
const FETCH_REPORT = 'FETCH_REPORT';
const START_FETCH_REPORT = 'START_FETCH_REPORT';
const FINISH_FETCH_REPORT = 'FINISH_FETCH_REPORT';
const CATCH_FETCH_REPORT = 'CATCH_FETCH_REPORT';
const RECEIVE_REPORT = 'RECEIVE_REPORT';

export const INITIAL_STATE = {
	isFetchingReport: {},
	reports: {},
};

export const actions = {
	/**
	 * Fetches a PageSpeed Insights report.
	 *
	 * @since n.e.x.t
	 * @private
	 *
	 * @param {string} url      URL used for generating the report.
	 * @param {string} strategy Strategy used for generating the report.
	 * @return {Object} Object with {response, error}
	 */
	*fetchReport( url, strategy ) {
		let response, error;

		yield {
			payload: { strategy, url },
			type: START_FETCH_REPORT,
		};

		try {
			const report = yield {
				payload: { strategy, url },
				type: FETCH_REPORT,
			};

			yield actions.receiveReport( report, { strategy, url } );

			yield {
				payload: { strategy, url },
				type: FINISH_FETCH_REPORT,
			};
		} catch ( e ) {
			error = e;
			yield {
				payload: {
					error,
					strategy,
					url,
				},
				type: CATCH_FETCH_REPORT,
			};
		}

		return { response, error };
	},

	/**
	 * Adds report to the store.
	 *
	 * @since n.e.x.t
	 * @private
	 *
	 * @param {Object} report        Report to add.
	 * @param {Object} args          Options used for generating the report.
	 * @param {string} args.strategy Strategy used for generating the report.
	 * @param {string} args.url      URL used for generating the report.
	 * @return {Object} Redux-style action.
	 */
	receiveReport( report, { strategy, url } ) {
		invariant( isPlainObject( report ), 'report must be an object to receive.' );
		invariant( typeof strategy === 'string', 'a valid strategy is required to receive report.' );
		invariant( isURL( url ), 'a valid url is required to receive report.' );

		return {
			payload: { report, strategy, url },
			type: RECEIVE_REPORT,
		};
	},

};

export const controls = {
	[ FETCH_REPORT ]: ( { payload: { strategy, url } } ) => {
		return API.get( 'modules', 'pagespeed-insights', 'pagespeed', { strategy, url } );
	},
};

export const reducer = ( state, { type, payload } ) => {
	switch ( type ) {
		case START_FETCH_REPORT: {
			const { strategy, url } = payload;

			return {
				...state,
				isFetchingReport: {
					...state.isFetchingReport,
					[ `${ strategy }::${ url }` ]: true,
				},
			};
		}

		case FINISH_FETCH_REPORT: {
			const { strategy, url } = payload;

			return {
				...state,
				isFetchingReport: {
					...state.isFetchingReport,
					[ `${ strategy }::${ url }` ]: false,
				},
			};
		}

		case RECEIVE_REPORT: {
			const { report, strategy, url } = payload;

			return {
				...state,
				reports: {
					...state.reports,
					[ `${ strategy }::${ url }` ]: { ...report },
				},
			};
		}

		case CATCH_FETCH_REPORT: {
			const { error, strategy, url } = payload;

			return {
				...state,
				error,
				isFetchingReport: {
					...state.isFetchingReport,
					[ `${ strategy }::${ url }` ]: false,
				},
			};
		}

		default: {
			return { ...state };
		}
	}
};

export const resolvers = {
	*getReport( url, strategy ) {
		if ( ! url || ! strategy ) {
			return;
		}

		const registry = yield Data.commonActions.getRegistry();
		const existingReport = registry.select( STORE_NAME ).getReport( url, strategy );

		// If there is already a report loaded in state, consider it fulfilled and don't make an API request.
		if ( existingReport ) {
			return;
		}

		yield actions.fetchReport( url, strategy );
	},
};

export const selectors = {
	/**
	 * Gets a PageSpeed Insights report for the given strategy and URL.
	 *
	 * @since n.e.x.t
	 *
	 * @param {Object} state    Data store's state.
	 * @param {string} url      URL used for generating the report.
	 * @param {string} strategy Strategy used for generating the report.
	 * @return {(Object|undefined)} A PageSpeed Insights report; `undefined` if not loaded.
	 */
	getReport( state, url, strategy ) {
		const { reports } = state;

		return reports[ `${ strategy }::${ url }` ];
	},
};

export default {
	INITIAL_STATE,
	actions,
	controls,
	reducer,
	resolvers,
	selectors,
};
<commit_msg>Add invariant validation to fetchReport.<commit_after>/**
 * modules/pagespeed-insights data store: report.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';
import { isPlainObject } from 'lodash';

/**
 * WordPress dependencies
 */
import { isURL } from '@wordpress/url';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import Data from 'googlesitekit-data';
import { STORE_NAME } from './constants';

// Actions
const FETCH_REPORT = 'FETCH_REPORT';
const START_FETCH_REPORT = 'START_FETCH_REPORT';
const FINISH_FETCH_REPORT = 'FINISH_FETCH_REPORT';
const CATCH_FETCH_REPORT = 'CATCH_FETCH_REPORT';
const RECEIVE_REPORT = 'RECEIVE_REPORT';

export const INITIAL_STATE = {
	isFetchingReport: {},
	reports: {},
};

export const actions = {
	/**
	 * Fetches a PageSpeed Insights report.
	 *
	 * @since n.e.x.t
	 * @private
	 *
	 * @param {string} url      URL used for generating the report.
	 * @param {string} strategy Strategy used for generating the report.
	 * @return {Object} Object with {response, error}
	 */
	*fetchReport( url, strategy ) {
		invariant( isURL( url ), 'a valid url is required to fetch a report.' );
		invariant( typeof strategy === 'string', 'a valid strategy is required to fetch a report.' );
		let response, error;

		yield {
			payload: { strategy, url },
			type: START_FETCH_REPORT,
		};

		try {
			const report = yield {
				payload: { strategy, url },
				type: FETCH_REPORT,
			};

			yield actions.receiveReport( report, { strategy, url } );

			yield {
				payload: { strategy, url },
				type: FINISH_FETCH_REPORT,
			};
		} catch ( e ) {
			error = e;
			yield {
				payload: {
					error,
					strategy,
					url,
				},
				type: CATCH_FETCH_REPORT,
			};
		}

		return { response, error };
	},

	/**
	 * Adds report to the store.
	 *
	 * @since n.e.x.t
	 * @private
	 *
	 * @param {Object} report        Report to add.
	 * @param {Object} args          Options used for generating the report.
	 * @param {string} args.strategy Strategy used for generating the report.
	 * @param {string} args.url      URL used for generating the report.
	 * @return {Object} Redux-style action.
	 */
	receiveReport( report, { strategy, url } ) {
		invariant( isPlainObject( report ), 'report must be an object to receive.' );
		invariant( typeof strategy === 'string', 'a valid strategy is required to receive report.' );
		invariant( isURL( url ), 'a valid url is required to receive report.' );

		return {
			payload: { report, strategy, url },
			type: RECEIVE_REPORT,
		};
	},

};

export const controls = {
	[ FETCH_REPORT ]: ( { payload: { strategy, url } } ) => {
		return API.get( 'modules', 'pagespeed-insights', 'pagespeed', { strategy, url } );
	},
};

export const reducer = ( state, { type, payload } ) => {
	switch ( type ) {
		case START_FETCH_REPORT: {
			const { strategy, url } = payload;

			return {
				...state,
				isFetchingReport: {
					...state.isFetchingReport,
					[ `${ strategy }::${ url }` ]: true,
				},
			};
		}

		case FINISH_FETCH_REPORT: {
			const { strategy, url } = payload;

			return {
				...state,
				isFetchingReport: {
					...state.isFetchingReport,
					[ `${ strategy }::${ url }` ]: false,
				},
			};
		}

		case RECEIVE_REPORT: {
			const { report, strategy, url } = payload;

			return {
				...state,
				reports: {
					...state.reports,
					[ `${ strategy }::${ url }` ]: { ...report },
				},
			};
		}

		case CATCH_FETCH_REPORT: {
			const { error, strategy, url } = payload;

			return {
				...state,
				error,
				isFetchingReport: {
					...state.isFetchingReport,
					[ `${ strategy }::${ url }` ]: false,
				},
			};
		}

		default: {
			return { ...state };
		}
	}
};

export const resolvers = {
	*getReport( url, strategy ) {
		if ( ! url || ! strategy ) {
			return;
		}

		const registry = yield Data.commonActions.getRegistry();
		const existingReport = registry.select( STORE_NAME ).getReport( url, strategy );

		// If there is already a report loaded in state, consider it fulfilled and don't make an API request.
		if ( existingReport ) {
			return;
		}

		yield actions.fetchReport( url, strategy );
	},
};

export const selectors = {
	/**
	 * Gets a PageSpeed Insights report for the given strategy and URL.
	 *
	 * @since n.e.x.t
	 *
	 * @param {Object} state    Data store's state.
	 * @param {string} url      URL used for generating the report.
	 * @param {string} strategy Strategy used for generating the report.
	 * @return {(Object|undefined)} A PageSpeed Insights report; `undefined` if not loaded.
	 */
	getReport( state, url, strategy ) {
		const { reports } = state;

		return reports[ `${ strategy }::${ url }` ];
	},
};

export default {
	INITIAL_STATE,
	actions,
	controls,
	reducer,
	resolvers,
	selectors,
};
<|endoftext|>


<commit_before>function include_user_filter(settings) {
    function createMenuButton(group, label) {
        return $("<a>", {
            "href": "#",
            "class": "brbtv-user-actions-item yt-ui-menu-item " + group
        }).text(label);
    }

    const ADD_ACTION = true;
    const REMOVE_ACTION = false;

    YouTubeLive.onChatLoaded(function (youtube) {
        var theCss = "#brbtv-user-actions-menu {" +
            "background-color: rgba(0, 0, 0, 0.498039);" +
            "display: none;" +
            "position: absolute;" +
            "outline: none; position: fixed; left: 1747.39px; top: 315px; z-index: 103;}\n";
        theCss += "#brbtv-user-actions-menu ytg-menu-popup-renderer {outline: none; box-sizing: border-box; max-width: 160.609px; max-height: 96px;}";
        theCss += ".brbtv-user-actions-item {color: white; font-family: Roboto, Arial, sans-serif; font-size: 15px; display: block;}";
        theCss += ".show-brbtv-user-actions-menu {display: block !important;}";
        theCss += ".brbtv-highlighted-message {background-color: rgb(204, 0, 0) !important; border-top: 0 !important; border-bottom: 0 !important;}";
        theCss += ".brbtv-highlighted-message .comment-time, .brbtv-highlighted-message .byline {color: rgba(255,255,255,0.54) !important;}";
        theCss += ".brbtv-highlighted-message .mention {background-color: transparent !important;}";
        theCss += ".brbtv-highlighted-message .comment-text {color: #fff !important;}";
        theCss += ".brbtv-highlighted-message .accent-bar {background-color: rgb(204, 0, 0) !important;}";
        theCss += ".brbtv-highlighted-message #author-name a {color: #fff !important;}";
        theCss += ".brbtv-muted-message .yt-user-name {text-decoration: line-through !important;}";

        theCss += ".brbtv-author-link {cursor: pointer; color: inherit;}";
        addCssToHead(theCss);

        var mutedUsers = new Set();
        for (let i = 0; i < settings.ignoredUsers.length; i++) {
            mutedUsers.add(settings.ignoredUsers[i].id);
        }

        var highlightedUsers = new Set();
        for (let i = 0; i < settings.highlightedUsers.length; i++) {
            highlightedUsers.add(settings.highlightedUsers[i].id);
        }

        youtube.addStorageListener(function (changes, namespace) {
            var ignoredUserChange = changes["ignoredUsers"];
            if (ignoredUserChange) {
                mutedUsers = new Set();
                for (let i = 0; i < ignoredUserChange.newValue.length; i++) {
                    mutedUsers.add(ignoredUserChange.newValue[i].id);
                }
            }

            var highlightedUserChange = changes["highlightedUsers"];
            if (highlightedUserChange) {
                highlightedUsers = new Set();
                for (let i = 0; i < highlightedUserChange.newValue.length; i++) {
                    highlightedUsers.add(highlightedUserChange.newValue[i].id);
                }
            }
        });

        if (!$("#brbtv-user-actions-menu").length) {
            let jUserMenu = $("<div>", {
                "id": "brbtv-user-actions-menu"
            });
            $("yt-live-chat-renderer").prepend(jUserMenu);
            delete jUserMenu;
        }

        function updateChromeStore(jUserLink, ytId, storageKey, isAddToList) {
            let query = {};
            query[storageKey] = [];
            chrome.storage.sync.get(query, function (items) {
                var theUpdatedArray = items[storageKey];
                if (isAddToList) {
                    theUpdatedArray.push({
                        name: jUserLink.text().trim(),
                        id: ytId,
                        addedTime: Date.now()
                    });
                } else {
                    theUpdatedArray = theUpdatedArray.filter(u => u.id != ytId);
                }

                query[storageKey] = theUpdatedArray;

                chrome.storage.sync.set(query);
            });
        }

        function isMessageByUser(jChatMessage, userId) {
            let parts = userId.split(" ");
            let photoSrc = parts[0];
            let authorName = parts.slice(1).join(" ");

            return jChatMessage.find('#author-photo[src="' + photoSrc + '"]').length && jChatMessage.find("#author-name").text() == authorName;
        }

        function addHighlightUserButton(ytId, jUserLink) {
            let jHighlightUser = createMenuButton("brbtv-highlight-button", chrome.i18n.getMessage("userActionHighlight"));
            jHighlightUser[0].addEventListener('click', function (e) {
                if (!highlightedUsers.has(ytId)) {
                    highlightedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.addClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jHighlightUser);
        }

        function addMenuItem(jItem) {
            $("#brbtv-user-actions-menu").append(jItem);
        }

        function addUnhighlightUserButton(ytId, jUserLink) {
            let jUnhighlightUser = createMenuButton("brbtv-unhighlight-button", chrome.i18n.getMessage("userActionUnHighlight"));
            jUnhighlightUser[0].addEventListener('click', function (e) {
                if (highlightedUsers.has(ytId)) {
                    highlightedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.removeClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jUnhighlightUser);
        }

        function addMuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-mute-button", chrome.i18n.getMessage("userActionMute"));
            jMuteUser[0].addEventListener('click', function (e) {
                if (!mutedUsers.has(ytId)) {
                    mutedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.addClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jMuteUser);
        }

        function addUnmuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-unmute-button", chrome.i18n.getMessage("userActionUnMute"));
            jMuteUser[0].addEventListener('click', function (e) {
                if (mutedUsers.has(ytId)) {
                    mutedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.removeClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jMuteUser);
        }

        function addHideMenuFunction(jUserLink) {
            var hideMenuFunction = function (e) {
                if (e.target != jUserLink[0]) {
                    $("#brbtv-user-actions-menu").removeClass("show-brbtv-user-actions-menu");
                    $(this).off("click", hideMenuFunction);
                }
            };
            $("body").on("click", hideMenuFunction); // necessary exception from no-jQuery-handlers rule: we have to detach it globally after page change
        }

        function insertDoubleclickedAuthor(e) {
            $("#brbtv-user-actions-menu").removeClass("show-brbtv-user-actions-menu");

            var replacement = '@' + $(e.currentTarget).text();

            replacement += "\u00A0";
            var jTextInput = youtube.getJChatInputField();
            if (jTextInput.length) {
                let caretPosition = getCaretPosition(jTextInput[0]);
                jTextInput[0].normalize();

                // next, find the text node containing the caret
                // by this, we can safely skip other DOM elements created by YT (like img for emotes)
                var lengthPassed = 0;
                var replacementPerformed = false;

                jTextInput.contents().filter(function () {
                    return this.nodeType === 3; // i.e. this.nodeType == TEXT_NODE
                }).each(function (idx, elem) {
                    if (replacementPerformed) return;
                    if (caretPosition >= elem.nodeValue.length + lengthPassed) {
                        lengthPassed += elem.nodeValue.length;
                    } else {
                        elem.nodeValue = elem.nodeValue.replaceBetween(
                            caretPosition - lengthPassed,
                            caretPosition - lengthPassed,
                            replacement);
                        replacementPerformed = true;
                    }
                });

                if (!replacementPerformed) jTextInput.append(document.createTextNode(replacement));
                setCaretPosition(jTextInput[0], caretPosition + replacement.length);
                jTextInput.focus();
                jTextInput[0].dispatchEvent(new CustomEvent("input"));
            }
        }

        youtube.registerChatMessageObserver(function (message) {
            let jMessage = $(message);

            // TODO find new-member-announcement equivalent in new chat
            if (jMessage.hasClass("new-member-announcement")) return;

            let authorPhotoSrc = jMessage.find('img[id="author-photo"]').attr("src");
            let authorName = jMessage.find("#author-name").text();
            let ytId = authorPhotoSrc + " " + authorName;

            if (mutedUsers.has(ytId)) {
                jMessage.remove();
                return;
            }

            let jUserLink = $("<a>", {
                href: "#",
                class: "brbtv-author-link"
            }).text(authorName);

            jMessage.find("#author-name").html(jUserLink);

            if (highlightedUsers.has(ytId)) {
                jMessage.addClass("brbtv-highlighted-message");
            }

            jUserLink[0].addEventListener('click', function (e) {
                let jUserLink = $(e.target);
                let jUserMenu = $("#brbtv-user-actions-menu");
                jUserMenu.empty();

                //let jVisitProfile = createMenuButton("brbtv-visit-button", chrome.i18n.getMessage("userActionVisitProfile"));
                //jVisitProfile.attr("href", jUserLink.attr('href'));
                //jUserMenu.append(jVisitProfile);

                if (highlightedUsers.has(ytId)) {
                    addUnhighlightUserButton(ytId, jUserLink);
                } else {
                    addHighlightUserButton(ytId, jUserLink);
                }

                if (!mutedUsers.has(ytId)) {
                    addMuteButton(ytId, jUserLink);
                } else {
                    addUnmuteButton(ytId, jUserLink);
                }
                e.preventDefault();
                addHideMenuFunction(jUserLink);

                let linkPosition = jUserLink.offset();
                let topPosition = linkPosition.top + jUserLink.height();
                if (topPosition + jUserMenu.height() > $("body").height()) topPosition = linkPosition.top - jUserMenu.height() - jUserLink.height();
                jUserMenu.css("top", topPosition + "px");
                jUserMenu.css("left", linkPosition.left + "px");

                jUserMenu.addClass("show-brbtv-user-actions-menu");
            });

            // insert the name as a mention on doubleclick
            jUserLink[0].addEventListener('dblclick', insertDoubleclickedAuthor);

            jUserLink = null;

        }, true);
    });
}<commit_msg>retrieve photo src for action menu only after clicking a user name; do not show menu for authors without avatar loaded<commit_after>function include_user_filter(settings) {
    function createMenuButton(group, label) {
        return $("<a>", {
            "href": "#",
            "class": "brbtv-user-actions-item yt-ui-menu-item " + group
        }).text(label);
    }

    const ADD_ACTION = true;
    const REMOVE_ACTION = false;

    YouTubeLive.onChatLoaded(function (youtube) {
        var theCss = "#brbtv-user-actions-menu {" +
            "background-color: rgba(0, 0, 0, 0.498039);" +
            "display: none;" +
            "position: absolute;" +
            "outline: none; position: fixed; left: 1747.39px; top: 315px; z-index: 103;}\n";
        theCss += "#brbtv-user-actions-menu ytg-menu-popup-renderer {outline: none; box-sizing: border-box; max-width: 160.609px; max-height: 96px;}";
        theCss += ".brbtv-user-actions-item {color: white; font-family: Roboto, Arial, sans-serif; font-size: 15px; display: block;}";
        theCss += ".show-brbtv-user-actions-menu {display: block !important;}";
        theCss += ".brbtv-highlighted-message {background-color: rgb(204, 0, 0) !important; border-top: 0 !important; border-bottom: 0 !important;}";
        theCss += ".brbtv-highlighted-message .comment-time, .brbtv-highlighted-message .byline {color: rgba(255,255,255,0.54) !important;}";
        theCss += ".brbtv-highlighted-message .mention {background-color: transparent !important;}";
        theCss += ".brbtv-highlighted-message .comment-text {color: #fff !important;}";
        theCss += ".brbtv-highlighted-message .accent-bar {background-color: rgb(204, 0, 0) !important;}";
        theCss += ".brbtv-highlighted-message #author-name a {color: #fff !important;}";
        theCss += ".brbtv-muted-message .yt-user-name {text-decoration: line-through !important;}";

        theCss += ".brbtv-author-link {cursor: pointer; color: inherit;}";
        addCssToHead(theCss);

        var mutedUsers = new Set();
        for (let i = 0; i < settings.ignoredUsers.length; i++) {
            mutedUsers.add(settings.ignoredUsers[i].id);
        }

        var highlightedUsers = new Set();
        for (let i = 0; i < settings.highlightedUsers.length; i++) {
            highlightedUsers.add(settings.highlightedUsers[i].id);
        }

        youtube.addStorageListener(function (changes, namespace) {
            var ignoredUserChange = changes["ignoredUsers"];
            if (ignoredUserChange) {
                mutedUsers = new Set();
                for (let i = 0; i < ignoredUserChange.newValue.length; i++) {
                    mutedUsers.add(ignoredUserChange.newValue[i].id);
                }
            }

            var highlightedUserChange = changes["highlightedUsers"];
            if (highlightedUserChange) {
                highlightedUsers = new Set();
                for (let i = 0; i < highlightedUserChange.newValue.length; i++) {
                    highlightedUsers.add(highlightedUserChange.newValue[i].id);
                }
            }
        });

        if (!$("#brbtv-user-actions-menu").length) {
            let jUserMenu = $("<div>", {
                "id": "brbtv-user-actions-menu"
            });
            $("yt-live-chat-renderer").prepend(jUserMenu);
            delete jUserMenu;
        }

        function updateChromeStore(jUserLink, ytId, storageKey, isAddToList) {
            let query = {};
            query[storageKey] = [];
            chrome.storage.sync.get(query, function (items) {
                var theUpdatedArray = items[storageKey];
                if (isAddToList) {
                    theUpdatedArray.push({
                        name: jUserLink.text().trim(),
                        id: ytId,
                        addedTime: Date.now()
                    });
                } else {
                    theUpdatedArray = theUpdatedArray.filter(u => u.id != ytId);
                }

                query[storageKey] = theUpdatedArray;

                chrome.storage.sync.set(query);
            });
        }

        function isMessageByUser(jChatMessage, userId) {
            let parts = userId.split(" ");
            let photoSrc = parts[0];
            let authorName = parts.slice(1).join(" ");

            return jChatMessage.find('#author-photo[src="' + photoSrc + '"]').length && jChatMessage.find("#author-name").text() == authorName;
        }

        function addHighlightUserButton(ytId, jUserLink) {
            let jHighlightUser = createMenuButton("brbtv-highlight-button", chrome.i18n.getMessage("userActionHighlight"));
            jHighlightUser[0].addEventListener('click', function (e) {
                if (!highlightedUsers.has(ytId)) {
                    highlightedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.addClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jHighlightUser);
        }

        function addMenuItem(jItem) {
            $("#brbtv-user-actions-menu").append(jItem);
        }

        function addUnhighlightUserButton(ytId, jUserLink) {
            let jUnhighlightUser = createMenuButton("brbtv-unhighlight-button", chrome.i18n.getMessage("userActionUnHighlight"));
            jUnhighlightUser[0].addEventListener('click', function (e) {
                if (highlightedUsers.has(ytId)) {
                    highlightedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.removeClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jUnhighlightUser);
        }

        function addMuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-mute-button", chrome.i18n.getMessage("userActionMute"));
            jMuteUser[0].addEventListener('click', function (e) {
                if (!mutedUsers.has(ytId)) {
                    mutedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.addClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jMuteUser);
        }

        function addUnmuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-unmute-button", chrome.i18n.getMessage("userActionUnMute"));
            jMuteUser[0].addEventListener('click', function (e) {
                if (mutedUsers.has(ytId)) {
                    mutedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (isMessageByUser(jIteratedMessage, ytId)) {
                            jIteratedMessage.removeClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            addMenuItem(jMuteUser);
        }

        function addHideMenuFunction(jUserLink) {
            var hideMenuFunction = function (e) {
                if (e.target != jUserLink[0]) {
                    $("#brbtv-user-actions-menu").removeClass("show-brbtv-user-actions-menu");
                    $(this).off("click", hideMenuFunction);
                }
            };
            $("body").on("click", hideMenuFunction); // necessary exception from no-jQuery-handlers rule: we have to detach it globally after page change
        }

        function insertDoubleclickedAuthor(e) {
            $("#brbtv-user-actions-menu").removeClass("show-brbtv-user-actions-menu");

            var replacement = '@' + $(e.currentTarget).text();

            replacement += "\u00A0";
            var jTextInput = youtube.getJChatInputField();
            if (jTextInput.length) {
                let caretPosition = getCaretPosition(jTextInput[0]);
                jTextInput[0].normalize();

                // next, find the text node containing the caret
                // by this, we can safely skip other DOM elements created by YT (like img for emotes)
                var lengthPassed = 0;
                var replacementPerformed = false;

                jTextInput.contents().filter(function () {
                    return this.nodeType === 3; // i.e. this.nodeType == TEXT_NODE
                }).each(function (idx, elem) {
                    if (replacementPerformed) return;
                    if (caretPosition >= elem.nodeValue.length + lengthPassed) {
                        lengthPassed += elem.nodeValue.length;
                    } else {
                        elem.nodeValue = elem.nodeValue.replaceBetween(
                            caretPosition - lengthPassed,
                            caretPosition - lengthPassed,
                            replacement);
                        replacementPerformed = true;
                    }
                });

                if (!replacementPerformed) jTextInput.append(document.createTextNode(replacement));
                setCaretPosition(jTextInput[0], caretPosition + replacement.length);
                jTextInput.focus();
                jTextInput[0].dispatchEvent(new CustomEvent("input"));
            }
        }

        function showActionMenu(e) {
            let jUserLink = $(e.target);
            let jMessage = jUserLink.closest("yt-live-chat-text-message-renderer");
            let jUserMenu = $("#brbtv-user-actions-menu");
            let authorPhotoSrc = jMessage.find('img[id="author-photo"]').attr("src");
            let authorName = jMessage.find("#author-name").text();
            let ytId = authorPhotoSrc + " " + authorName;
            jUserMenu.empty();

            //let jVisitProfile = createMenuButton("brbtv-visit-button", chrome.i18n.getMessage("userActionVisitProfile"));
            //jVisitProfile.attr("href", jUserLink.attr('href'));
            //jUserMenu.append(jVisitProfile);

            if (highlightedUsers.has(ytId)) {
                addUnhighlightUserButton(ytId, jUserLink);
            } else {
                addHighlightUserButton(ytId, jUserLink);
            }

            if (!mutedUsers.has(ytId)) {
                addMuteButton(ytId, jUserLink);
            } else {
                addUnmuteButton(ytId, jUserLink);
            }
            e.preventDefault();
            addHideMenuFunction(jUserLink);

            let linkPosition = jUserLink.offset();
            let topPosition = linkPosition.top + jUserLink.height();
            if (topPosition + jUserMenu.height() > $("body").height()) topPosition = linkPosition.top - jUserMenu.height() - jUserLink.height();
            jUserMenu.css("top", topPosition + "px");
            jUserMenu.css("left", linkPosition.left + "px");

            jUserMenu.addClass("show-brbtv-user-actions-menu");
        }

        youtube.registerChatMessageObserver(function (message) {
            let jMessage = $(message);

            // TODO find new-member-announcement equivalent in new chat
            if (jMessage.hasClass("new-member-announcement")) return;

            let authorPhotoSrc = jMessage.find('img[id="author-photo"]').attr("src");
            let authorName = jMessage.find("#author-name").text();
            let ytId = authorPhotoSrc + " " + authorName;

            // don't show menu if we don't have a photo to work with
            if (authorPhotoSrc == "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7") {
                return;
            }

            if (mutedUsers.has(ytId)) {
                jMessage.remove();
                return;
            }

            let jUserLink = $("<a>", {
                href: "#",
                class: "brbtv-author-link"
            }).text(authorName);

            jMessage.find("#author-name").html(jUserLink);

            if (highlightedUsers.has(ytId)) {
                jMessage.addClass("brbtv-highlighted-message");
            }

            jUserLink[0].addEventListener('click', showActionMenu);

            // insert the name as a mention on doubleclick
            jUserLink[0].addEventListener('dblclick', insertDoubleclickedAuthor);

            jUserLink = null;

        }, true);
    });
}<|endoftext|>


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

//#include aura.locker.SecureThing
var ObscureThing = (function() {
  "use strict";

  function getThing(o) {
    return o._get("o", $A.lockerService.masterKey);
  }

  function getKey(o) {
    return $A.lockerService.util._getKey(o, $A.lockerService.masterKey);
  }

  /**
   * When a locked down component does not have access to a DOM element
   * or another component, it will instead get access to an ObscureThing
   * instance, this way the element or component cannot be manipulated
   * in user-land, but can be re-piped into the framework, which
   * could unwrap the ObscureThing, and use the underlaying object.
   **/
  function ObscureThing(o, key) {
    SecureThing.call(this, key, "o");
    this._set("o", o, $A.lockerService.masterKey);
    Object.freeze(this);
  }

  ObscureThing.prototype = Object.create(SecureThing.prototype, {
    toString : {
      value : function() {
        return "ObscureThing: " + getThing(this) + "{ key: " + JSON.stringify(getKey(this)) + " }";
      }
    },
    unwrap: {
      value: function(mk) {
        if (mk !== $A.lockerService.masterKey) {
          throw new Error("Access denied");
        }
        return getThing(this);
      },
      enumerable: false
    }
  });

  ObscureThing.prototype.constructor = ObscureThing;

  return ObscureThing;
})();
<commit_msg>PR-284-locker-second-attempt<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#include aura.locker.SecureThing
var ObscureThing = (function() {
  "use strict";

  function getThing(o) {
    return o._get("o", $A.lockerService.masterKey);
  }

  function getKey(o) {
    return $A.lockerService.util._getKey(o, $A.lockerService.masterKey);
  }

  /**
   * When a locked down component does not have access to a DOM element
   * or another component, it will instead get access to an ObscureThing
   * instance, this way the element or component cannot be manipulated
   * in user-land, but can be re-piped into the framework, which
   * could unwrap the ObscureThing, and use the underlaying object.
   **/
  function ObscureThing(o, key) {
    SecureThing.call(this, key, "o");
    this._set("o", o, $A.lockerService.masterKey);
    Object.freeze(this);
  }

  ObscureThing.prototype = Object.create(SecureThing.prototype, {
    toString : {
      value : function() {
        return "ObscureThing: " + getThing(this) + "{ key: " + JSON.stringify(getKey(this)) + " }";
      }
    },
    unwrap: {
      value: function(mk) {
        if (mk !== $A.lockerService.masterKey) {
          throw new Error("Access denied");
        }
        return getThing(this);
      },
      enumerable: false
    }
  });

  ObscureThing.prototype.constructor = ObscureThing;

  return ObscureThing;

})();
<|endoftext|>


<commit_before>var mod = {};
module.exports = mod;

mod.loop = function(room, cnt) {
    var spawns = _.filter(Game.spawns, function(spawn) { return spawn.room == room; });
    var spawn = spawns[0];
    //Check energy available first
    if(room.energyAvailable < 150) {
        //console.log('Not enough energy to spawn next creep');
        return;
    }

    //Population control
    //At least, we need one harvester and one hauler
    // if there is no more creep, so we can make spawn back to life
    if(cnt.harvester < 1) {
        this.spawnHarvester(spawn);
    } else if(cnt.hauler < 1) {
        this.spawnHauler(spawn);
    } else if(cnt.harvester < 2) {
        this.spawnHarvester(spawn);
    } else if(cnt.hauler < 2) {
        this.spawnHauler(spawn);
    } else if(cnt.upgrader < 3) {
        this.spawnUpgrader(spawn);
    } else {
        var targets = room.find(FIND_CONSTRUCTION_SITES);
        if(targets.length && cnt.builder < 2) {
            this.spawnBuilder(spawn);
        } else if(cnt.upgrader < 5) {
            this.spawnUpgrader(spawn);
        }
    }
};

mod.spawnHarvester = function(spawn) {
    var a = ['[H]John','[H]Amy','[H]Bob']
    var result = OK;
    var name;

    for(var i=0;i<a.length;i++) {
        name = a[i];
        result = spawn.spawnCreep([WORK, CARRY, MOVE], name, { dryRun: true });
        if(result==OK) {
            spawn.spawnCreep([WORK, CARRY, MOVE], name, {
                memory: {role: 'harvester'}
            });
            console.log('Spawning '+name);
            break;
        }
    }
};

mod.spawnHauler = function(spawn) {
    var a = ['[Ha]Gold','[Ha]Iron']
    var result = OK;
    var name;

    for(var i=0;i<a.length;i++) {
        name = a[i];
        result = spawn.spawnCreep([CARRY, MOVE], name, { dryRun: true });
        if(result==OK) {
            spawn.spawnCreep([CARRY, MOVE], name, {
                memory: {role: 'hauler'}
            });
            console.log('Spawning '+name);
            break;
        }
    }
};

mod.spawnUpgrader = function(spawn) {
    var a = ['[U]Dog','[U]Cat','[U]Meow','[U]Mummy','[U]Ass','[U]God']
    var result = OK;
    var name;

    for(var i=0;i<a.length;i++) {
        name = a[i];
        result = spawn.spawnCreep([WORK, CARRY, MOVE], name, { dryRun: true });
        if(result==OK) {
            spawn.spawnCreep([WORK, CARRY, MOVE], name, {
                memory: {role: 'upgrader'}
            });
            console.log('Spawning '+name);
            break;
        }
    }
};

mod.spawnBuilder = function(spawn) {
    var a = ['[B]Amd','[B]Lucky','[B]Gentleman']
    var result = OK;
    var name;

    for(var i=0;i<a.length;i++) {
        name = a[i];
        result = spawn.spawnCreep([WORK, CARRY, MOVE], name, { dryRun: true });
        if(result==OK) {
            spawn.spawnCreep([WORK, CARRY, MOVE], name, {
                memory: {role: 'builder'}
            });
            console.log('Spawning '+name);
            break;
        }
    }
};

<commit_msg>refactor util.spawner<commit_after>var mod = {};
module.exports = mod;

mod.loop = function(room, cnt) {
    var spawns = _.filter(Game.spawns, function(spawn) { return spawn.room == room; });
    this.spawn = spawns[0];

    this.energyAvailable = room.energyAvailable;

    //Population control
    //At least, we need one harvester and one hauler
    // if there is no more creep, so we can make spawn back to life
    if(cnt.harvester < 1) {
        this.spawnHarvester(true);
    } else if(cnt.hauler < 1) {
        this.spawnHauler(true);
    } else if(cnt.harvester < 2) {
        this.spawnHarvester();
    } else if(cnt.hauler < 2) {
        this.spawnHauler();
    } else if(cnt.upgrader < 3) {
        this.spawnUpgrader();
    } else {
        var targets = room.find(FIND_CONSTRUCTION_SITES);
        if(targets.length && cnt.builder < 2) {
            this.spawnBuilder();
        } else if(cnt.upgrader < 5) {
            this.spawnUpgrader();
        }
    }
};
//TODO memorize source and mark it, calcaulate available spot
mod.spawnHarvester = function(minimum = false) {
    var essBody = [WORK, CARRY, MOVE];
    var extraBody = [WORK];
    var names = ['[H]John','[H]Amy','[H]Bob']
    this.spawn0(essBody, extraBody, minimum, names, {role: 'harvester'});
};

mod.spawnHauler = function(minimum) {
    var essBody = [CARRY, MOVE];
    var extraBody = [CARRY, MOVE];
    var names = ['[Ha]Gold','[Ha]Iron'];
    this.spawn0(essBody, extraBody, minimum, names, {role: 'hauler'});
};

mod.spawnUpgrader = function(minimum) {
    var essBody = [WORK, CARRY, MOVE];
    var extraBody = [WORK, WORK, CARRY];
    var names = ['[U]Dog','[U]Cat','[U]Meow','[U]Mummy','[U]Ass','[U]God']
    this.spawn0(essBody, extraBody, minimum, names, {role: 'upgrader'});
};

mod.spawnBuilder = function(minimum) {
    var essBody = [WORK, CARRY, MOVE];
    var extraBody = [WORK, CARRY];
    var names = ['[B]Amd','[B]Lucky','[B]Gentleman'];
    this.spawn0(essBody, extraBody, minimum, names, {role: 'builder'});
};

mod.spawn0 = function(essBody, extraBody, minimum, names, memory) {
    var spawn = this.spawn;
    //Calculate body and examine whether energyAvailable is enough
    var body = minimum ? essBody : this.getMaxiumBody(essBody, extraBody);
    var bodyCost = this.getBodyCost(body);
    if(this.energyAvailable < bodyCost) return;
    //Calculate name
    var name;
    var result;
    for(var i=0;i<names.length;i++) {
        name = names[i];
        result = spawn.spawnCreep(body, name, { dryRun: true });
        if(result==OK) {
            spawn.spawnCreep(body, name, {
                memory: memory,
            });
            console.log('Spawning '+name);
            break;
        }
    }
}

mod.getMaxiumBody = function(essBody, extraBody) {
    var essCost = this.getBodyCost(essBody);
    var extraCost = this.getBodyCost(extraBody);
    var extraAmount = _.floor((this.energyAvailable - essCost) / extraCost);
    var body = essBody;
    for(var i=0; i<extraAmount; i++) {
        body.push(extraBody);
    }
    return _.flattenDeep(body);
}

mod.getBodyCost = function(bodyParts) {
    var cost = 0;
    for(var i=0; i<bodyParts.length; i++) {
        cost += BODYPART_COST[bodyParts[i]];
    }
    return cost;
}

<|endoftext|>


<commit_before>import { spawn } from 'child_process';
import debug from 'debug';
import fs from 'fs-promise';
import mkdirp from 'mkdirp';
import ora from 'ora';
import os from 'os';
import path from 'path';
import pify from 'pify';

const d = debug('electron-forge:rebuild');

export default async (buildPath, electronVersion, pPlatform, pArch) => {
  const rebuilds = [];

  const rebuildModuleAt = async (modulePath) => {
    if (await fs.exists(path.resolve(modulePath, 'binding.gyp'))) {
      const metaPath = path.resolve(modulePath, 'build', 'Release', '.forge-meta');
      if (await fs.exists(metaPath)) {
        const meta = await fs.readFile(metaPath, 'utf8');
        if (meta === pArch) {
          d(`skipping: ${path.basename(modulePath)} as it is already built`);
          return;
        }
      }
      d('rebuilding:', path.basename(modulePath));
      const rebuildArgs = [
        'rebuild',
        `--target=${electronVersion}`,
        `--arch=${pArch}`,
        '--dist-url=https://atom.io/download/electron',
      ];
      await new Promise((resolve, reject) => {
        const child = spawn(process.execPath, [path.resolve(__dirname, '../../node_modules/.bin/node-gyp')].concat(rebuildArgs), {
          cwd: modulePath,
          // stdio: 'inherit',
          env: Object.assign({}, process.env, {
            HOME: path.resolve(os.homedir(), '.electron-gyp'),
            USERPROFILE: path.resolve(os.homedir(), '.electron-gyp'),
            npm_config_disturl: 'https://atom.io/download/electron',
            npm_config_runtime: 'electron',
            npm_config_arch: pArch,
            npm_config_target_arch: pArch,
          }),
        });
        child.on('exit', async (code) => {
          d('built:', path.basename(modulePath));
          if (code !== 0) return reject(new Error(`Failed to rebuild: ${modulePath}`));
          await pify(mkdirp)(path.dirname(metaPath));
          await fs.writeFile(metaPath, pArch);
          resolve();
        });
      });
    }
  };
  const rebuildAllModulesIn = (nodeModulesPath) => {
    for (const modulePath of fs.readdirSync(nodeModulesPath)) {
      rebuilds.push(rebuildModuleAt(path.resolve(nodeModulesPath, modulePath)));
      if (fs.existsSync(path.resolve(nodeModulesPath, modulePath, 'node_modules'))) {
        rebuildAllModulesIn(path.resolve(nodeModulesPath, modulePath, 'node_modules'));
      }
    }
  };
  const nativeSpinner = ora.ora('Preparing native dependencies').start();
  rebuildAllModulesIn(path.resolve(buildPath, 'node_modules'));
  try {
    await Promise.all(rebuilds);
  } catch (err) {
    nativeSpinner.fail();
    throw err;
  }
  nativeSpinner.succeed();
};
<commit_msg>fix(packager): rebuild pre-gyp modules with their binary variables<commit_after>import { spawn } from 'child_process';
import debug from 'debug';
import fs from 'fs-promise';
import mkdirp from 'mkdirp';
import ora from 'ora';
import os from 'os';
import path from 'path';
import pify from 'pify';

const d = debug('electron-forge:rebuild');

export default async (buildPath, electronVersion, pPlatform, pArch) => {
  const rebuilds = [];

  const rebuildModuleAt = async (modulePath) => {
    if (await fs.exists(path.resolve(modulePath, 'binding.gyp'))) {
      const metaPath = path.resolve(modulePath, 'build', 'Release', '.forge-meta');
      if (await fs.exists(metaPath)) {
        const meta = await fs.readFile(metaPath, 'utf8');
        if (meta === pArch) {
          d(`skipping: ${path.basename(modulePath)} as it is already built`);
          return;
        }
      }
      d('rebuilding:', path.basename(modulePath));
      const rebuildArgs = [
        'rebuild',
        `--target=${electronVersion}`,
        `--arch=${pArch}`,
        '--dist-url=https://atom.io/download/electron',
        '--build-from-source',
      ];

      const modulePackageJSON = JSON.parse(await fs.readFile(path.resolve(modulePath, 'package.json')));
      Object.keys(modulePackageJSON.binary || {}).forEach((binaryKey) => {
        let value = modulePackageJSON.binary[binaryKey];
        if (binaryKey === 'module_path') {
          value = path.resolve(modulePath, value);
        }
        rebuildArgs.push(`--${binaryKey}=${value}`);
      });

      await new Promise((resolve, reject) => {
        const child = spawn(process.execPath, [path.resolve(__dirname, '../../node_modules/.bin/node-gyp')].concat(rebuildArgs), {
          cwd: modulePath,
          // stdio: 'inherit',
          env: Object.assign({}, process.env, {
            HOME: path.resolve(os.homedir(), '.electron-gyp'),
            USERPROFILE: path.resolve(os.homedir(), '.electron-gyp'),
            npm_config_disturl: 'https://atom.io/download/electron',
            npm_config_runtime: 'electron',
            npm_config_arch: pArch,
            npm_config_target_arch: pArch,
            npm_config_build_from_source: true,
          }),
        });
        child.on('exit', async (code) => {
          d('built:', path.basename(modulePath));
          if (code !== 0) return reject(new Error(`Failed to rebuild: ${modulePath}`));
          await pify(mkdirp)(path.dirname(metaPath));
          await fs.writeFile(metaPath, pArch);
          resolve();
        });
      });
    }
  };
  const rebuildAllModulesIn = (nodeModulesPath) => {
    for (const modulePath of fs.readdirSync(nodeModulesPath)) {
      rebuilds.push(rebuildModuleAt(path.resolve(nodeModulesPath, modulePath)));
      if (fs.existsSync(path.resolve(nodeModulesPath, modulePath, 'node_modules'))) {
        rebuildAllModulesIn(path.resolve(nodeModulesPath, modulePath, 'node_modules'));
      }
    }
  };
  const nativeSpinner = ora.ora('Preparing native dependencies').start();
  rebuildAllModulesIn(path.resolve(buildPath, 'node_modules'));
  try {
    await Promise.all(rebuilds);
  } catch (err) {
    nativeSpinner.fail();
    throw err;
  }
  nativeSpinner.succeed();
};
<|endoftext|>


<commit_before>import Component from '@ember/component';
import layout from './template';
import { get, setProperties, observer } from '@ember/object';

function maybeInt(str) {
  const num = parseInt(str,10);
  if ( num+'' === str ) {
    return num;
  }

  return str;
}

export default Component.extend({
  layout,
  workload: null,
  scaleMode: null,
  editing: null,
  isUpgrade: null,

  classNames: ['accordion-wrapper'],
  _strategy: null,
  workloadConfig: null,
  batchSize: null,

  didReceiveAttrs() {
    const config = get(this, 'workloadConfig');
    let  maxSurge = get(config, 'maxSurge');
    let  maxUnavailable = get(config, 'maxUnavailable');
    let  actualStrategy = get(config, 'strategy');

    const changes = {};

    if ( !actualStrategy ) {
      actualStrategy = 'RollingUpdate';
      maxSurge = 1;
      maxUnavailable = null;
    }

    if ( actualStrategy === 'RollingUpdate' ) {
      if ( maxSurge && maxUnavailable ) {
        changes['_strategy'] = 'custom';
      } else if ( maxSurge ) {
        changes['_strategy'] = 'startFirst';
        changes['batchSize'] = maxSurge;
      } else if ( maxUnavailable ) {
        changes['_strategy'] = 'stopFirst';
        changes['batchSize'] = maxUnavailable;
      } else {
        changes['_strategy'] = 'stopFirst';
      }
    }

    setProperties(this, changes);
    this.strategyChanged();
  },

  strategyChanged: observer('_strategy','batchSize', function() {
    const _strategy = get(this, '_strategy');
    const config    = get(this, 'workloadConfig');

    let batchSize = maybeInt(get(this, 'batchSize'));
    let maxSurge = maybeInt(get(config, 'maxSurge'));
    let maxUnavailable = maybeInt(get(config, 'maxUnavailable'));

    if ( !maxSurge && !maxUnavailable ) {
      maxSurge = 1;
      maxUnavailable = 0;
    }

    if ( _strategy === 'startFirst' ) {
      setProperties(config, {
        strategy: 'RollingUpdate',
        maxSurge: batchSize,
        maxUnavailable: 0,
      });
    } else if ( _strategy === 'stopFirst' ) {
      setProperties(config, {
        strategy: 'RollingUpdate',
        maxSurge: 0,
        maxUnavailable: batchSize,
      });
    } else if ( _strategy === 'custom' ) {
      setProperties(config, {
        strategy: 'RollingUpdate',
        maxSurge: maxSurge,
        maxUnavailable: maxUnavailable
      });
    } else if ( _strategy === 'recreate' ) {
      setProperties(config, {
        strategy: 'Recreate',
        maxSurge: null,
        maxUnavailable: null,
      });
    }
  }),
});
<commit_msg>Fix upgrade strategy issue<commit_after>import Component from '@ember/component';
import layout from './template';
import { get, setProperties, observer } from '@ember/object';

function maybeInt(str) {
  const num = parseInt(str,10);
  if ( num+'' === str ) {
    return num;
  }

  return str;
}

export default Component.extend({
  layout,
  workload: null,
  scaleMode: null,
  editing: null,
  isUpgrade: null,

  classNames: ['accordion-wrapper'],
  _strategy: null,
  workloadConfig: null,
  batchSize: null,

  didReceiveAttrs() {
    const config = get(this, 'workloadConfig');
    let  maxSurge = get(config, 'maxSurge');
    let  maxUnavailable = get(config, 'maxUnavailable');
    let  actualStrategy = get(config, 'strategy');

    const changes = {};

    if ( !actualStrategy ) {
      actualStrategy = 'RollingUpdate';
      maxSurge = 1;
      maxUnavailable = null;
    }

    if ( actualStrategy === 'RollingUpdate' ) {
      if ( maxSurge && maxUnavailable ) {
        changes['_strategy'] = 'custom';
      } else if ( maxSurge ) {
        changes['_strategy'] = 'startFirst';
        changes['batchSize'] = maxSurge;
      } else if ( maxUnavailable ) {
        changes['_strategy'] = 'stopFirst';
        changes['batchSize'] = maxUnavailable;
      } else {
        changes['_strategy'] = 'stopFirst';
      }
    }

    if ( actualStrategy === 'Recreate' ) {
      changes['_strategy'] = 'recreate';
    }

    setProperties(this, changes);
    this.strategyChanged();
  },

  strategyChanged: observer('_strategy','batchSize', function() {
    const _strategy = get(this, '_strategy');
    const config    = get(this, 'workloadConfig');

    let batchSize = maybeInt(get(this, 'batchSize'));
    let maxSurge = maybeInt(get(config, 'maxSurge'));
    let maxUnavailable = maybeInt(get(config, 'maxUnavailable'));

    if ( !maxSurge && !maxUnavailable ) {
      maxSurge = 1;
      maxUnavailable = 0;
    }

    if ( _strategy === 'startFirst' ) {
      setProperties(config, {
        strategy: 'RollingUpdate',
        maxSurge: batchSize,
        maxUnavailable: 0,
      });
    } else if ( _strategy === 'stopFirst' ) {
      setProperties(config, {
        strategy: 'RollingUpdate',
        maxSurge: 0,
        maxUnavailable: batchSize,
      });
    } else if ( _strategy === 'custom' ) {
      setProperties(config, {
        strategy: 'RollingUpdate',
        maxSurge: maxSurge,
        maxUnavailable: maxUnavailable
      });
    } else if ( _strategy === 'recreate' ) {
      setProperties(config, {
        strategy: 'Recreate',
        maxSurge: null,
        maxUnavailable: null,
      });
    }
  }),
});
<|endoftext|>


<commit_before>/**
 * This file is part of the NovaeCalc project.
 *
 * It is permitted to use, redistribute and/or modify this software
 * under the terms of the BSD License
 *
 * @author Felix Maier <maier.felix96@gmail.com>
 * @copyright (c) 2015 Felix Maier, @felixmaier
 *
 * You may not change or remove these lines
 *
 */

"use strict";

  /**
   * Read arguments
   *
   * @method readArguments
   * @return {array} function arguments array
   * @static
   */
  ENGEL.PARSER.prototype.readArguments = function() {

    var block = arguments[0] || this.block;

    var argumentz = [];

    var args = [];

    var record = false;

    /** To ignore parentheses */
    var jumper = 0;

    /** Empty arguments */
    if (this.emptyArguments()) return ([]);

    while (block[0]) {

      if (this.currentBlock.type === "LX_MATH") {
        if (block[0].type === "LX_LPAR") {
          record = true;
        }
      }

      if (record && block[0].type === "LX_RPAR") {
        argumentz.push(this.parseArguments(args));
        args = [];
      }

      if (block[0].type === "LX_RPAR" && record) {
        record = false;
      }

      if (block[0].type === "LX_MATH") {
        if (block[0].type !== "LX_COMMA") {
          args.push(block[0]);
        }
        block.shift();
        argumentz.push(this.readArguments(block));
      }

      if (record && block[0]) {
        if (["LX_LPAR", "LX_RPAR"].indexOf(block[0].type) <= -1) {
          args.push(block[0]);
        }
      }

      block.shift();

    }

    return (argumentz[0]);

  };

  /**
   * Parse a argument
   *
   * @method parseArguments
   * @static
   */
  ENGEL.PARSER.prototype.parseArguments = function(block) {

    var args = [];

    var array = [];

    while (block[0]) {

      if (block[0].type !== "LX_COMMA") {
        array.push(block[0]);
      }

      if (block[0].type === "LX_COMMA" || block.length === 1) {
        args.push(this.injectBlock(array));
        array = [];
      }

      block.shift();

    }

    return (args);

  };

  /**
   * Inject a block array and auto parse it
   *
   * @method injectBlock
   * @static
   */
  ENGEL.PARSER.prototype.injectBlock = function(block) {

    var blockBackup = this.block.slice(0);

    this.block = block;

    this.shift();

    this.addSemicolon();

    var result = this.ruleExpression();

    this.block = blockBackup.slice(0);

    return (result);

  };

  /**
   * Check if function arguments are empty
   *
   * @method emptyArguments
   * @static
   */
  ENGEL.PARSER.prototype.emptyArguments = function() {

    if (this.block[0] && this.block[1]) {
      if (this.block[0].type === "LX_LPAR") {
        if (this.block[1].type === "LX_RPAR") {
          this.shift();
          this.shift();
          this.shift();
          return (true);
        }
      }
    }

    return (false);

  };<commit_msg>Updates<commit_after>/**
 * This file is part of the NovaeCalc project.
 *
 * It is permitted to use, redistribute and/or modify this software
 * under the terms of the BSD License
 *
 * @author Felix Maier <maier.felix96@gmail.com>
 * @copyright (c) 2015 Felix Maier, @felixmaier
 *
 * You may not change or remove these lines
 *
 */

"use strict";

  /**
   * Read arguments
   *
   * @method readArguments
   * @return {array} function arguments array
   * @static
   */
  ENGEL.PARSER.prototype.readArguments = function() {

    var block = arguments[0] || this.block;

    var argumentz = [];

    var args = [];

    var record = false;

    /** To ignore parentheses */
    var jumper = 0;

    /** Empty arguments */
    if (this.emptyArguments()) return ([]);

    while (block[0]) {

      if (this.currentBlock.type === "LX_MATH") {
        if (block[0].type === "LX_LPAR") {
          record = true;
          jumper++;
        }
      }

      if (record && jumper === 0) {
        jumper--;
        argumentz.push(this.parseArguments(args));
        args = [];
      }

      if (record && jumper <= 0 && block[0].type === "LX_RPAR") {
        record = false;
      }

      if (block[0].type === "LX_MATH") {
        if (block[0].type !== "LX_COMMA") {
          args.push(block[0]);
        }
        block.shift();
        argumentz.push(this.readArguments(block));
      }

      if (record && block[0]) {
        args.push(block[0]);
        if (block[0].type === "LX_RPAR") {
          jumper--;
        }
      } else {
        break;
      }

      //console.log(arguments[0] ? true : false, jumper, block[0]);

      block.shift();

    }

    return (argumentz[0]);

  };

  /**
   * Parse a argument
   *
   * @method parseArguments
   * @static
   */
  ENGEL.PARSER.prototype.parseArguments = function(block) {

    var args = [];

    var array = [];

    while (block[0]) {

      if (block[0].type !== "LX_COMMA") {
        array.push(block[0]);
      }

      if (block[0].type === "LX_COMMA" || block.length === 1) {
        args.push(this.injectBlock(array));
        array = [];
      }

      block.shift();

    }

    return (args);

  };

  /**
   * Inject a block array and auto parse it
   *
   * @method injectBlock
   * @static
   */
  ENGEL.PARSER.prototype.injectBlock = function(block) {

    var blockBackup = this.block.slice(0);

    this.block = block;

    this.shift();

    this.addSemicolon();

    var result = this.ruleExpression();

    this.block = blockBackup.slice(0);

    return (result);

  };

  /**
   * Check if function arguments are empty
   *
   * @method emptyArguments
   * @static
   */
  ENGEL.PARSER.prototype.emptyArguments = function() {

    if (this.block[0] && this.block[1]) {
      if (this.block[0].type === "LX_LPAR") {
        if (this.block[1].type === "LX_RPAR") {
          this.shift();
          this.shift();
          this.shift();
          return (true);
        }
      }
    }

    return (false);

  };<|endoftext|>


<commit_before>angular.module('webapp').controller('PlannerCalendarCtrl', PlannerCalendarCtrl)
PlannerCalendarCtrl.$inject = ['SessionsService', 'EventService', 'moment']

/**
 * @ngdoc controller
 * @name webapp.controller:PlannerCalendarCtrl
 * @description In charge of the planner calendar view.
 */
function PlannerCalendarCtrl(SessionsService, EventService, moment) {
    var vm = this

    vm.titleName = "Planner"

    vm.selectedIndex = 0

    vm.timeslots = []

    vm.days = []

    vm.sessions = null

    EventService.loadEvent().then(function() {
        if (EventService.event.start_date && EventService.event.end_date) {
            var start = moment(EventService.event.start_date)
            var end = moment(EventService.event.end_date)
            while (start.isSameOrBefore(end)) {
                vm.days.push(angular.copy(start))
                start.add(1, 'days')
            }
        }

        if (EventService.event.timeslots) {
            EventService.event.timeslots.forEach(function(item) {
                vm.timeslots.push({
                    start_time: new Date(item.start_time),
                    end_time: new Date(item.end_time)
                })
            })
        }

        vm.getSessions(0)

    })

    vm.selectDay = function(index) {
        vm.selectedIndex = index
        vm.getSessions(index)
    }

    vm.getSessions = function(index) {
        SessionsService.getSessionsByDate(vm.days[index]).then(function(sessions) {
            vm.sessions = sessions
        })
    }

    vm.showSession = function(session) {
        vm.$router.navigate(['PlannerSession', {
            id: session.$id
        }])
    }
}
<commit_msg>CatchUp Gautier<commit_after>angular.module('webapp').controller('PlannerCalendarCtrl', PlannerCalendarCtrl)
PlannerCalendarCtrl.$inject = ['SessionsService', 'EventService', 'moment']

/**
 * @ngdoc controller
 * @name webapp.controller:PlannerCalendarCtrl
 * @description In charge of the planner calendar view.
 */
function PlannerCalendarCtrl(SessionsService, EventService, moment) {
    var vm = this

    vm.titleName = "Planner"

    vm.selectedIndex = 0

    vm.timeslots = []

    vm.days = []

    vm.sessions = null

    EventService.loadEvent().then(function() {
      console.log(vm)
        if (EventService.event.start_date && EventService.event.end_date) {
            var start = moment(EventService.event.start_date)
            var end = moment(EventService.event.end_date)
            while (start.isSameOrBefore(end)) {
                vm.days.push(angular.copy(start))
                start.add(1, 'days')
            }
        }

        if (EventService.event.timeslots) {
            EventService.event.timeslots.forEach(function(item) {
                vm.timeslots.push({
                    start_time: new Date(item.start_time),
                    end_time: new Date(item.end_time)
                })
            })
        }
        vm.getSessions(0)

    })

    vm.selectDay = function(index) {
        vm.selectedIndex = index
        vm.getSessions(index)
    }

    vm.getSessions = function(index) {
        SessionsService.getSessionsByDate(vm.days[index]).then(function(sessions) {
            vm.sessions = sessions
        })
    }

    vm.showSession = function(session) {
        vm.$router.navigate(['PlannerSession', {
            id: session.$id
        }])
    }
}
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
	helpers = require('../helpers'),
	when = require('when'),
	_ = require('lodash'),
	Scoresheet = mongoose.model('Scoresheet'),
	EmailUpdate = mongoose.model('EmailUpdate'),
	User = mongoose.model('User'),
	UserStanding = mongoose.model('UserStanding'),
	MatchScore = mongoose.model('MatchScore');

var matchesSchedule = _.flatten(_.pluck(require('../../models/matches-schedule').schedule, 'matches'));
var teamsNames = require('../../models/matches-schedule').teamsNames;

var findByMatchId = function(matches, matchId){
	return _.find(matches, function(match){
		return match.matchId === matchId;
	});
};

var storeEmail = function(emailOptions){

	var deferred = when.defer();

	var user = emailOptions.user,
		standings = emailOptions.standings,
		scoresheet = emailOptions.userScoresheet;

	var matchesInCurrentUpdate = _.pluck(standings.matches, 'matchId');

	var matchesScores = _.map(matchesInCurrentUpdate, function(matchId){
		return findByMatchId(emailOptions.matchScores, matchId);
	});

	var predictionsMessage = [], predictionNotProvided;
	_.each(matchesScores, function(realScore){
		var prediction = findByMatchId(standings.matches, realScore.matchId);

		var match = findByMatchId(matchesSchedule, realScore.matchId);

		if(_.isUndefined(prediction.team1Score) || _.isUndefined(prediction.team2Score)){

			predictionsMessage.push('You did not enter a prediction for '+
			 teamsNames[match.team1] + ' vs ' + teamsNames[match.team2] +
			  '.  -1 points');
				predictionNotProvided = true;
		} else {
			predictionsMessage.push('' +
				teamsNames[match.team1] + ' ' + prediction.team1Score +
				' - ' + teamsNames[match.team2] + ' ' + prediction.team2Score +
				' (' + realScore.team1Score + ' - ' + realScore.team2Score + ')' +
				'. Points: ' + prediction.points);
		}
	});

	predictionsMessage = predictionsMessage.reverse().slice(0, 5);

	var nextMatchPredictionsMessages = [];

	_.times(5, function(n){
		var nextMatchPrediction = findByMatchId(scoresheet.scores, (_.max(matchesInCurrentUpdate) + n + 1));
		var nextMatch = findByMatchId(matchesSchedule,  _.max(matchesInCurrentUpdate) + n + 1);

		if(nextMatchPrediction){

			if(_.isUndefined(nextMatchPrediction.team1Score) || _.isUndefined(nextMatchPrediction.team2Score)){
				nextMatchPredictionsMessages.push('You have not entered a prediction for ' +
					teamsNames[nextMatch.team1] + ' vs ' + teamsNames[nextMatch.team2] + '');
			} else {
				nextMatchPredictionsMessages.push(
				 '' + teamsNames[nextMatch.team1] + ' ' +
				 nextMatchPrediction.team1Score +
				 ' - ' +'' + teamsNames[nextMatch.team2] + ' ' +
				 nextMatchPrediction.team2Score);
			}
		}
	});

	var htmlMessage = 'Hello ' + user.displayName + ',' +
		 '

' +
		 emailOptions.bodyCustomMessage +
		  '

' +
		  '
Your last predictions
' +
		  predictionsMessage.join('
') +
		  '

' +
		  '
Your predictions for the next games
' +
		  nextMatchPredictionsMessages.join('
') +
		  '

You can change your predictions up to two hours from the start of the game.

' +
		  '
Current Points: '+ user.points +'
 ' +
		  '
My Standings
'  +
		  '
Koora 2014
'  +
		  '
@Koora_WorldCup
' ;

	 	 var emailUpdate = new EmailUpdate({
	 	 	user: user._id,
	 	 	matchId: _.max(matchesInCurrentUpdate),
	 	 	toEmail: user.email,
	 	 	subject: emailOptions.subject,
	 	 	emailBody: htmlMessage
	 	 });
	 	 emailUpdate.save(function(err, doc){
	 	 	if(err){
	 	 		console.log('error while saving email', err);
	 	 	}
	 	 	deferred.resolve(doc|| {});
	 	 });
	return deferred.promise;
};

module.exports.getEmailUpdates = function(req, res){
	EmailUpdate.find({}, function(err, emails){
		res.jsonp(emails);
	});
};

var getAll = function(modelName, query){
	var deferred = when.defer();
	modelName.find({} || query).populate('user').exec(function(err, res){
		if(err){
			console.log('error getting %s', modelName && modelName.toString(), err);
			deferred.reject(err);
		}
		deferred.resolve(res);
	});
	return deferred.promise;
};

var getOne = function(modelName, query){
	var deferred = when.defer();
	modelName.findOne(query).populate('user').exec(function(err, res){
		if(err){
			console.log('error getting %s', modelName && modelName.toString(), err);
			deferred.reject(err);
		}
		deferred.resolve(res);
	});
	return deferred.promise;
};

var purgeEmailUpdates = function(){
	var deferred = when.defer();
	EmailUpdate.remove({}, function(err, doc){
		if(err){
			console.log('error purging emails', doc);
			deferred.reject(err);
		} else deferred.resolve();
	});
	return deferred.promise;
};

module.exports.generateEmails = function(req, res){
	console.log('generating emails');
	return purgeEmailUpdates().then(function(){
		return getAll(UserStanding);
	}).then(function(allUsersStandings){
		return getAll(MatchScore).then(function(matchScores){
			return when.map(allUsersStandings, function(userStandings){
				return getOne(Scoresheet, {user: userStandings.user._id}).then(function(userScoresheet){
					var emailOptions = {
						standings: userStandings,
						user: userStandings.user,
						matchScores: matchScores,
						userScoresheet: userScoresheet
					};

					emailOptions = _.extend(emailOptions, req.body);

					return storeEmail(emailOptions);
				});

			}).then(function(allEmails){
				res.jsonp(allEmails);
			});
		});
	});
};

var sendGridUser = process.env.SENDGRID_USERNAME || 'app25678727@heroku.com';
var sendGridPass = process.env.SENDGRID_PASSWORD || 'yopsydme';

var sendgrid  = require('sendgrid')(sendGridUser, sendGridPass);

module.exports.sendEmails = function(req, res){
	console.log('sending emails');
	var emailsSent = 0, emailsWithErrors = 0, emailsSentAndDbUpdated = 0;
	EmailUpdate.find({isSent: false}, function(err, emails){
		return when.map(_.map(emails, function(email){
			var deferred = when.defer();
			var toEmail;

			if (process.env.NODE_ENV !== 'production') {
				toEmail = 'kabaros+' + email.toEmail.replace(/@.+/, '') + '@gmail.com';
			} else toEmail = email.toEmail;

			console.log('sending email to ' + toEmail);

		 	sendgrid.send({
			 	  to:       toEmail,
			 	  from:     'me@kabaros.com',
			 	  subject:  email.subject,
			 	  html:     email.emailBody,
			 	}, function(err, json) {
			 	  if (err) {
			 	   	console.error(err);
			 	   	emailsWithErrors++;
			 	   }
			 	   console.log(json);
			 	   emailsSent++;
			 	   EmailUpdate.findByIdAndUpdate(email._id, {
			 	   	isSent: true,
			 	   	opResponse: json
			 	   }, function(){
			 	   	emailsSentAndDbUpdated++;
			 	   	deferred.resolve(email);
			 	   });
			 });
			return deferred.promise;

		})).then(function(emails){
			res.jsonp(200, {
				emailsSent: emailsSent,
				emailsWithErrors: emailsWithErrors,
				emailsSentAndDbUpdated: emailsSentAndDbUpdated
			});
		});
	});
};

<commit_msg>email admin fix<commit_after>'use strict';

var mongoose = require('mongoose'),
	helpers = require('../helpers'),
	when = require('when'),
	_ = require('lodash'),
	Scoresheet = mongoose.model('Scoresheet'),
	EmailUpdate = mongoose.model('EmailUpdate'),
	User = mongoose.model('User'),
	UserStanding = mongoose.model('UserStanding'),
	MatchScore = mongoose.model('MatchScore');

var matchesSchedule = _.flatten(_.pluck(require('../../models/matches-schedule').schedule, 'matches'));
var teamsNames = require('../../models/matches-schedule').teamsNames;

var findByMatchId = function(matches, matchId){
	return _.find(matches, function(match){
		return match.matchId === matchId;
	});
};

var storeEmail = function(emailOptions){

	var deferred = when.defer();

	var user = emailOptions.user,
		standings = emailOptions.standings,
		scoresheet = emailOptions.userScoresheet;

	var matchesInCurrentUpdate = _.pluck(standings.matches, 'matchId');

	var matchesScores = _.map(matchesInCurrentUpdate, function(matchId){
		return findByMatchId(emailOptions.matchScores, matchId);
	});

	var predictionsMessage = [], predictionNotProvided;
	_.each(matchesScores, function(realScore){
		var prediction = findByMatchId(standings.matches, realScore.matchId);

		var match = findByMatchId(matchesSchedule, realScore.matchId);

		if(_.isUndefined(prediction.team1Score) || _.isUndefined(prediction.team2Score)){

			predictionsMessage.push('You did not enter a prediction for '+
			 teamsNames[match.team1] + ' vs ' + teamsNames[match.team2] +
			  '.  -1 points');
				predictionNotProvided = true;
		} else {
			predictionsMessage.push('' +
				teamsNames[match.team1] + ' ' + prediction.team1Score +
				' - ' + teamsNames[match.team2] + ' ' + prediction.team2Score +
				' (' + realScore.team1Score + ' - ' + realScore.team2Score + ')' +
				'. Points: ' + prediction.points);
		}
	});

	predictionsMessage = predictionsMessage.reverse().slice(0, 5);

	var nextMatchPredictionsMessages = [];

	_.times(5, function(n){
		var nextMatchPrediction = findByMatchId(scoresheet.scores, (_.max(matchesInCurrentUpdate) + n + 1));
		var nextMatch = findByMatchId(matchesSchedule,  _.max(matchesInCurrentUpdate) + n + 1);

		if(nextMatchPrediction){

			if(_.isUndefined(nextMatchPrediction.team1Score) || _.isUndefined(nextMatchPrediction.team2Score)){
				nextMatchPredictionsMessages.push('You have not entered a prediction for ' +
					teamsNames[nextMatch.team1] + ' vs ' + teamsNames[nextMatch.team2] + '');
			} else {
				nextMatchPredictionsMessages.push(
				 '' + teamsNames[nextMatch.team1] + ' ' +
				 nextMatchPrediction.team1Score +
				 ' - ' +'' + teamsNames[nextMatch.team2] + ' ' +
				 nextMatchPrediction.team2Score);
			}
		}
	});

	var htmlMessage = 'Hello ' + user.displayName + ',' +
		 '

' +
		 emailOptions.bodyCustomMessage +
		  '

' +
		  '
Your last predictions
' +
		  predictionsMessage.join('
') +
		  '

' +
		  '
Your predictions for the next games
' +
		  nextMatchPredictionsMessages.join('
') +
		  '

You can change your predictions up to two hours from the start of the game.

' +
		  '
Current Points: '+ user.points +'
 ' +
		  '
My Standings
'  +
		  '
Koora 2014
'  +
		  '
@Koora_WorldCup
' ;

	 	 var emailUpdate = new EmailUpdate({
	 	 	user: user._id,
	 	 	matchId: _.max(matchesInCurrentUpdate),
	 	 	toEmail: user.email,
	 	 	subject: emailOptions.subject,
	 	 	emailBody: htmlMessage
	 	 });
	 	 emailUpdate.save(function(err, doc){
	 	 	if(err){
	 	 		console.log('error while saving email', err);
	 	 	}
	 	 	deferred.resolve(doc|| {});
	 	 });
	return deferred.promise;
};

module.exports.getEmailUpdates = function(req, res){
	EmailUpdate.find({}, function(err, emails){
		res.jsonp(emails);
	});
};

var getAll = function(modelName, query){
	var deferred = when.defer();
	modelName.find({} || query).populate('user').exec(function(err, res){
		if(err){
			console.log('error getting %s', modelName && modelName.toString(), err);
			deferred.reject(err);
		}
		deferred.resolve(res);
	});
	return deferred.promise;
};

var getOne = function(modelName, query){
	var deferred = when.defer();
	modelName.findOne(query).populate('user').exec(function(err, res){
		if(err){
			console.log('error getting %s', modelName && modelName.toString(), err);
			deferred.reject(err);
		}
		deferred.resolve(res);
	});
	return deferred.promise;
};

var purgeEmailUpdates = function(){
	var deferred = when.defer();
	EmailUpdate.remove({}, function(err, doc){
		if(err){
			console.log('error purging emails', doc);
			deferred.reject(err);
		} else deferred.resolve();
	});
	return deferred.promise;
};

module.exports.generateEmails = function(req, res){
	console.log('generating emails');
	return purgeEmailUpdates().then(function(){
		return getAll(UserStanding);
	}).then(function(allUsersStandings){
		return getAll(MatchScore).then(function(matchScores){
			return when.map(allUsersStandings, function(userStandings){
				if(!userStandings.user)
					return;
				return getOne(Scoresheet, {user: userStandings.user._id}).then(function(userScoresheet){
					var emailOptions = {
						standings: userStandings,
						user: userStandings.user,
						matchScores: matchScores,
						userScoresheet: userScoresheet
					};

					emailOptions = _.extend(emailOptions, req.body);

					return storeEmail(emailOptions);
				});

			}).then(function(allEmails){
				res.jsonp(_.compact(allEmails));
			});
		});
	});
};

var sendGridUser = process.env.SENDGRID_USERNAME || 'app25678727@heroku.com';
var sendGridPass = process.env.SENDGRID_PASSWORD || 'yopsydme';

var sendgrid  = require('sendgrid')(sendGridUser, sendGridPass);

module.exports.sendEmails = function(req, res){
	console.log('sending emails');
	var emailsSent = 0, emailsWithErrors = 0, emailsSentAndDbUpdated = 0;
	EmailUpdate.find({isSent: false}, function(err, emails){
		return when.map(_.map(emails, function(email){
			var deferred = when.defer();
			var toEmail;

			if (process.env.NODE_ENV !== 'production') {
				toEmail = 'kabaros+' + email.toEmail.replace(/@.+/, '') + '@gmail.com';
			} else toEmail = email.toEmail;

			console.log('sending email to ' + toEmail);

		 	sendgrid.send({
			 	  to:       toEmail,
			 	  from:     'me@kabaros.com',
			 	  subject:  email.subject,
			 	  html:     email.emailBody,
			 	}, function(err, json) {
			 	  if (err) {
			 	   	console.error(err);
			 	   	emailsWithErrors++;
			 	   }
			 	   console.log(json);
			 	   emailsSent++;
			 	   EmailUpdate.findByIdAndUpdate(email._id, {
			 	   	isSent: true,
			 	   	opResponse: json
			 	   }, function(){
			 	   	emailsSentAndDbUpdated++;
			 	   	deferred.resolve(email);
			 	   });
			 });
			return deferred.promise;

		})).then(function(emails){
			res.jsonp(200, {
				emailsSent: emailsSent,
				emailsWithErrors: emailsWithErrors,
				emailsSentAndDbUpdated: emailsSentAndDbUpdated
			});
		});
	});
};

<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {Card, CardHeader, CardMedia} from 'material-ui/Card';
import { push } from 'react-router-redux'
import { connect } from 'react-redux'

import './index.css'
import { symbols } from '../../elements'

const style = {
  height: '90%',
  width: '90%',
  margin: 20,
  textAlign: 'center',
  //display: 'inline-block',
};

const cardHeaderStyle = {
  textAlign: 'left',
}

const cardMediaStyle = {
  width: '40%',
  margin: 20,
  display: 'inline-block'
};

class SearchResult extends Component {

  onTouchTap = () => {
    this.props.dispatch(push(`/tomo/${this.props._id}`))
  }

  render = () => {
    const imageUrl = `${window.location.origin}/api/v1/file/${this.props.imageFileId}/download`;
    const species = this.props.atomicSpecies.map((an) => symbols[an]).join(', ');
    const speciesText = `Atomic Species: ${species}`;
    return (
      <Card style={style} zDepth={2} onTouchTap={this.onTouchTap}>
        <CardHeader
          style={cardHeaderStyle}
          title={this.props.title}
          subtitle={speciesText}
        />
        <CardMedia style={cardMediaStyle}>

        </CardMedia>
      </Card>
    );
  }
}

SearchResult.propTypes = {
  _id: PropTypes.string,
  title: PropTypes.string,
  authors: PropTypes.array,
  imageFileId:  PropTypes.string,
}

SearchResult.defaultProps = {
}

function mapStateToProps(state) {
  return {};
}

export default connect(mapStateToProps)(SearchResult)
<commit_msg>Remove unecessary padding<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {Card, CardHeader, CardMedia} from 'material-ui/Card';
import { push } from 'react-router-redux'
import { connect } from 'react-redux'

import './index.css'
import { symbols } from '../../elements'

const style = {
  height: '90%',
  width: '90%',
  margin: 20,
  textAlign: 'center',
  //display: 'inline-block',
};

const cardHeaderStyle = {
  textAlign: 'left'
}

const textStyle = {
  paddingRight: '0px'
}

const cardMediaStyle = {
  width: '40%',
  margin: 20,
  display: 'inline-block'
};

class SearchResult extends Component {

  onTouchTap = () => {
    this.props.dispatch(push(`/tomo/${this.props._id}`))
  }

  render = () => {
    const imageUrl = `${window.location.origin}/api/v1/file/${this.props.imageFileId}/download`;
    const species = this.props.atomicSpecies.map((an) => symbols[an]).join(', ');
    const speciesText = `Atomic Species: ${species}`;
    return (
      <Card style={style} zDepth={2} onTouchTap={this.onTouchTap}>
        <CardHeader
          style={cardHeaderStyle}
          textStyle={textStyle}
          title={this.props.title}
          subtitle={speciesText}
        />
        <CardMedia style={cardMediaStyle}>

        </CardMedia>
      </Card>
    );
  }
}

SearchResult.propTypes = {
  _id: PropTypes.string,
  title: PropTypes.string,
  authors: PropTypes.array,
  imageFileId:  PropTypes.string,
}

SearchResult.defaultProps = {
}

function mapStateToProps(state) {
  return {};
}

export default connect(mapStateToProps)(SearchResult)
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import {Table} from 'react-bootstrap'

import Fieldset from 'components/Fieldset'
import LinkTo from 'components/LinkTo'

export default class OrganizationApprovals extends Component {
	render() {
		let org = this.props.organization
		let approvalSteps = org.approvalSteps

		return <Fieldset id="approvals" title="Approval process">
			{approvalSteps.map((step, idx) =>
				<Fieldset title={`Step ${idx + 1}: ${step.name}`} key={'step_' + idx}>

								Name
								Position

							{step.approvers.map((position, approverIdx) =>
								<tr key={position.uuid} id={`step_${idx}_approver_${approverIdx}`} >
									{position.person && <LinkTo person={position.person} />}
									<LinkTo position={position} />

							)}

				</Fieldset>
			)}

			{approvalSteps.length === 0 && This organization doesn't have any approval steps}
		</Fieldset>
	}
}
<commit_msg>NCI-Agency/anet#362: Mark vacant positions in approval steps as ‘Unfilled’<commit_after>import React, {Component} from 'react'
import {Table} from 'react-bootstrap'

import Fieldset from 'components/Fieldset'
import LinkTo from 'components/LinkTo'

export default class OrganizationApprovals extends Component {
	render() {
		let org = this.props.organization
		let approvalSteps = org.approvalSteps

		return <Fieldset id="approvals" title="Approval process">
			{approvalSteps.map((step, idx) =>
				<Fieldset title={`Step ${idx + 1}: ${step.name}`} key={'step_' + idx}>

								Name
								Position

							{step.approvers.map((position, approverIdx) =>
								<tr key={position.uuid} id={`step_${idx}_approver_${approverIdx}`} >
									{(position.person && position.person.uuid)
										? {position.person && <LinkTo person={position.person} />}
										: Unfilled	}
									<LinkTo position={position} />

							)}

				</Fieldset>
			)}

			{approvalSteps.length === 0 && This organization doesn't have any approval steps}
		</Fieldset>
	}
}
<|endoftext|>


<commit_before>import { ScrollContainer as OriginalScrollContainer } from 'react-router-scroll-4';

// ScrollContainer is used to automatically scroll to the top when pushing a
// new history state and remembering the scroll position when going back.
// There are a few things we need to do differently, though.
const defaultShouldUpdateScroll = (prevRouterProps, { location }) => {
  return !(prevRouterProps?.location?.state?.mastodonModalKey || location.state?.mastodonModalKey);
}

export default
class ScrollContainer extends OriginalScrollContainer {
  static defaultProps = {
    shouldUpdateScroll: defaultShouldUpdateScroll,
  };
}
<commit_msg>Small scroll/history behavior fixup to take weird browser patterns into account<commit_after>import { ScrollContainer as OriginalScrollContainer } from 'react-router-scroll-4';

// ScrollContainer is used to automatically scroll to the top when pushing a
// new history state and remembering the scroll position when going back.
// There are a few things we need to do differently, though.
const defaultShouldUpdateScroll = (prevRouterProps, { location }) => {
  // If the change is caused by opening a modal, do not scroll to top
  return !(location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey);
}

export default
class ScrollContainer extends OriginalScrollContainer {
  static defaultProps = {
    shouldUpdateScroll: defaultShouldUpdateScroll,
  };
}
<|endoftext|>


<commit_before>var config = require('./config.js');
var SyncService = require('ninya-sync-elasticsearch');

var syncService = new SyncService({
    batchSize: 350,
    tableName: 'users',
    elasticsearchIndex: 'production_v4',
    stackexchangeSite: 'stackoverflow',
    dbConnectionString: config.dbConnectionString,
    elasticsearchEndpoint: config.elasticsearchEndpoint
});

syncService
    .createIndex()
    .then(function(){
        process.exit();
    });

//let it run for a maximum of 9 minutes to not have jobs queing up
setTimeout(function(){
    process.exit();
}, 9 * 60 * 1000);<commit_msg>chore(elasticsearch): change back to sync working index<commit_after>var config = require('./config.js');
var SyncService = require('ninya-sync-elasticsearch');

var syncService = new SyncService({
    batchSize: 350,
    tableName: 'users_working',
    elasticsearchIndex: 'production_v4',
    stackexchangeSite: 'stackoverflow',
    dbConnectionString: config.dbConnectionString,
    elasticsearchEndpoint: config.elasticsearchEndpoint
});

syncService
    .createIndex()
    .then(function(){
        process.exit();
    });

//let it run for a maximum of 9 minutes to not have jobs queing up
setTimeout(function(){
    process.exit();
}, 9 * 60 * 1000);<|endoftext|>


<commit_before>var app = angular.module('ngRouteAnimationManager', ['ngAnimate']);

app.run(['$rootScope', 'RouteAnimationManager', function($rootScope, RouteAnimationManager) {
  $rootScope.$on('$routeChangeStart', function(scope, next, current) {
    RouteAnimationManager.setAnimationClass(current, next );
  });

  $rootScope.RouteAnimationManager = {
    animationClass : RouteAnimationManager.animationClass
  };
}]);

app.provider('RouteAnimationManager', function()  {

  //private vars
  var _defaultAnimation = '';
  var _animationClass = { name:''};

  //configurable function
  this.setDefaultAnimation = function(animation) {
    _defaultAnimation = animation;
  };

  //return factory instance
  this.$get = function() {
    return new RouteAnimationManager();
  };

  //define factory instance
  function RouteAnimationManager() {
    this.setAnimationClass =  function(currentRoute, nextRoute) {

      if (!currentRoute || !nextRoute || !nextRoute.originalPath || !nextRoute.data || !nextRoute.data.animationConf) {return undefined;}

      console.log(currentRoute.originalPath.substring(1));

      var conf = nextRoute.data.animationConf;
      var name = currentRoute.originalPath.substring(1) || 'root'; //root refers to the '/' route

      _animationClass.name = conf[name] ||  conf.fallback || _defaultAnimation;
    };

    this.animationClass = _animationClass;
  }
});

app.directive('routeAnimationManager', function() {
  return {
    restrict: 'AE',
    transclude: true,
    replace: true,
    template: '

'
  }
});<commit_msg>Remove the log in the route animation manager.<commit_after>var app = angular.module('ngRouteAnimationManager', ['ngAnimate']);

app.run(['$rootScope', 'RouteAnimationManager', function($rootScope, RouteAnimationManager) {
  $rootScope.$on('$routeChangeStart', function(scope, next, current) {
    RouteAnimationManager.setAnimationClass(current, next );
  });

  $rootScope.RouteAnimationManager = {
    animationClass : RouteAnimationManager.animationClass
  };
}]);

app.provider('RouteAnimationManager', function()  {

  //private vars
  var _defaultAnimation = '';
  var _animationClass = { name:''};

  //configurable function
  this.setDefaultAnimation = function(animation) {
    _defaultAnimation = animation;
  };

  //return factory instance
  this.$get = function() {
    return new RouteAnimationManager();
  };

  //define factory instance
  function RouteAnimationManager() {
    this.setAnimationClass =  function(currentRoute, nextRoute) {
      if (!currentRoute || !nextRoute || !nextRoute.originalPath || !nextRoute.data || !nextRoute.data.animationConf) {return undefined;}

      var conf = nextRoute.data.animationConf;
      var name = currentRoute.originalPath.substring(1) || 'root'; //root refers to the '/' route

      _animationClass.name = conf[name] ||  conf.fallback || _defaultAnimation;
    };

    this.animationClass = _animationClass;
  }
});

app.directive('routeAnimationManager', function() {
  return {
    restrict: 'AE',
    transclude: true,
    replace: true,
    template: '

'
  }
});<|endoftext|>


<commit_before>'use strict';

// Assign env variables
Object.assign(process.env, require('./app/env.json'));

// Modules to control application life and create native browser window
const path = require('path');
const { app, Menu, protocol } = require('electron');
const log = require('electron-log');
const pkg = require('./package.json');
const { isMas, isWindows, isLinux } = require('./lib/constants');
const menuTemplate = require('./lib/menu');
const openWindow = require('./lib/openWindow');
const Sentry = require('@sentry/electron');
const updater = require('./lib/updater');

if (process.env.NODE_ENV === 'production') {
  log.transports.file.level = false;
}

if (require('electron-squirrel-startup')) return;

// Suppress deprecation warning
app.allowRendererProcessReuse = true;

if (isWindows) {
  app.setAboutPanelOptions({
    iconPath: path.join(__dirname, 'resources/64x64.png'),
  });
}

if (isLinux) {
  app.setAboutPanelOptions({
    applicationName: app.name,
    applicationVersion: app.getVersion(),
    website: pkg.homepage,
    iconPath: path.join(__dirname, 'resources/64x64.png'),
  });
}

const lock = app.requestSingleInstanceLock();

// https://github.com/electron/electron/issues/15958
if (!isMas && !lock) {
  app.quit();
}
// Init crashReporter
Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.SENTRY_ENVIRONMENT,
  release: process.env.RELEASE,
});

// Set up Application Menu
const menu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menu);

if (!app.isDefaultProtocolClient('coinspace')) {
  // Define custom protocol handler. Deep linking works on packaged versions of the application!
  app.setAsDefaultProtocolClient('coinspace');
}

// The application has finished basic startup
app.on('will-finish-launching', () => {
  // Protocol handler for macOS
  app.on('open-url', (event, url) => {
    event.preventDefault();
    openWindow(url);
  });
});

// Someone tried to run a second instance
app.on('second-instance', (event, argv) => {
  openWindow(argv.find(item => item.startsWith('coinspace')));
});

// 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.whenReady().then(() => {
  protocol.registerStringProtocol('coinspace', (request, cb) => {
    openWindow(request.url);
    cb('ok');
  });
  openWindow();
  updater({ log });

  app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    openWindow();
  });
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS 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();
  }
});
<commit_msg>fix(electron): revert return statement<commit_after>'use strict';

// Assign env variables
Object.assign(process.env, require('./app/env.json'));

// Modules to control application life and create native browser window
const path = require('path');
const { app, Menu, protocol } = require('electron');
const log = require('electron-log');
const pkg = require('./package.json');
const { isMas, isWindows, isLinux } = require('./lib/constants');
const menuTemplate = require('./lib/menu');
const openWindow = require('./lib/openWindow');
const Sentry = require('@sentry/electron');
const updater = require('./lib/updater');

if (process.env.NODE_ENV === 'production') {
  log.transports.file.level = false;
}

if (require('electron-squirrel-startup')) return;

// Suppress deprecation warning
app.allowRendererProcessReuse = true;

if (isWindows) {
  app.setAboutPanelOptions({
    iconPath: path.join(__dirname, 'resources/64x64.png'),
  });
}

if (isLinux) {
  app.setAboutPanelOptions({
    applicationName: app.name,
    applicationVersion: app.getVersion(),
    website: pkg.homepage,
    iconPath: path.join(__dirname, 'resources/64x64.png'),
  });
}

const lock = app.requestSingleInstanceLock();

// https://github.com/electron/electron/issues/15958
if (!isMas && !lock) {
  app.quit();
  return;
}

// Init crashReporter
Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.SENTRY_ENVIRONMENT,
  release: process.env.RELEASE,
});

// Set up Application Menu
const menu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menu);

if (!app.isDefaultProtocolClient('coinspace')) {
  // Define custom protocol handler. Deep linking works on packaged versions of the application!
  app.setAsDefaultProtocolClient('coinspace');
}

// The application has finished basic startup
app.on('will-finish-launching', () => {
  // Protocol handler for macOS
  app.on('open-url', (event, url) => {
    event.preventDefault();
    openWindow(url);
  });
});

// Someone tried to run a second instance
app.on('second-instance', (event, argv) => {
  openWindow(argv.find(item => item.startsWith('coinspace')));
});

// 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.whenReady().then(() => {
  protocol.registerStringProtocol('coinspace', (request, cb) => {
    openWindow(request.url);
    cb('ok');
  });
  openWindow();
  updater({ log });

  app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    openWindow();
  });
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS 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();
  }
});
<|endoftext|>