<commit_before>var RoomHandler = function () {
	this.rooms = {};
};

RoomHandler.prototype.handleWhereAmI = function (type, data) {
	var handler = this;

	var path = window.location.pathname;
	var roomId = +path.substr(7);

	if (data.length === 0) {
		// TODO: Show room search
		window.location = "/rooms/1";
	} else {
		forEach(data, function (room) {
			handler.add(room);

			if (roomId == room.id) {
				roomHandler.focus(roomId);
			}
		});
	}

	notificationCenter.checkPings();
};

RoomHandler.prototype.handleActivity = function (type, data) {
	var elements = document.getElementsByClassName("user-activity-" + data.userId);

	forEach(elements, function(element) {
		element.setAttribute("data-state", data.state);
	});
};

RoomHandler.prototype.handleTranscript = function (type, data) {
	var room = this.rooms[data.roomId];
	room.infiniteScroll = false;

	var node = this.getRoom(room.id);

	var tempScroll = node.scrollHeight - node.scrollTop;

	forEach(data.messages, function (message) {
		messageHandler.insertMessage(room, message, node);
	});

	if (data.messages.length > 0) {
		node.scrollTop = node.scrollHeight - tempScroll;
	} else {
		room.firstLoadableMessage = +node.children.item(0).getAttribute("data-id");
	}
};

RoomHandler.prototype.handleStars = function (type, data) {
	var stars = document.getElementById('stars-' + data.roomId);
	stars.innerHTML = templateManager.get("starred_messages")(data);

	forEach(stars.children, function (o, i) {
		var node = o.querySelector(".starred-message-text");
		formatter.formatMessage(node, data.messages[i].messageText.replace(/^:\d+ /, ""), null, data.user);

		node = o.querySelector(".starred-message-meta time");
		node.textContent = moment.unix(data.messages[i].time).fromNow();
	});

	forEach(stars.querySelectorAll(".star-message"), function (o) {
		o.addEventListener("click", function () {
			var star = this.getAttribute("data-starred") === "0";
			this.setAttribute("data-starred", star ? "1" : "0");

			var event = star ? "star" : "unstar";
			dataHandler.send(event, {
				messageId: +this.getAttribute("data-message-id")
			});
		});
	});
};

RoomHandler.prototype.handlePing = function (type, data) {
	var node = this.getTab(data.roomId).querySelector(".pings");
	var room = this.rooms[data.roomId];

	room.pings.push(data.messageId);
	node.setAttribute("data-pings", room.pings.length);
	notificationCenter.checkPings();

	notificationCenter.notifyMessage("Ping from " + data.user.name + " in " + room.name);
};

RoomHandler.prototype.handlePingClear = function (type, data) {
	for(var x in this.rooms) {
		var room = this.rooms[x];

		for(var i = room.pings.length - 1; i >= 0; i--) {
			if(room.pings[i] === data.messageId) {
				var node = roomHandler.getTab(room.id).querySelector(".pings");
				room.pings.splice(i, 1);

				node.setAttribute("data-pings", room.pings.length);
				notificationCenter.checkPings();
			}
		}
	}
};

RoomHandler.prototype.add = function (data) {
	var handler = this;

	if (data.id in this.rooms) {
		dataHandler.send("missed-query", {
			roomId: data.id,
			last: this.rooms[data.id].lastMessage
		});

		return;
	}

	this.rooms[data.id] = data;
	this.rooms[data.id].firstMessage = -1;
	this.rooms[data.id].lastMessage = -1;
	this.rooms[data.id].firstLoadableMessage = null;
	this.rooms[data.id].infiniteScroll = false;
	this.rooms[data.id].defaultScroll = true;

	var roomNode = nodeFromHTML(templateManager.get("room")(data));
	var roomTabNode = nodeFromHTML(templateManager.get("room_tab")(data));
	var starsNode = nodeFromHTML(templateManager.get("stars")({roomId: data.id}));
	var infoNode = nodeFromHTML(templateManager.get("room_info")(data));

	document.getElementById("rooms").appendChild(roomNode);
	document.getElementById("room-tabs").appendChild(roomTabNode);
	document.getElementById("stars").appendChild(starsNode);
	document.getElementById("room-infos").appendChild(infoNode);

	roomTabNode.addEventListener("click", function () {
		forEach(document.getElementsByClassName("room-current"), function (o) {
			o.classList.remove("room-current");
		});

		forEach(document.getElementsByClassName("room-tab-current"), function (o) {
			o.classList.remove("room-tab-current");
		});

		forEach(document.getElementsByClassName("stars-current"), function (o) {
			o.classList.remove("stars-current");
		});

		forEach(document.getElementsByClassName("room-info-current"), function (o) {
			o.classList.remove("room-info-current");
		});

		roomNode.classList.add("room-current");
		roomTabNode.classList.add("room-tab-current");
		starsNode.classList.add("stars-current");
		infoNode.classList.add("room-info-current");

		var newmessages = parseInt(roomTabNode.getAttribute("data-new-messages"));
		roomTabNode.setAttribute("data-new-messages", "0");

		history.replaceState(null, "", "/rooms/" + data.id);

		if (handler.rooms[data.id].defaultScroll) {
			roomNode.scrollTop += roomNode.clientHeight;
		}

		if ((newmessages || 0) === 0 || roomNode.scrollHeight === roomNode.clientHeight) {
			notificationCenter.hideMessageIndicator();
		} else {
			notificationCenter.showMessageIndicator();
		}
	});

	var pingNode = roomTabNode.querySelector(".pings");
	pingNode.setAttribute("data-pings", this.rooms[data.id].pings.length.toString());

	pingNode.addEventListener("click", function () {
		var messageId = roomHandler.rooms[data.id].pings.shift();

		if (messageId === "undefined") {
			return;
		}

		roomHandler.showMessage(messageId);
		dataHandler.send("ping", {messageId: messageId});
		this.setAttribute("data-pings", roomHandler.rooms[data.id].pings.length.toString());
		notificationCenter.checkPings();
	});

	roomNode.addEventListener("scroll", function () {
		clearTimeout(handler.rooms[data.id].scrollTimeout);

		var node = this;

		handler.rooms[data.id].scrollTimeout = setTimeout(function () {
			handler.onScroll(node, data);
		}, 200);
	});

	dataHandler.send("missed-query", {
		roomId: data.id,
		last: -1
	});

	dataHandler.send("stars", {roomId: data.id});
};

RoomHandler.prototype.showMessage = function (id) {
	var messageNode = messageHandler.getDOM(id);

	if (messageNode === null) {
		window.open("/message/" + id + "#" + id, '_blank');
		return;
	}

	var roomNode = messageNode.parentNode;
	var roomId = +roomNode.getAttribute("data-id");
	this.focus(roomId);

	var pos = messageNode.offsetTop;
	var height = messageNode.clientHeight;

	if (pos < roomNode.scrollTop) {
		roomNode.scrollTop = pos;
		this.rooms[roomId].defaultScroll = false;
	}

	else if (pos + height > roomNode.scrollTop + roomNode.clientHeight) {
		roomNode.scrollTop = pos + height - roomNode.clientHeight;
		this.rooms[roomId].defaultScroll = false;
	}

	messageNode.style.background = "#ff9";

	setTimeout(function () {
		messageNode.style.background = "";
	}, 1000);
};

RoomHandler.prototype.focus = function (id) {
	this.getTab(id).dispatchEvent(new Event('click'));
	var roomNode = this.getRoom(id);

	if (roomNode.scrollHeight === roomNode.clientHeight) {
		this.rooms[id].defaultScroll = true;
		notificationCenter.hideMessageIndicator();
	}
};

RoomHandler.prototype.getTab = function (id) {
	return document.getElementById("room-tab-" + id);
};

RoomHandler.prototype.getRoom = function (id) {
	return document.getElementById("room-" + id);
};

RoomHandler.prototype.getCurrentRoom = function () {
	var id = +document.querySelector(".room-current").getAttribute("data-id");
	return this.rooms[id];
};

RoomHandler.prototype.onScroll = function (node, data) {
	var room = this.rooms[data.id];
	var roomNode = this.getRoom(data.id);

	if (roomNode.scrollTop === roomNode.scrollHeight - roomNode.clientHeight) {
		this.rooms[data.id].defaultScroll = true;
		notificationCenter.hideMessageIndicator();
	} else {
		this.rooms[data.id].defaultScroll = false;
	}

	if (room.infiniteScroll || room.firstLoadableMessage === this.rooms[room.id].firstMessage) {
		return;
	}

	if (node.scrollTop < 600) {
		room.infiniteScroll = true;

		dataHandler.send("transcript", {
			roomId: room.id,
			direction: "older",
			messageId: this.rooms[room.id].firstMessage
		});
	}
};
<commit_msg>Fix Ping Edit Bug<commit_after>var RoomHandler = function () {
	this.rooms = {};
};

