<commit_before>// This is main process of Electron, started as first thing when your
// app starts. This script is running through entire life of your application.
// It doesn't have any windows which you can see on screen, but we can open
// window from here.

import path from 'path';
import url from 'url';
import { app, Menu, Tray } from 'electron';
import { devMenuTemplate } from './menu/dev_menu_template';
import { editMenuTemplate } from './menu/edit_menu_template';
import createWindow from './helpers/window';

// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from './env';

const setApplicationMenu = () => {
    const menus = [editMenuTemplate];
    if (env.name !== 'production') {
        menus.push(devMenuTemplate);
    }
    Menu.setApplicationMenu(Menu.buildFromTemplate(menus));
};

let mainWindow = null;
let tray = null;
const setTrayMenu = () => {
    tray = new Tray(path.join(__dirname, '/assets/icon.png'));
    const contextMenu = Menu.buildFromTemplate([
        {
            label: 'Open',
            click: () => {
                mainWindow.show();
            }
        },
        {
            label: 'Quit',
            click: () => {
                app.isQuiting = true;
                app.quit();
            }
        }
    ]);
    tray.setToolTip('wpdivbek');
    tray.setContextMenu(contextMenu);
};

// Save userData in separate folders for each environment.
// Thanks to this you can use production and development versions of the app
// on same machine like those are two separate apps.
if (env.name !== 'production') {
    const userDataPath = app.getPath('userData');
    app.setPath('userData', `${userDataPath} (${env.name})`);
}

app.on('ready', () => {
    setApplicationMenu();
    setTrayMenu();

    mainWindow = createWindow('main', {
        width: 1000,
        height: 600,
    });

    mainWindow.loadURL(url.format({
        pathname: path.join(__dirname, 'app.html'),
        protocol: 'file:',
        slashes: true,
    }));

    mainWindow.on('minimize', function(event) {
        event.preventDefault()
        mainWindow.hide();
    });

    mainWindow.on('close', function(event) {
        if (!app.isQuiting) {
            event.preventDefault()
            mainWindow.hide();
        }
        return false;
    });

    if (env.name === 'development') {
        mainWindow.openDevTools();
    }
});

app.on('window-all-closed', () => {
    app.quit();
});
<commit_msg>feat(app): only allow one instance<commit_after>// This is main process of Electron, started as first thing when your
// app starts. This script is running through entire life of your application.
// It doesn't have any windows which you can see on screen, but we can open
// window from here.

import path from 'path';
import url from 'url';
import { app, Menu, Tray } from 'electron';
import { devMenuTemplate } from './menu/dev_menu_template';
import { editMenuTemplate } from './menu/edit_menu_template';
import createWindow from './helpers/window';

// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from './env';

const setApplicationMenu = () => {
    const menus = [editMenuTemplate];
    if (env.name !== 'production') {
        menus.push(devMenuTemplate);
    }
    Menu.setApplicationMenu(Menu.buildFromTemplate(menus));
};

let mainWindow = null;
let tray = null;
const setTrayMenu = () => {
    tray = new Tray(path.join(__dirname, '/assets/icon.png'));
    const contextMenu = Menu.buildFromTemplate([
        {
            label: 'Open',
            click: () => {
                mainWindow.show();
            }
        },
        {
            label: 'Quit',
            click: () => {
                app.isQuiting = true;
                app.quit();
            }
        }
    ]);
    tray.setToolTip('wpdivbek');
    tray.setContextMenu(contextMenu);
};

// Save userData in separate folders for each environment.
// Thanks to this you can use production and development versions of the app
// on same machine like those are two separate apps.
if (env.name !== 'production') {
    const userDataPath = app.getPath('userData');
    app.setPath('userData', `${userDataPath} (${env.name})`);
}

var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
  // Someone tried to run a second instance, we should focus our window.
  if (mainWindow) {
    if (mainWindow.isMinimized()) {
        // mainWindow.restore();
        mainWindow.show();
    }
    mainWindow.focus();
  }
});

if (shouldQuit) {
  app.quit();
}else{

    app.on('ready', () => {
        setApplicationMenu();
        setTrayMenu();

        mainWindow = createWindow('main', {
            width: 1000,
            height: 600,
        });

        mainWindow.loadURL(url.format({
            pathname: path.join(__dirname, 'app.html'),
            protocol: 'file:',
            slashes: true,
        }));

        mainWindow.on('minimize', function(event) {
            event.preventDefault()
            mainWindow.hide();
        });

        mainWindow.on('close', function(event) {
            if (!app.isQuiting) {
                event.preventDefault()
                mainWindow.hide();
            }
            return false;
        });

        if (env.name === 'development') {
            mainWindow.openDevTools();
        }
    });

    app.on('window-all-closed', () => {
        app.quit();
    });

}<|endoftext|>


<commit_before>(function($){
    function fetch(){
        var projects = config.getActiveProjects();
        var ajaxProjectEvents = [];
        var recentEvents = config.getRecentEvents();
        var notificationCount = 0;

        var notifiedHistories = [];
        $.each(projects, function(projectId, project){
            var df = gitlab.getProjectEvents(projectId).done(function(projectEvents){
                // latest check
                if(projectEvents.length < 1){
                    return;
                }

                var latest = projectEvents[0];
                var recent = recentEvents[projectId];

                if(!recent){
                    recentEvents[projectId] = latest;

                    // Not show notification when first running
                    return;
                }

                if(isSameEvent(latest, recent)){
                    // not changed
                   return;
                }
                recentEvents[projectId] = latest;

                var eventCount = 0;
                $.each(projectEvents, function(index, projectEvent){
                    if(isSameEvent(projectEvent, recent)){
                        return false;
                    }
                    var configEvents = projects[projectId].events;
                    if(configEvents[projectEvent.target_type]){
                        if(eventCount >= config.getMaxEventCount()){
                            return false;
                        }
                        eventCount++;
                        var message = "[" + projectEvent.target_type + "] #" + projectEvent.target_id + " " + projectEvent.target_title +  " " + projectEvent.action_name;
                        var notificationId = gitlab.getEventUrl(projectEvent) + ";" + (new Date()).getTime();
                        projectEvent.project_name = projects[projectEvent.project_id].name;
                        projectEvent.notified_at = new Date();
                        chrome.notifications.create(
                            notificationId,
                            {
                                type:     "basic",
                                iconUrl:  "img/gitlab-icon.png",
                                title:    projectEvent.project_name,
                                message:  message,
                                priority: 0
                            },
                            function(notificationId){
//                                alert("failed notification: " + notificationId);
                            }
                        );
                        notifiedHistories.push(projectEvent);

                        notificationCount++;
                        showNotificationCount(notificationCount);
                    }
                });
            });
            ajaxProjectEvents.push(df);
        });

        $.when.apply(null, ajaxProjectEvents).then(function(){
            config.addNotifiedHistories(notifiedHistories);
            config.setRecentEvents(recentEvents);
        });
    }

    function isSameEvent(event1, event2){
        return event1.target_id == event2.target_id && event1.target_type == event2.target_type && event1.action_name == event2.action_name;
    }

    function showNotificationCount(count){
        chrome.browserAction.setBadgeText({text: String(count)});
    }

    $(document).ready(function(){
        chrome.notifications.onClicked.addListener(function(notificationId){
            var url = notificationId.split(";", 2)[0];
            chrome.tabs.create({'url': url});
        });

        chrome.browserAction.setBadgeText({text: ""});
        fetch();
        setInterval(function(){
            fetch();
        }, config.getPollingSecond() * 1000);
    });
})(jQuery);
<commit_msg>modify: open iid url at notification<commit_after>(function($){
    function fetch(){
        var projects = config.getActiveProjects();
        var ajaxProjectEvents = [];
        var recentEvents = config.getRecentEvents();
        var notificationCount = 0;

        var notifiedHistories = [];
        $.each(projects, function(projectId, project){
            var df = gitlab.getProjectEvents(projectId).done(function(projectEvents){
                // latest check
                if(projectEvents.length < 1){
                    return;
                }

                var latest = projectEvents[0];
                var recent = recentEvents[projectId];

                if(!recent){
                    recentEvents[projectId] = latest;

                    // Not show notification when first running
                    return;
                }

                if(isSameEvent(latest, recent)){
                    // not changed
                   return;
                }
                recentEvents[projectId] = latest;

                var eventCount = 0;
                $.each(projectEvents, function(index, projectEvent){
                    if(isSameEvent(projectEvent, recent)){
                        return false;
                    }
                    var configEvents = projects[projectId].events;
                    if(configEvents[projectEvent.target_type]){
                        if(eventCount >= config.getMaxEventCount()){
                            return false;
                        }
                        eventCount++;
                        var message = "[" + projectEvent.target_type + "] #" + projectEvent.target_id + " " + projectEvent.target_title +  " " + projectEvent.action_name;
                        projectEvent.project_name = projects[projectEvent.project_id].name;
                        projectEvent.notified_at = new Date();

                        var notificationId =  JSON.stringify({
                            project_name: projectEvent.project_name,
                            target_type:  projectEvent.target_type,
                            target_id:    projectEvent.target_id,
                            notified_at:  (new Date()).getTime()
                        });

                        chrome.notifications.create(
                            notificationId,
                            {
                                type:     "basic",
                                iconUrl:  "img/gitlab-icon.png",
                                title:    projectEvent.project_name,
                                message:  message,
                                priority: 0
                            },
                            function(notificationId){
//                                alert("failed notification: " + notificationId);
                            }
                        );
                        notifiedHistories.push(projectEvent);

                        notificationCount++;
                        showNotificationCount(notificationCount);
                    }
                });
            });
            ajaxProjectEvents.push(df);
        });

        $.when.apply(null, ajaxProjectEvents).then(function(){
            config.addNotifiedHistories(notifiedHistories);
            config.setRecentEvents(recentEvents);
        });
    }

    function isSameEvent(event1, event2){
        return event1.target_id == event2.target_id && event1.target_type == event2.target_type && event1.action_name == event2.action_name;
    }

    function showNotificationCount(count){
        chrome.browserAction.setBadgeText({text: String(count)});
    }

    $(document).ready(function(){
        chrome.notifications.onClicked.addListener(function(notificationId){
            // open event page
            gitlab.getEventInternalUrl(JSON.parse(notificationId), function(url){
                chrome.tabs.create({url: url});
            });
        });

        chrome.browserAction.setBadgeText({text: ""});
        fetch();
        setInterval(function(){
            fetch();
        }, config.getPollingSecond() * 1000);
    });
})(jQuery);
<|endoftext|>


<commit_before>var initDone = false;
var peer = RulePeer.getInstance();
var wordPeer = WordPeer.getInstance();
var existingTabs = new Array();
var tabBadgeMap = new Array(); /* tabId, badgeCount */

/**
 * Initialization
 */
function onStart ()
{
	updateDbIfNeeded(createRuleTable);
}
function createRuleTable ()
{
	console.log("createRuleTable");
	peer.createTable(createWordTable);
}
function createWordTable ()
{
	wordPeer.createTable(loadLists);
}
function loadLists (callback)
{
	peer.select('', onRuleListLoaded, null);
}
function onRuleListLoaded (list)
{
	var count = '' + list.length;
	Analytics.trackEvent('loadRuleList', count);
	ruleList = list;
	wordPeer.select('', onWordListLoaded, null);
}
function removeFromExistingTabList (tabIdToRemove)
{
	for (var id in existingTabs)
	{
		if (tabIdToRemove==id) existingTabs[id] = null;
	}
}
function addToExistingTabList (tabIdToAdd)
{
	existingTabs[tabIdToAdd] = true;
}
function onWordListLoaded (wordList)
{
	var count = '' + wordList.length;
	Analytics.trackEvent('loadWordList', count);
	var ruleMap = new Array();
	for (var i=0, l=ruleList.length; i<l; i++)
	{
		ruleMap[ruleList[i].rule_id] = ruleList[i];
	}
	for (var i = 0, l = wordList.length; i < l; i++)
	{
		var rule = ruleMap[wordList[i].rule_id];
		if (rule)
		{
			rule.words.push(wordList[i]);
		}
	}
	loadRulePickerSrc();
	saveUuidIfNotSet();
}

