<commit_before>var ui = {
	clouds: {
		init: function(number) {
			var startTimeout = 0;
			for (var i = 0; i < number; i++) {
				setTimeout(ui.clouds.createCloud, startTimeout);
				startTimeout += 4000 + Math.floor(Math.random() * 5000);
			}
		},

		createCloud: function() {
			var minTopPosition = 40;
			var maxTopPosition = 600;
			var lastTopPosition = 0;

			var cloudContainer = $('');
			var cloud = $('');
			cloud.appendTo(cloudContainer);

			do {
				topPosition = minTopPosition + Math.round(Math.random() * (maxTopPosition - minTopPosition));
			} while (Math.abs(topPosition - lastTopPosition) < 200);
			lastTopPosition = topPosition;

			cloudContainer.css({
				top: topPosition
			});

			cloud.css({
				zoom: Math.random() / 2 + 0.5
			});

			cloudContainer.appendTo("body");

			cloud.animate({
				opacity: Math.random() / 2 + 0.5
			}, 1000);

			var transitionDuration = 20000 + Math.floor(Math.random() * 50000);
			cloudContainer.transition({
				left: $("body").width() - 200,
				duration: transitionDuration,
				easing: "linear"
			});

			setTimeout(function() {
				ui.clouds.destroyCloud(cloud, cloudContainer);
			}, transitionDuration - 1000);
		},

		destroyCloud: function (cloud, container) {
			cloud.animate({
				opacity: 0
			}, 1000, function() {
				container.remove();
				setTimeout(ui.clouds.createCloud, 3000 + Math.floor(Math.random() * 3000));
			});
		}
	},

	verses: {
		apiEndpoint: "https://us-central1-longest-poem-in-the-world.cloudfunctions.net/list-verses",

		init: function() {
			ui.verses.template = $("#verseTemplate").html();
			ui.verses.streamPosition = 0;
			ui.verses.perPage = 16;

			// http://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
			ui.isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;

			$("#more > a").click(function(e) {
				e.preventDefault();
				ui.verses.streamPosition += ui.verses.perPage;
				ui.verses.fetch();
			});

			ui.verses.fetch();
		},

		fetch: function(start) {
			$("#loading").show();
			$.get(ui.verses.apiEndpoint, function(data) {
				// TODO: check success
				ui.verses.render(data.verses);
				$("#total").html(ui.verses.formatTotal(data.total));
				$("#loading").hide();

				// $("#more").show();
			}, "json");
		},

		render: function(verses) {
			var versesHtml = '';
			for (var i = 0; i < verses.length; i++) {
				var text = (ui.isSafari) ? verses[i].text : ui.verses.stripEmoji(verses[i].text);
				versesHtml += ui.verses.template.format(verses[i].username, verses[i].id, verses[i].author, text);
			}

			if ($("#verses li").length === 0) {
				$("#verses").html(versesHtml);
			} else {
				$("#verses").animate({
					opacity: 0
				}, 200, function() {
					$("#verses").html(versesHtml);
					$("#verses").animate({
						opacity: 1
					}, 200);
				});
			}
		},

		formatTotal: function(number) {
			number = number.toString();

			var result = [];
			do {
				result.push(number.substr(-3));
				number = number.substr(0, number.length - 3);
			} while (number.length > 0);

			result.reverse();
			return result.join(",");
		},

		stripEmoji: function(text) {
			return text.split("").map(function(c) {
				var charCode = c.charCodeAt(0);
				return (charCode >= 50000) ? '' : c;
			}).join("");
		}
	},

	init: function() {
		ui.clouds.init(5);
		ui.verses.init();
	}
};

$(ui.init);

// http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format
if (!String.prototype.format) {
	String.prototype.format = function() {
		var args = arguments;
		return this.replace(/{(\d+)}/g, function(match, number) {
			return (typeof args[number] != 'undefined') ? args[number] : match;
		});
	};
}
<commit_msg>Remove whitespace<commit_after>var ui = {
	clouds: {
		init: function(number) {
			var startTimeout = 0;
			for (var i = 0; i < number; i++) {
				setTimeout(ui.clouds.createCloud, startTimeout);
				startTimeout += 4000 + Math.floor(Math.random() * 5000);
			}
		},

		createCloud: function() {
			var minTopPosition = 40;
			var maxTopPosition = 600;
			var lastTopPosition = 0;

			var cloudContainer = $('');
			var cloud = $('');
			cloud.appendTo(cloudContainer);

			do {
				topPosition = minTopPosition + Math.round(Math.random() * (maxTopPosition - minTopPosition));
			} while (Math.abs(topPosition - lastTopPosition) < 200);
			lastTopPosition = topPosition;

			cloudContainer.css({
				top: topPosition
			});

			cloud.css({
				zoom: Math.random() / 2 + 0.5
			});

			cloudContainer.appendTo("body");

			cloud.animate({
				opacity: Math.random() / 2 + 0.5
			}, 1000);

			var transitionDuration = 20000 + Math.floor(Math.random() * 50000);
			cloudContainer.transition({
				left: $("body").width() - 200,
				duration: transitionDuration,
				easing: "linear"
			});

			setTimeout(function() {
				ui.clouds.destroyCloud(cloud, cloudContainer);
			}, transitionDuration - 1000);
		},

		destroyCloud: function (cloud, container) {
			cloud.animate({
				opacity: 0
			}, 1000, function() {
				container.remove();
				setTimeout(ui.clouds.createCloud, 3000 + Math.floor(Math.random() * 3000));
			});
		}
	},

	verses: {
		apiEndpoint: "https://us-central1-longest-poem-in-the-world.cloudfunctions.net/list-verses",

		init: function() {
			ui.verses.template = $("#verseTemplate").html();
			ui.verses.streamPosition = 0;
			ui.verses.perPage = 16;

			// http://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
			ui.isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;

			$("#more > a").click(function(e) {
				e.preventDefault();
				ui.verses.streamPosition += ui.verses.perPage;
				ui.verses.fetch();
			});

			ui.verses.fetch();
		},

		fetch: function(start) {
			$("#loading").show();
			$.get(ui.verses.apiEndpoint, function(data) {
				// TODO: check success
				ui.verses.render(data.verses);
				$("#total").html(ui.verses.formatTotal(data.total));
				$("#loading").hide();

				// $("#more").show();
			}, "json");
		},

		render: function(verses) {
			var versesHtml = '';
			for (var i = 0; i < verses.length; i++) {
				var text = (ui.isSafari) ? verses[i].text : ui.verses.stripEmoji(verses[i].text);
				versesHtml += ui.verses.template.format(verses[i].username, verses[i].id, verses[i].author, text);
			}

			if ($("#verses li").length === 0) {
				$("#verses").html(versesHtml);
			} else {
				$("#verses").animate({
					opacity: 0
				}, 200, function() {
					$("#verses").html(versesHtml);
					$("#verses").animate({
						opacity: 1
					}, 200);
				});
			}
		},

		formatTotal: function(number) {
			number = number.toString();

			var result = [];
			do {
				result.push(number.substr(-3));
				number = number.substr(0, number.length - 3);
			} while (number.length > 0);

			result.reverse();
			return result.join(",");
		},

		stripEmoji: function(text) {
			return text.split("").map(function(c) {
				var charCode = c.charCodeAt(0);
				return (charCode >= 50000) ? '' : c;
			}).join("");
		}
	},

	init: function() {
		ui.clouds.init(5);
		ui.verses.init();
	}
};

$(ui.init);

// http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format
if (!String.prototype.format) {
	String.prototype.format = function() {
		var args = arguments;
		return this.replace(/{(\d+)}/g, function(match, number) {
			return (typeof args[number] != 'undefined') ? args[number] : match;
		});
	};
}
<|endoftext|>