RoomHandler.prototype.handleWhereAmI = function (type, data) {
	var handler = this;

	var path = window.location.pathname;
	var roomId = +path.substr(7);

	if (data.length === 0) {
		// TODO: Show room search
		window.location = "/rooms/1";
	} else {
		forEach(data, function (room) {
			handler.add(room);

			if (roomId == room.id) {
				roomHandler.focus(roomId);
			}
		});
	}

	notificationCenter.checkPings();
};

RoomHandler.prototype.handleActivity = function (type, data) {
	var elements = document.getElementsByClassName("user-activity-" + data.userId);

	forEach(elements, function(element) {
		element.setAttribute("data-state", data.state);
	});
};

RoomHandler.prototype.handleTranscript = function (type, data) {
	var room = this.rooms[data.roomId];
	room.infiniteScroll = false;

	var node = this.getRoom(room.id);

	var tempScroll = node.scrollHeight - node.scrollTop;

	forEach(data.messages, function (message) {
		messageHandler.insertMessage(room, message, node);
	});

	if (data.messages.length > 0) {
		node.scrollTop = node.scrollHeight - tempScroll;
	} else {
		room.firstLoadableMessage = +node.children.item(0).getAttribute("data-id");
	}
};

RoomHandler.prototype.handleStars = function (type, data) {
	var stars = document.getElementById('stars-' + data.roomId);
	stars.innerHTML = templateManager.get("starred_messages")(data);

	forEach(stars.children, function (o, i) {
		var node = o.querySelector(".starred-message-text");
		formatter.formatMessage(node, data.messages[i].messageText.replace(/^:\d+ /, ""), null, data.user);

		node = o.querySelector(".starred-message-meta time");
		node.textContent = moment.unix(data.messages[i].time).fromNow();
	});

	forEach(stars.querySelectorAll(".star-message"), function (o) {
		o.addEventListener("click", function () {
			var star = this.getAttribute("data-starred") === "0";
			this.setAttribute("data-starred", star ? "1" : "0");

			var event = star ? "star" : "unstar";
			dataHandler.send(event, {
				messageId: +this.getAttribute("data-message-id")
			});
		});
	});
};

RoomHandler.prototype.handlePing = function (type, data) {
	var node = this.getTab(data.roomId).querySelector(".pings");
	var room = this.rooms[data.roomId];

	for(var i = room.pings.length - 1; i >= 0; i--) {
		if(room.pings[i] === data.messageId) {
			return;
		}
	}

	room.pings.push(data.messageId);
	node.setAttribute("data-pings", room.pings.length);
	notificationCenter.checkPings();

	notificationCenter.notifyMessage("Ping from " + data.user.name + " in " + room.name);
};

RoomHandler.prototype.handlePingClear = function (type, data) {
	for(var x in this.rooms) {
		var room = this.rooms[x];

		for(var i = room.pings.length - 1; i >= 0; i--) {
			if(room.pings[i] === data.messageId) {
				var node = roomHandler.getTab(room.id).querySelector(".pings");
				room.pings.splice(i, 1);

				node.setAttribute("data-pings", room.pings.length);
				notificationCenter.checkPings();
			}
		}
	}
};

RoomHandler.prototype.add = function (data) {
	var handler = this;

	if (data.id in this.rooms) {
		dataHandler.send("missed-query", {
			roomId: data.id,
			last: this.rooms[data.id].lastMessage
		});

		return;
	}

	this.rooms[data.id] = data;
	this.rooms[data.id].firstMessage = -1;
	this.rooms[data.id].lastMessage = -1;
	this.rooms[data.id].firstLoadableMessage = null;
	this.rooms[data.id].infiniteScroll = false;
	this.rooms[data.id].defaultScroll = true;

	var roomNode = nodeFromHTML(templateManager.get("room")(data));
	var roomTabNode = nodeFromHTML(templateManager.get("room_tab")(data));
	var starsNode = nodeFromHTML(templateManager.get("stars")({roomId: data.id}));
	var infoNode = nodeFromHTML(templateManager.get("room_info")(data));

	document.getElementById("rooms").appendChild(roomNode);
	document.getElementById("room-tabs").appendChild(roomTabNode);
	document.getElementById("stars").appendChild(starsNode);
	document.getElementById("room-infos").appendChild(infoNode);

	roomTabNode.addEventListener("click", function () {
		forEach(document.getElementsByClassName("room-current"), function (o) {
			o.classList.remove("room-current");
		});

		forEach(document.getElementsByClassName("room-tab-current"), function (o) {
			o.classList.remove("room-tab-current");
		});

		forEach(document.getElementsByClassName("stars-current"), function (o) {
			o.classList.remove("stars-current");
		});

		forEach(document.getElementsByClassName("room-info-current"), function (o) {
			o.classList.remove("room-info-current");
		});

		roomNode.classList.add("room-current");
		roomTabNode.classList.add("room-tab-current");
		starsNode.classList.add("stars-current");
		infoNode.classList.add("room-info-current");

		var newmessages = parseInt(roomTabNode.getAttribute("data-new-messages"));
		roomTabNode.setAttribute("data-new-messages", "0");

		history.replaceState(null, "", "/rooms/" + data.id);

		if (handler.rooms[data.id].defaultScroll) {
			roomNode.scrollTop += roomNode.clientHeight;
		}

		if ((newmessages || 0) === 0 || roomNode.scrollHeight === roomNode.clientHeight) {
			notificationCenter.hideMessageIndicator();
		} else {
			notificationCenter.showMessageIndicator();
		}
	});

	var pingNode = roomTabNode.querySelector(".pings");
	pingNode.setAttribute("data-pings", this.rooms[data.id].pings.length.toString());

	pingNode.addEventListener("click", function () {
		var messageId = roomHandler.rooms[data.id].pings.shift();

		if (messageId === "undefined") {
			return;
		}

		roomHandler.showMessage(messageId);
		dataHandler.send("ping", {messageId: messageId});
		this.setAttribute("data-pings", roomHandler.rooms[data.id].pings.length.toString());
		notificationCenter.checkPings();
	});

	roomNode.addEventListener("scroll", function () {
		clearTimeout(handler.rooms[data.id].scrollTimeout);

		var node = this;

		handler.rooms[data.id].scrollTimeout = setTimeout(function () {
			handler.onScroll(node, data);
		}, 200);
	});

	dataHandler.send("missed-query", {
		roomId: data.id,
		last: -1
	});

	dataHandler.send("stars", {roomId: data.id});
};

RoomHandler.prototype.showMessage = function (id) {
	var messageNode = messageHandler.getDOM(id);

	if (messageNode === null) {
		window.open("/message/" + id + "#" + id, '_blank');
		return;
	}

	var roomNode = messageNode.parentNode;
	var roomId = +roomNode.getAttribute("data-id");
	this.focus(roomId);

	var pos = messageNode.offsetTop;
	var height = messageNode.clientHeight;

	if (pos < roomNode.scrollTop) {
		roomNode.scrollTop = pos;
		this.rooms[roomId].defaultScroll = false;
	}

	else if (pos + height > roomNode.scrollTop + roomNode.clientHeight) {
		roomNode.scrollTop = pos + height - roomNode.clientHeight;
		this.rooms[roomId].defaultScroll = false;
	}

	messageNode.style.background = "#ff9";

	setTimeout(function () {
		messageNode.style.background = "";
	}, 1000);
};

RoomHandler.prototype.focus = function (id) {
	this.getTab(id).dispatchEvent(new Event('click'));
	var roomNode = this.getRoom(id);

	if (roomNode.scrollHeight === roomNode.clientHeight) {
		this.rooms[id].defaultScroll = true;
		notificationCenter.hideMessageIndicator();
	}
};

RoomHandler.prototype.getTab = function (id) {
	return document.getElementById("room-tab-" + id);
};

RoomHandler.prototype.getRoom = function (id) {
	return document.getElementById("room-" + id);
};

RoomHandler.prototype.getCurrentRoom = function () {
	var id = +document.querySelector(".room-current").getAttribute("data-id");
	return this.rooms[id];
};

RoomHandler.prototype.onScroll = function (node, data) {
	var room = this.rooms[data.id];
	var roomNode = this.getRoom(data.id);

	if (roomNode.scrollTop === roomNode.scrollHeight - roomNode.clientHeight) {
		this.rooms[data.id].defaultScroll = true;
		notificationCenter.hideMessageIndicator();
	} else {
		this.rooms[data.id].defaultScroll = false;
	}

	if (room.infiniteScroll || room.firstLoadableMessage === this.rooms[room.id].firstMessage) {
		return;
	}

	if (node.scrollTop < 600) {
		room.infiniteScroll = true;

		dataHandler.send("transcript", {
			roomId: room.id,
			direction: "older",
			messageId: this.rooms[room.id].firstMessage
		});
	}
};
<|endoftext|>