function saveUuidIfNotSet ()
{
	for (var i=0; i<ruleList.length; i++)
	{
		var rule = ruleList[i];
		var needSave = false;
		if (CustomBlockerUtil.isEmpty(rule.user_identifier))
		{
			needSave = true;
			rule.user_identifier = UUID.generate();
		}
		if (CustomBlockerUtil.isEmpty(rule.global_identifier))
		{
			needSave = true;
			rule.global_identifier = UUID.generate();
		}
		if (needSave)
		{
		peer.saveObject(rule, function ()
			{
				var bgWindow = chrome.extension.getBackgroundPage();
				bgWindow.reloadLists();
			});
		}
	}
}

function reloadLists ()
{
	loadLists();
}
function openRulePicker (selectedRule)
{
	var status = (selectedRule)?'edit':'create';
	Analytics.trackEvent('openRulePicker', status);
	try
	{
		chrome.tabs.getSelected(null,function(tab)
		{
			chrome.tabs.sendRequest(tab.id,
			{
				command: 'ruleEditor',
				src: rulePickerSrc,
				rule: selectedRule,
				appliedRuleList: appliedRuleMap[tab.id]
			}, getForegroundCallback(tab.id));
		});
	}
	catch (ex) {console.log(ex)}
}
var tabOnUpdate = function(tabId, changeInfo, tab)
{
	addToExistingTabList(tabId);
	// ON/OFF
	var isDisabled = ('true' == localStorage.blockDisabled);
	_setIconDisabled(isDisabled, tabId);
	if (isDisabled) {
		return;
	}
	var url = tab.url;
	if (isValidURL(url) && changeInfo.status == "complete")
	{
		chrome.tabs.sendRequest(tabId,
		{
			command:'init',
			rules: ruleList,
			tabId: tabId
		},
		getForegroundCallback (tabId)
		);
	}
}
var VALID_URL_REGEX = new RegExp('^https?:');
function isValidURL (url)
{
	return  url && url.match(VALID_URL_REGEX);
}

function getForegroundCallback (tabId)
{
	return function(param)
	{
		if (!param) return;
		var useCallback = false;
		switch (param.command)
		{
			case 'badge':
				execCallbackBadge(tabId, param);
				break;
			case 'setApplied':
				execCallbackSetApplied(tabId, param);
				break;
			case 'db':
				useCallback = true;
				execCallbackDb(tabId, param);
				break;
			case 'reload':
				useCallback = true;
				execCallbackReload(tabId, param);
				break;
		}

		// Set callback
		if (!useCallback)
		{
			chrome.tabs.sendRequest(tabId,
			{
				command: (param.nextAction || 'badge')
			}, getForegroundCallback (tabId));
		}
	};

};
function execCallbackReload (tabId, param)
{
	chrome.tabs.sendRequest(tabId,
	{
		command: (param.nextAction),
		rules: ruleList
	}, getForegroundCallback (tabId));

}
function execCallbackDb (tabId, param)
{
	try
	{
		var exPeer;
		if ('save' == param.dbCommand)
		{
			Analytics.trackEvent('save', 'save');
			var rule =param.obj;
			var saveRuleTask = new SaveRuleTask(rule, reloadLists, tabId);
			saveRuleTask.exec(param.nextAction);
		}
	}
	catch (e)
	{
		console.log(e)
	}
}
function execCallbackSetApplied (tabId, param)
{
	var list = param.list || new Array();
	try
	{
		chrome.browserAction.setIcon(
			{
				path:((list.length>0)?'icon.png':'icon_disabled.png'),
				tabId:tabId
			});
	}
	catch (ex)
	{
		console.log(ex);
	}
	appliedRuleMap[tabId] = list;

};
function execCallbackBadge (tabId, param)
{
	var count = param.count;
	try {
		var badgeText = ''+count;
		tabBadgeMap[tabId] = badgeText;
		chrome.browserAction.setBadgeText({
			text: badgeText,
			tabId: tabId
		});
		chrome.browserAction.setTitle({
			title: getBadgeTooltipString(count),
			tabId:tabId
		});
		appliedRuleMap[tabId] = param.rules;
	} catch (ex)
	{
		console.log(ex)
	}

}
function getAppliedRules (callback)
{
	chrome.tabs.getSelected(null,function(tab)
	{
		try
		{
			callback(appliedRuleMap[tab.id]);
		}
		catch (ex) {console.log(ex)}
	});

}
var rulePickerSrc = '';
var smartRuleEditorSrc = '';
function loadRulePickerSrc()
{
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function()
	{
		if (xhr.readyState==4)
		{
			if (xhr.status==0 || xhr.status==200)
			{
				rulePickerSrc = xhr.responseText;
				loadSmartRuleEditorSrc();
			}
		}
	}
	xhr.open("GET", chrome.extension.getURL('/rule_editor_'+chrome.i18n.getMessage("extLocale")+'.html'), true);
	xhr.send();
}
function loadSmartRuleEditorSrc()
{
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function()
	{
		if (xhr.readyState==4)
		{
			if (xhr.status==0 || xhr.status==200)
			{
				smartRuleEditorSrc = xhr.responseText;
			}
		}
	}
	xhr.open("GET", chrome.extension.getURL('/smart_rule_editor_'+chrome.i18n.getMessage("extLocale")+'.html'), true);
	xhr.send();
}

var SaveRuleTask = function (rule, reloadLists, tabId)
{
	var saveWords = new Array();
	var deleteWords = new Array();

	for (var i=0, l=rule.words.length; i<l; i++)
	{
		var word = rule.words[i];
		if (word.isNew)
		{
			saveWords.push(word);
		}
		else if (word.deleted)
		{
			deleteWords.push(word);
		}
	}

	this.rule = rule;
	this.tabId = tabId;

	this.saveWords = saveWords;
	this.deleteWords = deleteWords;

	this.reloadLists /* function */ = reloadLists;
};
SaveRuleTask.prototype.exec = function (nextAction)
{
	//peer, wordPeer
	peer.saveObject(this.rule, this.getNextTask(nextAction));
};
SaveRuleTask.prototype.getNextTask = function (nextAction)
{
	var self = this;
	return function ()
	{
		var nextSaveWord = self.getNextSaveWord();
		if (nextSaveWord)
		{
			wordPeer.saveObject(nextSaveWord, self.getNextTask(nextAction));
			return;
		}
		var nextDeleteWord = self.getNextDeleteWord();
		if (nextDeleteWord)
		{
			wordPeer.deleteObject(nextDeleteWord, self.getNextTask(nextAction));
			return;
		}
		chrome.tabs.sendRequest(self.tabId,
		{
			command:nextAction,
			rules: ruleList,
			tabId: self.tabId,
			rule: self.rule
		}
		, getForegroundCallback(self.tabId)
		);
		self.reloadLists();
	}
};
SaveRuleTask.prototype.getNextSaveWord = function ()
{
	for (var i=0, l=this.saveWords.length; i<l; i++)
	{
		var word = this.saveWords[i];
		if (word.dirty)
		{
			word.rule_id = this.rule.rule_id;
			return word;
		}
	}
	return null;
};
SaveRuleTask.prototype.getNextDeleteWord = function ()
{
	for (var i=0, l=this.deleteWords.length; i<l; i++)
	{
		var word = this.deleteWords[i];
		if (word.dirty)
		{
			word.rule_id = this.rule.rule_id;
			return word;
		}
	}
};

var ruleList = new Array();
var appliedRuleMap = new Array();
if (!chrome.tabs.customBlockerOnUpdateSet)
{
	chrome.tabs.onUpdated.addListener(tabOnUpdate);
	chrome.tabs.onRemoved.addListener
		(function(tabId, removeInfo)
			{
				removeFromExistingTabList(tabId);
				appliedRuleMap[tabId] = null;
			});
	chrome.tabs.onSelectionChanged.addListener
		(function(_tabId, selectInfo)
			{
				var tabId = parseInt(_tabId);
				for (var _index in existingTabs)
				{
					var tabIdToDisable = parseInt(_index);
					if (tabIdToDisable && tabIdToDisable!=tabId)
					{
						chrome.tabs.sendRequest(tabIdToDisable,
							{
								command: 'stop'
							}, getForegroundCallback (tabIdToDisable));
					}
				}
				try
				{
					if ('true' == localStorage.blockDisabled)
						_setIconDisabled(!applied, tabId);
					else
					{
						var applied = appliedRuleMap[tabId]
							&& appliedRuleMap[tabId].length>0;
						chrome.browserAction.setIcon(
						{
							path:(applied)?'icon.png':'icon_disabled.png',
							tabId:tabId
						});

					}
					chrome.tabs.sendRequest(tabId,
						{
							command: 'resume'
						}, getForegroundCallback(tabId));
					if (tabBadgeMap[tabId])
					{
						chrome.browserAction.setBadgeText({
							text: tabBadgeMap[tabId],
							tabId: tabId
						});
					}
				}
				catch (ex) {console.log(ex);}
			});
}
function setIconDisabled (isDisabled)
{
	chrome.tabs.getSelected(null,function(tab)
	{
		_setIconDisabled(isDisabled,tab.id);
	});
}
function _setIconDisabled (isDisabled, tabId)
{
	chrome.browserAction.setBadgeText({
		text:(isDisabled)?'OFF':'',
		tabId: tabId
	});
	chrome.browserAction.setIcon(
	{
		path:(isDisabled)?'icon_disabled.png':'icon.png',
		tabId:tabId
	});

}
function highlightRuleElements (rule)
{
	chrome.tabs.getSelected(null,function(tab)
		{
			chrome.tabs.sendRequest(tab.id,
				{
					command: 'highlight',
					rule: rule
				}, getForegroundCallback(tab.id));
		});
}
function getBadgeTooltipString (count) {
	if (count > 1)
		return chrome.i18n.getMessage("tooltipCount").replace("__count__",count);
	else
		return chrome.i18n.getMessage("tooltipCountSingle");
}
chrome.tabs.customBlockerOnUpdateSet = true;
onStart();

function menuCreateOnRightClick(clicked, tab) {
	sendQuickRuleCreationRequest(clicked, tab, true);
	Analytics.trackEvent('contextMenu', 'create');
};

function menuAddOnRightClick(clicked, tab) {
	sendQuickRuleCreationRequest(clicked, tab, false);
	Analytics.trackEvent('contextMenu', 'add');
};

function sendQuickRuleCreationRequest (clicked, tab, needSuggestion) {
	chrome.tabs.sendRequest(
			tab.id,
			{
				command: 'quickRuleCreation',
				src: smartRuleEditorSrc,
				appliedRuleList: appliedRuleMap[tab.id],
				selectionText: clicked.selectionText,
				needSuggestion: needSuggestion
			},
			getForegroundCallback(tab.id)
		);
};

var menuIdCreate = chrome.contextMenus.create({"title": chrome.i18n.getMessage('menuCreateRule'), "contexts":["selection"],
	"onclick": menuCreateOnRightClick});
var menuIdAdd = chrome.contextMenus.create({"title": chrome.i18n.getMessage('menuAddToExistingRule'), "contexts":["selection"],
	"onclick": menuAddOnRightClick});