<commit_before>/* Donutio 2.2 by Michael Hohlovich */
!function(t){t.fn.donutio=function(a){var o=t.extend({multiple:!0,color:"#f00",backColor:"#eee",radius:200,width:10,padding:10,type:"donut",active:0},a),u=2*(o.radius+o.padding),s=o.data.length,l=r(o.data),d=n(o.data,l),h=(360-d.reduce(function(t,e){return t+e}))/s;if(o.multiple)for(i=0;s>i;i++)e(u,h,o,d,i,this);else e(u,h,o,d,o.active,this);return this};var e=function(e,r,i,n,s,l){var d=a(e),h=o("svg");h.setAttribute("width",e),h.setAttribute("height",e);var c=0,f=0;for(j=0;j<i.data.length;j++){c=f+r,f=c+n[j];var p=o("path");"donut"==i.type?(p.setAttribute("stroke-width",i.width),p.setAttribute("fill","none"),j==s?p.setAttribute("stroke",i.color):p.setAttribute("stroke",i.backColor)):(p.setAttribute("stroke-width",0),j==s?p.setAttribute("fill",i.color):p.setAttribute("fill",i.backColor)),p.setAttribute("d",u(i.type,Math.floor(e/2),Math.floor(e/2),i.radius,c,f)),h.appendChild(p)}d.append(h),"text"in i.data[s]&&i.data[s].text.forEach(function(e,r){var i=t("").html(e);d.append(i)}),l.append(d)},r=function(t){var e=0;return t.forEach(function(t){e+=Math.abs(t.value)}),e},n=function(t,e){var r=[];return t.forEach(function(t){var i=Math.floor(Math.abs(t.value)/e*100),n=Math.ceil(3.6*i);r.push(n)}),r},a=function(e){return t("
").css({width:e,height:e})},o=function(t){var e=document.createElementNS("http://www.w3.org/2000/svg",t);return"svg"==t&&e.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),e},u=function(t,e,r,i,n,a){var o=s(e,r,i,a),u=s(e,r,i,n),l=180>=a-n?"0":"1",d=[];return d="donut"==t?["M",o.x,o.y,"A",i,i,0,l,0,u.x,u.y].join(" "):["M",o.x,o.y,"A",i,i,0,l,0,u.x,u.y,"L",e,r,"L",o.x,o.y].join(" ")},s=function(t,e,r,i){var n=(i-90)*Math.PI/180;return{x:t+r*Math.cos(n),y:e+r*Math.sin(n)}}}(jQuery);<commit_msg>Update jquery.donutio.min.js<commit_after>/* Donutio 2.2.0 by Michael Hohlovich */
!function(t){t.fn.donutio=function(a){var o=t.extend({multiple:!0,color:"#f00",backColor:"#eee",radius:200,width:10,padding:10,type:"donut",active:0},a),u=2*(o.radius+o.padding),s=o.data.length,l=r(o.data),d=n(o.data,l),h=(360-d.reduce(function(t,e){return t+e}))/s;if(o.multiple)for(i=0;s>i;i++)e(u,h,o,d,i,this);else e(u,h,o,d,o.active,this);return this};var e=function(e,r,i,n,s,l){var d=a(e),h=o("svg");h.setAttribute("width",e),h.setAttribute("height",e);var c=0,f=0;for(j=0;j<i.data.length;j++){c=f+r,f=c+n[j];var p=o("path");"donut"==i.type?(p.setAttribute("stroke-width",i.width),p.setAttribute("fill","none"),j==s?p.setAttribute("stroke",i.color):p.setAttribute("stroke",i.backColor)):(p.setAttribute("stroke-width",0),j==s?p.setAttribute("fill",i.color):p.setAttribute("fill",i.backColor)),p.setAttribute("d",u(i.type,Math.floor(e/2),Math.floor(e/2),i.radius,c,f)),h.appendChild(p)}d.append(h),"text"in i.data[s]&&i.data[s].text.forEach(function(e,r){var i=t("").html(e);d.append(i)}),l.append(d)},r=function(t){var e=0;return t.forEach(function(t){e+=Math.abs(t.value)}),e},n=function(t,e){var r=[];return t.forEach(function(t){var i=Math.floor(Math.abs(t.value)/e*100),n=Math.ceil(3.6*i);r.push(n)}),r},a=function(e){return t("
").css({width:e,height:e})},o=function(t){var e=document.createElementNS("http://www.w3.org/2000/svg",t);return"svg"==t&&e.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),e},u=function(t,e,r,i,n,a){var o=s(e,r,i,a),u=s(e,r,i,n),l=180>=a-n?"0":"1",d=[];return d="donut"==t?["M",o.x,o.y,"A",i,i,0,l,0,u.x,u.y].join(" "):["M",o.x,o.y,"A",i,i,0,l,0,u.x,u.y,"L",e,r,"L",o.x,o.y].join(" ")},s=function(t,e,r,i){var n=(i-90)*Math.PI/180;return{x:t+r*Math.cos(n),y:e+r*Math.sin(n)}}}(jQuery);
<|endoftext|>


<commit_before>enyo.kind({
	name: "App",
	kind: "FittableRows",
	fit: true,
	components:[
		{kind: "onyx.Toolbar", style: "height:2em;padding:2px", components: [
            {kind: "onyx.MenuDecorator", style:"float:right;margin:0", onSelect: "itemSelected", components: [
                {content: "Bookmarks menu"},
                {kind: "onyx.Menu", components: [
                    {components: [
                        {kind: "onyx.IconButton", src: "assets/menu-icon-bookmark.png"},
                        {content: "Bookmarks"}
                    ]},
                    {content: "Favorites"},
                    {classes: "onyx-menu-divider"},
                    {content: "Recents"}
                ]}
            ]}
        ]},
		{kind: "enyo.Scroller", fit: true, components: [
			{name: "main", classes: "nice-padding", allowHtml: true}
		]}
	],
    getSignalNumber(num) {
        /*
        What this function does is splits the numbers into 4 segments that
        we have pictures for and uses the rounding function to assign them
        currectly
        */
        return Number(Math.round(num/25))*25
    }
});
<commit_msg>Fixed a typo :)<commit_after>enyo.kind({
	name: "App",
	kind: "FittableRows",
	fit: true,
	components:[
		{kind: "onyx.Toolbar", style: "height:2em;padding:2px", components: [
            {kind: "onyx.MenuDecorator", style:"float:right;margin:0", onSelect: "itemSelected", components: [
                {content: "Bookmarks menu"},
                {kind: "onyx.Menu", components: [
                    {components: [
                        {kind: "onyx.IconButton", src: "assets/menu-icon-bookmark.png"},
                        {content: "Bookmarks"}
                    ]},
                    {content: "Favorites"},
                    {classes: "onyx-menu-divider"},
                    {content: "Recents"}
                ]}
            ]}
        ]},
		{kind: "enyo.Scroller", fit: true, components: [
			{name: "main", classes: "nice-padding", allowHtml: true}
		]}
	],
    getSignalNumber: function(num) {
        /*
        What this function does is splits the numbers into 4 segments that
        we have pictures for and uses the rounding function to assign them
        currectly
        */
        return Number(Math.round(num/25))*25
    }
});
<|endoftext|>


<commit_before>//@ts-check

import html2canvas from "html2canvas";
import SpeedTestWorker from "./worker";

/**
 * Speed Test web UI
 *
 * @class WebUI
 */
export default class WebUI {
    /**
     * Create an instance of WebUI.
     */
    constructor() {
        this.page = "home";

        this.STATUS = {
            WAITING: 0,
            STARTING: 1,
            RUNNING: 2,
            DONE: 3,
            ABORTED: 4,
            FAILED: -1
        };

        this.config = {
            updateDelay: 150,
            endless: false // false
        };
        this.lastAsn = null;
        this.resultsString = null;
        this.queueTest = false;
        this.statusInterval = null;
        this.workerReady = false;

        this.worker = new SpeedTestWorker();
        this.worker.addEventListener("message", event => {
            this.processWorkerResponse(event);
        });

        this.$shareResultsButton = document.querySelector(
            "#commands button#share-results"
        );
        this.$showResultsHistoryButton = document.querySelector(
            "#commands button#show-results-history"
        );
        this.$startButton = document.querySelector("#commands button#start");
        this.$stopButton = document.querySelector("#commands button#stop");
        this.$httpsAlert = document.querySelector("#https-alert");
        this.$httpsAlertMessage = document.querySelector(
            "#https-alert .message"
        );
        this.$history = document.querySelector("#history");
        this.$historyResults = document.querySelector("#history table tbody");
        this.$share = document.querySelector("#share");
        this.$shareResultsLink = document.querySelector("#share-results-link");
        this.$shareResultsLinkCopyButton = document.querySelector(
            "#share-results-link-copy"
        );
        this.$shareResultsImage = document.querySelector(
            "#share-results-image"
        );
        this.$speedtest = document.querySelector("#speedtest");
        this.$ipResult = document.querySelector("#ip");
        this.$ipValue = document.querySelector("#ip span.value");
        this.$asnValue = document.querySelector("#ip span.asn");
        this.$latencyResult = document.querySelector("#latency");
        this.$latencyValue = document.querySelector("#latency span.value");
        this.$jitterResult = document.querySelector("#jitter");
        this.$jitterValue = document.querySelector("#jitter span.value");
        this.$downloadResult = document.querySelector("#download");
        this.$downloadValue = document.querySelector("#download span.value");
        this.$uploadResult = document.querySelector("#upload");
        this.$uploadValue = document.querySelector("#upload span.value");
        this.$progress = document.querySelector("#progress");
        this.$progressBar = document.querySelector("#progress .progress-bar");
        this.$credits = document.querySelector("#credits");
        this.$closeButtons = document.querySelectorAll("button.close");

        this.$shareResultsButton.addEventListener(
            "click",
            this.shareResultsButtonClickHandler.bind(this)
        );
        this.$showResultsHistoryButton.addEventListener(
            "click",
            this.showResultsHistoryButtonClickHandler.bind(this)
        );
        this.$startButton.addEventListener(
            "click",
            this.startButtonClickHandler.bind(this)
        );
        this.$stopButton.addEventListener(
            "click",
            this.stopButtonClickHandler.bind(this)
        );
        this.$closeButtons.forEach($closeButton =>
            $closeButton.addEventListener(
                "click",
                this.alertCloseButtonClickHandler.bind(this)
            )
        );
        this.$shareResultsLink.addEventListener(
            "click",
            this.shareResultsLinkClickHandler.bind(this)
        );
        this.$shareResultsLinkCopyButton.addEventListener(
            "click",
            this.shareResultsLinkCopyButtonClickHandler.bind(this)
        );

        window.addEventListener("popstate", () => {
            switch (document.location.pathname) {
                case "/result":
                    this.showPage("speedtest");
                    this.loadResultsFromUri();
                    break;

                case "/results":
                    this.showPage("history");
                    this.loadResultsHistory();
                    break;

                case "/run":
                    this.showPage("speedtest");
                    this.startTest();
                    break;

                case "/share":
                    this.showPage("share");
                    this.loadResultsFromUri();
                    this.generateShareResultsLinks();
                    break;

                default:
                    this.showPage("speedtest");
                    this.stopTest(true);
                    break;
            }
        });
        window.dispatchEvent(new Event("popstate"));
    }

    startButtonClickHandler() {
        this.showPage("speedtest");
        window.history.pushState({}, "Speed Test - Running...", "/run");
        this.startTest();
    }

    stopButtonClickHandler() {
        this.showPage("speedtest");
        window.history.pushState({}, "Speed Test", "/");
        this.stopTest();
    }

    /**
     * Start a speed test.
     */
    startTest() {
        if (this.running) return;
        if (!this.workerReady) {
            this.queueTest = true;
            return;
        }
        this.running = true;

        this.$shareResultsButton.setAttribute("hidden", "");
        this.$startButton.setAttribute("hidden", "");
        this.$stopButton.removeAttribute("hidden");

        this.setProgressBar(0);
        this.clearResults();

        this.worker.postMessage("start");

        window.clearInterval(this.statusInterval);
        this.statusInterval = window.setInterval(() => {
            this.worker.postMessage("status");
        }, this.config.updateDelay);
    }

    /**
     * Abort a running speed test.
     */
    stopTest(clearResults = false) {
        if (!this.running) return;
        this.running = false;

        window.clearInterval(this.statusInterval);
        this.statusInterval = null;

        if (this.worker) this.worker.postMessage("abort");

        this.setProgressBar(0);
        this.resetHiglightStep();
        if (clearResults) this.clearResults();
    }

    /**
     * Process an event response from the speed test Worker
     *
     * @param {MessageEvent} event
     */
    processWorkerResponse(event) {
        if (!this.workerReady) {
            if (!event.data.ready) return;
            this.workerReady = event.data.ready;

            if (!event.data.config.hideCredits) {
                this.$credits.removeAttribute("hidden");
            }

            if (event.data.alerts.https) {
                this.$httpsAlert.removeAttribute("hidden");
                this.$httpsAlertMessage.innerHTML = event.data.alerts.https;
            }
        }

        if (this.queueTest && this.workerReady) {
            this.queueTest = false;
            this.startTest();
            return;
        }

        switch (event.data.status) {
            case this.STATUS.RUNNING:
                this.processData(event.data || {});
                break;
            case this.STATUS.DONE:
                window.clearInterval(this.statusInterval);

                this.processData(event.data || {});
                if (this.config.endless) {
                    this.startTest();
                    return;
                }

                this.running = false;
                event.data.results.timestamp = new Date().getTime();
                event.data.results.asn = this.lastAsn;
                this.storeLatestResults(event.data.results);

                this.setProgressBar(0);
                this.$startButton.removeAttribute("hidden");
                this.$stopButton.setAttribute("hidden", "");

                break;
            case this.STATUS.ABORTED:
                window.clearInterval(this.statusInterval);

                this.processData(event.data || {});
                this.$shareResultsButton.setAttribute("hidden", "");
                this.$startButton.removeAttribute("hidden");
                this.$stopButton.setAttribute("hidden", "");
                break;
        }
    }

    /**
     * Reset the current results.
     */
    clearResults() {
        this.$ipValue.innerHTML = "";
        this.$latencyValue.innerHTML = "";
        this.$jitterValue.innerHTML = "";
        this.$downloadValue.innerHTML = "";
        this.$uploadValue.innerHTML = "";
    }

    /**
     * Process a set of data.
     *
     * @param {Object} data
     */
    processData(data) {
        if (!this.running) {
            return;
        }

        if (data.step === "ip") {
            this.$ipValue.innerHTML = data.results.ip;
            this.$asnValue.style.display = "none";
            this.$asnValue.innerHTML = "";
            this.getIpInfo(data.results.ip).then(info => {
                if (info.bogon) return;
                if (!info.org) return;

                this.$asnValue.style.display = "block";
                this.$asnValue.innerHTML = this.lastAsn = info.org;
            });

            return;
        }

        if (this.previousStep !== data.step) this.highlightStep(data.step);
        this.previousStep = data.step;

        this.$latencyValue.innerHTML = data.results.latency.avg || "";
        this.$jitterValue.innerHTML = data.results.latency.jitter || "";
        const downloadValue = data.results.download
            ? +data.results.download.speed / (1024 * 1024)
            : 0;
        this.$downloadValue.innerHTML = downloadValue
            ? downloadValue.toFixed(2)
            : "";
        const uploadValue = data.results.upload
            ? +data.results.upload.speed / (1024 * 1024)
            : 0;
        this.$uploadValue.innerHTML = uploadValue ? uploadValue.toFixed(2) : "";

        switch (data.step) {
            case "latency":
                this.setProgressBar(data.results.latency.progress);
                break;
            case "download":
                this.setProgressBar(data.results.download.progress, "download");
                break;
            case "upload":
                this.setProgressBar(data.results.upload.progress);
                break;
        }
    }

    /**
     * Resets the highlighted step.
     */
    resetHiglightStep() {
        document
            .querySelectorAll(".result")
            .forEach(elem => elem.classList.remove("active"));
    }

    /**
     * Highlights the current running step.
     * @param {String} step
     */
    highlightStep(step) {
        this.resetHiglightStep();

        switch (step) {
            case "latency":
                this.$latencyResult.classList.add("active");
                this.$jitterResult.classList.add("active");
                break;
            case "download":
                this.$downloadResult.classList.add("active");
                break;
            case "upload":
                this.$uploadResult.classList.add("active");
                break;
        }
    }

    /**
     * Set a value on the progress bar
     *
     * @param {Number} progress
     * @param {String} mode
     */
    setProgressBar(progress, mode = "") {
        this.$progress.style.flexDirection =
            mode === "download" ? "row-reverse" : "row";
        this.$progressBar.style.width = progress * 100 + "%";
    }

    /**
     * Get IP information from "ipinfo.io"
     *
     * @param {String} ip
     */
    getIpInfo(ip) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.addEventListener("readystatechange", () => {
                if (xhr.readyState === XMLHttpRequest.DONE) {
                    if (xhr.status === 200) {
                        resolve(JSON.parse(xhr.responseText));
                    } else {
                        reject(xhr.statusText);
                    }
                }
            });
            xhr.open("GET", `//ipinfo.io/${ip}/json`, true);
            xhr.send(null);
        });
    }

    showPage(page) {
        this.page = page;

        this.$history.setAttribute("hidden", "");
        this.$share.setAttribute("hidden", "");
        this.$speedtest.setAttribute("hidden", "");
        this[`$${page}`].removeAttribute("hidden");
    }

    /**
     * Show the page to share results
     */
    generateShareResultsLinks() {
        this.$shareResultsLink.value = `${window.location.origin}/result${
            window.location.hash
        }`;

        html2canvas(this.$speedtest, {
            logging: false,
            scale: 1,
            onclone: doc => {
                const $el = doc.querySelector("#speedtest");
                $el.removeAttribute("hidden");
                $el.classList.add("share");
            }
        }).then(canvas => {
            this.$shareResultsImage.src = canvas.toDataURL("image/png");
        });
    }

    /**
     * Prepare the share results button with a PNG image
     */
    shareResultsButtonClickHandler() {
        this.generateShareResultsLinks();
        this.showPage("share");
        window.history.pushState(
            {},
            "Speed Test - Share Results",
            `/share#${this.resultsString}`
        );
    }

    /**
     * Select the share result link on input click
     */
    shareResultsLinkClickHandler() {
        this.$shareResultsLink.select();
    }

    /**
     * Select anc copy the share result link on "Copy" button click
     */
    shareResultsLinkCopyButtonClickHandler() {
        this.$shareResultsLink.select();
        document.execCommand("copy");
    }

    /**
     * Close alert boxes on click
     *
     * @param {MouseEvent} e
     */
    alertCloseButtonClickHandler(e) {
        e.target.parentElement.setAttribute("hidden", "");
    }

    /**
     * Store a speed test run results to the local storage
     *
     * @param {Object} results
     */
    storeLatestResults(results) {
        const resultsHistory =
            JSON.parse(localStorage.getItem("history")) || {};
        resultsHistory[results.timestamp] = {
            latency: results.latency.avg,
            jitter: results.latency.jitter,
            download: results.download.speed,
            upload: results.upload.speed,
            ip: results.ip,
            asn: results.asn
        };
        localStorage.setItem(
            "history",
            JSON.stringify(this.limitResultsHistory(resultsHistory))
        );

        this.resultsString = this.getResultsString(results);
        this.$shareResultsButton.removeAttribute("hidden");
        window.history.pushState(
            {},
            "Speed Test - Results",
            `/result#${this.resultsString}`
        );
    }

    limitResultsHistory(resultsHistory, maxEntries = 5) {
        const filteredResults = {};
        Object.keys(resultsHistory)
            .sort((a, b) => +b - +a)
            .slice(0, maxEntries)
            .map(
                timestamp =>
                    (filteredResults[timestamp] = resultsHistory[timestamp])
            );
        return filteredResults;
    }

    /**
     * Load the results from the currect URI
     */
    loadResultsFromUri() {
        const [
            latency,
            jitter,
            download,
            upload,
            ip,
            asn
        ] = window.location.hash.replace("#", "").split(",");

        this.$ipValue.innerHTML = ip;
        this.$asnValue.innerHTML = decodeURIComponent(asn);
        this.$latencyValue.innerHTML = latency;
        this.$jitterValue.innerHTML = jitter;
        this.$downloadValue.innerHTML = (+download / (1024 * 1024)).toFixed(2);
        this.$uploadValue.innerHTML = (+upload / (1024 * 1024)).toFixed(2);

        // this.resultsString = `${latency},${jitter},${download},${upload},${ip},${asn}`;
    }

    /**
     * Toggle history results
     */
    showResultsHistoryButtonClickHandler() {
        this.stopTest();
        this.clearResults();

        this.loadResultsHistory();
        this.showPage("history");
        window.history.pushState({}, "Speed Test - Results", "/results");
    }

    loadResultsHistory() {
        const history = JSON.parse(localStorage.getItem("history")) || {};

        this.$historyResults.innerHTML = "";
        if (Object.entries(history).length === 0) {
            const $resultsRow = document.createElement("tr");
            $resultsRow.innerHTML =
                'No results.
Run a speed test now.	';
            this.$historyResults.appendChild($resultsRow);

            return;
        }

        Object.entries(history).forEach(([timestamp, results]) => {
            const date = new Date(+timestamp);
            const $resultsRow = document.createElement("tr");
            $resultsRow.innerHTML = `
                ${date.toLocaleDateString()}
${date.toLocaleTimeString()}
                ${results.latency} ms
                ${results.jitter} ms
                ${(results.download / 1024 ** 2).toFixed(2)} Mbps
                ${(results.upload / 1024 ** 2).toFixed(2)} Mbps
                ${results.ip}${
                    results.asn ? `<br>(${results.asn})` : ""
                }

            `;
            this.$historyResults.appendChild($resultsRow);
        });
    }

    getResultsString(results) {
        return `${results.latency},${results.jitter},${
            results.download
        },${results.upload},${results.ip},${results.asn || ""}`;
    }
}
<commit_msg>Fix results format<commit_after>//@ts-check

import html2canvas from "html2canvas";
import SpeedTestWorker from "./worker";

/**
 * Speed Test web UI
 *
 * @class WebUI
 */
export default class WebUI {
    /**
     * Create an instance of WebUI.
     */
    constructor() {
        this.page = "home";

        this.STATUS = {
            WAITING: 0,
            STARTING: 1,
            RUNNING: 2,
            DONE: 3,
            ABORTED: 4,
            FAILED: -1
        };

        this.config = {
            updateDelay: 150,
            endless: false // false
        };
        this.lastAsn = null;
        this.resultsString = null;
        this.queueTest = false;
        this.statusInterval = null;
        this.workerReady = false;

        this.worker = new SpeedTestWorker();
        this.worker.addEventListener("message", event => {
            this.processWorkerResponse(event);
        });

        this.$shareResultsButton = document.querySelector(
            "#commands button#share-results"
        );
        this.$showResultsHistoryButton = document.querySelector(
            "#commands button#show-results-history"
        );
        this.$startButton = document.querySelector("#commands button#start");
        this.$stopButton = document.querySelector("#commands button#stop");
        this.$httpsAlert = document.querySelector("#https-alert");
        this.$httpsAlertMessage = document.querySelector(
            "#https-alert .message"
        );
        this.$history = document.querySelector("#history");
        this.$historyResults = document.querySelector("#history table tbody");
        this.$share = document.querySelector("#share");
        this.$shareResultsLink = document.querySelector("#share-results-link");
        this.$shareResultsLinkCopyButton = document.querySelector(
            "#share-results-link-copy"
        );
        this.$shareResultsImage = document.querySelector(
            "#share-results-image"
        );
        this.$speedtest = document.querySelector("#speedtest");
        this.$ipResult = document.querySelector("#ip");
        this.$ipValue = document.querySelector("#ip span.value");
        this.$asnValue = document.querySelector("#ip span.asn");
        this.$latencyResult = document.querySelector("#latency");
        this.$latencyValue = document.querySelector("#latency span.value");
        this.$jitterResult = document.querySelector("#jitter");
        this.$jitterValue = document.querySelector("#jitter span.value");
        this.$downloadResult = document.querySelector("#download");
        this.$downloadValue = document.querySelector("#download span.value");
        this.$uploadResult = document.querySelector("#upload");
        this.$uploadValue = document.querySelector("#upload span.value");
        this.$progress = document.querySelector("#progress");
        this.$progressBar = document.querySelector("#progress .progress-bar");
        this.$credits = document.querySelector("#credits");
        this.$closeButtons = document.querySelectorAll("button.close");

        this.$shareResultsButton.addEventListener(
            "click",
            this.shareResultsButtonClickHandler.bind(this)
        );
        this.$showResultsHistoryButton.addEventListener(
            "click",
            this.showResultsHistoryButtonClickHandler.bind(this)
        );
        this.$startButton.addEventListener(
            "click",
            this.startButtonClickHandler.bind(this)
        );
        this.$stopButton.addEventListener(
            "click",
            this.stopButtonClickHandler.bind(this)
        );
        this.$closeButtons.forEach($closeButton =>
            $closeButton.addEventListener(
                "click",
                this.alertCloseButtonClickHandler.bind(this)
            )
        );
        this.$shareResultsLink.addEventListener(
            "click",
            this.shareResultsLinkClickHandler.bind(this)
        );
        this.$shareResultsLinkCopyButton.addEventListener(
            "click",
            this.shareResultsLinkCopyButtonClickHandler.bind(this)
        );

        window.addEventListener("popstate", () => {
            switch (document.location.pathname) {
                case "/result":
                    this.showPage("speedtest");
                    this.loadResultsFromUri();
                    break;

                case "/results":
                    this.showPage("history");
                    this.loadResultsHistory();
                    break;

                case "/run":
                    this.showPage("speedtest");
                    this.startTest();
                    break;

                case "/share":
                    this.showPage("share");
                    this.loadResultsFromUri();
                    this.generateShareResultsLinks();
                    break;

                default:
                    this.showPage("speedtest");
                    this.stopTest(true);
                    break;
            }
        });
        window.dispatchEvent(new Event("popstate"));
    }

    startButtonClickHandler() {
        this.showPage("speedtest");
        window.history.pushState({}, "Speed Test - Running...", "/run");
        this.startTest();
    }

    stopButtonClickHandler() {
        this.showPage("speedtest");
        window.history.pushState({}, "Speed Test", "/");
        this.stopTest();
    }

    /**
     * Start a speed test.
     */
    startTest() {
        if (this.running) return;
        if (!this.workerReady) {
            this.queueTest = true;
            return;
        }
        this.running = true;

        this.$shareResultsButton.setAttribute("hidden", "");
        this.$startButton.setAttribute("hidden", "");
        this.$stopButton.removeAttribute("hidden");

        this.setProgressBar(0);
        this.clearResults();

        this.worker.postMessage("start");

        window.clearInterval(this.statusInterval);
        this.statusInterval = window.setInterval(() => {
            this.worker.postMessage("status");
        }, this.config.updateDelay);
    }

    /**
     * Abort a running speed test.
     */
    stopTest(clearResults = false) {
        if (!this.running) return;
        this.running = false;

        window.clearInterval(this.statusInterval);
        this.statusInterval = null;

        if (this.worker) this.worker.postMessage("abort");

        this.setProgressBar(0);
        this.resetHiglightStep();
        if (clearResults) this.clearResults();
    }

    /**
     * Process an event response from the speed test Worker
     *
     * @param {MessageEvent} event
     */
    processWorkerResponse(event) {
        if (!this.workerReady) {
            if (!event.data.ready) return;
            this.workerReady = event.data.ready;

            if (!event.data.config.hideCredits) {
                this.$credits.removeAttribute("hidden");
            }

            if (event.data.alerts.https) {
                this.$httpsAlert.removeAttribute("hidden");
                this.$httpsAlertMessage.innerHTML = event.data.alerts.https;
            }
        }

        if (this.queueTest && this.workerReady) {
            this.queueTest = false;
            this.startTest();
            return;
        }

        switch (event.data.status) {
            case this.STATUS.RUNNING:
                this.processData(event.data || {});
                break;
            case this.STATUS.DONE:
                window.clearInterval(this.statusInterval);

                this.processData(event.data || {});
                if (this.config.endless) {
                    this.startTest();
                    return;
                }

                this.running = false;
                event.data.results.timestamp = new Date().getTime();
                event.data.results.asn = this.lastAsn;
                this.storeLatestResults(event.data.results);

                this.setProgressBar(0);
                this.$startButton.removeAttribute("hidden");
                this.$stopButton.setAttribute("hidden", "");

                break;
            case this.STATUS.ABORTED:
                window.clearInterval(this.statusInterval);

                this.processData(event.data || {});
                this.$shareResultsButton.setAttribute("hidden", "");
                this.$startButton.removeAttribute("hidden");
                this.$stopButton.setAttribute("hidden", "");
                break;
        }
    }

    /**
     * Reset the current results.
     */
    clearResults() {
        this.$ipValue.innerHTML = "";
        this.$latencyValue.innerHTML = "";
        this.$jitterValue.innerHTML = "";
        this.$downloadValue.innerHTML = "";
        this.$uploadValue.innerHTML = "";
    }

    /**
     * Process a set of data.
     *
     * @param {Object} data
     */
    processData(data) {
        if (!this.running) {
            return;
        }

        if (data.step === "ip") {
            this.$ipValue.innerHTML = data.results.ip;
            this.$asnValue.style.display = "none";
            this.$asnValue.innerHTML = "";
            this.getIpInfo(data.results.ip).then(info => {
                if (info.bogon) return;
                if (!info.org) return;

                this.$asnValue.style.display = "block";
                this.$asnValue.innerHTML = this.lastAsn = info.org;
            });

            return;
        }

        if (this.previousStep !== data.step) this.highlightStep(data.step);
        this.previousStep = data.step;

        this.$latencyValue.innerHTML = data.results.latency.avg || "";
        this.$jitterValue.innerHTML = data.results.latency.jitter || "";
        const downloadValue = data.results.download
            ? +data.results.download.speed / (1024 * 1024)
            : 0;
        this.$downloadValue.innerHTML = downloadValue
            ? downloadValue.toFixed(2)
            : "";
        const uploadValue = data.results.upload
            ? +data.results.upload.speed / (1024 * 1024)
            : 0;
        this.$uploadValue.innerHTML = uploadValue ? uploadValue.toFixed(2) : "";

        switch (data.step) {
            case "latency":
                this.setProgressBar(data.results.latency.progress);
                break;
            case "download":
                this.setProgressBar(data.results.download.progress, "download");
                break;
            case "upload":
                this.setProgressBar(data.results.upload.progress);
                break;
        }
    }

    /**
     * Resets the highlighted step.
     */
    resetHiglightStep() {
        document
            .querySelectorAll(".result")
            .forEach(elem => elem.classList.remove("active"));
    }

    /**
     * Highlights the current running step.
     * @param {String} step
     */
    highlightStep(step) {
        this.resetHiglightStep();

        switch (step) {
            case "latency":
                this.$latencyResult.classList.add("active");
                this.$jitterResult.classList.add("active");
                break;
            case "download":
                this.$downloadResult.classList.add("active");
                break;
            case "upload":
                this.$uploadResult.classList.add("active");
                break;
        }
    }

    /**
     * Set a value on the progress bar
     *
     * @param {Number} progress
     * @param {String} mode
     */
    setProgressBar(progress, mode = "") {
        this.$progress.style.flexDirection =
            mode === "download" ? "row-reverse" : "row";
        this.$progressBar.style.width = progress * 100 + "%";
    }

    /**
     * Get IP information from "ipinfo.io"
     *
     * @param {String} ip
     */
    getIpInfo(ip) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.addEventListener("readystatechange", () => {
                if (xhr.readyState === XMLHttpRequest.DONE) {
                    if (xhr.status === 200) {
                        resolve(JSON.parse(xhr.responseText));
                    } else {
                        reject(xhr.statusText);
                    }
                }
            });
            xhr.open("GET", `//ipinfo.io/${ip}/json`, true);
            xhr.send(null);
        });
    }

    showPage(page) {
        this.page = page;

        this.$history.setAttribute("hidden", "");
        this.$share.setAttribute("hidden", "");
        this.$speedtest.setAttribute("hidden", "");
        this[`$${page}`].removeAttribute("hidden");
    }

    /**
     * Show the page to share results
     */
    generateShareResultsLinks() {
        this.$shareResultsLink.value = `${window.location.origin}/result${
            window.location.hash
        }`;

        html2canvas(this.$speedtest, {
            logging: false,
            scale: 1,
            onclone: doc => {
                const $el = doc.querySelector("#speedtest");
                $el.removeAttribute("hidden");
                $el.classList.add("share");
            }
        }).then(canvas => {
            this.$shareResultsImage.src = canvas.toDataURL("image/png");
        });
    }

    /**
     * Prepare the share results button with a PNG image
     */
    shareResultsButtonClickHandler() {
        this.generateShareResultsLinks();
        this.showPage("share");
        window.history.pushState(
            {},
            "Speed Test - Share Results",
            `/share#${this.resultsString}`
        );
    }

    /**
     * Select the share result link on input click
     */
    shareResultsLinkClickHandler() {
        this.$shareResultsLink.select();
    }

    /**
     * Select anc copy the share result link on "Copy" button click
     */
    shareResultsLinkCopyButtonClickHandler() {
        this.$shareResultsLink.select();
        document.execCommand("copy");
    }

    /**
     * Close alert boxes on click
     *
     * @param {MouseEvent} e
     */
    alertCloseButtonClickHandler(e) {
        e.target.parentElement.setAttribute("hidden", "");
    }

    /**
     * Store a speed test run results to the local storage
     *
     * @param {Object} results
     */
    storeLatestResults(results) {
        const resultsHistory =
            JSON.parse(localStorage.getItem("history")) || {};
        resultsHistory[results.timestamp] = results;
        localStorage.setItem(
            "history",
            JSON.stringify(this.limitResultsHistory(resultsHistory))
        );

        this.resultsString = this.getResultsString(results);
        this.$shareResultsButton.removeAttribute("hidden");
        window.history.pushState(
            {},
            "Speed Test - Results",
            `/result#${this.resultsString}`
        );
    }

    limitResultsHistory(resultsHistory, maxEntries = 5) {
        const filteredResults = {};
        Object.keys(resultsHistory)
            .sort((a, b) => +b - +a)
            .slice(0, maxEntries)
            .map(
                timestamp =>
                    (filteredResults[timestamp] = resultsHistory[timestamp])
            );
        return filteredResults;
    }

    /**
     * Load the results from the currect URI
     */
    loadResultsFromUri() {
        const [
            latency,
            jitter,
            download,
            upload,
            ip,
            asn
        ] = window.location.hash.replace("#", "").split(",");

        this.$ipValue.innerHTML = ip;
        this.$asnValue.innerHTML = decodeURIComponent(asn);
        this.$latencyValue.innerHTML = latency;
        this.$jitterValue.innerHTML = jitter;
        this.$downloadValue.innerHTML = (+download / (1024 * 1024)).toFixed(2);
        this.$uploadValue.innerHTML = (+upload / (1024 * 1024)).toFixed(2);

        // this.resultsString = `${latency},${jitter},${download},${upload},${ip},${asn}`;
    }

    /**
     * Toggle history results
     */
    showResultsHistoryButtonClickHandler() {
        this.stopTest();
        this.clearResults();

        this.loadResultsHistory();
        this.showPage("history");
        window.history.pushState({}, "Speed Test - Results", "/results");
    }

    loadResultsHistory() {
        const history = JSON.parse(localStorage.getItem("history")) || {};

        this.$historyResults.innerHTML = "";
        if (Object.entries(history).length === 0) {
            const $resultsRow = document.createElement("tr");
            $resultsRow.innerHTML =
                'No results.
Run a speed test now.	';
            this.$historyResults.appendChild($resultsRow);

            return;
        }

        Object.entries(history).forEach(([timestamp, results]) => {
            const date = new Date(+timestamp);
            const $resultsRow = document.createElement("tr");
            $resultsRow.innerHTML = `
                ${date.toLocaleDateString()}
${date.toLocaleTimeString()}
                ${results.latency.avg} ms
                ${results.latency.jitter} ms
                ${(results.download.speed / 1024 ** 2).toFixed(2)} Mbps
                ${(results.upload.speed / 1024 ** 2).toFixed(2)} Mbps
                ${results.ip}${
                    results.asn ? `<br>(${results.asn})` : ""
                }

            `;
            this.$historyResults.appendChild($resultsRow);
        });
    }

    getResultsString(results) {
        return `${results.latency.avg},${results.latency.jitter},${
            results.download.speed
        },${results.upload.speed},${results.ip},${results.asn || ""}`;
    }
}
<|endoftext|>