<commit_before>var _      = require('underscore')
var async  = require('async')
var op     = require('object-path')
var router = require('express').Router()
var soap   = require('soap')

var entu   = require('../../helpers/entu')

router.get('/', function(req, res) {
    res.redirect('https://id.entu.ee/auth/id-card/callback')
})

router.get('/callback', function(req, res, next) {
    async.waterfall([
        function (callback) {
            if (req.headers.ssl_client_verify === 'SUCCESS' && req.headers.ssl_client_cert) {
                callback(null)
            } else {
                callback(new Error('ID-Card reading error'))
            }
        },
        function (callback) {
            soap.createClient('https://digidocservice.sk.ee/?wsdl', callback)
        },
        function (client, callback) {
            client.CheckCertificate({ Certificate: req.headers.ssl_client_cert }, callback)
        },
        function (result, callback) {
            if(op.get(result, ['Status', '$value']) !== 'GOOD') { return callback(new Error('Not valid ID-Card')) }

            var user = {}
            var name = _.compact([
                op.get(result, ['UserGivenname', '$value']),
                op.get(result, ['UserSurname', '$value'])
            ]).join(' ')

            op.set(user, 'provider', 'id-card')
            op.set(user, 'id', op.get(result, ['UserIDCode', '$value']))
            op.set(user, 'name', name)

            entu.addUserSession({ request: req, user: user }, function (err, sessionId) {
                if (err) { return callback(err) }

                callback(null, sessionId)
            })
        }
    ], function (err, sessionId) {
        if(err) { return next(err) }

        var redirectUrl = req.cookies.redirect
        if(redirectUrl) {
            res.clearCookie('redirect')
            res.redirect(redirectUrl + '?session=' + sessionId)
        } else {
            res.redirect('/auth/session/' + sessionId)
        }
    })
})

module.exports = router
<commit_msg>Logout cert<commit_after>var _      = require('underscore')
var async  = require('async')
var op     = require('object-path')
var router = require('express').Router()
var soap   = require('soap')

var entu   = require('../../helpers/entu')

router.get('/', function(req, res) {
    res.redirect('https://id.entu.ee/auth/id-card/callback')
})

router.get('/callback', function(req, res, next) {
    console.log(req.headers.ssl_client_cert)

    async.waterfall([
        function (callback) {
            if (req.headers.ssl_client_verify === 'SUCCESS' && req.headers.ssl_client_cert) {
                callback(null)
            } else {
                callback(new Error('ID-Card reading error'))
            }
        },
        function (callback) {
            soap.createClient('https://digidocservice.sk.ee/?wsdl', callback)
        },
        function (client, callback) {
            client.CheckCertificate({ Certificate: req.headers.ssl_client_cert }, callback)
        },
        function (result, callback) {
            if(op.get(result, ['Status', '$value']) !== 'GOOD') { return callback(new Error('Not valid ID-Card')) }

            var user = {}
            var name = _.compact([
                op.get(result, ['UserGivenname', '$value']),
                op.get(result, ['UserSurname', '$value'])
            ]).join(' ')

            op.set(user, 'provider', 'id-card')
            op.set(user, 'id', op.get(result, ['UserIDCode', '$value']))
            op.set(user, 'name', name)

            entu.addUserSession({ request: req, user: user }, callback)
        }
    ], function (err, sessionId) {
        if(err) { return next(err) }

        var redirectUrl = req.cookies.redirect
        if(redirectUrl) {
            res.clearCookie('redirect')
            res.redirect(redirectUrl + '?session=' + sessionId)
        } else {
            res.redirect('/auth/session/' + sessionId)
        }
    })
})

module.exports = router
<|endoftext|>


<commit_before>import browser from 'detect-browser'
import translations from './translations'

(function () {
  let options = INSTALL_OPTIONS
  let appElement
  const {localStorage = {}} = window
  const {body} = document
  const DAY_DURATION = 1000 * 60 * 60 * 24
  const now = new Date()
  const weekAgo = new Date(now - DAY_DURATION * 7)
  const seenRecently = localStorage.cfBetterBrowserDismissedAt && new Date(parseInt(localStorage.cfBetterBrowserDismissedAt, 10)) >= weekAgo

  const browserVersion = parseFloat(browser.version.match(/(\d.)\./))
  const browserMinimum = options[browser.name] || 0

  const legacyBodyClass = 'cloudflare-old-browser-body'

  function removeBodyClass () {
    body.className = body.className.replace(new RegExp(`(?:^|s)${legacyBodyClass}(?!S)`, 'g'), '')
  }

  function updateElement () {
    const outdated = browserVersion < browserMinimum
    let visibility = !seenRecently && outdated ? 'visible' : 'hidden'

    removeBodyClass()
    if (INSTALL_ID === 'preview') visibility = 'visible'
    if (visibility !== 'visible') return

    const language = window.navigator.language || window.navigator.userLanguage || 'en'
    const [messageLabel, moreLabel] = translations[language] || translations[language.substring(0, 2)] || translations.en

    appElement = appElement || document.createElement('cloudflare-app')
    appElement.setAttribute('app-id', 'a-better-browser')
    appElement.id = 'cloudflare-old-browser' // Legacy ID

    appElement.innerHTML = `
      <cloudflare-app-message>
        ${messageLabel}
        ${moreLabel}
        </cloudflare-app-message>
      <cloudflare-app-close>×</cloudflare-app-close>
    `
    const closeButton = appElement.querySelector('cloudflare-app-close')
    closeButton.id = 'cloudflare-old-browser-close' // Legacy ID

    closeButton.addEventListener('click', () => {
      appElement.setAttribute('data-visibility', 'hidden')
      localStorage.cfBetterBrowserDismissedAt = now.getTime()
      removeBodyClass()
    })

    appElement.setAttribute('data-visibility', visibility)
    body.appendChild(appElement)

    body.className += legacyBodyClass
    body.setAttribute('data-cf-browser-state', outdated ? 'outdated' : 'modern')
    body.setAttribute('data-cf-browser-version', browserVersion)
    body.setAttribute('data-cf-browser-name', browser.name)
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', updateElement)
  } else {
    updateElement()
  }

  window.INSTALL_SCOPE = {
    setOptions (nextOptions) {
      options = nextOptions
      updateElement()
    }
  }
}())
<commit_msg>Support decimals in version numbers.<commit_after>import browser from 'detect-browser'
import translations from './translations'

(function () {
  let options = INSTALL_OPTIONS
  let appElement
  const {localStorage = {}} = window
  const {body} = document
  const DAY_DURATION = 1000 * 60 * 60 * 24
  const now = new Date()
  const weekAgo = new Date(now - DAY_DURATION * 7)
  const seenRecently = localStorage.cfBetterBrowserDismissedAt && new Date(parseInt(localStorage.cfBetterBrowserDismissedAt, 10)) >= weekAgo

  const browserVersion = parseFloat(browser.version.match(/^(\d+\.?\d*)/))
  const browserMinimum = options[browser.name] || 0

  const legacyBodyClass = 'cloudflare-old-browser-body'

  function removeBodyClass () {
    body.className = body.className.replace(new RegExp(`(?:^|s)${legacyBodyClass}(?!S)`, 'g'), '')
  }

  function updateElement () {
    const outdated = browserVersion < browserMinimum
    let visibility = !seenRecently && outdated ? 'visible' : 'hidden'

    removeBodyClass()
    if (INSTALL_ID === 'preview') visibility = 'visible'
    if (visibility !== 'visible') return

    const language = window.navigator.language || window.navigator.userLanguage || 'en'
    const [messageLabel, moreLabel] = translations[language] || translations[language.substring(0, 2)] || translations.en

    appElement = appElement || document.createElement('cloudflare-app')
    appElement.setAttribute('app-id', 'a-better-browser')
    appElement.id = 'cloudflare-old-browser' // Legacy ID

    appElement.innerHTML = `
      <cloudflare-app-message>
        ${messageLabel}
        ${moreLabel}
        </cloudflare-app-message>
      <cloudflare-app-close>×</cloudflare-app-close>
    `
    const closeButton = appElement.querySelector('cloudflare-app-close')
    closeButton.id = 'cloudflare-old-browser-close' // Legacy ID

    closeButton.addEventListener('click', () => {
      appElement.setAttribute('data-visibility', 'hidden')
      localStorage.cfBetterBrowserDismissedAt = now.getTime()
      removeBodyClass()
    })

    appElement.setAttribute('data-visibility', visibility)
    body.appendChild(appElement)

    body.className += legacyBodyClass
    body.setAttribute('data-cf-browser-state', outdated ? 'outdated' : 'modern')
    body.setAttribute('data-cf-browser-version', browserVersion)
    body.setAttribute('data-cf-browser-name', browser.name)
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', updateElement)
  } else {
    updateElement()
  }

  window.INSTALL_SCOPE = {
    setOptions (nextOptions) {
      options = nextOptions
      updateElement()
    }
  }
}())
<|endoftext|>