chrome.runtime.onInstalled.addListener(function(details) {
	console.log("reason=" + details.reason);
	console.log("previousVersion=" + details.previousVersion);
	if ("install"==details.reason) { //TODO debug
		console.log("New install.");
		window.open(chrome.extension.getURL('/welcome_install_'+chrome.i18n.getMessage("extLocale")+'.html'));
	}
	else if (details.reason=="update" && details.previousVersion && details.previousVersion.match(/^2\.3\./)) {
		window.open(chrome.extension.getURL('/welcome_'+chrome.i18n.getMessage("extLocale")+'.html'));
	}
});
<commit_msg>Add flag<commit_after>var initDone = false;
var peer = RulePeer.getInstance();
var wordPeer = WordPeer.getInstance();
var existingTabs = new Array();
var tabBadgeMap = new Array(); /* tabId, badgeCount */

/**
 * Initialization
 */
function onStart ()
{
	updateDbIfNeeded(createRuleTable);
}
function createRuleTable ()
{
	console.log("createRuleTable");
	peer.createTable(createWordTable);
}
function createWordTable ()
{
	wordPeer.createTable(loadLists);
}
function loadLists (callback)
{
	peer.select('', onRuleListLoaded, null);
}
function onRuleListLoaded (list)
{
	var count = '' + list.length;
	Analytics.trackEvent('loadRuleList', count);
	ruleList = list;
	wordPeer.select('', onWordListLoaded, null);
}
function removeFromExistingTabList (tabIdToRemove)
{
	for (var id in existingTabs)
	{
		if (tabIdToRemove==id) existingTabs[id] = null;
	}
}
function addToExistingTabList (tabIdToAdd)
{
	existingTabs[tabIdToAdd] = true;
}
function onWordListLoaded (wordList)
{
	var count = '' + wordList.length;
	Analytics.trackEvent('loadWordList', count);
	var ruleMap = new Array();
	for (var i=0, l=ruleList.length; i<l; i++)
	{
		ruleMap[ruleList[i].rule_id] = ruleList[i];
	}
	for (var i = 0, l = wordList.length; i < l; i++)
	{
		var rule = ruleMap[wordList[i].rule_id];
		if (rule)
		{
			rule.words.push(wordList[i]);
		}
	}
	loadRulePickerSrc();
	saveUuidIfNotSet();
}

function saveUuidIfNotSet ()
{
	for (var i=0; i<ruleList.length; i++)
	{
		var rule = ruleList[i];
		var needSave = false;
		if (CustomBlockerUtil.isEmpty(rule.user_identifier))
		{
			needSave = true;
			rule.user_identifier = UUID.generate();
		}
		if (CustomBlockerUtil.isEmpty(rule.global_identifier))
		{
			needSave = true;
			rule.global_identifier = UUID.generate();
		}
		if (needSave)
		{
		peer.saveObject(rule, function ()
			{
				var bgWindow = chrome.extension.getBackgroundPage();
				bgWindow.reloadLists();
			});
		}
	}
}

function reloadLists ()
{
	loadLists();
}
function openRulePicker (selectedRule)
{
	var status = (selectedRule)?'edit':'create';
	Analytics.trackEvent('openRulePicker', status);
	try
	{
		chrome.tabs.getSelected(null,function(tab)
		{
			chrome.tabs.sendRequest(tab.id,
			{
				command: 'ruleEditor',
				src: rulePickerSrc,
				rule: selectedRule,
				appliedRuleList: appliedRuleMap[tab.id]
			}, getForegroundCallback(tab.id));
		});
	}
	catch (ex) {console.log(ex)}
}
var tabOnUpdate = function(tabId, changeInfo, tab)
{
	addToExistingTabList(tabId);
	// ON/OFF
	var isDisabled = ('true' == localStorage.blockDisabled);
	_setIconDisabled(isDisabled, tabId);
	if (isDisabled) {
		return;
	}
	var url = tab.url;
	if (isValidURL(url) && changeInfo.status == "complete")
	{
		chrome.tabs.sendRequest(tabId,
		{
			command:'init',
			rules: ruleList,
			tabId: tabId
		},
		getForegroundCallback (tabId)
		);
	}
}
var VALID_URL_REGEX = new RegExp('^https?:');
function isValidURL (url)
{
	return  url && url.match(VALID_URL_REGEX);
}

function getForegroundCallback (tabId)
{
	return function(param)
	{
		if (!param) return;
		var useCallback = false;
		switch (param.command)
		{
			case 'badge':
				execCallbackBadge(tabId, param);
				break;
			case 'setApplied':
				execCallbackSetApplied(tabId, param);
				break;
			case 'db':
				useCallback = true;
				execCallbackDb(tabId, param);
				break;
			case 'reload':
				useCallback = true;
				execCallbackReload(tabId, param);
				break;
		}

		// Set callback
		if (!useCallback)
		{
			chrome.tabs.sendRequest(tabId,
			{
				command: (param.nextAction || 'badge')
			}, getForegroundCallback (tabId));
		}
	};

};
function execCallbackReload (tabId, param)
{
	chrome.tabs.sendRequest(tabId,
	{
		command: (param.nextAction),
		rules: ruleList
	}, getForegroundCallback (tabId));

}
function execCallbackDb (tabId, param)
{
	try
	{
		var exPeer;
		if ('save' == param.dbCommand)
		{
			Analytics.trackEvent('save', 'save');
			var rule =param.obj;
			var saveRuleTask = new SaveRuleTask(rule, reloadLists, tabId);
			saveRuleTask.exec(param.nextAction);
		}
	}
	catch (e)
	{
		console.log(e)
	}
}
function execCallbackSetApplied (tabId, param)
{
	var list = param.list || new Array();
	try
	{
		chrome.browserAction.setIcon(
			{
				path:((list.length>0)?'icon.png':'icon_disabled.png'),
				tabId:tabId
			});
	}
	catch (ex)
	{
		console.log(ex);
	}
	appliedRuleMap[tabId] = list;

};
function execCallbackBadge (tabId, param)
{
	var count = param.count;
	try {
		var badgeText = ''+count;
		tabBadgeMap[tabId] = badgeText;
		chrome.browserAction.setBadgeText({
			text: badgeText,
			tabId: tabId
		});
		chrome.browserAction.setTitle({
			title: getBadgeTooltipString(count),
			tabId:tabId
		});
		appliedRuleMap[tabId] = param.rules;
	} catch (ex)
	{
		console.log(ex)
	}

}
function getAppliedRules (callback)
{
	chrome.tabs.getSelected(null,function(tab)
	{
		try
		{
			callback(appliedRuleMap[tab.id]);
		}
		catch (ex) {console.log(ex)}
	});

}
var rulePickerSrc = '';
var smartRuleEditorSrc = '';
function loadRulePickerSrc()
{
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function()
	{
		if (xhr.readyState==4)
		{
			if (xhr.status==0 || xhr.status==200)
			{
				rulePickerSrc = xhr.responseText;
				loadSmartRuleEditorSrc();
			}
		}
	}
	xhr.open("GET", chrome.extension.getURL('/rule_editor_'+chrome.i18n.getMessage("extLocale")+'.html'), true);
	xhr.send();
}
function loadSmartRuleEditorSrc()
{
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function()
	{
		if (xhr.readyState==4)
		{
			if (xhr.status==0 || xhr.status==200)
			{
				smartRuleEditorSrc = xhr.responseText;
			}
		}
	}
	xhr.open("GET", chrome.extension.getURL('/smart_rule_editor_'+chrome.i18n.getMessage("extLocale")+'.html'), true);
	xhr.send();
}

var SaveRuleTask = function (rule, reloadLists, tabId)
{
	var saveWords = new Array();
	var deleteWords = new Array();

	for (var i=0, l=rule.words.length; i<l; i++)
	{
		var word = rule.words[i];
		if (word.isNew)
		{
			saveWords.push(word);
		}
		else if (word.deleted)
		{
			deleteWords.push(word);
		}
	}

	this.rule = rule;
	this.tabId = tabId;

	this.saveWords = saveWords;
	this.deleteWords = deleteWords;

	this.reloadLists /* function */ = reloadLists;
};
SaveRuleTask.prototype.exec = function (nextAction)
{
	//peer, wordPeer
	peer.saveObject(this.rule, this.getNextTask(nextAction));
};
SaveRuleTask.prototype.getNextTask = function (nextAction)
{
	var self = this;
	return function ()
	{
		var nextSaveWord = self.getNextSaveWord();
		if (nextSaveWord)
		{
			wordPeer.saveObject(nextSaveWord, self.getNextTask(nextAction));
			return;
		}
		var nextDeleteWord = self.getNextDeleteWord();
		if (nextDeleteWord)
		{
			wordPeer.deleteObject(nextDeleteWord, self.getNextTask(nextAction));
			return;
		}
		chrome.tabs.sendRequest(self.tabId,
		{
			command:nextAction,
			rules: ruleList,
			tabId: self.tabId,
			rule: self.rule
		}
		, getForegroundCallback(self.tabId)
		);
		self.reloadLists();
	}
};
SaveRuleTask.prototype.getNextSaveWord = function ()
{
	for (var i=0, l=this.saveWords.length; i<l; i++)
	{
		var word = this.saveWords[i];
		if (word.dirty)
		{
			word.rule_id = this.rule.rule_id;
			return word;
		}
	}
	return null;
};
SaveRuleTask.prototype.getNextDeleteWord = function ()
{
	for (var i=0, l=this.deleteWords.length; i<l; i++)
	{
		var word = this.deleteWords[i];
		if (word.dirty)
		{
			word.rule_id = this.rule.rule_id;
			return word;
		}
	}
};

var ruleList = new Array();
var appliedRuleMap = new Array();
if (!chrome.tabs.customBlockerOnUpdateSet)
{
	chrome.tabs.onUpdated.addListener(tabOnUpdate);
	chrome.tabs.onRemoved.addListener
		(function(tabId, removeInfo)
			{
				removeFromExistingTabList(tabId);
				appliedRuleMap[tabId] = null;
			});
	chrome.tabs.onSelectionChanged.addListener
		(function(_tabId, selectInfo)
			{
				var tabId = parseInt(_tabId);
				for (var _index in existingTabs)
				{
					var tabIdToDisable = parseInt(_index);
					if (tabIdToDisable && tabIdToDisable!=tabId)
					{
						chrome.tabs.sendRequest(tabIdToDisable,
							{
								command: 'stop'
							}, getForegroundCallback (tabIdToDisable));
					}
				}
				try
				{
					if ('true' == localStorage.blockDisabled)
						_setIconDisabled(!applied, tabId);
					else
					{
						var applied = appliedRuleMap[tabId]
							&& appliedRuleMap[tabId].length>0;
						chrome.browserAction.setIcon(
						{
							path:(applied)?'icon.png':'icon_disabled.png',
							tabId:tabId
						});

					}
					chrome.tabs.sendRequest(tabId,
						{
							command: 'resume'
						}, getForegroundCallback(tabId));
					if (tabBadgeMap[tabId])
					{
						chrome.browserAction.setBadgeText({
							text: tabBadgeMap[tabId],
							tabId: tabId
						});
					}
				}
				catch (ex) {console.log(ex);}
			});
}
function setIconDisabled (isDisabled)
{
	chrome.tabs.getSelected(null,function(tab)
	{
		_setIconDisabled(isDisabled,tab.id);
	});
}
function _setIconDisabled (isDisabled, tabId)
{
	chrome.browserAction.setBadgeText({
		text:(isDisabled)?'OFF':'',
		tabId: tabId
	});
	chrome.browserAction.setIcon(
	{
		path:(isDisabled)?'icon_disabled.png':'icon.png',
		tabId:tabId
	});

}
function highlightRuleElements (rule)
{
	chrome.tabs.getSelected(null,function(tab)
		{
			chrome.tabs.sendRequest(tab.id,
				{
					command: 'highlight',
					rule: rule
				}, getForegroundCallback(tab.id));
		});
}
function getBadgeTooltipString (count) {
	if (count > 1)
		return chrome.i18n.getMessage("tooltipCount").replace("__count__",count);
	else
		return chrome.i18n.getMessage("tooltipCountSingle");
}
chrome.tabs.customBlockerOnUpdateSet = true;
onStart();