<commit_before>/*
* jQuery Mobile Framework : "page" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/

(function( $, undefined ) {

$.widget( "mobile.page", $.mobile.widget, {
	options: {
		backBtnText: "Back",
		addBackBtn: false,
		backBtnTheme: null,
		degradeInputs: {
			color: false,
			date: false,
			datetime: false,
			"datetime-local": false,
			email: false,
			month: false,
			number: false,
			range: "number",
			search: true,
			tel: false,
			time: false,
			url: false,
			week: false
		},
		keepNative: null
	},

	_create: function() {
		var $elem = this.element,
			o = this.options;

		this.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')" +
						( o.keepNative ? ", " + o.keepNative : "" );

		if ( this._trigger( "beforeCreate" ) === false ) {
			return;
		}

		// Some of the form elements currently rely on the presence of ui-page and ui-content
		// classes so we'll handle page and content roles outside of the main role processing
		// loop below.
		$elem.find( ":jqmData(role='page'), :jqmData(role='content')" ).andSelf().each(function() {
			var $this = $( this );

			$this.addClass( "ui-" + $this.jqmData( "role" ) );
		});

		$elem.find( ":jqmData(role='nojs')" ).addClass( "ui-nojs" );

		// Pre-find data els
		var $dataEls = $elem.find( ":jqmData(role)" ).andSelf().each(function() {
			var $this = $( this ),
				role = $this.jqmData( "role" ),
				theme = $this.jqmData( "theme" ),
				$headeranchors,
				leftbtn, rightbtn, backBtn;

			//apply theming and markup modifications to page,header,content,footer
			if ( role === "header" || role === "footer" ) {
				$this.addClass( "ui-bar-" + (theme || $this.parent( ":jqmData(role='page')" ).jqmData( "theme" ) || "a") );

				// Add ARIA role
				$this.attr( "role", role === "header" ? "banner" : "contentinfo" );

				// Right,left buttons
				$headeranchors = $this.children( "a" );
				leftbtn = $headeranchors.hasClass( "ui-btn-left" );
				rightbtn = $headeranchors.hasClass( "ui-btn-right" );

				if ( !leftbtn ) {
					leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
				}

				if ( !rightbtn ) {
					rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
				}

				// Auto-add back btn on pages beyond first view
				if ( o.addBackBtn && role === "header" &&
						$( ".ui-page" ).length > 1 &&
						$elem.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
						!leftbtn && $this.jqmData( "backbtn" ) !== false ) {

					backBtn = $( ""+ o.backBtnText +"" ).prependTo( $this );

					// If theme is provided, override default inheritance
					if ( o.backBtnTheme ) {
						backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme );
					}
				}

				// Page title
				$this.children( "h1, h2, h3, h4, h5, h6" )
					.addClass( "ui-title" )
					// Regardless of h element number in src, it becomes h1 for the enhanced page
					.attr({
						"tabindex": "0",
						"role": "heading",
						"aria-level": "1"
					});

			} else if ( role === "content" ) {

				if ( theme ) {
					$this.addClass( "ui-body-" + theme );
				}

				// Add ARIA role
				$this.attr( "role", "main" );

			} else if ( role === "page" ) {
				$this.addClass( "ui-body-" + (theme || "c") );
			}

			switch ( role ) {
				case "header":
				case "footer":
				case "page":
				case "content":
					$this.addClass( "ui-" + role );
					break;
				case "collapsible":
				case "fieldcontain":
				case "navbar":
				case "listview":
				case "dialog":
					$this[ role ]();
					break;
			}
		});

		//enhance form controls
  	this._enhanceControls();

		//links in bars, or those with  data-role become buttons
		$elem.find( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a" )
			.not( ".ui-btn" )
			.not( this.keepNative )
			.buttonMarkup();

		$elem.find( ":jqmData(role='controlgroup')" )
			.controlgroup({
				dontFilterOutInvisible: true
			});

		// Links within content areas
		$elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" )
			.not( this.keepNative )
			.addClass( "ui-link" );

		// Fix toolbars
		$elem.fixHeaderFooter();
	},

	_typeAttributeRegex: /\s+type=["']?\w+['"]?/,

	_enhanceControls: function() {
		var o = this.options,
			self = this,
			allControls, nonNativeControls, textInputs;

		// degrade inputs to avoid poorly implemented native functionality
		this.element.find( "input" ).not(this.keepNative).each(function() {
			var $this = $( this ),
				type = this.getAttribute( "type" ),
				optType = o.degradeInputs[ type ] || "text";

			if ( o.degradeInputs[ type ] ) {
				$this.replaceWith(
					$( "
" ).html( $this.clone() ).html()
						.replace( self._typeAttributeRegex, " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\" " )
				);
			}
		});

		// We re-find form elements since the degredation code above
		// may have injected new elements. We cache the non-native control
		// query to reduce the number of times we search through the entire page.

		allControls = this.element.find("input, textarea, select, button");
		nonNativeControls = allControls.not(this.keepNative);

		// XXX: Temporary workaround for issue 785. Turn off autocorrect and
		//      autocomplete since the popup they use can't be dismissed by
		//      the user. Note that we test for the presence of the feature
		//      by looking for the autocorrect property on the input element.

		textInputs = allControls.filter( "input[type=text]" );

		if ( textInputs.length && typeof textInputs[0].autocorrect !== "undefined" ) {
			textInputs.each(function() {
				// Set the attribute instead of the property just in case there
				// is code that attempts to make modifications via HTML.
				this.setAttribute( "autocorrect", "off" );
				this.setAttribute( "autocomplete", "off" );
			});
		}

		// enchance form controls
		nonNativeControls
			.filter( "[type='radio'], [type='checkbox']" )
			.checkboxradio();

		nonNativeControls
			.filter( "button, [type='button'], [type='submit'], [type='reset'], [type='image']" )
			.button();

		nonNativeControls
			.filter( "input, textarea" )
			.not( "[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']" )
			.textinput();

		nonNativeControls
			.filter( "input, select" )
			.filter( ":jqmData(role='slider'), :jqmData(type='range')" )
			.slider();

		nonNativeControls
			.filter( "select:not(:jqmData(role='slider'))" )
			.selectmenu();
	}
});

})( jQuery );
<commit_msg>globalpagecreate-Event<commit_after>/*
* jQuery Mobile Framework : "page" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/

(function( $, undefined ) {

$.widget( "mobile.page", $.mobile.widget, {
	options: {
		backBtnText: "Back",
		addBackBtn: false,
		backBtnTheme: null,
		degradeInputs: {
			color: false,
			date: false,
			datetime: false,
			"datetime-local": false,
			email: false,
			month: false,
			number: false,
			range: "number",
			search: true,
			tel: false,
			time: false,
			url: false,
			week: false
		},
		keepNative: null
	},

	_create: function() {
		var $elem = this.element,
			o = this.options;

		this.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')" +
						( o.keepNative ? ", " + o.keepNative : "" );

		if ( this._trigger( "beforeCreate" ) === false ) {
			return;
		}

		// Some of the form elements currently rely on the presence of ui-page and ui-content
		// classes so we'll handle page and content roles outside of the main role processing
		// loop below.
		$elem.find( ":jqmData(role='page'), :jqmData(role='content')" ).andSelf().each(function() {
			var $this = $( this );

			$this.addClass( "ui-" + $this.jqmData( "role" ) );
		});

		$elem.find( ":jqmData(role='nojs')" ).addClass( "ui-nojs" );

		// Pre-find data els
		var $dataEls = $elem.find( ":jqmData(role)" ).andSelf().each(function() {
			var $this = $( this ),
				role = $this.jqmData( "role" ),
				theme = $this.jqmData( "theme" ),
				$headeranchors,
				leftbtn, rightbtn, backBtn;

			//apply theming and markup modifications to page,header,content,footer
			if ( role === "header" || role === "footer" ) {
				$this.addClass( "ui-bar-" + (theme || $this.parent( ":jqmData(role='page')" ).jqmData( "theme" ) || "a") );

				// Add ARIA role
				$this.attr( "role", role === "header" ? "banner" : "contentinfo" );

				// Right,left buttons
				$headeranchors = $this.children( "a" );
				leftbtn = $headeranchors.hasClass( "ui-btn-left" );
				rightbtn = $headeranchors.hasClass( "ui-btn-right" );

				if ( !leftbtn ) {
					leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
				}

				if ( !rightbtn ) {
					rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
				}

				// Auto-add back btn on pages beyond first view
				if ( o.addBackBtn && role === "header" &&
						$( ".ui-page" ).length > 1 &&
						$elem.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
						!leftbtn && $this.jqmData( "backbtn" ) !== false ) {

					backBtn = $( ""+ o.backBtnText +"" ).prependTo( $this );

					// If theme is provided, override default inheritance
					if ( o.backBtnTheme ) {
						backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme );
					}
				}

				// Page title
				$this.children( "h1, h2, h3, h4, h5, h6" )
					.addClass( "ui-title" )
					// Regardless of h element number in src, it becomes h1 for the enhanced page
					.attr({
						"tabindex": "0",
						"role": "heading",
						"aria-level": "1"
					});

			} else if ( role === "content" ) {

				if ( theme ) {
					$this.addClass( "ui-body-" + theme );
				}

				// Add ARIA role
				$this.attr( "role", "main" );

			} else if ( role === "page" ) {
				$('body').trigger("globalpagecreate", $this);
				$this.addClass( "ui-body-" + (theme || "c") );
			}

			switch ( role ) {
				case "header":
				case "footer":
				case "page":
				case "content":
					$this.addClass( "ui-" + role );
					break;
				case "collapsible":
				case "fieldcontain":
				case "navbar":
				case "listview":
				case "dialog":
					$this[ role ]();
					break;
			}
		});

		//enhance form controls
  	this._enhanceControls();

		//links in bars, or those with  data-role become buttons
		$elem.find( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a" )
			.not( ".ui-btn" )
			.not( this.keepNative )
			.buttonMarkup();

		$elem.find( ":jqmData(role='controlgroup')" )
			.controlgroup({
				dontFilterOutInvisible: true
			});

		// Links within content areas
		$elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" )
			.not( this.keepNative )
			.addClass( "ui-link" );

		// Fix toolbars
		$elem.fixHeaderFooter();
	},

	_typeAttributeRegex: /\s+type=["']?\w+['"]?/,

	_enhanceControls: function() {
		var o = this.options,
			self = this,
			allControls, nonNativeControls, textInputs;

		// degrade inputs to avoid poorly implemented native functionality
		this.element.find( "input" ).not(this.keepNative).each(function() {
			var $this = $( this ),
				type = this.getAttribute( "type" ),
				optType = o.degradeInputs[ type ] || "text";

			if ( o.degradeInputs[ type ] ) {
				$this.replaceWith(
					$( "
" ).html( $this.clone() ).html()
						.replace( self._typeAttributeRegex, " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\" " )
				);
			}
		});

		// We re-find form elements since the degredation code above
		// may have injected new elements. We cache the non-native control
		// query to reduce the number of times we search through the entire page.

		allControls = this.element.find("input, textarea, select, button");
		nonNativeControls = allControls.not(this.keepNative);

		// XXX: Temporary workaround for issue 785. Turn off autocorrect and
		//      autocomplete since the popup they use can't be dismissed by
		//      the user. Note that we test for the presence of the feature
		//      by looking for the autocorrect property on the input element.

		textInputs = allControls.filter( "input[type=text]" );

		if ( textInputs.length && typeof textInputs[0].autocorrect !== "undefined" ) {
			textInputs.each(function() {
				// Set the attribute instead of the property just in case there
				// is code that attempts to make modifications via HTML.
				this.setAttribute( "autocorrect", "off" );
				this.setAttribute( "autocomplete", "off" );
			});
		}

		// enchance form controls
		nonNativeControls
			.filter( "[type='radio'], [type='checkbox']" )
			.checkboxradio();

		nonNativeControls
			.filter( "button, [type='button'], [type='submit'], [type='reset'], [type='image']" )
			.button();

		nonNativeControls
			.filter( "input, textarea" )
			.not( "[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']" )
			.textinput();

		nonNativeControls
			.filter( "input, select" )
			.filter( ":jqmData(role='slider'), :jqmData(type='range')" )
			.slider();

		nonNativeControls
			.filter( "select:not(:jqmData(role='slider'))" )
			.selectmenu();
	}
});

})( jQuery );
<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on views, and components
angular.module('myApp', [
  'ngRoute',
  'myApp.view1',
  'myApp.view2',
  'myApp.version'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.otherwise({redirectTo: '/view1'});
}]);
<commit_msg>Add controller logic.<commit_after>'use strict';

// Declare app level module which depends on views, and components
angular.module('schedulerApp', [
  'ngRoute',
  'ngResource'
])
.factory('db', [ '$resource', '$q', '$rootScope', function($resource, $q, $rootScope) {

	var
		Things = $resource("http://10.0.1.168:8000/rest/v1/things", {}),
		Rooms = $resource("http://10.0.1.168:8000/rest/v1/rooms", {}),
		Tasks = $resource("http://10.0.1.168:8100/rest/v1/tasks", {}),
		Task = $resource("http://10.0.1.168:8100/rest/v1/tasks/:id", {}),
		refreshThings = function() {
			return Things.get({}).$promise.then(
				function(things) {
					service.things = {}
					angular.forEach(things.data,
						function(thing) {
							var found = false
							if (!thing.promoted || !thing.name || !thing.location) {
								console.debug("skipping thing because not promoted, described or assigned to room", thing)
								return
							}
							angular.forEach(thing.device.channels, function(channel) {
								if (channel.supportedMethods && channel.supportedMethods.indexOf("turnOff") > 0) {
									found = true
								}
							})
							if (found) {
								service.things[thing["id"]] = thing
							}
						}
					)
					return service
				}
			)
		},
		refreshRooms = function() {
			return Rooms.get({}).$promise.then(
				function(rooms) {
					service.rooms = {}
					angular.forEach(rooms.data, function(room) {
						service.rooms[room["id"]] = room
					})
					return service
				}
			)
		},
		refreshTasks = function() {
			return Tasks.get({}).$promise.then(
				function(tasks) {
					service.tasks = {}
					angular.forEach(tasks.schedule, function(task) {
						if (task.description && task.description != '') {
							service.tasks[task["id"]] = task
						}
					})
					return service
				}
			)
		},
		service = {
			things: { } ,
			rooms: { } ,
			tasks: { } ,
			save: function(task) {
				var deferred = $q.defer()
				Tasks.save(
					{},
					task,
					function(r) {
						refreshTasks().then(
							function() { deferred.resolve(r) },
							deferred.reject
						)},
					deferred.reject)
				return deferred.promise
			},
			delete: function(id) {
				var deferred = $q.defer()
				Task.delete({"id": id},
					function(r) {
						refreshTasks().then(function() { deferred.resolve(r)}, deferred.reject)
					},
					deferred.reject
				)
				return deferred.promise
			},
			refresh: function() {
				return $q.all([ refreshRooms(),	refreshThings(), refreshTasks() ]).then(
					function() {
						return service
					}
				)
			}
		}
	return service
}])
.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/list', {templateUrl: 'task-list.html', controller: 'TaskList'});
  $routeProvider.when('/edit/:id', {templateUrl: 'task-edit.html', controller: 'TaskEdit'});
  $routeProvider.when('/create', {templateUrl: 'task-edit.html', controller: 'TaskEdit'});
  $routeProvider.otherwise({redirectTo: '/list'});
}])
.controller('ModelRefresh', ['$scope', 'db', function($scope, db) {
	db.refresh().then(
		function(things) {
			return things
		},
		function(err) {
			$scope.message = err
		}
	)
}])
.controller('TaskEdit', ['$scope', '$location', 'db', '$routeParams', function($scope, $location, db, $routeParams) {

	$scope.thingToModel = function(thing) {
		var result = {}
		result.id = thing.id
		result.description = thing.name
		var room = db.rooms[thing.location]
		if (!room) {
			return null
		}
		result.room = room.name
		result.on = "true"
		return result
	}

	$scope.actionToModel = function(action) {
	    // {
        //    "action" : "turnOn",
        //    "thingID" : "94dc7d1a-aa67-11e4-803a-7c669d02a706",
        //     "type" : "thing-action"
        // }
        //
        // ==>
        //
	    // {
	    //	  "id": thing-id
        //    "description" : "thing description",
        //	  "room": "room description"
        //	  "on": true
        // }
        //

		var result = {}
		switch (action["action"]) {
		case "turnOn":
			result.on = "true"
			break
		case "turnOff":
			result.on = "false"
			break
		default:
			console.debug("bad action ", action)
			return null
		}

		if (action.type != "thing-action") {
			console.debug("bad type ", action.type)
			return null
		}

		if (!action.thingID) {
			console.debug("missing thing id")
			return null
		}

		result.id = action.thingID
		var thing = db.things[result.id]
		if (!thing) {
			console.debug("invalid thing id", result.id)
			return null
		}
		result.description = thing.name
		var room = db.rooms[thing.location]
		if (!room) {
			console.debug("invalid room id", thing.location)
			return null
		}
		result.room = room.name

		return result
	}

	$scope.selectedThings = {}
	$scope.availableThings = {}

	$scope.task = function() {
		return db.tasks[$routeParams["id"]]
	}

	$scope.$watch('task()', function(task) {
		$scope.availableThings = {}
		angular.forEach(db.things, function(t) {
			var m = $scope.thingToModel(t)
			if (m) {
				$scope.availableThings[t["id"]] = m
				$scope.selected = t["id"]
			}
		})
		if (!task) {
			return
		}
		$scope.description = task.description
		$scope.timeOfDay = task.window.after.param
		angular.forEach(task.open, function(action) {
			var thing = $scope.actionToModel(action)
			if (thing) {
				$scope.selectedThings[thing.id] = thing
				delete $scope.availableThings[thing.id]
			} else {
				console.debug(action)
			}
		})
		$scope.updateSelected()
	})

	$scope.selected = null

	$scope.save = function() {
		$scope.message = ""

		var task = {
			"id": $routeParams["id"],
			"description": $scope.description,
			"open":
				(function() {
					var results = []
					angular.forEach($scope.selectedThings, function(m) {
						results.push(
							{
								"type": "thing-action",
								"action": (m.on == "true" ? "turnOn" : "turnOff"),
								"thingID": m.id
							}
						)
					})
					return results
				}())
			,
			"window": {
				"after": {
					"rule": "time-of-day",
					"param": $scope.timeOfDay
				},
				"before": {
					"rule": "delay",
					"param": "00:01:00"
				}
			}
		}

		db.save(task).then(
			function() {
				$location.path('/list')
			}, function(r) {
				$scope.message = message
			})
	}

	$scope.delete = function() {
		db.delete($routeParams["id"]).then(
			function() {
				$location.path('/list')
			}, function(m) {
				$scope.message = m
			})
	}

	$scope.updateSelected = function() {
		$scope.selected = null
		angular.forEach($scope.availableThings, function(m) {
			$scope.selected = m.id
		})
	}
	$scope.add = function() {
		if ($scope.selected) {
			$scope.selectedThings[$scope.selected] = $scope.availableThings[$scope.selected]
			delete $scope.availableThings[$scope.selected]
			$scope.updateSelected()
		}

	}

	$scope.remove = function() {
		var tmp = []
		angular.forEach($scope.selectedThings, function (m) {
			if (m.selected) {
				tmp.push(m.id)
			}
		})
		angular.forEach(tmp, function(id) {
			var m = $scope.selectedThings[id]
			delete $scope.selectedThings[id]
			$scope.availableThings[id] = m
		})
		$scope.updateSelected()
	}

	$scope.cancel = function() {
		$location.path('/list')
	}
}])
.controller('TaskList', ['$scope', 'db', '$rootScope', function($scope, db, $rootScope) {
	$scope.tasks = {}
	$scope.db = db
	$scope.$watch("db.tasks", function(tasks) {
		$scope.tasks = db.tasks
	})
}])

<|endoftext|>


<commit_before>
/***************************
 * TEST ASM.JS CORRECTNESS *
 ***************************/