<commit_before>
/*

This file is part of Aaron Rest Server.

Aaron Rest Server is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Aaron Rest Server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Aaron Rest Server.  If not, see <http://www.gnu.org/licenses/>.

*/

'use strict';

var util      = require('util');
var orgLog    = util.debuglog('org');

//var config    = require('../config');

var pool = null;

function updateOrganization(req, res) {
  orgLog('update request received!');
  pool.getConnection(function(err, connection) {
    if(err) {
      console.error(err);
      return res.send(500, new Error('mysql'));
    }

    // TODO: check permissions!

    var post = {};
    if(typeof req.params.shortname !== 'string') {
      console.error('updateOrganization: invalid-input-data');
      return res.send(400, new Error('invalid-input-data'));
    }
    /*if(typeof req.body.organization_shortname === 'string') {
      if(req.body.organization_shortname.length > 0  && req.body.organization_shortname.length < 256) {
        post.organization_shortname = req.body.organization_shortname;
      } else {
        console.error('updateOrganization: invalid-input-data, shortname');
        return res.send(400, new Error('invalid-input-data, shortname'));
      }
    }*/
    if(typeof req.body.organization_name === 'string') {
      if(req.body.organization_name.length > 0  && req.body.organization_name.length < 256) {
        post.organization_name = req.body.organization_name;
      } else {
        console.error('updateOrganization: invalid-input-data, name');
        return res.send(400, new Error('invalid-input-data, name'));
      }
    }
    if(Object.keys(post).length === 0) {
      console.error('updateOrganization: invalid-input-data');
      return res.send(400, new Error('no-data-inputted'));
    }
    var query = connection.query(
      'UPDATE organizations '+
      'SET ? '+
      'WHERE organization_name = ?;'
      , [post, req.params.organization_shortname], function(err, results) {
        connection.release();
        if(err) {
          console.error(err, query.sql);
          return res.send(500, new Error('mysql'));
        }
        console.log(results);
        return res.send(200, {message: 'success'});
      }
    );
  });
}

function getMyOrganizations(req, res) {
  orgLog('update request received!');
  pool.getConnection(function(err, connection) {
    if(err) {
      console.error(err);
      return res.send(500, new Error('mysql'));
    }
    connection.query(
      'SELECT organization_shortname, organization_name FROM users '+
      'INNER JOIN users_has_workplaces ON user_id = users_user_id '+
      'INNER JOIN workplaces ON workplace_id = workplaces_workplace_id '+
      'INNER JOIN organizations ON organizations_organization_shortname = organization_shortname '+
      'WHERE user_email = ? OR user_pemail = ?;', [req.authUser, req.authUser], function(err, results) {
        if(err) {
          console.error(err);
          return res.send(500, new Error('mysql'));
        }
        res.send(200, results);
      }
    );
  });
}

function activateRoute(server, mysqlPool, checkAuth) {
  pool = mysqlPool;
  server.put('/organization/:shortname', checkAuth, updateOrganization);
  server.get('/organization/for/me', checkAuth, getMyOrganizations);
}

module.exports.activateRoute = activateRoute;<commit_msg>changed debug message<commit_after>
/*

This file is part of Aaron Rest Server.

Aaron Rest Server is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Aaron Rest Server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Aaron Rest Server.  If not, see <http://www.gnu.org/licenses/>.

*/

'use strict';

var util      = require('util');
var orgLog    = util.debuglog('org');

//var config    = require('../config');

var pool = null;

function updateOrganization(req, res) {
  orgLog('update request received!');
  pool.getConnection(function(err, connection) {
    if(err) {
      console.error(err);
      return res.send(500, new Error('mysql'));
    }

    // TODO: check permissions!

    var post = {};
    if(typeof req.params.shortname !== 'string') {
      console.error('updateOrganization: invalid-input-data');
      return res.send(400, new Error('invalid-input-data'));
    }
    /*if(typeof req.body.organization_shortname === 'string') {
      if(req.body.organization_shortname.length > 0  && req.body.organization_shortname.length < 256) {
        post.organization_shortname = req.body.organization_shortname;
      } else {
        console.error('updateOrganization: invalid-input-data, shortname');
        return res.send(400, new Error('invalid-input-data, shortname'));
      }
    }*/
    if(typeof req.body.organization_name === 'string') {
      if(req.body.organization_name.length > 0  && req.body.organization_name.length < 256) {
        post.organization_name = req.body.organization_name;
      } else {
        console.error('updateOrganization: invalid-input-data, name');
        return res.send(400, new Error('invalid-input-data, name'));
      }
    }
    if(Object.keys(post).length === 0) {
      console.error('updateOrganization: invalid-input-data');
      return res.send(400, new Error('no-data-inputted'));
    }
    var query = connection.query(
      'UPDATE organizations '+
      'SET ? '+
      'WHERE organization_name = ?;'
      , [post, req.params.organization_shortname], function(err, results) {
        connection.release();
        if(err) {
          console.error(err, query.sql);
          return res.send(500, new Error('mysql'));
        }
        console.log(results);
        return res.send(200, {message: 'success'});
      }
    );
  });
}

function getMyOrganizations(req, res) {
  orgLog('fetch users organizations received!');
  pool.getConnection(function(err, connection) {
    if(err) {
      console.error(err);
      return res.send(500, new Error('mysql'));
    }
    connection.query(
      'SELECT organization_shortname, organization_name FROM users '+
      'INNER JOIN users_has_workplaces ON user_id = users_user_id '+
      'INNER JOIN workplaces ON workplace_id = workplaces_workplace_id '+
      'INNER JOIN organizations ON organizations_organization_shortname = organization_shortname '+
      'WHERE user_email = ? OR user_pemail = ?;', [req.authUser, req.authUser], function(err, results) {
        if(err) {
          console.error(err);
          return res.send(500, new Error('mysql'));
        }
        res.send(200, results);
      }
    );
  });
}

function activateRoute(server, mysqlPool, checkAuth) {
  pool = mysqlPool;
  server.put('/organization/:shortname', checkAuth, updateOrganization);
  server.get('/organization/for/me', checkAuth, getMyOrganizations);
}

module.exports.activateRoute = activateRoute;<|endoftext|>


<commit_before>'use strict';

var passport = require('passport'),
    nconf = require('nconf'),
    utils = require('../lib/utils'),
    geboSchema = require('../schemata/gebo'),
    agentSchema = require('../schemata/agent'),
    extend = require('extend'),
    q = require('q');

module.exports = function(email) {

    // Turn the email into a mongo-friend database name
    var dbName = utils.ensureDbName(email);

    /**
     * Receive a request for consideration
     */
    exports.request = [
        passport.authenticate('bearer', { session: false }),
        function(req, res) {

            // There might be files attached to the request
            var params = req.body;
            extend(true, params, req.files);

            _verify(req.user, params).
                then(function(verified) {
                        console.log('request');
                        console.log(req.body);
                        console.log(req.user);
                        console.log(req.authInfo);
                        console.log('params');
                        console.log(params);
                        console.log('verified');
                        console.log(verified);

                        var action = require('../config/action')(dbName);
                        action[req.body.action](verified, params).
                            then(function(data) {
                                res.send(data);
                              }).
                            catch(function(err) {
                                console.log(err);
                                res.send(404, err);
                              });
                      }).
                catch(function(err) {
                    console.log(err);
                    res.send(401, err);
                  });
          }
      ];

    /**
     * Determine what permissions an agent has on a
     * given object
     *
     * @param Object
     * @param Object
     *
     * @return promise
     */
    function _verify(agent, params) {
        var deferred = q.defer();

	var verified = {
                collectionName: utils.getMongoCollectionName(params.collectionName),
                admin: agent.admin,
                dbName: utils.getMongoDbName(params.dbName)
            };

        if (!verified.dbName) {
          verified.dbName = utils.getMongoDbName(agent.email);
        }

        if (utils.getMongoDbName(agent.email) !== verified.dbName && !verified.admin) {
          var agentDb = new agentSchema(verified.dbName);

          agentDb.friendModel.findOne({ email: agent.email}, function(err, friend) {
                if (err) {
                  deferred.reject(err);
                }
                if (!friend) {
                  deferred.reject('I don\'t know you');
                }
                else {
                  // Search the array for requested resource
                  var index = utils.getIndexOfObject(friend.hisPermissions, 'email', verified.collectionName);

                  if (index > -1) {
                    verified.read = friend.hisPermissions[index].read;
                    verified.write = friend.hisPermissions[index].write;
                    verified.execute = friend.hisPermissions[index].execute;
                    deferred.resolve(verified);
                  }
                  else {
                    deferred.reject('You don\'t have access to that resource');
                  }
                }
                agentDb.connection.db.close();
              });
        }
        // This agent is requesting access to his own resources
        else {
          verified.read = true;
          verified.write = true;
          verified.execute = true;
          deferred.resolve(verified);
        }

        return deferred.promise;
      };
    exports.verify = _verify;

    return exports;
  };