function menuCreateOnRightClick(clicked, tab) {
	sendQuickRuleCreationRequest(clicked, tab, true);
	Analytics.trackEvent('contextMenu', 'create');
};

function menuAddOnRightClick(clicked, tab) {
	sendQuickRuleCreationRequest(clicked, tab, false);
	Analytics.trackEvent('contextMenu', 'add');
};

function sendQuickRuleCreationRequest (clicked, tab, needSuggestion) {
	chrome.tabs.sendRequest(
			tab.id,
			{
				command: 'quickRuleCreation',
				src: smartRuleEditorSrc,
				appliedRuleList: appliedRuleMap[tab.id],
				selectionText: clicked.selectionText,
				needSuggestion: needSuggestion
			},
			getForegroundCallback(tab.id)
		);
};

var menuIdCreate = chrome.contextMenus.create({"title": chrome.i18n.getMessage('menuCreateRule'), "contexts":["selection"],
	"onclick": menuCreateOnRightClick});
var menuIdAdd = chrome.contextMenus.create({"title": chrome.i18n.getMessage('menuAddToExistingRule'), "contexts":["selection"],
	"onclick": menuAddOnRightClick});

chrome.runtime.onInstalled.addListener(function(details) {
	console.log("reason=" + details.reason);
	console.log("previousVersion=" + details.previousVersion);
	if ("install"==details.reason) { //TODO debug
		console.log("New install.");
		window.open(chrome.extension.getURL('/welcome_install_'+chrome.i18n.getMessage("extLocale")+'.html?install'));
	}
	else if (details.reason=="update" && details.previousVersion && details.previousVersion.match(/^2\.3\./)) {
		window.open(chrome.extension.getURL('/welcome_'+chrome.i18n.getMessage("extLocale")+'.html'));
	}
});
<|endoftext|>


<commit_before>'use strict';

var config = (() => {
	var sys = {
		impl: chrome.storage.local,
		get: (name, defaultVal) => new Promise((res) => {
			sys.impl.get(name, (confs) => {
				if (typeof name === "string") res((name in confs) ? confs[name] : defaultVal);
				else res(confs);
			});
		}),
		set: (n, v) => new Promise((res) => {
			var setObj = {};
			if (typeof n === "string") setObj[n] = v;
			else setObj = n;
			sys.impl.set(setObj, res);
		})
	};

	chrome.storage.local.get('sys.local', (items) => {
		if (!items['sys.local']) {
			sys.impl = chrome.storage.sync;
		}
	});

	return sys;
})()

function genID() {
	return (+ new Date()).toString(36) + (Math.random())
}

/////////////////////////////////////////////////////////////////////////////////////

var box = { html: '', style: '' };
var styleDefault, styleUser;

Promise.all([
	window.fetch('box/style.css').then(res => res.text()),
	config.get("user.style", "")
]).then((styles) => {
	styleDefault = styles[0];
	styleUser = styles[1];
	box.style = styleDefault + styleUser;
})

function UpdateBoxHtml(html) {
	var h =
		html.replace(/(src|href)=(["'])(.+?)\2/g, (whole, a, quote, uri) => {
			if (/^\w+\:/.test(uri)) return whole;
			return a + '=' + quote + chrome.runtime.getURL((uri[0] === "/" ? uri : "/box/" + uri)) + quote;
		})
	box.html = h;
}
window.fetch('box/box.html').then(res => res.text()).then(UpdateBoxHtml)

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
	let resp = {};
	switch (msg.type || msg) {
		case "box":
			sendResponse(box)
			break
		case "loaded_mods":
			Object.keys(loaded_mods).forEach((modName) => {
				let mod = loaded_mods[modName]
				resp[modName] = {
					id: mod.id,
					profile: mod.profile
				}
			})
			sendResponse(resp)
			break
		case "conf":
			if (!msg.data) {
				//getting
				sendResponse(conf)
			} else {
				conf = msg.data
			}
			break
	}
})

////////////////////////////////////////////////////////////////////////////

var conf = {
	mods: []
}
var loaded_mods = {}  //a dict

function handleModuleResponse(msg) {
	if (msg.type === "instance") {
		console.log("module response!", msg.instance.id, msg.instance)
		var infos = msg.instance.id.split("|") // 0: portID 1: reqID 2: order
		var port = port_cs[infos[0]]
		if (!port) return
		port.postMessage({
			id: infos[1],
			order: ~~infos[2],
			instance: msg.instance
		})
	}
}

function handleConnection(port) {
	if (port.name !== "module") return

	var inited = false;
	function onetimeCheck(message) {
		if (inited) return
		inited = true

		if (message.type !== 'profile') {
			port.disconnect()
			return
		}

		var profile = message.profile
		var id = port.sender.id + ":" + profile.id

		loaded_mods[id] = {
			id: id,
			port: port,
			profile: profile
		}

		//FIXME! DEBUG CODE! DO NOT PUBLISTH!
		conf.mods.push(id)

		port.onMessage.addListener(handleModuleResponse)
		port.onDisconnect.addListener(() => {
			delete loaded_mods[id]
		})
	}
	port.onMessage.addListener(onetimeCheck)
}

chrome.runtime.onConnect.addListener(handleConnection)
chrome.runtime.onConnectExternal.addListener(handleConnection)

function local_connect(prop) {
	var c2sListeners = []
	var s2cListeners = []

	var portForServer = {
		name: prop.name,
		sender: {
			id: chrome.runtime.id
		},
		onMessage: {
			addListener: (l) => { c2sListeners.push(l) }
		},
		onDisconnect: {
			addListener: (l) => { }
		},
		postMessage: (msg) => {
			s2cListeners.forEach(l => l(msg))
		}
	}
	handleConnection(portForServer)

	var port = {
		onMessage: {
			addListener: (l) => { s2cListeners.push(l) }
		},
		postMessage: (msg) => {
			c2sListeners.forEach(l => l(msg))
		}
	}
	return port;
}

//////////////////////////////////THIS PART IS FOR CONTENT SCRIPTS

var port_cs = {} //ports that content script created

chrome.runtime.onConnect.addListener((port) => {
	if (port.name !== "page") return
	var portID = genID()
	port_cs[portID] = port

	port.onDisconnect.addListener(() => {
		delete port_cs[portID]
	})
	port.onMessage.addListener((msg) => {
		let baseReq = JSON.stringify(msg.info)
		conf.mods.forEach((mod_id, index) => {
			let mod = loaded_mods[mod_id]
			let instanceRequest = JSON.parse(baseReq)
			instanceRequest.id = (portID + "|" + msg.id + "|" + index)
			instanceRequest.for = mod_id
			if (!mod) return

			console.log('dispatch', mod_id, instanceRequest);

			mod.port.postMessage({
				type: "request",
				request: instanceRequest
			})
		})
	})
})
<commit_msg>fix: saving conf<commit_after>'use strict';

var config = (() => {
	var sys = {
		impl: chrome.storage.local,
		get: (name, defaultVal) => new Promise((res) => {
			sys.impl.get(name, (confs) => {
				if (typeof name === "string") res((name in confs) ? confs[name] : defaultVal);
				else res(confs);
			});
		}),
		set: (n, v) => new Promise((res) => {
			var setObj = {};
			if (typeof n === "string") setObj[n] = v;
			else setObj = n;
			sys.impl.set(setObj, res);
		})
	};

	chrome.storage.local.get('sys.local', (items) => {
		if (!items['sys.local']) {
			sys.impl = chrome.storage.sync;
		}
	});

	return sys;
})()

function genID() {
	return (+ new Date()).toString(36) + (Math.random())
}

/////////////////////////////////////////////////////////////////////////////////////

var box = { html: '', style: '' };
var styleDefault, styleUser;

Promise.all([
	window.fetch('box/style.css').then(res => res.text()),
	config.get("user.style", "")
]).then((styles) => {
	styleDefault = styles[0];
	styleUser = styles[1];
	box.style = styleDefault + styleUser;
})

function UpdateBoxHtml(html) {
	var h =
		html.replace(/(src|href)=(["'])(.+?)\2/g, (whole, a, quote, uri) => {
			if (/^\w+\:/.test(uri)) return whole;
			return a + '=' + quote + chrome.runtime.getURL((uri[0] === "/" ? uri : "/box/" + uri)) + quote;
		})
	box.html = h;
}
window.fetch('box/box.html').then(res => res.text()).then(UpdateBoxHtml)

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
	let resp = {};
	switch (msg.type || msg) {
		case "box":
			sendResponse(box)
			break
		case "loaded_mods":
			Object.keys(loaded_mods).forEach((modName) => {
				let mod = loaded_mods[modName]
				resp[modName] = {
					id: mod.id,
					profile: mod.profile
				}
			})
			sendResponse(resp)
			break
		case "conf":
			if (!msg.data) {
				//getting
				sendResponse(conf)
			} else {
				conf = msg.data
				sendResponse(true)
			}
			break
	}
})

////////////////////////////////////////////////////////////////////////////

var conf = {
	mods: []
}
var loaded_mods = {}  //a dict

function handleModuleResponse(msg) {
	if (msg.type === "instance") {
		console.log("module response!", msg.instance.id, msg.instance)
		var infos = msg.instance.id.split("|") // 0: portID 1: reqID 2: order
		var port = port_cs[infos[0]]
		if (!port) return
		port.postMessage({
			id: infos[1],
			order: ~~infos[2],
			instance: msg.instance
		})
	}
}

function handleConnection(port) {
	if (port.name !== "module") return

	var inited = false;
	function onetimeCheck(message) {
		if (inited) return
		inited = true

		if (message.type !== 'profile') {
			port.disconnect()
			return
		}

		var profile = message.profile
		var id = port.sender.id + ":" + profile.id

		loaded_mods[id] = {
			id: id,
			port: port,
			profile: profile
		}

		//FIXME! DEBUG CODE! DO NOT PUBLISTH!
		conf.mods.push(id)

		port.onMessage.addListener(handleModuleResponse)
		port.onDisconnect.addListener(() => {
			delete loaded_mods[id]
		})
	}
	port.onMessage.addListener(onetimeCheck)
}

chrome.runtime.onConnect.addListener(handleConnection)
chrome.runtime.onConnectExternal.addListener(handleConnection)

function local_connect(prop) {
	var c2sListeners = []
	var s2cListeners = []

	var portForServer = {
		name: prop.name,
		sender: {
			id: chrome.runtime.id
		},
		onMessage: {
			addListener: (l) => { c2sListeners.push(l) }
		},
		onDisconnect: {
			addListener: (l) => { }
		},
		postMessage: (msg) => {
			s2cListeners.forEach(l => l(msg))
		}
	}
	handleConnection(portForServer)

	var port = {
		onMessage: {
			addListener: (l) => { s2cListeners.push(l) }
		},
		postMessage: (msg) => {
			c2sListeners.forEach(l => l(msg))
		}
	}
	return port;
}

//////////////////////////////////THIS PART IS FOR CONTENT SCRIPTS

var port_cs = {} //ports that content script created

chrome.runtime.onConnect.addListener((port) => {
	if (port.name !== "page") return
	var portID = genID()
	port_cs[portID] = port

	port.onDisconnect.addListener(() => {
		delete port_cs[portID]
	})
	port.onMessage.addListener((msg) => {
		let baseReq = JSON.stringify(msg.info)
		conf.mods.forEach((mod_id, index) => {
			let mod = loaded_mods[mod_id]
			let instanceRequest = JSON.parse(baseReq)
			instanceRequest.id = (portID + "|" + msg.id + "|" + index)
			instanceRequest.for = mod_id
			if (!mod) return

			console.log('dispatch', mod_id, instanceRequest);

			mod.port.postMessage({
				type: "request",
				request: instanceRequest
			})
		})
	})
})
<|endoftext|>