// asm.js functions should always have the same semantics as JavaScript functions.
//
// We just need to watch out for:
// * Invalid asm.js
// * Foreign imports of impure functions
// * Mixing int and double heap views (NaN bits)
// * Allowing mutable state to diverge (mutable module globals, heap)

// In those cases, we can test that the asm-compiled version matches the normal js version.
// *  isAsmJSFunction(f)
// * !isAsmJSFunction(g)

// Because we pass the 'sanePlease' flag to asmJSInterior,
// * We don't expect any parse errors. (testOneAsmJSInterior currently relies on this.)
// * We expect only the following asm.js type errors:
//   * "numeric literal out of representable integer range" (https://github.com/dherman/asm.js/issues/67 makes composition hard)
//   * "no duplicate case labels" (because asmSwitchStatement doesn't avoid this)
// * And the following, infrequently, due to out-of-range integer literals:
//   * "one arg to int multiply must be a small (-2^20, 2^20) int literal"
//   * "arguments to / or % must both be double, signed, or unsigned, unsigned and signed are given"
//   * "unsigned is not a subtype of signed or doublish" [Math.abs]

var compareAsm = (function() {

  function isSameNumber(a, b)
  {
    if (!(typeof a == "number" && typeof b == "number"))
      return false;

    // Differentiate between 0 and -0
    if (a === 0 && b === 0)
      return 1/a === 1/b;

    // Don't differentiate between NaNs
    return a === b || (a !== a && b !== b);
  }

  var asmvals = [
    1, Math.PI, 42,
    // Special float values
    0, -0, 0/0, 1/0, -1/0,
    // Boundaries of int, signed, unsigned (near +/- 2^31, +/- 2^32)
     0x07fffffff,  0x080000000,  0x080000001,
    -0x07fffffff, -0x080000000, -0x080000001,
     0x0ffffffff,  0x100000000,  0x100000001,
    -0x0ffffffff, -0x100000000,  0x100000001,
    // Boundaries of double
    Number.MIN_VALUE, -Number.MIN_VALUE,
    Number.MAX_VALUE, -Number.MAX_VALUE,
  ];
  var asmvalsLen = asmvals.length;

  function compareUnaryFunctions(f, g)
  {
    for (var i = 0; i < asmvalsLen; ++i) {
      var x = asmvals[i];
      var fr = f(x);
      var gr = g(x);
      if (!isSameNumber(fr, gr)) {
        foundABug("asm mismatch", "(" + uneval(x) + ") -> " + uneval(fr) + " vs "  + uneval(gr));
      }
    }
  }

  function compareBinaryFunctions(f, g)
  {
    for (var i = 0; i < asmvalsLen; ++i) {
      var x = asmvals[i];
      for (var j = 0; j < asmvalsLen; ++j) {
        var y = asmvals[j];
        var fr = f(x, y);
        var gr = g(x, y);
        if (!isSameNumber(fr, gr)) {
          foundABug("asm mismatch", "(" + uneval(x) + ", " + uneval(y) + ") -> " + uneval(fr) + " vs "  + uneval(gr));
        }
      }
    }
  }

  return {compareUnaryFunctions: compareUnaryFunctions, compareBinaryFunctions: compareBinaryFunctions};
})();