<commit_msg>Add debug console output<commit_after>'use strict';

var passport = require('passport'),
    nconf = require('nconf'),
    utils = require('../lib/utils'),
    geboSchema = require('../schemata/gebo'),
    agentSchema = require('../schemata/agent'),
    extend = require('extend'),
    q = require('q');

module.exports = function(email) {

    // Turn the email into a mongo-friend database name
    var dbName = utils.ensureDbName(email);

    /**
     * Receive a request for consideration
     */
    exports.request = [
        passport.authenticate('bearer', { session: false }),
        function(req, res) {

            // There might be files attached to the request
            var params = req.body;
            extend(true, params, req.files);

            _verify(req.user, params).
                then(function(verified) {
                        console.log('request');
                        console.log(req.body);
                        console.log(req.user);
                        console.log(req.authInfo);
                        console.log('params');
                        console.log(params);
                        console.log('verified');
                        console.log(verified);

                        var action = require('../config/action')(dbName);
                        action[req.body.action](verified, params).
                            then(function(data) {
                                res.send(data);
                              }).
                            catch(function(err) {
                                console.log('action error');
                                console.log(err);
                                res.send(404, err);
                              });
                      }).
                catch(function(err) {
                    console.log('verification error');
                    console.log(err);
                    res.send(401, err);
                  });
          }
      ];

    /**
     * Determine what permissions an agent has on a
     * given object
     *
     * @param Object
     * @param Object
     *
     * @return promise
     */
    function _verify(agent, params) {
        var deferred = q.defer();

	var verified = {
                collectionName: utils.getMongoCollectionName(params.collectionName),
                admin: agent.admin,
                dbName: utils.getMongoDbName(params.dbName)
            };

        if (!verified.dbName) {
          verified.dbName = utils.getMongoDbName(agent.email);
        }

        if (utils.getMongoDbName(agent.email) !== verified.dbName && !verified.admin) {
          var agentDb = new agentSchema(verified.dbName);

          agentDb.friendModel.findOne({ email: agent.email}, function(err, friend) {
                console.log('friend');
                console.log(friend);
                if (err) {
                  deferred.reject(err);
                }
                if (!friend) {
                  deferred.reject('I don\'t know you');
                }
                else {
                  // Search the array for requested resource
                  var index = utils.getIndexOfObject(friend.hisPermissions, 'email', verified.collectionName);

                  if (index > -1) {
                    verified.read = friend.hisPermissions[index].read;
                    verified.write = friend.hisPermissions[index].write;
                    verified.execute = friend.hisPermissions[index].execute;
                    deferred.resolve(verified);
                  }
                  else {
                    deferred.reject('You don\'t have access to that resource');
                  }
                }
                agentDb.connection.db.close();
              });
        }
        // This agent is requesting access to his own resources
        else {
          verified.read = true;
          verified.write = true;
          verified.execute = true;
          deferred.resolve(verified);
        }

        return deferred.promise;
      };
    exports.verify = _verify;

    return exports;
  };

<|endoftext|>


<commit_before>var express = require('express')
var path = require('path')
var appDir = path.dirname(require.main.filename)
var familyDao = require(appDir + '/data/family-dao.js')

var router = express.Router()

// GET all the family
router.get('/', function (req, res) {
    familyDao.getAllFamily(function(family) {
        res.json(family)
    })
})

// GET the family member by id
router.get('/:familyMemberId', function (req, res) {
    var familyMemberId = req.params.familyMemberId
    console.log(familyMemberId)
    familyDao.getFamilyById(familyMemberId, function(family) {
        res.json(family)
    })
})

// POST the location to this family member by id
router.post('/:familyMemberId', function (req, res) {
    var familyMemberId = req.params.familyMemberId
    var body = req.body;
    console.log("familyMemberId: " + familyMemberId)
    console.log("body: " + req.body)
    familyDao.updateFamilyLocationById(familyMemberId, body, function(family) {
        res.json(family)
    })
})

// GET the family members at the location with this id
router.get('/location/:locationId', function (req, res) {
    var locationId = req.params.locationId
    console.log(locationId)
    familyDao.getFamilyByLocationId(locationId, function(family) {
        res.json(family)
    })
})

module.exports = router<commit_msg>Adding POST call to update family member's location - fix 5<commit_after>var express = require('express')
var path = require('path')
var appDir = path.dirname(require.main.filename)
var familyDao = require(appDir + '/data/family-dao.js')

var router = express.Router()

// GET all the family
router.get('/', function (req, res) {
    familyDao.getAllFamily(function(family) {
        res.json(family)
    })
})

// GET the family member by id
router.get('/:familyMemberId', function (req, res) {
    var familyMemberId = req.params.familyMemberId
    console.log(familyMemberId)
    familyDao.getFamilyById(familyMemberId, function(family) {
        res.json(family)
    })
})

// POST the location to this family member by id
router.post('/:familyMemberId', function (req, res) {
    var familyMemberId = req.params.familyMemberId
    var body = req.body;
    console.log("familyMemberId: " + familyMemberId)
    console.log("body: " +  JSON.stringify(req.body))
    familyDao.updateFamilyLocationById(familyMemberId, body, function(family) {
        res.json(family)
    })
})

// GET the family members at the location with this id
router.get('/location/:locationId', function (req, res) {
    var locationId = req.params.locationId
    console.log(locationId)
    familyDao.getFamilyByLocationId(locationId, function(family) {
        res.json(family)
    })
})

module.exports = router<|endoftext|>


<commit_before>'use strict';

const { Router } = require('express');
const jsonParser = require('body-parser').json();
const bearerAuth = require('../lib/bearer-auth');

const User = require('../model/user');
const Trade = require('../model/trade');

const tradeRouter = module.exports = new Router();

tradeRouter.post('/api/profile/trade', jsonParser, (req, res, next) => {
  const serial = req.body.serial;
  if(!serial || !buyPrice) return next(new Error('required arguments'));
  Trade.find(serial, (err, trade) => {
    if(err) return next(new Error('bad request'));
    const tradeCopy = Object.assign({}, trade);
    const currentDate = new Date();
    const price = req.body.buyPrice;
    trade.soldTo = req.user._id;
    trade.sellPrice = price;
    trade.sellDate = currentDate;
    trade.forSale = false;
    trade.save(() => {
      tradeCopy.purchasedFrom = req.user.username;
      tradeCopy.purchasePrice = price;
      tradeCopy.purchaseDate = currentDate;
      User.findById(req.user._id)
      .then(user => {
        user.trades.push(tradeCopy);
        return res.sendStatus(200);
      })
      .catch(() => next(new Error('bad request')));
    });
  });
});

tradeRouter.put('/api/profile/trade', jsonParser, (req, res, next) => {
  const { serial, forSale, askingPrice } = req.body;
  if (!forSale || !askingPrice) return next(new Error('required arguments'));
  Trade.find(serial)
    .then(trade => {
      trade.forSale = forSale;
      trade.askingPrice = askingPrice;
      trade.save(() => res.sendStatus(200));
    })
    .catch(() => next(new Error('bad request')));
});

tradeRouter.get('/api/profile/trade', (req, res, next) => {
  const { type, max } = req.params;
  Trade.find(type)
    .then(trades => {
      trades.filter(v => v < max);
      return res.json(trades);
    })
    .catch(() => next(new Error('bad request')));
});
<commit_msg>fix get route<commit_after>'use strict';

const { Router } = require('express');
const jsonParser = require('body-parser').json();
const bearerAuth = require('../lib/bearer-auth');

const User = require('../model/user');
const Trade = require('../model/trade');

const tradeRouter = module.exports = new Router();