<commit_before>import {join} from 'aurelia-path';
import extend from 'extend';
import * as LogManager from 'aurelia-logging';

export class BaseConfig {
  // prepends baseUrl
  withBase(url) {
    return join(this.baseUrl, url);
  }

  // merge current settings with incomming settings
  configure(incomming) {
    for (let key in incomming) {
      const value = incomming[key];
      if (value !== undefined) {
        if (Array.isArray(value) || typeof value !== 'object' || value === null) {
          this[key] = value;
        } else {
          extend(true, this[key], value);
        }
      }
    }
  }

  /* ----------- default  config ----------- */

  // Used internally. The used Rest instance; set during configuration (see index.js)
  client = null;

  // If using aurelia-api:
  // =====================

  // This is the name of the endpoint used for any requests made in relation to authentication (login, logout, etc.). An empty string selects the default endpoint of aurelia-api.
  endpoint = null;
  // When authenticated, these endpoints will have the token added to the header of any requests (for authorization). Accepts an array of endpoint names. An empty string selects the default endpoint of aurelia-api.
  configureEndpoints = null;

  // SPA related options
  // ===================

  // The SPA url to which the user is redirected after a successful login
  loginRedirect = '#/customer';
  // The SPA url to which the user is redirected after a successful logout
  logoutRedirect = '#/';
  // The SPA route used when an unauthenticated user tries to access an SPA page that requires authentication
  loginRoute = '/login';
  // Whether or not an authentication token is provided in the response to a successful signup
  loginOnSignup = true;
  // If loginOnSignup == false: The SPA url to which the user is redirected after a successful signup (else loginRedirect is used)
  signupRedirect = '#/login';

  // API related options
  // ===================

  // The base url used for all authentication related requests, including provider.url below.
  // This appends to the httpClient/endpoint base url, it does not override it.
  baseUrl = '';
  // The API endpoint to which login requests are sent
  loginUrl = '/auth/login';
  // The API endpoint to which signup requests are sent
  signupUrl = '/auth/signup';
  // The API endpoint used in profile requests (inc. `find/get` and `update`)
  profileUrl = '/auth/me';
  // The API endpoint used with oAuth to unlink authentication
  unlinkUrl = '/auth/unlink/';
  // The HTTP method used for 'unlink' requests (Options: 'get' or 'post')
  unlinkMethod = 'get';

  // Token Options
  // =============

  // The header property used to contain the authToken in the header of API requests that require authentication
  authHeader = 'Authorization';
  // The token name used in the header of API requests that require authentication
  authTokenType = 'Bearer';
  // The the property from which to get the access token after a successful login or signup
  accessTokenProp = 'access_token';

  // If the property defined by `accessTokenProp` is an object:
  // ------------------------------------------------------------

  //This is the property from which to get the token `{ "accessTokenProp": { "accessTokenName" : '...' } }`
  accessTokenName = 'token';
  // This allows the token to be a further object deeper `{ "accessTokenProp": { "accessTokenRoot" : { "accessTokenName" : '...' } } }`
  accessTokenRoot = false;

  // Refresh Token Options
  // =====================

  // Option to turn refresh tokens On/Off
  useRefreshToken = false;
  // The option to enable/disable the automatic refresh of Auth tokens using Refresh Tokens
  autoUpdateToken = true;
  // Oauth Client Id
  clientId = false;
  // The the property from which to get the refresh token after a successful token refresh
  refreshTokenProp = 'refresh_token';

  // If the property defined by `refreshTokenProp` is an object:
  // -----------------------------------------------------------

  // This is the property from which to get the token `{ "refreshTokenProp": { "refreshTokenName" : '...' } }`
  refreshTokenName = 'token';
  // This allows the refresh token to be a further object deeper `{ "refreshTokenProp": { "refreshTokenRoot" : { "refreshTokenName" : '...' } } }`
  refreshTokenRoot = false;

  // Miscellaneous Options
  // =====================

  // Whether to enable the fetch interceptor which automatically adds the authentication headers
  // (or not... e.g. if using a session based API or you want to override the default behaviour)
  httpInterceptor = true;
  // For OAuth only: Tell the API whether or not to include token cookies in the response (for session based APIs)
  withCredentials = true;
  // Controls how the popup is shown for different devices (Options: 'browser' or 'mobile')
  platform = 'browser';
  // Determines the `window` property name upon which aurelia-authentication data is stored (Default: `window.localStorage`)
  storage = 'localStorage';
  // The key used for storing the authentication response locally
  storageKey = 'aurelia_authentication';

  //OAuth provider specific related configuration
  // ============================================
  providers = {
    google: {
      name: 'google',
      url: '/auth/google',
      authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      scope: ['profile', 'email'],
      scopePrefix: 'openid',
      scopeDelimiter: ' ',
      requiredUrlParams: ['scope'],
      optionalUrlParams: ['display'],
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 452,
        height: 633
      }
    },
    facebook: {
      name: 'facebook',
      url: '/auth/facebook',
      authorizationEndpoint: 'https://www.facebook.com/v2.3/dialog/oauth',
      redirectUri: window.location.origin + '/' || window.location.protocol + '//' + window.location.host + '/',
      scope: ['email'],
      scopeDelimiter: ',',
      nonce: function() {
        return Math.random();
      },
      requiredUrlParams: ['nonce', 'display', 'scope'],
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 580,
        height: 400
      }
    },
    linkedin: {
      name: 'linkedin',
      url: '/auth/linkedin',
      authorizationEndpoint: 'https://www.linkedin.com/uas/oauth2/authorization',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      requiredUrlParams: ['state'],
      scope: ['r_emailaddress'],
      scopeDelimiter: ' ',
      state: 'STATE',
      type: '2.0',
      popupOptions: {
        width: 527,
        height: 582
      }
    },
    github: {
      name: 'github',
      url: '/auth/github',
      authorizationEndpoint: 'https://github.com/login/oauth/authorize',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      optionalUrlParams: ['scope'],
      scope: ['user:email'],
      scopeDelimiter: ' ',
      type: '2.0',
      popupOptions: {
        width: 1020,
        height: 618
      }
    },
    yahoo: {
      name: 'yahoo',
      url: '/auth/yahoo',
      authorizationEndpoint: 'https://api.login.yahoo.com/oauth2/request_auth',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      scope: [],
      scopeDelimiter: ',',
      type: '2.0',
      popupOptions: {
        width: 559,
        height: 519
      }
    },
    twitter: {
      name: 'twitter',
      url: '/auth/twitter',
      authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
      type: '1.0',
      popupOptions: {
        width: 495,
        height: 645
      }
    },
    live: {
      name: 'live',
      url: '/auth/live',
      authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      scope: ['wl.emails'],
      scopeDelimiter: ' ',
      requiredUrlParams: ['display', 'scope'],
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 500,
        height: 560
      }
    },
    instagram: {
      name: 'instagram',
      url: '/auth/instagram',
      authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      requiredUrlParams: ['scope'],
      scope: ['basic'],
      scopeDelimiter: '+',
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 550,
        height: 369
      }
    }
  };

  /* deprecated defaults */
  _authToken = 'Bearer';
  _responseTokenProp = 'access_token';
  _tokenName = 'token';
  _tokenRoot = false;
  _tokenPrefix = 'aurelia';

  /* deprecated methods and parameteres */
  get current() {
    logger.warn('BaseConfig.current() is deprecated. Use BaseConfig directly instead.');
    return this;
  }

  set authToken(authToken) {
    logger.warn('BaseConfig.authToken is deprecated. Use BaseConfig.authTokenType instead.');
    this._authTokenType = authToken;
    this.authTokenType = authToken;
    return authToken;
  }
  get authToken() {
    return this._authTokenType;
  }

  set responseTokenProp(responseTokenProp) {
    LogManager.getLogger('authentication').warn('BaseConfig.responseTokenProp is deprecated. Use BaseConfig.accessTokenProp instead.');
    this._responseTokenProp = responseTokenProp;
    this.accessTokenProp = responseTokenProp;
    return responseTokenProp;
  }
  get responseTokenProp() {
    return this._responseTokenProp;
  }

  set tokenRoot(tokenRoot) {
    LogManager.getLogger('authentication').warn('BaseConfig.tokenRoot is deprecated. Use BaseConfig.accessTokenRoot instead.');
    this._tokenRoot = tokenRoot;
    this.accessTokenRoot = tokenRoot;
    return tokenRoot;
  }
  get tokenRoot() {
    return this._tokenRoot;
  }

  set tokenName(tokenName) {
    LogManager.getLogger('authentication').warn('BaseConfig.tokenName is deprecated. Use BaseConfig.accessTokenName instead.');
    this._tokenName = tokenName;
    this.accessTokenName = tokenName;
    return tokenName;
  }
  get tokenName() {
    return this._tokenName;
  }

  set tokenPrefix(tokenPrefix) {
    LogManager.getLogger('authentication').warn('BaseConfig.tokenPrefix is obsolete. Use BaseConfig.storageKey instead.');
    this._tokenPrefix = tokenPrefix;
    return tokenPrefix;
  }
  get tokenPrefix() {
    return this._tokenPrefix || 'aurelia';
  }
}
<commit_msg>chore(logger): missed two<commit_after>import {join} from 'aurelia-path';
import extend from 'extend';
import * as LogManager from 'aurelia-logging';

export class BaseConfig {
  // prepends baseUrl
  withBase(url) {
    return join(this.baseUrl, url);
  }

  // merge current settings with incomming settings
  configure(incomming) {
    for (let key in incomming) {
      const value = incomming[key];
      if (value !== undefined) {
        if (Array.isArray(value) || typeof value !== 'object' || value === null) {
          this[key] = value;
        } else {
          extend(true, this[key], value);
        }
      }
    }
  }

  /* ----------- default  config ----------- */

  // Used internally. The used Rest instance; set during configuration (see index.js)
  client = null;

  // If using aurelia-api:
  // =====================

  // This is the name of the endpoint used for any requests made in relation to authentication (login, logout, etc.). An empty string selects the default endpoint of aurelia-api.
  endpoint = null;
  // When authenticated, these endpoints will have the token added to the header of any requests (for authorization). Accepts an array of endpoint names. An empty string selects the default endpoint of aurelia-api.
  configureEndpoints = null;

  // SPA related options
  // ===================

  // The SPA url to which the user is redirected after a successful login
  loginRedirect = '#/customer';
  // The SPA url to which the user is redirected after a successful logout
  logoutRedirect = '#/';
  // The SPA route used when an unauthenticated user tries to access an SPA page that requires authentication
  loginRoute = '/login';
  // Whether or not an authentication token is provided in the response to a successful signup
  loginOnSignup = true;
  // If loginOnSignup == false: The SPA url to which the user is redirected after a successful signup (else loginRedirect is used)
  signupRedirect = '#/login';

  // API related options
  // ===================

  // The base url used for all authentication related requests, including provider.url below.
  // This appends to the httpClient/endpoint base url, it does not override it.
  baseUrl = '';
  // The API endpoint to which login requests are sent
  loginUrl = '/auth/login';
  // The API endpoint to which signup requests are sent
  signupUrl = '/auth/signup';
  // The API endpoint used in profile requests (inc. `find/get` and `update`)
  profileUrl = '/auth/me';
  // The API endpoint used with oAuth to unlink authentication
  unlinkUrl = '/auth/unlink/';
  // The HTTP method used for 'unlink' requests (Options: 'get' or 'post')
  unlinkMethod = 'get';

  // Token Options
  // =============