function nanBitsMayBeVisible(s)
{
  // Does the code use more than one of {*int*, float32, or float64} views on the same array buffer?
  return (s.indexOf("Uint") != -1 || s.indexOf("Int") != -1) + (s.indexOf("Float32Array") != -1) + (s.indexOf("Float64Array") != -1) > 1;
}

var pureForeign = {
  identity:  function(x) { return x; },
  quadruple: function(x) { return x * 4; },
  half:      function(x) { return x / 2; },
  // Test coercion coming back from FFI.
  asString:  function(x) { return uneval(x); },
  asValueOf: function(x) { return { valueOf: function() { return x; } }; },
  // Test register arguments vs stack arguments.
  sum:       function()  { var s = 0; for (var i = 0; i < arguments.length; ++i) s += arguments[i]; return s; },
  // Will be replaced by calling makeRegisterStompFunction
  stomp:     function()  { },
};

var pureMath = ["abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "exp", "floor", "imul", "log", "max", "min", "pow", "round", "sin", "sqrt", "tan"];
for (var f in pureMath) {
  pureForeign["Math_" + pureMath[f]] = Math[pureMath[f]];
}

var pureMathNames = Object.keys(pureForeign);

function generateAsmDifferential()
{
  var foreignFunctions = rnd(10) ? [] : pureMathNames;
  return asmJSInterior(foreignFunctions, true);
}

function testAsmDifferential(stdlib, interior)
{
  if (nanBitsMayBeVisible(interior)) {
    dumpln("Skipping correctness test for asm module that could expose low bits of NaN");
    return;
  }

  var asmJs = "(function(stdlib, foreign, heap) { 'use asm'; " + interior + " })";
  var asmModule = eval(asmJs);

  if (isAsmJSModule(asmModule)) {
    var asmHeap = new ArrayBuffer(4096);
    (new Int32Array(asmHeap))[0] = 0x12345678;
    var asmFun = asmModule(stdlib, pureForeign, asmHeap);

    var normalHeap = new ArrayBuffer(4096);
    (new Int32Array(normalHeap))[0] = 0x12345678;
    var normalJs = "(function(stdlib, foreign, heap) { " + interior + " })";
    var normalModule = eval(normalJs);
    var normalFun = normalModule(stdlib, pureForeign, normalHeap);

    compareAsm.compareBinaryFunctions(asmFun, normalFun);
  }
}

// Call this instead of start() to run asm-differential tests
function startAsmDifferential()
{
  init(this);

  while (true) {

    var stompStr = makeRegisterStompFunction(8, [], true);
    print(stompStr);
    pureForeign.stomp = eval(stompStr);

    for (var i = 0; i < 100; ++i) {
      var interior = generateAsmDifferential();
      print(interior);
      testAsmDifferential(this, interior);
    }
    gc();
  }
}
<commit_msg>Fix startAsmDifferential (was broken by the jsfunfuzz split)<commit_after>
/***************************
 * TEST ASM.JS CORRECTNESS *
 ***************************/

// asm.js functions should always have the same semantics as JavaScript functions.
//
// We just need to watch out for:
// * Invalid asm.js
// * Foreign imports of impure functions
// * Mixing int and double heap views (NaN bits)
// * Allowing mutable state to diverge (mutable module globals, heap)

// In those cases, we can test that the asm-compiled version matches the normal js version.
// *  isAsmJSFunction(f)
// * !isAsmJSFunction(g)

// Because we pass the 'sanePlease' flag to asmJSInterior,
// * We don't expect any parse errors. (testOneAsmJSInterior currently relies on this.)
// * We expect only the following asm.js type errors:
//   * "numeric literal out of representable integer range" (https://github.com/dherman/asm.js/issues/67 makes composition hard)
//   * "no duplicate case labels" (because asmSwitchStatement doesn't avoid this)
// * And the following, infrequently, due to out-of-range integer literals:
//   * "one arg to int multiply must be a small (-2^20, 2^20) int literal"
//   * "arguments to / or % must both be double, signed, or unsigned, unsigned and signed are given"
//   * "unsigned is not a subtype of signed or doublish" [Math.abs]

var compareAsm = (function() {

  function isSameNumber(a, b)
  {
    if (!(typeof a == "number" && typeof b == "number"))
      return false;

    // Differentiate between 0 and -0
    if (a === 0 && b === 0)
      return 1/a === 1/b;

    // Don't differentiate between NaNs
    return a === b || (a !== a && b !== b);
  }

  var asmvals = [
    1, Math.PI, 42,
    // Special float values
    0, -0, 0/0, 1/0, -1/0,
    // Boundaries of int, signed, unsigned (near +/- 2^31, +/- 2^32)
     0x07fffffff,  0x080000000,  0x080000001,
    -0x07fffffff, -0x080000000, -0x080000001,
     0x0ffffffff,  0x100000000,  0x100000001,
    -0x0ffffffff, -0x100000000,  0x100000001,
    // Boundaries of double
    Number.MIN_VALUE, -Number.MIN_VALUE,
    Number.MAX_VALUE, -Number.MAX_VALUE,
  ];
  var asmvalsLen = asmvals.length;

  function compareUnaryFunctions(f, g)
  {
    for (var i = 0; i < asmvalsLen; ++i) {
      var x = asmvals[i];
      var fr = f(x);
      var gr = g(x);
      if (!isSameNumber(fr, gr)) {
        foundABug("asm mismatch", "(" + uneval(x) + ") -> " + uneval(fr) + " vs "  + uneval(gr));
      }
    }
  }

  function compareBinaryFunctions(f, g)
  {
    for (var i = 0; i < asmvalsLen; ++i) {
      var x = asmvals[i];
      for (var j = 0; j < asmvalsLen; ++j) {
        var y = asmvals[j];
        var fr = f(x, y);
        var gr = g(x, y);
        if (!isSameNumber(fr, gr)) {
          foundABug("asm mismatch", "(" + uneval(x) + ", " + uneval(y) + ") -> " + uneval(fr) + " vs "  + uneval(gr));
        }
      }
    }
  }

  return {compareUnaryFunctions: compareUnaryFunctions, compareBinaryFunctions: compareBinaryFunctions};
})();

function nanBitsMayBeVisible(s)
{
  // Does the code use more than one of {*int*, float32, or float64} views on the same array buffer?
  return (s.indexOf("Uint") != -1 || s.indexOf("Int") != -1) + (s.indexOf("Float32Array") != -1) + (s.indexOf("Float64Array") != -1) > 1;
}

var pureForeign = {
  identity:  function(x) { return x; },
  quadruple: function(x) { return x * 4; },
  half:      function(x) { return x / 2; },
  // Test coercion coming back from FFI.
  asString:  function(x) { return uneval(x); },
  asValueOf: function(x) { return { valueOf: function() { return x; } }; },
  // Test register arguments vs stack arguments.
  sum:       function()  { var s = 0; for (var i = 0; i < arguments.length; ++i) s += arguments[i]; return s; },
  // Will be replaced by calling makeRegisterStompFunction
  stomp:     function()  { },
};

var pureMath = ["abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "exp", "floor", "imul", "log", "max", "min", "pow", "round", "sin", "sqrt", "tan"];
for (var f in pureMath) {
  pureForeign["Math_" + pureMath[f]] = Math[pureMath[f]];
}

var pureMathNames = Object.keys(pureForeign);

function generateAsmDifferential()
{
  var foreignFunctions = rnd(10) ? [] : pureMathNames;
  return asmJSInterior(foreignFunctions, true);
}

function testAsmDifferential(stdlib, interior)
{
  if (nanBitsMayBeVisible(interior)) {
    dumpln("Skipping correctness test for asm module that could expose low bits of NaN");
    return;
  }

  var asmJs = "(function(stdlib, foreign, heap) { 'use asm'; " + interior + " })";
  var asmModule = eval(asmJs);

  if (isAsmJSModule(asmModule)) {
    var asmHeap = new ArrayBuffer(4096);
    (new Int32Array(asmHeap))[0] = 0x12345678;
    var asmFun = asmModule(stdlib, pureForeign, asmHeap);

    var normalHeap = new ArrayBuffer(4096);
    (new Int32Array(normalHeap))[0] = 0x12345678;
    var normalJs = "(function(stdlib, foreign, heap) { " + interior + " })";
    var normalModule = eval(normalJs);
    var normalFun = normalModule(stdlib, pureForeign, normalHeap);

    compareAsm.compareBinaryFunctions(asmFun, normalFun);
  }
}

// Call this instead of start() to run asm-differential tests
function startAsmDifferential()
{
  getListOfMakers(this);

  var fuzzSeed = Math.floor(Math.random() * Math.pow(2,28));
  dumpln("fuzzSeed: " + fuzzSeed);
  Random.init(fuzzSeed);

  while (true) {

    var stompStr = makeRegisterStompFunction(8, [], true);
    print(stompStr);
    pureForeign.stomp = eval(stompStr);

    for (var i = 0; i < 100; ++i) {
      var interior = generateAsmDifferential();
      print(interior);
      testAsmDifferential(this, interior);
    }
    gc();
  }
}
<|endoftext|>


<commit_before>"use strict"

const webpack = require("webpack")

module.exports = {
  entry: {
    "background": './src/background.js',
    "popup": './src/popup.js',
  },
  //devtool: 'source-map',
  cache: true,
  output: {
    path: `extension/js`,
    publicPath: '/',
    filename: "[name].js"
  },
}

<commit_msg>webpack: fix output.path to be absolute<commit_after>"use strict"

const path = require("path")
const webpack = require("webpack")

module.exports = {
  entry: {
    "background": './src/background.js',
    "popup": './src/popup.js',
  },
  //devtool: 'source-map',
  cache: true,
  output: {
    path: `${path.resolve(__dirname, 'extension/js')}`,
    publicPath: '/',
    filename: "[name].js"
  },
}

<|endoftext|>


<commit_before>require('dotenv').config();
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');

const production = process.env.NODE_ENV === 'production';
const hmr = process.argv.includes('--hot');

const browserSyncHost = process.env.BROWSERSYNC_HOST || 'localhost';
const browserSyncPort = parseInt(process.env.BROWSERSYNC_PORT || '3000', 10);
const webpackDevServerPort = parseInt(process.env.WEBPACKDEVSERVER_PORT || '8080', 10);

// Hot reloading file for Laravel detection
const hotfilename = 'public/hot';

if (fs.existsSync(hotfilename)) {
    fs.unlinkSync(hotfilename);
}

if (hmr) {
    fs.writeFileSync(hotfilename, 'hot reloading');
}

const extractSass = new ExtractTextPlugin({
    filename: production ? 'dist/css/[name].[contenthash].css' : 'css/[name].css',
    disable: hmr
});

module.exports = {
    entry: {
        frontend: [
            './resources/assets/js/frontend/app.js',
            './resources/assets/sass/frontend/app.scss'
        ],
        backend: [
            './resources/assets/js/backend/app.js',
            './resources/assets/sass/backend/app.scss'
        ],
        vendor: [
            'lodash',
            'moment',
            'jquery',
            'vue',
            'axios',
            'datatables.net',
            'select2',
            'sweetalert2',
            'slick-carousel'
        ]
    },
    output: {
        path: path.join(__dirname, '/public'),
        filename: production ? 'dist/js/[name].[chunkhash].js' : 'js/[name].js',
        publicPath: hmr ? `http://localhost:${webpackDevServerPort}/` : '/'
    },
    module: {
        rules: [
            {
                test: /\.scss$/,
                use: extractSass.extract({
                    use: [{
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    }, {
                        loader: 'postcss-loader',
                        options: {
                            sourceMap: true,
                            plugins: [
                                require('postcss-import')()
                            ]
                        }
                    }, {
                        loader: 'resolve-url-loader?sourceMap'
                    }, {
                        loader: 'sass-loader',
                        options: {
                            precision: 8,
                            outputStyle: 'expanded',
                            sourceMap: true
                        }
                    }],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                        js: 'babel-loader?cacheDirectory',
                        scss: 'vue-style-loader!css-loader!sass-loader',
                        sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
                    }
                }
            },
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                use: 'babel-loader?cacheDirectory'
            },
            {
                test: /\.html$/,
                loaders: ['html-loader']
            },
            {
                test: /\.(png|jpe?g|gif)$/,
                loaders: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: path => {
                                if (!/node_modules|bower_components/.test(path)) {
                                    return 'images/[name].[ext]?[hash]';
                                }

                                return 'images/vendor/' + path
                                        .replace(/\\/g, '/')
                                        .replace(
                                            /((.*(node_modules|bower_components))|images|image|img|assets)\//g, ''
                                        ) + '?[hash]';
                            },
                            publicPath: '/'
                        }
                    },
                    'img-loader'
                ]
            },
            {
                test: /\.(woff2?|ttf|eot|svg|otf)$/,
                loader: 'file-loader',
                options: {
                    name: 'fonts/[name].[ext]?[hash]'
                }
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            jQuery: 'jquery',
            $: 'jquery'
        }),
        new FriendlyErrorsWebpackPlugin(),
        new webpack.LoaderOptionsPlugin({
            minimize: production,
            options: {
                context: __dirname,
                output: {path: './'}
            }
        }),
        new WebpackNotifierPlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor', 'manifest'],
            minChunks: Infinity
        }),
        extractSass,
        new BrowserSyncPlugin(
            {
                host: browserSyncHost,
                port: browserSyncPort,
                open: browserSyncHost === 'localhost' ? 'local' : 'external',
                proxy: {
                    target: process.env.BROWSERSYNC_PROXY,
                    reqHeaders: function (config) {
                        return {
                            host: `${config.url.hostname}:${process.env.BROWSERSYNC_PORT}`
                        };
                    }
                },
                files: [
                    'app/**/*.php',
                    'resources/views/**/*.php',
                    'public/js/**/*.js',
                    'public/css/**/*.css'
                ]
            },
            {
                reload: false
            }
        )
    ],
    resolve: {
        extensions: ['*', '.js', '.jsx', '.vue'],

        alias: {
            vue$: 'vue/dist/vue.common.js'
        }
    },
    performance: {
        hints: false
    },
    devtool: production ? 'cheap-source-map' : 'cheap-module-eval-source-map',
    devServer: {
        headers: {
            "Access-Control-Allow-Origin": "*"
        },
        historyApiFallback: true,
        noInfo: true,
        compress: true,
        quiet: true,
        port: webpackDevServerPort
    }
};