tradeRouter.post('/api/profile/trade', jsonParser, (req, res, next) => {
  const serial = req.body.serial;
  if(!serial || !buyPrice) return next(new Error('required arguments'));
  Trade.find(serial, (err, trade) => {
    if(err) return next(new Error('bad request'));
    const tradeCopy = Object.assign({}, trade);
    const currentDate = new Date();
    const price = req.body.buyPrice;
    trade.soldTo = req.user._id;
    trade.sellPrice = price;
    trade.sellDate = currentDate;
    trade.forSale = false;
    trade.save(() => {
      tradeCopy.purchasedFrom = req.user.username;
      tradeCopy.purchasePrice = price;
      tradeCopy.purchaseDate = currentDate;
      User.findById(req.user._id)
      .then(user => {
        user.trades.push(tradeCopy);
        return res.sendStatus(200);
      })
      .catch(() => next(new Error('bad request')));
    });
  });
});

tradeRouter.put('/api/profile/trade', jsonParser, (req, res, next) => {
  const { serial, forSale, askingPrice } = req.body;
  if (!forSale || !askingPrice) return next(new Error('required arguments'));
  Trade.find(serial)
    .then(trade => {
      trade.forSale = forSale;
      trade.askingPrice = askingPrice;
      trade.save(() => res.sendStatus(200));
    })
    .catch(() => next(new Error('bad request')));
});

tradeRouter.get('/api/profile/trade', (req, res, next) => {
  const { type, max } = req.params;
  Trade.find(type)
    .then(trades => {
      trades = max ?  trades.filter(v => v < max) : trades;
      return res.json(trades);
    })
    .catch(() => next(new Error('bad request')));
});
<|endoftext|>


<commit_before>import doxme from "doxme";
import util from "gulp-util";
import {obj as through} from "through2";

var DoxmeError = util.PluginError.bind(null, "gulp-doxme");

export default (settings) => {
  return through(function gulpDoxme (file, encoding, done) {
    var data = file.data || (() => {
      try {return JSON.parse(file.contents.toString());}
      catch (error) {done(new DoxmeError(
        "Input must be a valid JSON file."
        ));}
      })();

    var markdown;
    try {markdown = doxme(data);}
    catch (error) {return done(new DoxmeError
      ( "Something went wrong with the doxme call. Here's what doxme says:\n"
      + error.message
      ));}

    var output = file.clone();
    output.path = util.replaceExtension(file.path, ".md");
    output.contents = new Buffer(markdown);
    done(null, output);
    });
  };
<commit_msg>Don't emit multiple errors<commit_after>import doxme from "doxme";
import util from "gulp-util";
import {obj as through} from "through2";

var DoxmeError = util.PluginError.bind(null, "gulp-doxme");

export default (settings) => {
  return through(function gulpDoxme (file, encoding, done) {
    var data = file.data;
    if (!data) {
      try {data = JSON.parse(file.contents.toString());}
      catch (error) {return done(new DoxmeError(
        "Input must be a valid JSON file."
        ));}
      }

    var markdown;
    try {markdown = doxme(data);}
    catch (error) {return done(new DoxmeError
      ( "Something went wrong with the doxme call. Here's what doxme says:\n"
      + error.message
      ));}

    var output = file.clone();
    output.path = util.replaceExtension(file.path, ".md");
    output.contents = new Buffer(markdown);
    done(null, output);
    });
  };
<|endoftext|>


<commit_before>// Load in dependencies
var cheerio = require('cheerio');
var request = require('request');

// Make a request, normalize our HTML via Cheerio
request('http://localhost:8080/', function (err, res, body) {
  // If there is an error, throw it
  if (err) {
    throw err;
  }

  // Otherwise, coerce our data
  var $ = cheerio.load(body);
  console.log($('head').html());
});
<commit_msg>dom nodes seem to be on a per-level basis<commit_after>// Load in dependencies
var htmlparser2 = require('htmlparser2');
var request = require('request');

// Make a request, normalize our HTML via Cheerio
request('http://localhost:8080/', function (err, res, body) {
  // If there is an error, throw it
  if (err) {
    throw err;
  }

  // Otherwise, coerce our data
  var dom = htmlparser2.parseDOM(body);
  var node = dom[0];
  while (node) {
    console.log('node', node);
    node = node.next;
  }
});
<|endoftext|>


<commit_before>/*
 File that will be injected in the page by the content script in order to retrieve angular
 performance metrics.

 Heavily inspired by:
 - ng stats
 - ng inspector
 - Angular Inspector
 - Batarang

 */