  // The header property used to contain the authToken in the header of API requests that require authentication
  authHeader = 'Authorization';
  // The token name used in the header of API requests that require authentication
  authTokenType = 'Bearer';
  // The the property from which to get the access token after a successful login or signup
  accessTokenProp = 'access_token';

  // If the property defined by `accessTokenProp` is an object:
  // ------------------------------------------------------------

  //This is the property from which to get the token `{ "accessTokenProp": { "accessTokenName" : '...' } }`
  accessTokenName = 'token';
  // This allows the token to be a further object deeper `{ "accessTokenProp": { "accessTokenRoot" : { "accessTokenName" : '...' } } }`
  accessTokenRoot = false;

  // Refresh Token Options
  // =====================

  // Option to turn refresh tokens On/Off
  useRefreshToken = false;
  // The option to enable/disable the automatic refresh of Auth tokens using Refresh Tokens
  autoUpdateToken = true;
  // Oauth Client Id
  clientId = false;
  // The the property from which to get the refresh token after a successful token refresh
  refreshTokenProp = 'refresh_token';

  // If the property defined by `refreshTokenProp` is an object:
  // -----------------------------------------------------------

  // This is the property from which to get the token `{ "refreshTokenProp": { "refreshTokenName" : '...' } }`
  refreshTokenName = 'token';
  // This allows the refresh token to be a further object deeper `{ "refreshTokenProp": { "refreshTokenRoot" : { "refreshTokenName" : '...' } } }`
  refreshTokenRoot = false;

  // Miscellaneous Options
  // =====================

  // Whether to enable the fetch interceptor which automatically adds the authentication headers
  // (or not... e.g. if using a session based API or you want to override the default behaviour)
  httpInterceptor = true;
  // For OAuth only: Tell the API whether or not to include token cookies in the response (for session based APIs)
  withCredentials = true;
  // Controls how the popup is shown for different devices (Options: 'browser' or 'mobile')
  platform = 'browser';
  // Determines the `window` property name upon which aurelia-authentication data is stored (Default: `window.localStorage`)
  storage = 'localStorage';
  // The key used for storing the authentication response locally
  storageKey = 'aurelia_authentication';

  //OAuth provider specific related configuration
  // ============================================
  providers = {
    google: {
      name: 'google',
      url: '/auth/google',
      authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      scope: ['profile', 'email'],
      scopePrefix: 'openid',
      scopeDelimiter: ' ',
      requiredUrlParams: ['scope'],
      optionalUrlParams: ['display'],
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 452,
        height: 633
      }
    },
    facebook: {
      name: 'facebook',
      url: '/auth/facebook',
      authorizationEndpoint: 'https://www.facebook.com/v2.3/dialog/oauth',
      redirectUri: window.location.origin + '/' || window.location.protocol + '//' + window.location.host + '/',
      scope: ['email'],
      scopeDelimiter: ',',
      nonce: function() {
        return Math.random();
      },
      requiredUrlParams: ['nonce', 'display', 'scope'],
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 580,
        height: 400
      }
    },
    linkedin: {
      name: 'linkedin',
      url: '/auth/linkedin',
      authorizationEndpoint: 'https://www.linkedin.com/uas/oauth2/authorization',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      requiredUrlParams: ['state'],
      scope: ['r_emailaddress'],
      scopeDelimiter: ' ',
      state: 'STATE',
      type: '2.0',
      popupOptions: {
        width: 527,
        height: 582
      }
    },
    github: {
      name: 'github',
      url: '/auth/github',
      authorizationEndpoint: 'https://github.com/login/oauth/authorize',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      optionalUrlParams: ['scope'],
      scope: ['user:email'],
      scopeDelimiter: ' ',
      type: '2.0',
      popupOptions: {
        width: 1020,
        height: 618
      }
    },
    yahoo: {
      name: 'yahoo',
      url: '/auth/yahoo',
      authorizationEndpoint: 'https://api.login.yahoo.com/oauth2/request_auth',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      scope: [],
      scopeDelimiter: ',',
      type: '2.0',
      popupOptions: {
        width: 559,
        height: 519
      }
    },
    twitter: {
      name: 'twitter',
      url: '/auth/twitter',
      authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
      type: '1.0',
      popupOptions: {
        width: 495,
        height: 645
      }
    },
    live: {
      name: 'live',
      url: '/auth/live',
      authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      scope: ['wl.emails'],
      scopeDelimiter: ' ',
      requiredUrlParams: ['display', 'scope'],
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 500,
        height: 560
      }
    },
    instagram: {
      name: 'instagram',
      url: '/auth/instagram',
      authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
      redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
      requiredUrlParams: ['scope'],
      scope: ['basic'],
      scopeDelimiter: '+',
      display: 'popup',
      type: '2.0',
      popupOptions: {
        width: 550,
        height: 369
      }
    }
  };

  /* deprecated defaults */
  _authToken = 'Bearer';
  _responseTokenProp = 'access_token';
  _tokenName = 'token';
  _tokenRoot = false;
  _tokenPrefix = 'aurelia';

  /* deprecated methods and parameteres */
  get current() {
    LogManager.getLogger('authentication').warn('BaseConfig.current() is deprecated. Use BaseConfig directly instead.');
    return this;
  }

  set authToken(authToken) {
    LogManager.getLogger('authentication').warn('BaseConfig.authToken is deprecated. Use BaseConfig.authTokenType instead.');
    this._authTokenType = authToken;
    this.authTokenType = authToken;
    return authToken;
  }
  get authToken() {
    return this._authTokenType;
  }

  set responseTokenProp(responseTokenProp) {
    LogManager.getLogger('authentication').warn('BaseConfig.responseTokenProp is deprecated. Use BaseConfig.accessTokenProp instead.');
    this._responseTokenProp = responseTokenProp;
    this.accessTokenProp = responseTokenProp;
    return responseTokenProp;
  }
  get responseTokenProp() {
    return this._responseTokenProp;
  }

  set tokenRoot(tokenRoot) {
    LogManager.getLogger('authentication').warn('BaseConfig.tokenRoot is deprecated. Use BaseConfig.accessTokenRoot instead.');
    this._tokenRoot = tokenRoot;
    this.accessTokenRoot = tokenRoot;
    return tokenRoot;
  }
  get tokenRoot() {
    return this._tokenRoot;
  }

  set tokenName(tokenName) {
    LogManager.getLogger('authentication').warn('BaseConfig.tokenName is deprecated. Use BaseConfig.accessTokenName instead.');
    this._tokenName = tokenName;
    this.accessTokenName = tokenName;
    return tokenName;
  }
  get tokenName() {
    return this._tokenName;
  }

  set tokenPrefix(tokenPrefix) {
    LogManager.getLogger('authentication').warn('BaseConfig.tokenPrefix is obsolete. Use BaseConfig.storageKey instead.');
    this._tokenPrefix = tokenPrefix;
    return tokenPrefix;
  }
  get tokenPrefix() {
    return this._tokenPrefix || 'aurelia';
  }
}
<|endoftext|>


<commit_before>var Size = Base.extend({
	initialize: function() {
		if (arguments.length == 2) {
			this.width = arguments[0];
			this.height = arguments[1];
		} else if (arguments.length == 1) {
			var arg = arguments[0];
			if (arg == null) {
				this.width = this.height = 0;
			} else if (arg.width !== undefined) {
				this.width = arg.width;
				this.height = arg.height;
			} else if (arg.x !== undefined) {
				this.width = arg.x;
				this.height = arg.y;
			} else if (Array.isArray(arg)) {
				this.width = arg[0];
				this.height = arg.length > 1 ? arg[1] : arg[0];
			} else if (typeof arg === 'number') {
				this.width = this.height = arg;
			} else {
				this.width = this.height = 0;
			}
		} else {
			this.width = this.height = 0;
		}
	},

	set: function(width, height) {
		this.width = width;
		this.height = height;
	},

	add: function() {
		var size = Size.read(arguments);
		return new Size(this.width + size.width, this.height + size.height);
	},

	subtract: function() {
		var size = Size.read(arguments);
		return new Size(this.width - size.width, this.height - size.height);
	},

	multiply: function() {
		var size = Size.read(arguments);
		return new Size(this.width * size.width, this.height * size.height);
	},

	divide: function() {
		var size = Size.read(arguments);
		return new Size(this.width / size.width, this.height / size.height);
	},

	modulo: function() {
		var size = Size.read(arguments);
		return new Size(this.width % size.width, this.height % size.height);
	},

	negate: function() {
		return new Size(-this.width, -this.height);
	},

	equals: function() {
		var size = Size.read(arguments);
		return this.width == size.width && this.height == size.height;
	},

	isNaN: function() {
		return isNaN(this.width) || isNaN(this.height);
	},

	round: function() {
		return new Size(Math.round(this.width), Math.round(this.height));
	},

	ceil: function() {
		return new Size(Math.ceil(this.width), Math.ceil(this.height));
	},

	floor: function() {
		return new Size(Math.floor(this.width), Math.floor(this.height));
	},

	abs: function() {
		return new Size(Math.abs(this.width), Math.abs(this.height));
	},

	dot: function(Size) {
		return this.width * size.width + this.height * size.height;
	},

	toString: function() {
		return '{ x: ' + this.width + ', y: ' + this.height + ' }';
	},

	statics: {
		read: function(args, index, length) {
			var index = index || 0, length = length || args.length - index;
			if (length == 1 && args[index] instanceof Size) {
				return args[index];
			} else if (length != 0) {
				var size = new Size(Size.dont);
				size.initialize.apply(size, index > 0
						? Array.prototype.slice.call(args, index) : args);
				return size;
			}
			return null;
		},

		min: function(Size1, Size2) {
			return new Size(
				Math.min(Size1.width, Size2.width),
				Math.min(Size1.height, Size2.height));
		},

		max: function(Size1, Size2) {
			return new Size(
				Math.max(Size1.width, Size2.width),
				Math.max(Size1.height, Size2.height));
		},

		random: function() {
			return new Size(Math.random(), Math.random());
		}
	}
});
<commit_msg>Add Size.create(), in analogy to Point.create().<commit_after>var Size = Base.extend({
	initialize: function() {
		if (arguments.length == 2) {
			this.width = arguments[0];
			this.height = arguments[1];
		} else if (arguments.length == 1) {
			var arg = arguments[0];
			if (arg == null) {
				this.width = this.height = 0;
			} else if (arg.width !== undefined) {
				this.width = arg.width;
				this.height = arg.height;
			} else if (arg.x !== undefined) {
				this.width = arg.x;
				this.height = arg.y;
			} else if (Array.isArray(arg)) {
				this.width = arg[0];
				this.height = arg.length > 1 ? arg[1] : arg[0];
			} else if (typeof arg === 'number') {
				this.width = this.height = arg;
			} else {
				this.width = this.height = 0;
			}
		} else {
			this.width = this.height = 0;
		}
	},

	set: function(width, height) {
		this.width = width;
		this.height = height;
	},

	add: function() {
		var size = Size.read(arguments);
		return Size.create(this.width + size.width, this.height + size.height);
	},

	subtract: function() {
		var size = Size.read(arguments);
		return Size.create(this.width - size.width, this.height - size.height);
	},

	multiply: function() {
		var size = Size.read(arguments);
		return Size.create(this.width * size.width, this.height * size.height);
	},

	divide: function() {
		var size = Size.read(arguments);
		return Size.create(this.width / size.width, this.height / size.height);
	},

	modulo: function() {
		var size = Size.read(arguments);
		return Size.create(this.width % size.width, this.height % size.height);
	},

	negate: function() {
		return Size.create(-this.width, -this.height);
	},

	equals: function() {
		var size = Size.read(arguments);
		return this.width == size.width && this.height == size.height;
	},

	isNaN: function() {
		return isNaN(this.width) || isNaN(this.height);
	},

	round: function() {
		return Size.create(Math.round(this.width), Math.round(this.height));
	},

	ceil: function() {
		return Size.create(Math.ceil(this.width), Math.ceil(this.height));
	},

	floor: function() {
		return Size.create(Math.floor(this.width), Math.floor(this.height));
	},

	abs: function() {
		return Size.create(Math.abs(this.width), Math.abs(this.height));
	},

	dot: function(Size) {
		return this.width * size.width + this.height * size.height;
	},

	toString: function() {
		return '{ x: ' + this.width + ', y: ' + this.height + ' }';
	},

	statics: {
		// See Point.create()
		create: function(width, height) {
			var size = new Size(Size.dont);
			size.width = width;
			size.height = height;
			return size;
		},

		read: function(args, index, length) {
			var index = index || 0, length = length || args.length - index;
			if (length == 1 && args[index] instanceof Size) {
				return args[index];
			} else if (length != 0) {
				var size = new Size(Size.dont);
				size.initialize.apply(size, index > 0
						? Array.prototype.slice.call(args, index) : args);
				return size;
			}
			return null;
		},

		min: function(Size1, Size2) {
			return Size.create(
				Math.min(Size1.width, Size2.width),
				Math.min(Size1.height, Size2.height));
		},

		max: function(Size1, Size2) {
			return Size.create(
				Math.max(Size1.width, Size2.width),
				Math.max(Size1.height, Size2.height));
		},

		random: function() {
			return Size.create(Math.random(), Math.random());
		}
	}
});
<|endoftext|>