let plugins = [];

if (production) {
    plugins = [
        new CleanWebpackPlugin(['dist', 'images/vendor'], {
            root: path.join(__dirname, '/public')
        }),
        new webpack.optimize.UglifyJsPlugin({
            sourceMap: true,
            compress: {
                warnings: false
            }
        }),
        new StatsWriterPlugin({
            filename: 'assets-manifest.json',
            transform(data) {
                return JSON.stringify({
                    '/js/manifest.js': `/${data.assetsByChunkName.manifest[0]}`,
                    '/js/vendor.js': `/${data.assetsByChunkName.vendor[0]}`,
                    '/js/frontend.js': `/${data.assetsByChunkName.frontend[0]}`,
                    '/css/frontend.css': `/${data.assetsByChunkName.frontend[1]}`,
                    '/js/backend.js': `/${data.assetsByChunkName.backend[0]}`,
                    '/css/backend.css': `/${data.assetsByChunkName.backend[1]}`
                }, null, 2);
            }
        })
    ];
}

module.exports.plugins.push(...plugins);
<commit_msg>hmr named modules<commit_after>require('dotenv').config();
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');

const production = process.env.NODE_ENV === 'production';
const hmr = process.argv.includes('--hot');

const browserSyncHost = process.env.BROWSERSYNC_HOST || 'localhost';
const browserSyncPort = parseInt(process.env.BROWSERSYNC_PORT || '3000', 10);
const webpackDevServerPort = parseInt(process.env.WEBPACKDEVSERVER_PORT || '8080', 10);