(function() {
  'use strict';

  var
    _angularInjector,
    _isMonitoringActive = true,
    _backUp = {
      digest: null,
      modules: {}
    };

  if (document.readyState === 'complete'){
    detectAngular();
  } else {
    window.onload(detectAngular)
  }

  /**
   * If angular is detected, bootstraps the inspector
   */
  function detectAngular(){
    if (typeof angular !== 'undefined') {

      window.postMessage({
        task: 'initDevToolPanel',
        source: 'angular-performance-inspector'
      }, '*');

      // We listen for async instrumentation instructions
      window.addEventListener('message', function(event){
        // We only accept messages from ourselves
        if (event.source != window || event.data.source !== 'angular-performance') {
          return;
        }

        var message = event.data;

        switch (message.task){

          case 'checkModuleName':
            var moduleServices = getNgModuleServices(message.moduleName);
            // If there is no services the method will return an empty object, if the module name is
            // invalid, it will return undefined.
            sendTask('reportModuleExistence', {
              moduleName: message.moduleName,
              services: (moduleServices) ? Object.keys(moduleServices) : undefined
            });
            break;

          case 'instrumentModuleServices':
            instrumentModuleServices(message.moduleName);
            break;

          case 'cleanUpInspectedApp':
            _isMonitoringActive = false;
            cleanUpInspectedApp();
            // Once everything is cleaned up, we can remove this script from the DOM
            sendTask('removeInspector');
            break;
        }
      });

      bootstrapInspector();
    }
  }

  /**
   * Function to set up all listeners and data mining tools
   */
  function bootstrapInspector(){

    _angularInjector = angular.element(document.querySelector('[ng-app],[data-ng-app]')).injector().get;

    instrumentDigest();
    initWatcherCount();
  }

  /**
   * This should clean up all that has been instrumented by the inspector and get them back
   * to their normal behaviour. (UnWrap everything)
   */
  function cleanUpInspectedApp(){
    restoreDigest();
    restoreModuleServices();
  }

  // ------------------------------------------------------------------------------------------
  //                                     Digest Monitoring
  // ------------------------------------------------------------------------------------------

  /**
   * Wraps the angular digest so that we can measure how long it take for the digest to happen.
   */
  function instrumentDigest(){

    var scopePrototype = Object.getPrototypeOf(getRootScope());
    _backUp.digest = scopePrototype.$digest;

    scopePrototype.$digest = function $digest() {
      var start = performance.now();
      _backUp.digest.apply(this, arguments);
      var time = (performance.now() - start);
      register('DigestTiming', {
        timestamp: Date.now(),
        time: time
      });
    };
  }

  /**
   * Restores the classic angular digest.
   */
  function restoreDigest(){
    Object.getPrototypeOf(getRootScope()).$digest = _backUp.digest;
  }

  // ------------------------------------------------------------------------------------------
  //                                Scope & Watcher Exploration
  // ------------------------------------------------------------------------------------------

  /**
   * Function to be called once to init the watcher retrieval.
   */
  function initWatcherCount(){
    register('RootWatcherCount', {
      timestamp: Date.now(),
      watcher:{
        watcherCount: getWatcherCountForScope(),
        location: window.location.href
      }
    });
    if (_isMonitoringActive) {
      setTimeout(initWatcherCount, 300);
    }
  }

  /**
   * Retrieves the watcher count for a particular scope
   *
   * @param {angular.scope} [$scope] - angular scope instance
   * @returns {number}               - angular scope count
   */
  function getWatcherCountForScope($scope) {
    var count = 0;
    iterateScopes($scope, function($scope) {
      count += getWatchersFromScope($scope).length;
    });
    return count;
  }

  /**
   * Apply a function down the angular scope
   *
   * @param {angular.scope} [current] - current angular $scope
   * @param {Function}      fn        - function to apply down the scope
   * @returns {*}
   */
  function iterateScopes(current, fn) {
    if (typeof current === 'function') {
      fn = current;
      current = null;
    }
    current = current || getRootScope();
    current = makeScopeReference(current);
    if (!current) {
      return;
    }
    var ret = fn(current);
    if (ret === false) {
      return ret;
    }
    return iterateChildren(current, fn);
  }

  /**
   * Apply a function on a scope siblings (same scope level) and down to their children
   *
   * @param {angular.scope} start - starting scope of the iteration
   * @param {Function}      fn    - function to be applied on the different scopes
   * @returns {*}
   */
  function iterateSiblings(start, fn) {
    var ret;
    while (!!(start = start.$$nextSibling)) {
      ret = fn(start);
      if (ret === false) {
        break;
      }

      ret = iterateChildren(start, fn);
      if (ret === false) {
        break;
      }
    }
    return ret;
  }

  /**
   * Apply a function on all the children scopes and their respective siblings
   *
   * @param {angular.scope} start - start node of the
   * @param {Function}      fn    - function to apply
   * @returns {*}
   */
  function iterateChildren(start, fn) {
    var ret;
    while (!!(start = start.$$childHead)) {
      ret = fn(start);
      if (ret === false) {
        break;
      }

      ret = iterateSiblings(start, fn);
      if (ret === false) {
        break;
      }
    }
    return ret;
  }

  /**
   * Gets the angular root scope
   *
   * @returns {angular.scope}
   */
  function getRootScope(){
    if (typeof $rootScope !== 'undefined') {
      return $rootScope;
    }
    var scopeEl = document.querySelector('.ng-scope');
    if (!scopeEl) {
      return null;
    }
    return angular.element(scopeEl).scope().$root;
  }

  /**
   * Retrieve all watchers from a scope
   *
   * @param {angular.scope} scope - angular scope to get the watchers from
   * @returns {Array}
   */
  function getWatchersFromScope(scope) {
    return scope && scope.$$watchers ? scope.$$watchers : [];
  }

  /**
   * Gets the id of a scope
   *
   * @param {angular.scope} scope - angular scope to get the id from
   * @returns {angular.scope}
   */
  function makeScopeReference(scope) {
    if (isScopeId(scope)) {
      scope = getScopeById(scope);
    }
    return scope;
  }

  /**
   * Gets the scope from an ID
   *
   * @param {String|Number} id - scope id
   * @returns {angular.scope}
   */
  function getScopeById(id) {
    var myScope = null;
    iterateScopes(function(scope) {
      if (scope.$id === id) {
        myScope = scope;
        return false;
      }
    });
    return myScope;
  }

  /**
   * Check if the scope passed as an argument is an id or not.
   *
   * @param {angular.scope} scope
   * @returns {boolean}
   */
  function isScopeId(scope) {
    return typeof scope === 'string' || typeof scope === 'number';
  }

  // ------------------------------------------------------------------------------------------
  //                                     Module & Services
  // ------------------------------------------------------------------------------------------

  /**
   * Gets all the services name from the specified module
   *
   * @param {String}  moduleName - name of the module to get the services from
   * @param {Object}  [services] - already found services (parent module) can be null
   * @returns {Object|undefined} map of all the angular services linked to the specified module.
   *                             returns undefined if the module isn't defined
   */
  function getNgModuleServices(moduleName, services){

    if (!services) {
      services = {};
    }

    var module;

    try {
      module = angular.module(moduleName);
    } catch(e){
      return;
    }

    angular.forEach(module._invokeQueue, function(service) {
      if (service[0] === '$provide' && service[1] === 'service') {
        services[service[2][0]] = _angularInjector(service[2][0]);
      }
    });

    angular.forEach(module.requires, function(dependencyModule) {
      getNgModuleServices(dependencyModule, services)
    });

    return services;
  }

  /**
   * This methods adds timers to all the functions of all the services of a given module
   *
   * @param {String} moduleName - module name to instrument.
   */
  function instrumentModuleServices(moduleName){

    _backUp.modules[moduleName] = {};
    var services = getNgModuleServices(moduleName);

    angular.forEach(Object.keys(services), function(serviceName){

      _backUp.modules[moduleName][serviceName] = {};
      var service = services[serviceName];

      angular.forEach(Object.getOwnPropertyNames(service), function(propertyName){

        // Early return for all properties that are not functions
        // arguments is a reserved property name
        if (propertyName === 'arguments' ||
            propertyName === 'caller' ||
            propertyName === 'callee' ||
            typeof service[propertyName] !== 'function' ||
            propertyName === 'constructor') {
          return;
        }

        var functionToWrap = _backUp.modules[moduleName][serviceName][propertyName] = service[propertyName];

        // We Wrap all the service functions to measure execution time.
        service[propertyName] = function(){
          var
            start = performance.now(),
            // Execute the function as usual
            result = functionToWrap.apply(this, arguments);

          // Register execution time in the extension registry
          register('SyncServiceFunctionCall', {
            module: moduleName,
            service: serviceName,
            func: propertyName,
            time: performance.now() - start
          });

          // We only consider promises since it is the default async handling in angular.
          if (result && typeof result.then === 'function') {
            // We reset the timer so that only async time gets taken.
            start = performance.now();

            // We Append our timing promise to the actual promise
            result.then(function() {
              register('ASyncServiceFunctionCall', {
                module: moduleName,
                service: serviceName,
                func: propertyName,
                time: performance.now() - start
              });
            })
          }
          return result;
        }
      })
    });
  }

  /**
   * Restores the services functions as they were before being wrapped
   *
   * @param {String} [moduleName] - name of the module to be unwrapped. If not mentioned, everything
   *                                should be restored.
   */
  function restoreModuleServices(moduleName){

    var modules;

    if (moduleName){

      if (_backUp.modules[moduleName]) {
        modules = [moduleName];
      } else {
        throw new Error('angular performance - We tried to restore the module '+ moduleName + 'but ' +
          'we could not find any back up :(');
      }

    } else {
      modules = Object.keys(_backUp.modules);
    }

    angular.forEach(modules, function(module){
      var services = getNgModuleServices(module);

      angular.forEach(Object.keys(_backUp.modules[module]), function(service){
        angular.forEach(Object.keys(_backUp.modules[module][service]), function(fnName){
          services[service][fnName] = _backUp.modules[module][service][fnName]
        });
      });

      // Clean up back up
      delete _backUp.modules[module];
    });
  }

  // ------------------------------------------------------------------------------------------
  //                                        Utils
  // ------------------------------------------------------------------------------------------

  /**
   * Reports a metric
   *
   * @param {String} task  - task to do
   * @param {Object} [value] - data that can be sent along with the task
   */
  function sendTask(task, value){
    window.postMessage({
      source: 'angular-performance-inspector',
      task: task,
      data: value
    }, '*');
  }

  /**
   * Register a metric into the devtool instance registry
   *
   * @param {String} variable - can be 'digestTiming'
   * @param {Object} value    - value to be registered with the variable
   */
  function register(variable, value){
    sendTask('register'+variable, value);
  }
})();
<commit_msg>#20 - integrating pull request<commit_after>/*
 File that will be injected in the page by the content script in order to retrieve angular
 performance metrics.

 Heavily inspired by:
 - ng stats
 - ng inspector
 - Angular Inspector
 - Batarang

 */