<commit_before>
// export public API
window.oboe = apiMethod('GET');
window.oboe.doGet    = apiMethod('GET');
window.oboe.doDelete = apiMethod('DELETE');
window.oboe.doPost   = apiMethod('POST', true);
window.oboe.doPut    =   apiMethod('PUT', true);

function apiMethod(httpMethodName, mayHaveRequestBody) {

   return function(firstArg){

      if (isString(firstArg)) {

         // parameters specified as arguments
         //
         //  if (mayHaveContext == true) method signature is:
         //     .doMethod( url, content, callback )
         //
         //  else it is:
         //     .doMethod( url, callback )
         //
         return wire(
                  httpMethodName,
                  firstArg,                                  // url
                  mayHaveRequestBody && arguments[1],        // body
                  arguments[mayHaveRequestBody? 2 : 1]       // callback
         );
      } else {

         // method signature is:
         //    .doMethod({url:u, body:b, complete:c, headers:{...}})

         return wire(
                  httpMethodName,
                  firstArg.url,
                  firstArg.body,
                  firstArg.complete,
                  firstArg.headers
         );
      }

   };
}

<commit_msg>don't create GET method twice<commit_after>
// export public API
window.oboe          = apiMethod('GET');
window.oboe.doGet    = window.oboe;
window.oboe.doDelete = apiMethod('DELETE');
window.oboe.doPost   = apiMethod('POST', true);
window.oboe.doPut    = apiMethod('PUT', true);

function apiMethod(httpMethodName, mayHaveRequestBody) {

   return function(firstArg){

      if (isString(firstArg)) {

         // parameters specified as arguments
         //
         //  if (mayHaveContext == true) method signature is:
         //     .doMethod( url, content, callback )
         //
         //  else it is:
         //     .doMethod( url, callback )
         //
         return wire(
                  httpMethodName,
                  firstArg,                                  // url
                  mayHaveRequestBody && arguments[1],        // body
                  arguments[mayHaveRequestBody? 2 : 1]       // callback
         );
      } else {

         // method signature is:
         //    .doMethod({url:u, body:b, complete:c, headers:{...}})

         return wire(
                  httpMethodName,
                  firstArg.url,
                  firstArg.body,
                  firstArg.complete,
                  firstArg.headers
         );
      }

   };
}

<|endoftext|>


<commit_before>// Add dependencies
const path = require('path');
const dockerHealthCheckServer = require('fastify')({ logger: false });
const promServer = require('fastify')({ logger: false });
const promFastifyMetricsServer = require('fastify')({ logger: false });
const metricsPlugin = require('fastify-metrics');

promServer.server.keepAliveTimeout = 0;
promFastifyMetricsServer.register(metricsPlugin, { endpoint: '/metrics' });

// Load code from sub modules
const globals = require('./globals');
const healthMetrics = require('./lib/healthmetrics');
const logDb = require('./lib/logdb');
const sessionMetrics = require('./lib/sessionmetrics');
const appNamesExtract = require('./lib/appnamesextract');
const heartbeat = require('./lib/heartbeat');
const serviceUptime = require('./lib/service_uptime');
const udpUserActivity = require('./lib/udp_handlers_user_activity');
const udpLogEvents = require('./lib/udp_handlers_log_events');
const telemetry = require('./lib/telemetry');
const promClient = require('./lib/prom-client');

globals.initInfluxDB();

if (
    (globals.config.has('Butler-SOS.uptimeMonitor.enabled') &&
        globals.config.get('Butler-SOS.uptimeMonitor.enabled') === true) ||
    (globals.config.has('Butler-SOS.uptimeMonitor.enable') &&
        globals.config.get('Butler-SOS.uptimeMonitor.enable') === true)
) {
    serviceUptime.serviceUptimeStart();
}

async function mainScript() {
    // Load certificates to use when connecting to healthcheck API
    const certFile = path.resolve(__dirname, globals.config.get('Butler-SOS.cert.clientCert'));
    const keyFile = path.resolve(__dirname, globals.config.get('Butler-SOS.cert.clientCertKey'));
    const caFile = path.resolve(__dirname, globals.config.get('Butler-SOS.cert.clientCertCA'));

    // Set up heartbeats, if enabled in the config file
    if (
        (globals.config.has('Butler-SOS.heartbeat.enabled') &&
            globals.config.get('Butler-SOS.heartbeat.enabled') === true) ||
        (globals.config.has('Butler-SOS.heartbeat.enable') &&
            globals.config.get('Butler-SOS.heartbeat.enable') === true)
    ) {
        heartbeat.setupHeartbeatTimer(globals.config, globals.logger);
    }

    try {
        // Get host info
        globals.hostInfo = await globals.initHostInfo();
        globals.logger.debug('CONFIG: Initiated host info data structures');

        // Set specific log level (if/when needed to override the config file setting)
        // Possible values are { error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }
        // Default is to use log level defined in config file
        globals.logger.info('--------------------------------------');
        globals.logger.info('Starting Butler SOS');
        globals.logger.info(`Log level: ${globals.getLoggingLevel()}`);
        globals.logger.info(`App version: ${globals.appVersion}`);
        globals.logger.info('');
        globals.logger.info(`Node version   : ${globals.hostInfo.node.nodeVersion}`);
        globals.logger.info(`Architecture   : ${globals.hostInfo.si.os.arch}`);
        globals.logger.info(`Platform       : ${globals.hostInfo.si.os.platform}`);
        globals.logger.info(`Release        : ${globals.hostInfo.si.os.release}`);
        globals.logger.info(`Distro         : ${globals.hostInfo.si.os.distro}`);
        globals.logger.info(`Codename       : ${globals.hostInfo.si.os.codename}`);
        globals.logger.info(`Virtual        : ${globals.hostInfo.si.system.virtual}`);
        globals.logger.info(`Processors     : ${globals.hostInfo.si.cpu.processors}`);
        globals.logger.info(`Physical cores : ${globals.hostInfo.si.cpu.physicalCores}`);
        globals.logger.info(`Cores          : ${globals.hostInfo.si.cpu.cores}`);
        globals.logger.info(`Docker arch.   : ${globals.hostInfo.si.cpu.hypervizor}`);
        globals.logger.info(`Total memory   : ${globals.hostInfo.si.memory.total}`);
        globals.logger.info('--------------------------------------');

        // Log info about what Qlik Sense certificates are being used
        globals.logger.info(`Client cert: ${certFile}`);
        globals.logger.info(`Client cert key: ${keyFile}`);
        globals.logger.info(`CA cert: ${caFile}`);

        // Set up anon usage reports, if enabled
        if (
            globals.config.has('Butler-SOS.anonTelemetry') === false ||
            (globals.config.has('Butler-SOS.anonTelemetry') === true &&
                globals.config.get('Butler-SOS.anonTelemetry') === true)
        ) {
            telemetry.setupAnonUsageReportTimer();
            globals.logger.verbose('MAIN: Anonymous telemetry reporting has been set up.');
        }
    } catch (err) {
        globals.logger.error(`CONFIG: Error initiating host info: ${err}`);
    }

    // Set up UDP handler for user activity/events
    if (
        globals.config.has('Butler-SOS.userEvents.enable') &&
        globals.config.get('Butler-SOS.userEvents.enable')
    ) {
        udpUserActivity.udpInitUserActivityServer();

        globals.logger.debug(
            `MAIN: Server for user activity/events UDP server: ${globals.udpServerUserActivity.host}`
        );

        // Start UDP server for user activity events
        globals.udpServerUserActivity.socket.bind(
            globals.udpServerUserActivity.portUserActivity,
            globals.udpServerUserActivity.host
        );
    }

    // Set up UDP handler for log events
    if (
        (globals.config.has('Butler-SOS.logEvents.source.repository.enable') &&
            globals.config.get('Butler-SOS.logEvents.source.repository.enable')) ||
        (globals.config.has('Butler-SOS.logEvents.source.scheduler.enable') &&
            globals.config.get('Butler-SOS.logEvents.source.scheduler.enable'))
    ) {
        udpLogEvents.udpInitLogEventServer();

        globals.logger.debug(
            `MAIN: Server for user activity/events UDP server: ${globals.udpServerLogEvents.host}`
        );

        // Start UDP server for user activity events
        globals.udpServerLogEvents.socket.bind(
            globals.udpServerLogEvents.port,
            globals.udpServerLogEvents.host
        );
    }

    // Start Docker healthcheck REST server on port set in config file
    if (
        (globals.config.has('Butler-SOS.dockerHealthCheck.enabled') &&
            globals.config.get('Butler-SOS.dockerHealthCheck.enabled') === true) ||
        (globals.config.has('Butler-SOS.dockerHealthCheck.enable') &&
            globals.config.get('Butler-SOS.dockerHealthCheck.enable') === true)
    ) {
        try {
            globals.logger.verbose('MAIN: Starting Docker healthcheck server...');

            // Use http://localhost:12398/health as Docker healthcheck URL
            // eslint-disable-next-line global-require
            dockerHealthCheckServer.register(require('fastify-healthcheck'));
            await dockerHealthCheckServer.listen(
                globals.config.get('Butler-SOS.dockerHealthCheck.port')
            );

            globals.logger.info(
                `MAIN: Started Docker healthcheck server on port ${globals.config.get(
                    'Butler-SOS.dockerHealthCheck.port'
                )}.`
            );
        } catch (err) {
            globals.logger.error(
                `MAIN: Error while starting Docker healthcheck server on port ${globals.config.get(
                    'Butler-SOS.dockerHealthCheck.port'
                )}.`
            );
            dockerHealthCheckServer.log.error(err);
            process.exit(1);
        }
    }

    // Start Prometheus metrics REST server on port set in config file
    if (
        globals.config.has('Butler-SOS.prometheus.enable') &&
        globals.config.get('Butler-SOS.prometheus.enable') === true
    ) {
        const promHost = globals.config.has('Butler-SOS.prometheus.host')
            ? globals.config.get('Butler-SOS.prometheus.host')
            : '0.0.0.0';

        const promPort = globals.config.has('Butler-SOS.prometheus.port')
            ? globals.config.get('Butler-SOS.prometheus.port')
            : 9842;

        const promNodeHost = '0.0.0.0';
        const promNodePort = 9001;

        try {
            // Set up Butler SOS metrics
            globals.logger.info(
                `MAIN: Starting Prometheus Butler SOS endpoint on ${promHost}:${promPort}.`
            );
            promClient.setupPromClient(promServer, promPort, promHost);
        } catch (err) {
            globals.logger.error(
                `MAIN: Error while starting Prometheus Butler SOS endpoint on ${promHost}:${promPort}.`
            );
            promServer.log.error(err);
            process.exit(1);
        }

        try {
            // Set up Node.js internal metrics
            await promFastifyMetricsServer.listen(promNodePort, promNodeHost);
            globals.logger.info(
                `PROM: Prometheus Node.js metrics server now listening on port ${promNodeHost}:${promNodePort}`
            );
        } catch (err) {
            globals.logger.error(
                `MAIN: Error while starting Prometheus Node.js endpoint on ${promNodeHost}:${promNodePort}.`
            );
            promFastifyMetricsServer.log.error(err);
            process.exit(1);
        }
    }

    // Set up extraction of data from log db
    if (
        (globals.config.has('Butler-SOS.logdb.enableLogDb') &&
            globals.config.get('Butler-SOS.logdb.enableLogDb') === true) ||
        (globals.config.has('Butler-SOS.logdb.enable') &&
            globals.config.get('Butler-SOS.logdb.enable') === true)
    ) {
        logDb.setupLogDbTimer();
    }

    // Set up extraction of sessions data
    if (globals.config.get('Butler-SOS.userSessions.enableSessionExtract') === true) {
        sessionMetrics.setupUserSessionsTimer();
    }

    // Set up extraction on main metrics data (i.e. the Sense healthcheck API)
    healthMetrics.setupHealthMetricsTimer();

    // Set up extraction of app IDs and names
    if (globals.config.get('Butler-SOS.appNames.enableAppNameExtract') === true) {
        appNamesExtract.setupAppNamesExtractTimer();
    }
}