// Hot reloading file for Laravel detection
const hotfilename = 'public/hot';

if (fs.existsSync(hotfilename)) {
    fs.unlinkSync(hotfilename);
}

if (hmr) {
    fs.writeFileSync(hotfilename, 'hot reloading');
}

const extractSass = new ExtractTextPlugin({
    filename: production ? 'dist/css/[name].[contenthash].css' : 'css/[name].css',
    disable: hmr
});

module.exports = {
    entry: {
        frontend: [
            './resources/assets/js/frontend/app.js',
            './resources/assets/sass/frontend/app.scss'
        ],
        backend: [
            './resources/assets/js/backend/app.js',
            './resources/assets/sass/backend/app.scss'
        ],
        vendor: [
            'lodash',
            'moment',
            'jquery',
            'vue',
            'axios',
            'datatables.net',
            'select2',
            'sweetalert2',
            'slick-carousel'
        ]
    },
    output: {
        path: path.join(__dirname, '/public'),
        filename: production ? 'dist/js/[name].[chunkhash].js' : 'js/[name].js',
        publicPath: hmr ? `http://localhost:${webpackDevServerPort}/` : '/'
    },
    module: {
        rules: [
            {
                test: /\.scss$/,
                use: extractSass.extract({
                    use: [{
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    }, {
                        loader: 'postcss-loader',
                        options: {
                            sourceMap: true,
                            plugins: [
                                require('postcss-import')()
                            ]
                        }
                    }, {
                        loader: 'resolve-url-loader?sourceMap'
                    }, {
                        loader: 'sass-loader',
                        options: {
                            precision: 8,
                            outputStyle: 'expanded',
                            sourceMap: true
                        }
                    }],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                        js: 'babel-loader?cacheDirectory',
                        scss: 'vue-style-loader!css-loader!sass-loader',
                        sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
                    }
                }
            },
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                use: 'babel-loader?cacheDirectory'
            },
            {
                test: /\.html$/,
                loaders: ['html-loader']
            },
            {
                test: /\.(png|jpe?g|gif)$/,
                loaders: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: path => {
                                if (!/node_modules|bower_components/.test(path)) {
                                    return 'images/[name].[ext]?[hash]';
                                }

                                return 'images/vendor/' + path
                                        .replace(/\\/g, '/')
                                        .replace(
                                            /((.*(node_modules|bower_components))|images|image|img|assets)\//g, ''
                                        ) + '?[hash]';
                            },
                            publicPath: '/'
                        }
                    },
                    'img-loader'
                ]
            },
            {
                test: /\.(woff2?|ttf|eot|svg|otf)$/,
                loader: 'file-loader',
                options: {
                    name: 'fonts/[name].[ext]?[hash]'
                }
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            jQuery: 'jquery',
            $: 'jquery'
        }),
        new FriendlyErrorsWebpackPlugin(),
        new webpack.LoaderOptionsPlugin({
            minimize: production,
            options: {
                context: __dirname,
                output: {path: './'}
            }
        }),
        new WebpackNotifierPlugin(),
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor', 'manifest'],
            minChunks: Infinity
        }),
        extractSass,
        new BrowserSyncPlugin(
            {
                host: browserSyncHost,
                port: browserSyncPort,
                open: browserSyncHost === 'localhost' ? 'local' : 'external',
                proxy: {
                    target: process.env.BROWSERSYNC_PROXY,
                    reqHeaders: function (config) {
                        return {
                            host: `${config.url.hostname}:${process.env.BROWSERSYNC_PORT}`
                        };
                    }
                },
                files: [
                    'app/**/*.php',
                    'resources/views/**/*.php',
                    'public/js/**/*.js',
                    'public/css/**/*.css'
                ]
            },
            {
                reload: false
            }
        )
    ],
    resolve: {
        extensions: ['*', '.js', '.jsx', '.vue'],

        alias: {
            vue$: 'vue/dist/vue.common.js'
        }
    },
    performance: {
        hints: false
    },
    devtool: production ? 'cheap-source-map' : 'cheap-module-eval-source-map',
    devServer: {
        headers: {
            "Access-Control-Allow-Origin": "*"
        },
        historyApiFallback: true,
        noInfo: true,
        compress: true,
        quiet: true,
        port: webpackDevServerPort
    }
};

let plugins = [];

if (hmr) {
    plugins = [
        new webpack.NamedModulesPlugin()
    ];
}

if (production) {
    plugins = [
        new CleanWebpackPlugin(['dist', 'images/vendor'], {
            root: path.join(__dirname, '/public')
        }),
        new webpack.optimize.UglifyJsPlugin({
            sourceMap: true,
            compress: {
                warnings: false
            }
        }),
        new StatsWriterPlugin({
            filename: 'assets-manifest.json',
            transform(data) {
                return JSON.stringify({
                    '/js/manifest.js': `/${data.assetsByChunkName.manifest[0]}`,
                    '/js/vendor.js': `/${data.assetsByChunkName.vendor[0]}`,
                    '/js/frontend.js': `/${data.assetsByChunkName.frontend[0]}`,
                    '/css/frontend.css': `/${data.assetsByChunkName.frontend[1]}`,
                    '/js/backend.js': `/${data.assetsByChunkName.backend[0]}`,
                    '/css/backend.css': `/${data.assetsByChunkName.backend[1]}`
                }, null, 2);
            }
        })
    ];
}

module.exports.plugins.push(...plugins);
<|endoftext|>