(function() {
  'use strict';

  var
    _angularInjector,
    _isMonitoringActive = true,
    _backUp = {
      digest: null,
      modules: {}
    };

  if (document.readyState === 'complete'){
    setTimeout(detectAngular, 0);
  } else {
    window.onload(function() {
      setTimeout(detectAngular, 0);
    });
  }

  /**
   * If angular is detected, bootstraps the inspector
   */
  function detectAngular(){
    if (typeof angular !== 'undefined') {

      window.postMessage({
        task: 'initDevToolPanel',
        source: 'angular-performance-inspector'
      }, '*');

      // We listen for async instrumentation instructions
      window.addEventListener('message', function(event){
        // We only accept messages from ourselves
        if (event.source != window || event.data.source !== 'angular-performance') {
          return;
        }

        var message = event.data;

        switch (message.task){

          case 'checkModuleName':
            var moduleServices = getNgModuleServices(message.moduleName);
            // If there is no services the method will return an empty object, if the module name is
            // invalid, it will return undefined.
            sendTask('reportModuleExistence', {
              moduleName: message.moduleName,
              services: (moduleServices) ? Object.keys(moduleServices) : undefined
            });
            break;

          case 'instrumentModuleServices':
            instrumentModuleServices(message.moduleName);
            break;

          case 'cleanUpInspectedApp':
            _isMonitoringActive = false;
            cleanUpInspectedApp();
            // Once everything is cleaned up, we can remove this script from the DOM
            sendTask('removeInspector');
            break;
        }
      });

      bootstrapInspector();
    }
  }

  /**
   * Function to set up all listeners and data mining tools
   */
  function bootstrapInspector(){

    _angularInjector = angular.element(document.querySelector('[ng-app],[data-ng-app]')).injector().get;

    instrumentDigest();
    initWatcherCount();
  }

  /**
   * This should clean up all that has been instrumented by the inspector and get them back
   * to their normal behaviour. (UnWrap everything)
   */
  function cleanUpInspectedApp(){
    restoreDigest();
    restoreModuleServices();
  }

  // ------------------------------------------------------------------------------------------
  //                                     Digest Monitoring
  // ------------------------------------------------------------------------------------------

  /**
   * Wraps the angular digest so that we can measure how long it take for the digest to happen.
   */
  function instrumentDigest(){

    var scopePrototype = Object.getPrototypeOf(getRootScope());
    _backUp.digest = scopePrototype.$digest;

    scopePrototype.$digest = function $digest() {
      var start = performance.now();
      _backUp.digest.apply(this, arguments);
      var time = (performance.now() - start);
      register('DigestTiming', {
        timestamp: Date.now(),
        time: time
      });
    };
  }

  /**
   * Restores the classic angular digest.
   */
  function restoreDigest(){
    Object.getPrototypeOf(getRootScope()).$digest = _backUp.digest;
  }

  // ------------------------------------------------------------------------------------------
  //                                Scope & Watcher Exploration
  // ------------------------------------------------------------------------------------------

  /**
   * Function to be called once to init the watcher retrieval.
   */
  function initWatcherCount(){
    register('RootWatcherCount', {
      timestamp: Date.now(),
      watcher:{
        watcherCount: getWatcherCountForScope(),
        location: window.location.href
      }
    });
    if (_isMonitoringActive) {
      setTimeout(initWatcherCount, 300);
    }
  }

  /**
   * Retrieves the watcher count for a particular scope
   *
   * @param {angular.scope} [$scope] - angular scope instance
   * @returns {number}               - angular scope count
   */
  function getWatcherCountForScope($scope) {
    var count = 0;
    iterateScopes($scope, function($scope) {
      count += getWatchersFromScope($scope).length;
    });
    return count;
  }

  /**
   * Apply a function down the angular scope
   *
   * @param {angular.scope} [current] - current angular $scope
   * @param {Function}      fn        - function to apply down the scope
   * @returns {*}
   */
  function iterateScopes(current, fn) {
    if (typeof current === 'function') {
      fn = current;
      current = null;
    }
    current = current || getRootScope();
    current = makeScopeReference(current);
    if (!current) {
      return;
    }
    var ret = fn(current);
    if (ret === false) {
      return ret;
    }
    return iterateChildren(current, fn);
  }

  /**
   * Apply a function on a scope siblings (same scope level) and down to their children
   *
   * @param {angular.scope} start - starting scope of the iteration
   * @param {Function}      fn    - function to be applied on the different scopes
   * @returns {*}
   */
  function iterateSiblings(start, fn) {
    var ret;
    while (!!(start = start.$$nextSibling)) {
      ret = fn(start);
      if (ret === false) {
        break;
      }

      ret = iterateChildren(start, fn);
      if (ret === false) {
        break;
      }
    }
    return ret;
  }

  /**
   * Apply a function on all the children scopes and their respective siblings
   *
   * @param {angular.scope} start - start node of the
   * @param {Function}      fn    - function to apply
   * @returns {*}
   */
  function iterateChildren(start, fn) {
    var ret;
    while (!!(start = start.$$childHead)) {
      ret = fn(start);
      if (ret === false) {
        break;
      }

      ret = iterateSiblings(start, fn);
      if (ret === false) {
        break;
      }
    }
    return ret;
  }

  /**
   * Gets the angular root scope
   *
   * @returns {angular.scope}
   */
  function getRootScope(){
    if (typeof $rootScope !== 'undefined') {
      return $rootScope;
    }
    var scopeEl = document.querySelector('.ng-scope');
    if (!scopeEl) {
      return null;
    }
    return angular.element(scopeEl).scope().$root;
  }

  /**
   * Retrieve all watchers from a scope
   *
   * @param {angular.scope} scope - angular scope to get the watchers from
   * @returns {Array}
   */
  function getWatchersFromScope(scope) {
    return scope && scope.$$watchers ? scope.$$watchers : [];
  }

  /**
   * Gets the id of a scope
   *
   * @param {angular.scope} scope - angular scope to get the id from
   * @returns {angular.scope}
   */
  function makeScopeReference(scope) {
    if (isScopeId(scope)) {
      scope = getScopeById(scope);
    }
    return scope;
  }

  /**
   * Gets the scope from an ID
   *
   * @param {String|Number} id - scope id
   * @returns {angular.scope}
   */
  function getScopeById(id) {
    var myScope = null;
    iterateScopes(function(scope) {
      if (scope.$id === id) {
        myScope = scope;
        return false;
      }
    });
    return myScope;
  }

  /**
   * Check if the scope passed as an argument is an id or not.
   *
   * @param {angular.scope} scope
   * @returns {boolean}
   */
  function isScopeId(scope) {
    return typeof scope === 'string' || typeof scope === 'number';
  }

  // ------------------------------------------------------------------------------------------
  //                                     Module & Services
  // ------------------------------------------------------------------------------------------

  /**
   * Gets all the services name from the specified module
   *
   * @param {String}  moduleName - name of the module to get the services from
   * @param {Object}  [services] - already found services (parent module) can be null
   * @returns {Object|undefined} map of all the angular services linked to the specified module.
   *                             returns undefined if the module isn't defined
   */
  function getNgModuleServices(moduleName, services){

    if (!services) {
      services = {};
    }

    var module;

    try {
      module = angular.module(moduleName);
    } catch(e){
      return;
    }

    angular.forEach(module._invokeQueue, function(service) {
      if (service[0] === '$provide' && service[1] === 'service') {
        services[service[2][0]] = _angularInjector(service[2][0]);
      }
    });

    angular.forEach(module.requires, function(dependencyModule) {
      getNgModuleServices(dependencyModule, services)
    });

    return services;
  }

  /**
   * This methods adds timers to all the functions of all the services of a given module
   *
   * @param {String} moduleName - module name to instrument.
   */
  function instrumentModuleServices(moduleName){

    _backUp.modules[moduleName] = {};
    var services = getNgModuleServices(moduleName);

    angular.forEach(Object.keys(services), function(serviceName){

      _backUp.modules[moduleName][serviceName] = {};
      var service = services[serviceName];

      angular.forEach(Object.getOwnPropertyNames(service), function(propertyName){

        // Early return for all properties that are not functions
        // arguments is a reserved property name
        if (propertyName === 'arguments' ||
            propertyName === 'caller' ||
            propertyName === 'callee' ||
            typeof service[propertyName] !== 'function' ||
            propertyName === 'constructor') {
          return;
        }

        var functionToWrap = _backUp.modules[moduleName][serviceName][propertyName] = service[propertyName];

        // We Wrap all the service functions to measure execution time.
        service[propertyName] = function(){
          var
            start = performance.now(),
            // Execute the function as usual
            result = functionToWrap.apply(this, arguments);

          // Register execution time in the extension registry
          register('SyncServiceFunctionCall', {
            module: moduleName,
            service: serviceName,
            func: propertyName,
            time: performance.now() - start
          });

          // We only consider promises since it is the default async handling in angular.
          if (result && typeof result.then === 'function') {
            // We reset the timer so that only async time gets taken.
            start = performance.now();

            // We Append our timing promise to the actual promise
            result.then(function() {
              register('ASyncServiceFunctionCall', {
                module: moduleName,
                service: serviceName,
                func: propertyName,
                time: performance.now() - start
              });
            })
          }
          return result;
        }
      })
    });
  }

  /**
   * Restores the services functions as they were before being wrapped
   *
   * @param {String} [moduleName] - name of the module to be unwrapped. If not mentioned, everything
   *                                should be restored.
   */
  function restoreModuleServices(moduleName){

    var modules;

    if (moduleName){

      if (_backUp.modules[moduleName]) {
        modules = [moduleName];
      } else {
        throw new Error('angular performance - We tried to restore the module '+ moduleName + 'but ' +
          'we could not find any back up :(');
      }

    } else {
      modules = Object.keys(_backUp.modules);
    }

    angular.forEach(modules, function(module){
      var services = getNgModuleServices(module);

      angular.forEach(Object.keys(_backUp.modules[module]), function(service){
        angular.forEach(Object.keys(_backUp.modules[module][service]), function(fnName){
          services[service][fnName] = _backUp.modules[module][service][fnName]
        });
      });

      // Clean up back up
      delete _backUp.modules[module];
    });
  }

  // ------------------------------------------------------------------------------------------
  //                                        Utils
  // ------------------------------------------------------------------------------------------

  /**
   * Reports a metric
   *
   * @param {String} task  - task to do
   * @param {Object} [value] - data that can be sent along with the task
   */
  function sendTask(task, value){
    window.postMessage({
      source: 'angular-performance-inspector',
      task: task,
      data: value
    }, '*');
  }

  /**
   * Register a metric into the devtool instance registry
   *
   * @param {String} variable - can be 'digestTiming'
   * @param {Object} value    - value to be registered with the variable
   */
  function register(variable, value){
    sendTask('register'+variable, value);
  }
})();
<|endoftext|>