mainScript();
<commit_msg>feat(telemetry): Show instance ID on startup<commit_after>// Add dependencies
const path = require('path');
const dockerHealthCheckServer = require('fastify')({ logger: false });
const promServer = require('fastify')({ logger: false });
const promFastifyMetricsServer = require('fastify')({ logger: false });
const metricsPlugin = require('fastify-metrics');

promServer.server.keepAliveTimeout = 0;
promFastifyMetricsServer.register(metricsPlugin, { endpoint: '/metrics' });

// Load code from sub modules
const globals = require('./globals');
const healthMetrics = require('./lib/healthmetrics');
const logDb = require('./lib/logdb');
const sessionMetrics = require('./lib/sessionmetrics');
const appNamesExtract = require('./lib/appnamesextract');
const heartbeat = require('./lib/heartbeat');
const serviceUptime = require('./lib/service_uptime');
const udpUserActivity = require('./lib/udp_handlers_user_activity');
const udpLogEvents = require('./lib/udp_handlers_log_events');
const telemetry = require('./lib/telemetry');
const promClient = require('./lib/prom-client');

globals.initInfluxDB();

if (
    (globals.config.has('Butler-SOS.uptimeMonitor.enabled') &&
        globals.config.get('Butler-SOS.uptimeMonitor.enabled') === true) ||
    (globals.config.has('Butler-SOS.uptimeMonitor.enable') &&
        globals.config.get('Butler-SOS.uptimeMonitor.enable') === true)
) {
    serviceUptime.serviceUptimeStart();
}

async function mainScript() {
    // Load certificates to use when connecting to healthcheck API
    const certFile = path.resolve(__dirname, globals.config.get('Butler-SOS.cert.clientCert'));
    const keyFile = path.resolve(__dirname, globals.config.get('Butler-SOS.cert.clientCertKey'));
    const caFile = path.resolve(__dirname, globals.config.get('Butler-SOS.cert.clientCertCA'));

    // Set up heartbeats, if enabled in the config file
    if (
        (globals.config.has('Butler-SOS.heartbeat.enabled') &&
            globals.config.get('Butler-SOS.heartbeat.enabled') === true) ||
        (globals.config.has('Butler-SOS.heartbeat.enable') &&
            globals.config.get('Butler-SOS.heartbeat.enable') === true)
    ) {
        heartbeat.setupHeartbeatTimer(globals.config, globals.logger);
    }

    try {
        // Get host info
        globals.hostInfo = await globals.initHostInfo();
        globals.logger.debug('CONFIG: Initiated host info data structures');

        // Set specific log level (if/when needed to override the config file setting)
        // Possible values are { error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }
        // Default is to use log level defined in config file
        globals.logger.info('--------------------------------------');
        globals.logger.info('Starting Butler SOS');
        globals.logger.info(`Log level: ${globals.getLoggingLevel()}`);
        globals.logger.info(`App version: ${globals.appVersion}`);
        globals.logger.info(`Instance ID    : ${globals.hostInfo.id}`);
        globals.logger.info('');
        globals.logger.info(`Node version   : ${globals.hostInfo.node.nodeVersion}`);
        globals.logger.info(`Architecture   : ${globals.hostInfo.si.os.arch}`);
        globals.logger.info(`Platform       : ${globals.hostInfo.si.os.platform}`);
        globals.logger.info(`Release        : ${globals.hostInfo.si.os.release}`);
        globals.logger.info(`Distro         : ${globals.hostInfo.si.os.distro}`);
        globals.logger.info(`Codename       : ${globals.hostInfo.si.os.codename}`);
        globals.logger.info(`Virtual        : ${globals.hostInfo.si.system.virtual}`);
        globals.logger.info(`Processors     : ${globals.hostInfo.si.cpu.processors}`);
        globals.logger.info(`Physical cores : ${globals.hostInfo.si.cpu.physicalCores}`);
        globals.logger.info(`Cores          : ${globals.hostInfo.si.cpu.cores}`);
        globals.logger.info(`Docker arch.   : ${globals.hostInfo.si.cpu.hypervizor}`);
        globals.logger.info(`Total memory   : ${globals.hostInfo.si.memory.total}`);
        globals.logger.info('--------------------------------------');

        // Log info about what Qlik Sense certificates are being used
        globals.logger.info(`Client cert: ${certFile}`);
        globals.logger.info(`Client cert key: ${keyFile}`);
        globals.logger.info(`CA cert: ${caFile}`);

        // Set up anon usage reports, if enabled
        if (
            globals.config.has('Butler-SOS.anonTelemetry') === false ||
            (globals.config.has('Butler-SOS.anonTelemetry') === true &&
                globals.config.get('Butler-SOS.anonTelemetry') === true)
        ) {
            telemetry.setupAnonUsageReportTimer();
            globals.logger.verbose('MAIN: Anonymous telemetry reporting has been set up.');
        }
    } catch (err) {
        globals.logger.error(`CONFIG: Error initiating host info: ${err}`);
    }

    // Set up UDP handler for user activity/events
    if (
        globals.config.has('Butler-SOS.userEvents.enable') &&
        globals.config.get('Butler-SOS.userEvents.enable')
    ) {
        udpUserActivity.udpInitUserActivityServer();

        globals.logger.debug(
            `MAIN: Server for user activity/events UDP server: ${globals.udpServerUserActivity.host}`
        );

        // Start UDP server for user activity events
        globals.udpServerUserActivity.socket.bind(
            globals.udpServerUserActivity.portUserActivity,
            globals.udpServerUserActivity.host
        );
    }

    // Set up UDP handler for log events
    if (
        (globals.config.has('Butler-SOS.logEvents.source.repository.enable') &&
            globals.config.get('Butler-SOS.logEvents.source.repository.enable')) ||
        (globals.config.has('Butler-SOS.logEvents.source.scheduler.enable') &&
            globals.config.get('Butler-SOS.logEvents.source.scheduler.enable'))
    ) {
        udpLogEvents.udpInitLogEventServer();

        globals.logger.debug(
            `MAIN: Server for user activity/events UDP server: ${globals.udpServerLogEvents.host}`
        );

        // Start UDP server for user activity events
        globals.udpServerLogEvents.socket.bind(
            globals.udpServerLogEvents.port,
            globals.udpServerLogEvents.host
        );
    }

    // Start Docker healthcheck REST server on port set in config file
    if (
        (globals.config.has('Butler-SOS.dockerHealthCheck.enabled') &&
            globals.config.get('Butler-SOS.dockerHealthCheck.enabled') === true) ||
        (globals.config.has('Butler-SOS.dockerHealthCheck.enable') &&
            globals.config.get('Butler-SOS.dockerHealthCheck.enable') === true)
    ) {
        try {
            globals.logger.verbose('MAIN: Starting Docker healthcheck server...');

            // Use http://localhost:12398/health as Docker healthcheck URL
            // eslint-disable-next-line global-require
            dockerHealthCheckServer.register(require('fastify-healthcheck'));
            await dockerHealthCheckServer.listen(
                globals.config.get('Butler-SOS.dockerHealthCheck.port')
            );

            globals.logger.info(
                `MAIN: Started Docker healthcheck server on port ${globals.config.get(
                    'Butler-SOS.dockerHealthCheck.port'
                )}.`
            );
        } catch (err) {
            globals.logger.error(
                `MAIN: Error while starting Docker healthcheck server on port ${globals.config.get(
                    'Butler-SOS.dockerHealthCheck.port'
                )}.`
            );
            dockerHealthCheckServer.log.error(err);
            process.exit(1);
        }
    }

    // Start Prometheus metrics REST server on port set in config file
    if (
        globals.config.has('Butler-SOS.prometheus.enable') &&
        globals.config.get('Butler-SOS.prometheus.enable') === true
    ) {
        const promHost = globals.config.has('Butler-SOS.prometheus.host')
            ? globals.config.get('Butler-SOS.prometheus.host')
            : '0.0.0.0';

        const promPort = globals.config.has('Butler-SOS.prometheus.port')
            ? globals.config.get('Butler-SOS.prometheus.port')
            : 9842;

        const promNodeHost = '0.0.0.0';
        const promNodePort = 9001;

        try {
            // Set up Butler SOS metrics
            globals.logger.info(
                `MAIN: Starting Prometheus Butler SOS endpoint on ${promHost}:${promPort}.`
            );
            promClient.setupPromClient(promServer, promPort, promHost);
        } catch (err) {
            globals.logger.error(
                `MAIN: Error while starting Prometheus Butler SOS endpoint on ${promHost}:${promPort}.`
            );
            promServer.log.error(err);
            process.exit(1);
        }

        try {
            // Set up Node.js internal metrics
            await promFastifyMetricsServer.listen(promNodePort, promNodeHost);
            globals.logger.info(
                `PROM: Prometheus Node.js metrics server now listening on port ${promNodeHost}:${promNodePort}`
            );
        } catch (err) {
            globals.logger.error(
                `MAIN: Error while starting Prometheus Node.js endpoint on ${promNodeHost}:${promNodePort}.`
            );
            promFastifyMetricsServer.log.error(err);
            process.exit(1);
        }
    }

    // Set up extraction of data from log db
    if (
        (globals.config.has('Butler-SOS.logdb.enableLogDb') &&
            globals.config.get('Butler-SOS.logdb.enableLogDb') === true) ||
        (globals.config.has('Butler-SOS.logdb.enable') &&
            globals.config.get('Butler-SOS.logdb.enable') === true)
    ) {
        logDb.setupLogDbTimer();
    }

    // Set up extraction of sessions data
    if (globals.config.get('Butler-SOS.userSessions.enableSessionExtract') === true) {
        sessionMetrics.setupUserSessionsTimer();
    }

    // Set up extraction on main metrics data (i.e. the Sense healthcheck API)
    healthMetrics.setupHealthMetricsTimer();

    // Set up extraction of app IDs and names
    if (globals.config.get('Butler-SOS.appNames.enableAppNameExtract') === true) {
        appNamesExtract.setupAppNamesExtractTimer();
    }
}

mainScript();
<|endoftext|>