<commit_before>var CORS_PROXY_URL = "https://cors.bridged.cc/";
var CHECK_DOWNLOADS_FINISHED_EVERY_MS = 100;

/* User options */
var userDownload;
var targetName;
var section;
var maxImageCount;
var nameFormat;
var restrictByScore;
var restrictByScoreType;
var restrictByScoreValue;
var includeImages;
var includeGifs;
var includeNsfw;

var checkFinishedInterval;
var downloadRequests = new Set();
var downloadedCount;
var toDownloadCount;
var zip;

$(document).ready(function() {
    setRandomNamePlaceholder();

    $(".ui.checkbox").checkbox();
    $("select.dropdown").dropdown();

    /* Make sure one or both of include images and include animated images are checked */
    $.fn.form.settings.rules.includeAny = function(value) {
        return $("#includeImagesInput").parent().checkbox("is checked")
            || $("#includeGifsInput").parent().checkbox("is checked");
    };

    $(".ui.form")
        .form({
            fields: {
                targetNameInput : "empty",
                imageAmountInput : "integer[0..]",
                restrictByScoreValueInput : "integer[0..]",
                includeImagesInput : "includeAny",
                includeGifsInput : "includeAny"
            }
        })
        .on("change", "#includeImagesInput,#includeGifsInput", function(e) {
            /*
                Removes the red text from include images/include
                animated images when one of them have been pressed.
            */
            $(".ui.form").form("validate form");
        });

    $("#restrictByScoreInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("#restrictByScoreTypeInput").parent().removeClass("disabled");
            } else {
                $("#restrictByScoreTypeInput").parent().addClass("disabled");
            }
            $("#restrictByScoreValueInput").prop("disabled", !this.checked);
        }
    });

    $("#userDownloadInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("label[for=targetNameInput]").text("User Name");
                $("#targetNameInput").attr("placeholder", "uniquepassive");
                $("#sectionInput").parent().addClass("disabled");
                $("#searchFilterInput").prop("disabled", true);
            } else {
                $("label[for=targetNameInput]").text("Subreddit Name");
                $("#sectionInput").parent().removeClass("disabled");
                $("#searchFilterInput").prop("disabled", false);
                setRandomNamePlaceholder();
            }
            $("#targetNameInput").focus();
            $("#targetNameInput").select();
        }
    });
});

$("#downloadButton").click(function() {
    $("#unknownNameErrorBox").hide();
    $("#noImagesFoundWarningBox").hide();

    if ($(".ui.form").form("validate form")) {
        /* Reset states */
        $(".ui.form").addClass("loading");
        $("#downloadingInfoBox").show();
        downloadRequests.clear();
        downloadedCount = 0;
        toDownloadCount = 0;
        zip = new JSZip();
        updateUI();

        /* Read user options */
        userDownload = $("#userDownloadInput").parent().checkbox("is checked");
        targetName = $("#targetNameInput").val();
        section = $("#sectionInput").val();
        sectionTimespan = ""; // Set further down if section contains a timespan (eg. section is "top-week")
        searchFilter = $("#searchFilterInput").val();
        nameFormat = $("#nameFormatInput").val();
        restrictByScore = $("#restrictByScoreInput").parent().checkbox("is checked");
        restrictByScoreType = $("#restrictByScoreTypeInput").val();
        restrictByScoreValue = $("#restrictByScoreValueInput").val();
        includeImages = $("#includeImagesInput").parent().checkbox("is checked");
        includeGifs = $("#includeGifsInput").parent().checkbox("is checked");
        includeNsfw = $("#includeNsfwInput").parent().checkbox("is checked");

        if (userDownload) {
            /* Handle the user entering /user/ or user/ before the user name */
            if (targetName.startsWith("/user/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("user/")) {
                targetName = targetName.substring(2);
            }
        } else {
            /* Handle the user entering /r/ or r/ before the sub name */
            if (targetName.startsWith("/r/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("r/")) {
                targetName = targetName.substring(2);
            }
        }

        $(".targetNameText").text(targetName);

        if (userDownload) {
            $(".downloadTypeText").text("user");
        } else {
            $(".downloadTypeText").text("subreddit");
        }

        if (section.includes("-")) {
            var split = section.split("-");
            section = split[0];
            sectionTimespan = split[1];
        }

        /* Find images to scrape and start downloading */
        maxImageCount = $("#imageAmountInput").val();
        download();
    }
});

function updateUI() {
    $("#downloadedCountText").text(downloadedCount);
    $("#toDownloadCountText").text(toDownloadCount);
}

function download(anchor) {
    /* Max 100 posts per request */
    var maxImageCountNow = Math.min(maxImageCount - toDownloadCount, 100);

    /* Prevent extreme amounts of requests in the case that maxImageCountNow is for example 1 */
    if (maxImageCountNow < 50) {
        maxImageCountNow = 50;
    }

    var url;

    if (userDownload) {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/user/" + targetName
            + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    } else if (searchFilter) {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/r/" + targetName
            + "/search.json?q=" + searchFilter + "&restrict_sr=on&limit=" + maxImageCountNow
            + (includeNsfw ? "&include_over_18=on" : "")
            + (anchor !== undefined ? "&after=" + anchor : "");
    } else {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/r/" + targetName
            + "/" + section + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    }
    if (sectionTimespan) {
        url += "&t=" + sectionTimespan;
    }

    $.ajax({
        url: url,
        type: "GET",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        success: function(result, status, xhr) {
            /* Make sure we haven't been redirected to the search page = subreddit doesn't exist */
            if (!userDownload && !searchFilter && xhr.getResponseHeader("X-Final-Url").indexOf(section + ".json") === -1) {
                $("#unknownNameErrorBox").show();
                doneDownloading();
                return;
            }

            var children = result.data.children;

            for (var i = 0; i < children.length; i++) {
                if (toDownloadCount >= maxImageCount) {
                    break;
                }

                var post = children[i].data;
                var url = post.url;

                /* Only download if there's a URL */
                if (url == null) {
                    continue;
                }

                /* Respect user's nsfw option */
                if (!includeNsfw && post.over_18) {
                    continue;
                }

                /* Don't download images that come from posts with greater/less score than inputted */
                if (restrictByScore) {
                    if ((restrictByScoreType === "ge" && post.score < restrictByScoreValue)
                            || (restrictByScoreType === "le" && post.score > restrictByScoreValue)) {
                        continue;
                    }
                }

                /* Continue if direct url is a gif and user doesn't want to download gifs */
                if (!includeGifs && (url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1)) {
                    continue;
                }

                /* Continue if direct url is an image and user doesn't want to download images */
                if (!includeImages && (url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1)) {
                    continue;
                }

                if (isUrlDirect(url)) {
                    /* Handle item with extension (direct link) */
                    toDownloadCount++;
                    downloadUrl(url, post);
                } else if (url.startsWith("http://imgur.com/a/") || url.startsWith("https://imgur.com/a/")) {
                    /* Handle downloading an album */
                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/album/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var images = result.data.images;

                            for (var i = 0; i < images.length; i++) {
                                if (toDownloadCount >= maxImageCount) {
                                    break;
                                }

                                toDownloadCount++;

                                var url = images[i].link;
                                downloadUrl(url, this.post);
                            }
                        },
                        error: function(error) {
                            if (error.status !== 404) {
                                doneDownloading();
                                alert("Accessing the Imgur API failed!\nPlease contact the developer.\nResponse code: "
                                    + error.status + "\nResponse: " + error.responseText);
                            }
                            toDownloadCount--;
                        }
                    });
                } else if (url.startsWith("http://imgur.com/") || url.startsWith("https://imgur.com/")) {
                    /* Handle downloading a single-image album */
                    toDownloadCount++;

                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/image/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var url = result.data.link;
                            downloadUrl(url, this.post);
                        },
                        error: function(error) {
                            if (error.status !== 404) {
                                doneDownloading();
                                alert("Accessing the Imgur API failed!\nPlease contact the developer.\nResponse code: "
                                    + error.status + "\nResponse: " + error.responseText);
                            }
                            toDownloadCount--;
                        }
                    });
                }
            }

            if (children.length === 0 || toDownloadCount >= maxImageCount || result.data.after === null) {
                var reasonWasMaxImageCount = toDownloadCount >= maxImageCount;

                checkFinishedInterval = setInterval(function() {
                    if (reasonWasMaxImageCount && toDownloadCount < maxImageCount) {
                        // this happens if an image has failed to download
                        // and we need to try to download more images
                        clearInterval(checkFinishedInterval);
                        download(result.data.after);
                    } else if (downloadedCount === toDownloadCount) {
                        doneDownloading();
                    }
                }, CHECK_DOWNLOADS_FINISHED_EVERY_MS);
            } else {
                download(result.data.after);
            }
        },
        error: function(error) {
            if (error.status === 404 || error.status === 403) {
                /* If HTTP status is 404 or 403, the subreddit probably doesn't exist */
                $("#unknownNameErrorBox").show();
            } else if (error.status !== 200) {
                /* Notify user when a non-handled status code is received */
                alert("Unknown status code " + error.status + " received from lookup request.\nPlease contact the developer.");
            }
            doneDownloading();
        }
    });
}

function downloadUrl(url, post) {
    downloadImageAsBase64(url, post,
        function(url, post, data) {
            var destinationFileName;

            if (nameFormat === "file-name") {
                destinationFileName = getFileNameWithExtension(url);
            } else if (nameFormat === "post-id") {
                destinationFileName = post.name + getFileExtension(url);
            } else {
                /* default: post-name */
                var regex = /[^\/]+(?=\/$|$)/g;
                var postName = regex.exec(post.permalink)[0];
                destinationFileName = postName + getFileExtension(url);
            }

            zip.file(destinationFileName, data, { base64: true });
            downloadedCount++;
            updateUI();
        },
        function() {
            toDownloadCount--;
        }
    );
}

function isUrlDirect(url) {
    return url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1
        || url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1;
}

function getFileNameWithExtension(url) {
    var regex = /[^/\\&\?]+\.\w{3,4}(?=[\?&].*$|$)/;
    var m = regex.exec(url);
    return m[0];
}

function getFileExtension(url) {
    var fileNameWithExt = getFileNameWithExtension(url);

    return fileNameWithExt
        .substring(fileNameWithExt.lastIndexOf("."));
}

function doneDownloading() {
    // only run the "done" code if we're downloading
    if (!$(".ui.form").hasClass("loading")) {
        return;
    }

    $(".ui.form").removeClass("loading");
    $("#downloadingInfoBox").hide();

    for (var xhr in downloadRequests) {
        xhr.abort();
    }

    clearInterval(checkFinishedInterval);

    if (downloadedCount > 0) {
        zip.generateAsync({ type:"blob" })
            .then(function(content) {
                saveAs(content, targetName + "_" + section + ".zip");
            });
    } else {
        /* Only show the "no images found" warning if the subreddit exists */
        if (!$("#unknownNameErrorBox").is(":visible")) {
            $("#noImagesFoundWarningBox").show();
        }
    }
}

function downloadImageAsBase64(url, post, callback, errored) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        downloadRequests.delete(this);

        var reader = new FileReader();
        reader.onloadend = function() {
            callback(url, post, reader.result.split(",").pop());
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.onerror = function() {
        errored();
    };
    xhr.open("GET", CORS_PROXY_URL + url);
    xhr.responseType = "blob";
    xhr.send();

    downloadRequests.add(xhr);
}

/*
    Puts a random subreddit as sub name inputbox placeholder,
    list taken from https://www.reddit.com/reddits
*/
function setRandomNamePlaceholder() {
    var subreddits = [
        "funny",
        "pics",
        "me_irl",
        "aww",
        "dankmemes",
        "mildlyinteresting",
        "AdviceAnimals",
        "CrappyDesign",
        "OldSchoolCool",
        "2007scape"
    ];
    $("#targetNameInput").attr("placeholder",
        subreddits[Math.floor(Math.random() * subreddits.length)]);
}

// https://stackoverflow.com/a/30949767/4313694
$("button").on("mousedown",
    function(event) {
        event.preventDefault();
    }
);
<commit_msg>Fix already downloaded images being overwritten<commit_after>var CORS_PROXY_URL = "https://cors.bridged.cc/";
var CHECK_DOWNLOADS_FINISHED_EVERY_MS = 100;

/* User options */
var userDownload;
var targetName;
var section;
var maxImageCount;
var nameFormat;
var restrictByScore;
var restrictByScoreType;
var restrictByScoreValue;
var includeImages;
var includeGifs;
var includeNsfw;

var checkFinishedInterval;
var downloadRequests = new Set();
var downloadedCount;
var toDownloadCount;
var zip;

$(document).ready(function() {
    setRandomNamePlaceholder();

    $(".ui.checkbox").checkbox();
    $("select.dropdown").dropdown();

    /* Make sure one or both of include images and include animated images are checked */
    $.fn.form.settings.rules.includeAny = function(value) {
        return $("#includeImagesInput").parent().checkbox("is checked")
            || $("#includeGifsInput").parent().checkbox("is checked");
    };

    $(".ui.form")
        .form({
            fields: {
                targetNameInput : "empty",
                imageAmountInput : "integer[0..]",
                restrictByScoreValueInput : "integer[0..]",
                includeImagesInput : "includeAny",
                includeGifsInput : "includeAny"
            }
        })
        .on("change", "#includeImagesInput,#includeGifsInput", function(e) {
            /*
                Removes the red text from include images/include
                animated images when one of them have been pressed.
            */
            $(".ui.form").form("validate form");
        });

    $("#restrictByScoreInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("#restrictByScoreTypeInput").parent().removeClass("disabled");
            } else {
                $("#restrictByScoreTypeInput").parent().addClass("disabled");
            }
            $("#restrictByScoreValueInput").prop("disabled", !this.checked);
        }
    });

    $("#userDownloadInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("label[for=targetNameInput]").text("User Name");
                $("#targetNameInput").attr("placeholder", "uniquepassive");
                $("#sectionInput").parent().addClass("disabled");
                $("#searchFilterInput").prop("disabled", true);
            } else {
                $("label[for=targetNameInput]").text("Subreddit Name");
                $("#sectionInput").parent().removeClass("disabled");
                $("#searchFilterInput").prop("disabled", false);
                setRandomNamePlaceholder();
            }
            $("#targetNameInput").focus();
            $("#targetNameInput").select();
        }
    });
});

$("#downloadButton").click(function() {
    $("#unknownNameErrorBox").hide();
    $("#noImagesFoundWarningBox").hide();

    if ($(".ui.form").form("validate form")) {
        /* Reset states */
        $(".ui.form").addClass("loading");
        $("#downloadingInfoBox").show();
        downloadRequests.clear();
        downloadedCount = 0;
        toDownloadCount = 0;
        zip = new JSZip();
        updateUI();

        /* Read user options */
        userDownload = $("#userDownloadInput").parent().checkbox("is checked");
        targetName = $("#targetNameInput").val();
        section = $("#sectionInput").val();
        sectionTimespan = ""; // Set further down if section contains a timespan (eg. section is "top-week")
        searchFilter = $("#searchFilterInput").val();
        nameFormat = $("#nameFormatInput").val();
        restrictByScore = $("#restrictByScoreInput").parent().checkbox("is checked");
        restrictByScoreType = $("#restrictByScoreTypeInput").val();
        restrictByScoreValue = $("#restrictByScoreValueInput").val();
        includeImages = $("#includeImagesInput").parent().checkbox("is checked");
        includeGifs = $("#includeGifsInput").parent().checkbox("is checked");
        includeNsfw = $("#includeNsfwInput").parent().checkbox("is checked");

        if (userDownload) {
            /* Handle the user entering /user/ or user/ before the user name */
            if (targetName.startsWith("/user/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("user/")) {
                targetName = targetName.substring(2);
            }
        } else {
            /* Handle the user entering /r/ or r/ before the sub name */
            if (targetName.startsWith("/r/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("r/")) {
                targetName = targetName.substring(2);
            }
        }

        $(".targetNameText").text(targetName);

        if (userDownload) {
            $(".downloadTypeText").text("user");
        } else {
            $(".downloadTypeText").text("subreddit");
        }

        if (section.includes("-")) {
            var split = section.split("-");
            section = split[0];
            sectionTimespan = split[1];
        }

        /* Find images to scrape and start downloading */
        maxImageCount = $("#imageAmountInput").val();
        download();
    }
});

function updateUI() {
    $("#downloadedCountText").text(downloadedCount);
    $("#toDownloadCountText").text(toDownloadCount);
}

function download(anchor) {
    /* Max 100 posts per request */
    var maxImageCountNow = Math.min(maxImageCount - toDownloadCount, 100);

    /* Prevent extreme amounts of requests in the case that maxImageCountNow is for example 1 */
    if (maxImageCountNow < 50) {
        maxImageCountNow = 50;
    }

    var url;

    if (userDownload) {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/user/" + targetName
            + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    } else if (searchFilter) {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/r/" + targetName
            + "/search.json?q=" + searchFilter + "&restrict_sr=on&limit=" + maxImageCountNow
            + (includeNsfw ? "&include_over_18=on" : "")
            + (anchor !== undefined ? "&after=" + anchor : "");
    } else {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/r/" + targetName
            + "/" + section + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    }
    if (sectionTimespan) {
        url += "&t=" + sectionTimespan;
    }

    $.ajax({
        url: url,
        type: "GET",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        success: function(result, status, xhr) {
            /* Make sure we haven't been redirected to the search page = subreddit doesn't exist */
            if (!userDownload && !searchFilter && xhr.getResponseHeader("X-Final-Url").indexOf(section + ".json") === -1) {
                $("#unknownNameErrorBox").show();
                doneDownloading();
                return;
            }

            var children = result.data.children;

            for (var i = 0; i < children.length; i++) {
                if (toDownloadCount >= maxImageCount) {
                    break;
                }

                var post = children[i].data;
                var url = post.url;

                /* Only download if there's a URL */
                if (url == null) {
                    continue;
                }

                /* Respect user's nsfw option */
                if (!includeNsfw && post.over_18) {
                    continue;
                }

                /* Don't download images that come from posts with greater/less score than inputted */
                if (restrictByScore) {
                    if ((restrictByScoreType === "ge" && post.score < restrictByScoreValue)
                            || (restrictByScoreType === "le" && post.score > restrictByScoreValue)) {
                        continue;
                    }
                }

                /* Continue if direct url is a gif and user doesn't want to download gifs */
                if (!includeGifs && (url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1)) {
                    continue;
                }

                /* Continue if direct url is an image and user doesn't want to download images */
                if (!includeImages && (url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1)) {
                    continue;
                }

                if (isUrlDirect(url)) {
                    /* Handle item with extension (direct link) */
                    toDownloadCount++;
                    downloadUrl(url, post);
                } else if (url.startsWith("http://imgur.com/a/") || url.startsWith("https://imgur.com/a/")) {
                    /* Handle downloading an album */
                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/album/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var images = result.data.images;

                            for (var i = 0; i < images.length; i++) {
                                if (toDownloadCount >= maxImageCount) {
                                    break;
                                }

                                toDownloadCount++;

                                var url = images[i].link;
                                downloadUrl(url, this.post);
                            }
                        },
                        error: function(error) {
                            if (error.status !== 404) {
                                doneDownloading();
                                alert("Accessing the Imgur API failed!\nPlease contact the developer.\nResponse code: "
                                    + error.status + "\nResponse: " + error.responseText);
                            }
                            toDownloadCount--;
                        }
                    });
                } else if (url.startsWith("http://imgur.com/") || url.startsWith("https://imgur.com/")) {
                    /* Handle downloading a single-image album */
                    toDownloadCount++;

                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/image/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var url = result.data.link;
                            downloadUrl(url, this.post);
                        },
                        error: function(error) {
                            if (error.status !== 404) {
                                doneDownloading();
                                alert("Accessing the Imgur API failed!\nPlease contact the developer.\nResponse code: "
                                    + error.status + "\nResponse: " + error.responseText);
                            }
                            toDownloadCount--;
                        }
                    });
                }
            }

            if (children.length === 0 || toDownloadCount >= maxImageCount || result.data.after === null) {
                var reasonWasMaxImageCount = toDownloadCount >= maxImageCount;

                checkFinishedInterval = setInterval(function() {
                    if (reasonWasMaxImageCount && toDownloadCount < maxImageCount) {
                        // this happens if an image has failed to download
                        // and we need to try to download more images
                        clearInterval(checkFinishedInterval);
                        download(result.data.after);
                    } else if (downloadedCount === toDownloadCount) {
                        doneDownloading();
                    }
                }, CHECK_DOWNLOADS_FINISHED_EVERY_MS);
            } else {
                download(result.data.after);
            }
        },
        error: function(error) {
            if (error.status === 404 || error.status === 403) {
                /* If HTTP status is 404 or 403, the subreddit probably doesn't exist */
                $("#unknownNameErrorBox").show();
            } else if (error.status !== 200) {
                /* Notify user when a non-handled status code is received */
                alert("Unknown status code " + error.status + " received from lookup request.\nPlease contact the developer.");
            }
            doneDownloading();
        }
    });
}

function downloadUrl(url, post) {
    downloadImageAsBase64(url, post,
        function(url, post, data) {
            var fileName;
            var extension = getFileExtension(url);

            if (nameFormat === "file-name") {
                fileName = getFileName(url);
            } else if (nameFormat === "post-id") {
                fileName = post.name;
            } else {
                /* default: post-name */
                var regex = /[^\/]+(?=\/$|$)/g;
                fileName = regex.exec(post.permalink)[0];
            }

            /* post-id is the only file name guaranteed to be unique */
            if (nameFormat !== "post-id") {
                /* Make sure we don't overwrite a saved file */
                var oldFileName = fileName;
                var counter = 0;
                while (zip.file(oldFileName + extension)) {
                    oldFileName = fileName + "_" + counter++;
                }
                fileName = oldFileName;
            }

            zip.file(fileName + extension, data, { base64: true });
            downloadedCount++;
            updateUI();
        },
        function() {
            toDownloadCount--;
        }
    );
}

function isUrlDirect(url) {
    return url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1
        || url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1;
}

function getFileNameWithExtension(url) {
    var regex = /[^/\\&\?]+\.\w{3,4}(?=[\?&].*$|$)/;
    var m = regex.exec(url);
    return m[0];
}

function getFileName(url) {
    var fileNameWithExt = getFileNameWithExtension(url);
    return fileNameWithExt.substring(0, fileNameWithExt.lastIndexOf("."));
}

function getFileExtension(url) {
    var fileNameWithExt = getFileNameWithExtension(url);
    return fileNameWithExt.substring(fileNameWithExt.lastIndexOf("."));
}

function doneDownloading() {
    // only run the "done" code if we're downloading
    if (!$(".ui.form").hasClass("loading")) {
        return;
    }

    $(".ui.form").removeClass("loading");
    $("#downloadingInfoBox").hide();

    for (var xhr in downloadRequests) {
        xhr.abort();
    }

    clearInterval(checkFinishedInterval);

    if (downloadedCount > 0) {
        zip.generateAsync({ type:"blob" })
            .then(function(content) {
                saveAs(content, targetName + "_" + section + ".zip");
            });
    } else {
        /* Only show the "no images found" warning if the subreddit exists */
        if (!$("#unknownNameErrorBox").is(":visible")) {
            $("#noImagesFoundWarningBox").show();
        }
    }
}

function downloadImageAsBase64(url, post, callback, errored) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        downloadRequests.delete(this);

        var reader = new FileReader();
        reader.onloadend = function() {
            callback(url, post, reader.result.split(",").pop());
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.onerror = function() {
        errored();
    };
    xhr.open("GET", CORS_PROXY_URL + url);
    xhr.responseType = "blob";
    xhr.send();

    downloadRequests.add(xhr);
}

/*
    Puts a random subreddit as sub name inputbox placeholder,
    list taken from https://www.reddit.com/reddits
*/
function setRandomNamePlaceholder() {
    var subreddits = [
        "funny",
        "pics",
        "me_irl",
        "aww",
        "dankmemes",
        "mildlyinteresting",
        "AdviceAnimals",
        "CrappyDesign",
        "OldSchoolCool",
        "2007scape"
    ];
    $("#targetNameInput").attr("placeholder",
        subreddits[Math.floor(Math.random() * subreddits.length)]);
}

// https://stackoverflow.com/a/30949767/4313694
$("button").on("mousedown",
    function(event) {
        event.preventDefault();
    }
);
<|endoftext|>


<commit_before>angular.module("coopr-ngui.config", []).constant("MY_CONFIG", {
  "COOPR_SERVER_URI": "http://127.0.0.1:55054",
  "COOPR_CORS_PORT": 8081,
  "COOPR_UI_PORT": 8080
});<commit_msg>fix test<commit_after>angular.module("coopr-ngui.config", []).constant("MY_CONFIG", {
  "COOPR_SERVER_URI": "http://127.0.0.1:55054/v2/",
  "COOPR_CORS_PORT": 8081,
  "COOPR_UI_PORT": 8080
});<|endoftext|>


<commit_before>var Backbone = require('backbone');
var React = require('react');

console.log(Backbone.toString());
console.log(React.toString());

//
// browserify の変に見える挙動の再現
//
// 下のコードは正常に動くが
// 最初の false ブロック内の require を削除すると、
// 実行時に Cannot find module './required-data' のエラーになる
//
// これはそもそも限られたファイルを事前に結合する仕様上、
// 明示されていないパスのソースは読み込まない、たぶん仕様。
//
// https://github.com/substack/node-browserify/issues/883
//
// どちらかというと、これがそれを解決するハックっぽい
//
if (false) {
  require('./required-data');
} else {
  var dataPath = './required-data';
  console.log(require(dataPath));
}
<commit_msg>Add a comment<commit_after>var Backbone = require('backbone');
var React = require('react');

console.log(Backbone.toString());
console.log(React.toString());

//
// browserify の変に見える挙動の再現
//
// 下のコードは正常に動くが
// 最初の false ブロック内の require を削除すると、
// 実行時に Cannot find module './required-data' のエラーになる
//
// これは限られたファイルを事前に結合する browserify の仕様上、
// 明示されていないパスのソースは読み込めない
//
// Ref) https://github.com/substack/node-browserify/issues/883
//
// どちらかというと、これがそれを解決するハックっぽい
//
// !! 同じファイル内に書かないと意味が無かった !!
//
if (false) {
  require('./required-data');
} else {
  var dataPath = './required-data';
  console.log(require(dataPath));
}
<|endoftext|>


<commit_before>const seneca = require('./util');
const test = require('tape');

seneca.ready(function () {
	test('getMovie returns a seneca entity', function test(t) {
		t.plan(4);
		seneca.act({action: 'get', subject: 'movie', title: 'Die Hard'}, function (err, data) {
			t.equal(null, err, 'no error should be returned when movie is found');
			t.ok(data, 'data is returned');
		});
		seneca.act({action: 'get', subject: 'movie', title: 'Die Flarb'}, function (err, data) {
			t.error(err, 'an error should be returned when movie is not found');
			t.equal(data, null, 'no data is returned');
		});
	});
});
<commit_msg>Adding spaces to force a build on wercker<commit_after>const seneca = require('./util');
const test = require('tape');

seneca.ready(function () {

	test('getMovie returns a seneca entity', function test(t) {
		t.plan(4);
		seneca.act({action: 'get', subject: 'movie', title: 'Die Hard'}, function (err, data) {
			t.equal(null, err, 'no error should be returned when movie is found');
			t.ok(data, 'data is returned');
		});
		seneca.act({action: 'get', subject: 'movie', title: 'Die Flarb'}, function (err, data) {
			t.error(err, 'an error should be returned when movie is not found');
			t.equal(data, null, 'no data is returned');
		});
	});

});
<|endoftext|>


<commit_before>var alexa = require("alexa-app");
var search = require('youtube-search');
var fs = require('fs');
var request = require('request');

var app = new alexa.app("youtube");

var searchOpts = {
    maxResults: 1,
    type: 'video',
    key: process.env.YOUTUBE_API_KEY
};

var lastSearch;

app.pre = function(req, response, type) {
    if (req.applicationId !== process.env.ALEXA_APPLICATION_ID) {
        response.fail("Invalid application");
    }
};

app.intent("GetVideoIntent", {
        "slots": {
            "VideoQuery": "VIDEOS",
        },
        "utterances": [
            "search for {-|VideoQuery}",
            "find {-|VideoQuery}",
            "play {-|VideoQuery}",
            "start playing {-|VideoQuery}",
            "put on {-|VideoQuery}"
        ]
    },
    function(req, response) {
        var query = req.slot("VideoQuery");

        console.log('Searching ... ' + query);

        return new Promise((resolve, reject) => {
            search(query, searchOpts, function(err, results) {
                if (err) {
                    reject(err.message);
                } else if (results.length !== 1) {
                    resolve('I could not complete your request at this moment.', null, null);
                } else {
                    var metadata = results[0];
                    if (metadata.id === undefined) {
                        resolve(query + ' did not return any results on YouTube.', null, null);
                    } else {
                        console.log('Found ... ' + metadata.title);
                        var id = metadata.id;
                        var externalDownload = 'https://dmhacker-youtube.herokuapp.com/alexa/' + id;
                        request(externalDownload, function(err, res, body) {
                            console.log('Processed.');
                            if (err) {
                                reject(err.message);
                            } else {
                                recursive_check(id, 1000, function(err) {
                                    if (err) {
                                        reject(err.message);
                                    }
                                    else {
                                        lastSearch = JSON.parse(body).link;
                                        console.log('Stored @ '+lastSearch);
                                        resolve('I found a relevant video called ' + metadata.title + '.', lastSearch, metadata);
                                    }
                                });
                            }
                        });
                    }
                }
            });
        }).then(function (message, streamUrl, metadata) {
            response.say(message);
            if (streamUrl) {
                var stream = {
                    'url': streamUrl,
                    'token': metadata.id,
                    'offsetInMilliseconds': 0
                };
                response.audioPlayerPlayStream('REPLACE_ALL', stream);
                response.card({
                    'type': 'Simple',
                    'title': 'Search for "' + query + '"',
                    'content': 'Alexa found "' + metadata.title + '" at ' + metadata.link + '.'
                });
            }
            response.send();
        }).catch(function(reason) {
            response.fail(reason);
        });
    }
);

function recursive_check(id, delay, callback) {
    var linkCheck = 'https://dmhacker-youtube.herokuapp.com/alexa-check/' + id;
    request(linkCheck, function (err, res, body) {
        if (err) {
            callback(err);
        }
        else {
            var metadata = JSON.parse(body).metadata;
            if (!metadata) {
                callback(err);
            }
            else {
                if (metadata.downloaded) {
                    callback(null);
                }
                else {
                    setTimeout(function () {
                        recursive_check(id, delay, callback);
                    }, delay);
                }
            }
        }
    });
}

app.audioPlayer("PlaybackStarted", function(request, response) {
    console.log('Playback started.');
    console.log(request);
});

app.audioPlayer("PlaybackFailed", function(request, response) {
    console.log('Playback failed.');
    console.log(request);
});

app.intent("AMAZON.PauseIntent", {}, function(req, response) {
    response.audioPlayerStop();
});

app.intent("AMAZON.ResumeIntent", {}, function(req, response) {
    if (lastSearch === undefined) {
        response.say('You were not playing any video previously.');
    } else {
        response.audioPlayerPlayStream('ENQUEUE', {
            'url': lastSearch,
            'streamFormat': 'AUDIO_MPEG',
            'token': constants.token,
            'expectedPreviousToken': constants.expectedPreviousToken
        });
    }
});

app.intent("AMAZON.StopIntent", {}, function(req, response) {
    lastSearch = undefined;
    response.audioPlayerStop();
    response.audioPlayerClearQueue();
});

exports.handler = app.lambda();
<commit_msg>resolve takes only one parameter<commit_after>var alexa = require("alexa-app");
var search = require('youtube-search');
var fs = require('fs');
var request = require('request');

var app = new alexa.app("youtube");

var searchOpts = {
    maxResults: 1,
    type: 'video',
    key: process.env.YOUTUBE_API_KEY
};

var lastSearch;

app.pre = function(req, response, type) {
    if (req.applicationId !== process.env.ALEXA_APPLICATION_ID) {
        response.fail("Invalid application");
    }
};

app.intent("GetVideoIntent", {
        "slots": {
            "VideoQuery": "VIDEOS",
        },
        "utterances": [
            "search for {-|VideoQuery}",
            "find {-|VideoQuery}",
            "play {-|VideoQuery}",
            "start playing {-|VideoQuery}",
            "put on {-|VideoQuery}"
        ]
    },
    function(req, response) {
        var query = req.slot("VideoQuery");

        console.log('Searching ... ' + query);

        return new Promise((resolve, reject) => {
            search(query, searchOpts, function(err, results) {
                if (err) {
                    reject(err.message);
                } else if (results.length !== 1) {
                    resolve({
                        message: 'I could not complete your request at this moment.',
                        url: null,
                        metadata: null
                    });
                } else {
                    var metadata = results[0];
                    if (metadata.id === undefined) {
                        resolve({
                            message: query + ' did not return any results on YouTube.',
                            url: null,
                            metadata: null
                        });
                    } else {
                        console.log('Found ... ' + metadata.title);
                        var id = metadata.id;
                        var externalDownload = 'https://dmhacker-youtube.herokuapp.com/alexa/' + id;
                        request(externalDownload, function(err, res, body) {
                            console.log('Processed.');
                            if (err) {
                                reject(err.message);
                            } else {
                                recursive_check(id, 1000, function(err) {
                                    if (err) {
                                        reject(err.message);
                                    }
                                    else {
                                        lastSearch = JSON.parse(body).link;
                                        console.log('Stored @ '+lastSearch);
                                        resolve({
                                            message: 'I found a relevant video called ' + metadata.title + '.',
                                            url: lastSearch,
                                            metadata: metadata
                                        });
                                    }
                                });
                            }
                        });
                    }
                }
            });
        }).then(function (content) {
            var message = content.message;
            var streamUrl = content.url;
            var metadata = content.metadata;
            response.say(message);
            if (streamUrl) {
                response.audioPlayerPlayStream('REPLACE_ALL', {
                    'url': streamUrl,
                    'token': metadata.id,
                    'offsetInMilliseconds': 0
                });
                response.card({
                    'type': 'Simple',
                    'title': 'Search for "' + query + '"',
                    'content': 'Alexa found "' + metadata.title + '" at ' + metadata.link + '.'
                });
            }
            response.send();
        }).catch(function(reason) {
            response.fail(reason);
        });
    }
);

function recursive_check(id, delay, callback) {
    var linkCheck = 'https://dmhacker-youtube.herokuapp.com/alexa-check/' + id;
    request(linkCheck, function (err, res, body) {
        if (err) {
            callback(err);
        }
        else {
            var metadata = JSON.parse(body).metadata;
            if (!metadata) {
                callback(err);
            }
            else {
                if (metadata.downloaded) {
                    callback(null);
                }
                else {
                    setTimeout(function () {
                        recursive_check(id, delay, callback);
                    }, delay);
                }
            }
        }
    });
}

app.audioPlayer("PlaybackStarted", function(request, response) {
    console.log('Playback started.');
    console.log(request);
});

app.audioPlayer("PlaybackFailed", function(request, response) {
    console.log('Playback failed.');
    console.log(request);
});

app.intent("AMAZON.PauseIntent", {}, function(req, response) {
    response.audioPlayerStop();
});

app.intent("AMAZON.ResumeIntent", {}, function(req, response) {
    if (lastSearch === undefined) {
        response.say('You were not playing any video previously.');
    } else {
        response.audioPlayerPlayStream('ENQUEUE', {
            'url': lastSearch,
            'streamFormat': 'AUDIO_MPEG',
            'token': constants.token,
            'expectedPreviousToken': constants.expectedPreviousToken
        });
    }
});

app.intent("AMAZON.StopIntent", {}, function(req, response) {
    lastSearch = undefined;
    response.audioPlayerStop();
    response.audioPlayerClearQueue();
});

exports.handler = app.lambda();
<|endoftext|>


<commit_before>/*global require: false, module: false */
'use strict';

var _ = require('underscore');
var Rx = require('rx-dom');
require('rx.experimental');

function assertAll(arr) {
	_.each(arr, ([assertion, msg]) => {
		if (!assertion) {
			throw new Error(msg);
		}
	});
}

// immutable 'merge' method for plain js objects.
function merge(...args) {
	return _.extend.apply(null, [{}].concat(args));
}

// immutable 'set' method for plain js objects.
function assoc(o, ...args) {
	return merge(o, _.object.apply(null,
				_.partition(args, (a, i) => i % 2 === 0)));
}

//  XXX check rx versions. It's weird that it's modifying this header.
//	headers: {'Content-Type': 'application/json' },
function post(url, body) {
	return Rx.DOM.ajax(merge({
		url: url,
		body: body
	}, {method: 'POST'})).pluck('response').map(JSON.parse);
}

var methods = {
	variantSets: {
		selector: r => r.variantSets,
		defaults: {datasetIds: []},
		validate: function ({datasetIds}) {
			assertAll([
				[_.isArray(datasetIds), "datasetIds is not array"]
			]);
		},
		query: (url, body) => post(`${url}/variantsets/search`, body)
	},
	variants: {
		selector: r => r.variants,
		defaults: {callSetIds: []},
		validate: function ({start, end, callSetIds, referenceName, variantSetIds}) {
			assertAll([
				[_.isNumber(start), "start position is not number"],
				[_.isNumber(end), "end position is not number"],
				[_.isArray(callSetIds), "callSetsIds is not array"],
				[_.isString(referenceName), "referenceName is not string"],
				[_.isArray(variantSetIds), "variantSetIds is not array"],
				[start >= 0, "start position is negative"],
				[end >= 0, "end position is negative"],
				[end > start, "end is not greater than start"]
			]);
		},
		query: (url, body) => post(`${url}/variants/search`, body)
	},
	referenceSets: {
		selector: r => r.referenceSets,
		defaults: {md5checksums: [], accessions: []},
		validate: function ({md5checksums, accessions, assemblyId}) {
			assertAll([
				[_.isArray(md5checksums), "md5checksums is not array"],
				[_.isArray(accessions), "accessions is not array"],
				[!assemblyId || _.isString(assemblyId), "assemblyId is not string"]
			]);
		},
		query: (url, body) => post(`${url}/referencesets/search`, body)
	},
	references: {
		selector: r => r.references,
		defaults: {md5checksums: [], accessions: []},
		validate: function ({md5checksums, accessions}) {
			assertAll([
				[_.isArray(md5checksums), "md5checksums is not array"],
				[_.isArray(accessions), "accessions is not array"]
			]);
		},
		query: (url, body) => post(`${url}/references/search`, body)
	},
	reads: {
		selector: r => r.alignments,
		defaults: {readGroupIds: []},
		validate: function ({readGroupIds, referenceName, referenceId, start, end}) {
			assertAll([
				[_.isArray(readGroupIds), "readGroupIds is not array"],
				[!referenceName || _.iString(referenceName), "referenceName is not string"],
				[!referenceId || _.iString(referenceId), "referenceId is not string"],
				[_.isNumber(start), "start position is not number"],
				[start >= 0, "start position is negative"],
				[_.isNumber(end), "end position is not number"],
				[end >= 0, "end position is negative"],
				[end > start, "end is not greater than start"]
			]);
		},
		query: (url, body) => post(`${url}/reads/search`, body)
	},
	readGroupSets: {
		selector: r => r.readGroupSets,
		defaults: {datasetIds: []},
		validate: function ({datasetIds, name}) {
			assertAll([
				[_.isArray(datasetIds), "datasetIds is not array"],
				[!name || _.isString(name), "name is not array"]
			]);
		},
		query: (url, body) => post(`${url}/readgroupsets/search`, body)
	},
	callSets: {
		selector: r => r.callSets,
		defaults: {variantSetIds: []},
		validate: function ({variantSetIds, name}) {
			assertAll([
				[_.isArray(variantSetIds), "variantSetIds is not array"],
				[!name || _.isString(name), "name is not array"]
			]);
		},
		query: (url, body) => post(`${url}/callsets/search`, body)
	}
};

function onePageQuery(method) {
	return function (url, props) {
		var body = merge(method.defaults, props);
		method.validate(body);
		return method.query(url, body);
	};
}

function allPagesQuery(method) {
	return function (url, props) {
		var body = merge(method.defaults, props);
		method.validate(body);
		return method.query(url, body).expand(
			r => r.nextPageToken ?
				method.query(url, assoc(body, 'pageToken', r.nextPageToken)) :
				Rx.Observable.empty()
		).map(method.selector).toArray().map(a => _.flatten(a, true)); // XXX ob.reduce would be faster
	};
}

module.exports = assoc(_.mapObject(methods, onePageQuery),
		'all', _.mapObject(methods, allPagesQuery));
<commit_msg>Fix error message.<commit_after>/*global require: false, module: false */
'use strict';

var _ = require('underscore');
var Rx = require('rx-dom');
require('rx.experimental');

function assertAll(arr) {
	_.each(arr, ([assertion, msg]) => {
		if (!assertion) {
			throw new Error(msg);
		}
	});
}

// immutable 'merge' method for plain js objects.
function merge(...args) {
	return _.extend.apply(null, [{}].concat(args));
}

// immutable 'set' method for plain js objects.
function assoc(o, ...args) {
	return merge(o, _.object.apply(null,
				_.partition(args, (a, i) => i % 2 === 0)));
}

//  XXX check rx versions. It's weird that it's modifying this header.
//	headers: {'Content-Type': 'application/json' },
function post(url, body) {
	return Rx.DOM.ajax(merge({
		url: url,
		body: body
	}, {method: 'POST'})).pluck('response').map(JSON.parse);
}

var methods = {
	variantSets: {
		selector: r => r.variantSets,
		defaults: {datasetIds: []},
		validate: function ({datasetIds}) {
			assertAll([
				[_.isArray(datasetIds), "datasetIds is not array"]
			]);
		},
		query: (url, body) => post(`${url}/variantsets/search`, body)
	},
	variants: {
		selector: r => r.variants,
		defaults: {callSetIds: []},
		validate: function ({start, end, callSetIds, referenceName, variantSetIds}) {
			assertAll([
				[_.isNumber(start), "start position is not number"],
				[_.isNumber(end), "end position is not number"],
				[_.isArray(callSetIds), "callSetsIds is not array"],
				[_.isString(referenceName), "referenceName is not string"],
				[_.isArray(variantSetIds), "variantSetIds is not array"],
				[start >= 0, "start position is negative"],
				[end >= 0, "end position is negative"],
				[end > start, "end is not greater than start"]
			]);
		},
		query: (url, body) => post(`${url}/variants/search`, body)
	},
	referenceSets: {
		selector: r => r.referenceSets,
		defaults: {md5checksums: [], accessions: []},
		validate: function ({md5checksums, accessions, assemblyId}) {
			assertAll([
				[_.isArray(md5checksums), "md5checksums is not array"],
				[_.isArray(accessions), "accessions is not array"],
				[!assemblyId || _.isString(assemblyId), "assemblyId is not string"]
			]);
		},
		query: (url, body) => post(`${url}/referencesets/search`, body)
	},
	references: {
		selector: r => r.references,
		defaults: {md5checksums: [], accessions: []},
		validate: function ({md5checksums, accessions}) {
			assertAll([
				[_.isArray(md5checksums), "md5checksums is not array"],
				[_.isArray(accessions), "accessions is not array"]
			]);
		},
		query: (url, body) => post(`${url}/references/search`, body)
	},
	reads: {
		selector: r => r.alignments,
		defaults: {readGroupIds: []},
		validate: function ({readGroupIds, referenceName, referenceId, start, end}) {
			assertAll([
				[_.isArray(readGroupIds), "readGroupIds is not array"],
				[!referenceName || _.iString(referenceName), "referenceName is not string"],
				[!referenceId || _.iString(referenceId), "referenceId is not string"],
				[_.isNumber(start), "start position is not number"],
				[start >= 0, "start position is negative"],
				[_.isNumber(end), "end position is not number"],
				[end >= 0, "end position is negative"],
				[end > start, "end is not greater than start"]
			]);
		},
		query: (url, body) => post(`${url}/reads/search`, body)
	},
	readGroupSets: {
		selector: r => r.readGroupSets,
		defaults: {datasetIds: []},
		validate: function ({datasetIds, name}) {
			assertAll([
				[_.isArray(datasetIds), "datasetIds is not array"],
				[!name || _.isString(name), "name is not array"]
			]);
		},
		query: (url, body) => post(`${url}/readgroupsets/search`, body)
	},
	callSets: {
		selector: r => r.callSets,
		defaults: {variantSetIds: []},
		validate: function ({variantSetIds, name}) {
			assertAll([
				[_.isArray(variantSetIds), "variantSetIds is not array"],
				[!name || _.isString(name), "name is not string"]
			]);
		},
		query: (url, body) => post(`${url}/callsets/search`, body)
	}
};

function onePageQuery(method) {
	return function (url, props) {
		var body = merge(method.defaults, props);
		method.validate(body);
		return method.query(url, body);
	};
}

function allPagesQuery(method) {
	return function (url, props) {
		var body = merge(method.defaults, props);
		method.validate(body);
		return method.query(url, body).expand(
			r => r.nextPageToken ?
				method.query(url, assoc(body, 'pageToken', r.nextPageToken)) :
				Rx.Observable.empty()
		).map(method.selector).toArray().map(a => _.flatten(a, true)); // XXX ob.reduce would be faster
	};
}

module.exports = assoc(_.mapObject(methods, onePageQuery),
		'all', _.mapObject(methods, allPagesQuery));
<|endoftext|>


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

define('ace_configuration', ["app", "ace/ace"], function (app, ace) {
  var path = app.host + app.root + 'js/ace';
  var config = require("ace/config");
  config.set("packaged", true);
  config.set("workerPath",path);
  config.set("modePath",path);
  config.set("themePath", path);
  return ace;
});

define([
  "app",
  // Libs
  "api",
  "ace_configuration",
  "spin"
],

function(app, FauxtonAPI, ace, spin) {
  var Components = FauxtonAPI.addon();

  Components.Pagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/pagination",

    initialize: function(options) {
      this.page = parseInt(options.page, 10);
      this.perPage = options.perPage;
      this.total = options.total;
      this.totalPages = Math.ceil(this.total / this.perPage);
      this.urlFun = options.urlFun;
    },

    serialize: function() {
      return {
        page: this.page,
        perPage: this.perPage,
        total: this.total,
        totalPages: this.totalPages,
        urlFun: this.urlFun
      };
    }
  });

  Components.IndexPagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/index_pagination",
    events: {
      "click a": 'scrollTo',
      "click a#next": 'nextClicked',
      "click a#previous": 'previousClicked'
    },

    scrollTo: function () {
      if (!this.scrollToSelector) { return; }
      $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow');
    },

    initialize: function (options) {
      this.previousUrlfn = options.previousUrlfn;
      this.nextUrlfn = options.nextUrlfn;
      this.canShowPreviousfn = options.canShowPreviousfn;
      this.canShowNextfn = options.canShowNextfn;
      this.scrollToSelector = options.scrollToSelector;
      _.bindAll(this);
      this.previousParams = [];
    },

    previousClicked: function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (!this.canShowPreviousfn()) { return; }
      FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'previous');
    },

    nextClicked: function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (!this.canShowNextfn()) { return; }

      var params = _.clone(this.collection.params);

      if (params) {
        this.previousParams.push(params);
      }

      FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'next');
    },

    serialize: function () {
      return {
        canShowNextfn: this.canShowNextfn,
        canShowPreviousfn: this.canShowPreviousfn,
      };
    },

    pageLimit: function () {
      var limit = 20;

      if (this.collection.params.limit && this.collection.skipFirstItem) {
        limit = parseInt(this.collection.params.limit, 10) - 1;
      } else if (this.collection.params.limit) {
        limit = parseInt(this.collection.params.limit, 10);
      }

      return limit;
    },

    pageStart: function () {
      return (this.previousParams.length * this.pageLimit()) + 1;

    },

    pageEnd: function () {
      if (this.collection.length < this.pageLimit()) {
        return (this.previousParams.length * this.pageLimit()) + this.collection.length;
      }

      return (this.previousParams.length * this.pageLimit()) + this.pageLimit();
    }

  });

  //TODO allow more of the typeahead options.
  //Current this just does what we need but we
  //need to support the other typeahead options.
  Components.Typeahead = FauxtonAPI.View.extend({

    initialize: function (options) {
      this.source = options.source;
      _.bindAll(this);
    },

    afterRender: function () {
      var onUpdate = this.onUpdate;

      this.$el.typeahead({
        source: this.source,
        updater: function (item) {
          if (onUpdate) {
            onUpdate(item);
          }

          return item;
        }
      });
    }

  });

  Components.ModalView = FauxtonAPI.View.extend({

    disableLoader: true,

    initialize: function (options) {
      _.bindAll(this);
    },

    showModal: function () {
      if (this._showModal){ this._showModal();}
      this.clear_error_msg();
      this.$('.modal').modal();
      // hack to get modal visible
      $('.modal-backdrop').css('z-index',1025);
    },

    hideModal: function () {
      this.$('.modal').modal('hide');
    },

    set_error_msg: function (msg) {
      var text;
      if (typeof(msg) == 'string') {
        text = msg;
      } else {
        text = JSON.parse(msg.responseText).reason;
      }
      this.$('#modal-error').text(text).removeClass('hide');
    },

    clear_error_msg: function () {
      this.$('#modal-error').text(' ').addClass('hide');
    },

    serialize: function () {
      if (this.model){
        return this.model.toJSON();
      }
      return {};
    }
  });

  Components.DbSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.dbLimit = options.dbLimit || 30;
      this.onUpdate = options.onUpdate;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/_all_dbs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.dbLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          process(data);
        }
      });
    }
  });

  Components.DocSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.docLimit = options.docLimit || 30;
      this.database = options.database;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/",
        this.database.id,
        "/_all_docs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.docLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          var ids = _.map(data.rows, function (row) {
            return row.id;
          });
          process(ids);
        }
      });
    }
  });

  Components.Editor = FauxtonAPI.View.extend({
    initialize: function (options) {
      this.editorId = options.editorId;
      this.mode = options.mode || "json";
      this.commands = options.commands;
      this.theme = options.theme || 'crimson_editor';
      this.couchJSHINT = options.couchJSHINT;
      this.edited = false;

      _.bindAll(this);
    },

    afterRender: function () {
      this.editor = ace.edit(this.editorId);
      this.setHeightToLineCount();
      this.editor.getSession().setUseWorker(false);
      this.editor.setTheme("ace/theme/" + this.theme);

      this.editor.getSession().setMode("ace/mode/" + this.mode);
      this.editor.setShowPrintMargin(false);
      this.addCommands();

      if (this.couchJSHINT) {
        this.removeIncorrectAnnotations();
      }

      var that = this;
      this.editor.getSession().on('change', function () {
        that.setHeightToLineCount();
        that.edited = true;
      });

      $(window).on('beforeunload.editor', function() {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });

      FauxtonAPI.beforeUnload("editor", function (deferred) {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });
    },

    cleanup: function () {
      $(window).off('beforeunload.editor');
      FauxtonAPI.removeBeforeUnload("editor");
    },

    setHeightToLineCount: function () {
      var lines = this.editor.getSession().getDocument().getLength();
      this.editor.setOptions({
        maxLines: lines
      });

      this.editor.resize();
    },

    getLines: function(){
     return this.editor.getSession().getDocument().getLength();
    },

    addCommands: function () {
      _.each(this.commands, function (command) {
        this.editor.commands.addCommand(command);
      }, this);
    },

    removeIncorrectAnnotations: function () {
      var editor = this.editor,
          isIgnorableError = this.isIgnorableError;

      this.editor.getSession().on("changeAnnotation", function () {
        var annotations = editor.getSession().getAnnotations();

        var newAnnotations = _.reduce(annotations, function (annotations, error) {
          if (!isIgnorableError(error.raw)) {
            annotations.push(error);
          }
          return annotations;
        }, []);

        if (annotations.length !== newAnnotations.length) {
          editor.getSession().setAnnotations(newAnnotations);
        }
      });
    },

    editSaved: function () {
      this.edited = false;
    },

    setReadOnly: function (value) {
      return this.editor.setReadOnly(value);
    },

    setValue: function (data, lineNumber) {
      lineNumber = lineNumber ? lineNumber : -1;
      this.editor.setValue(data, lineNumber);
    },

    getValue: function () {
      return this.editor.getValue();
    },

    getAnnotations: function () {
      return this.editor.getSession().getAnnotations();
    },

    hadValidCode: function () {
     var errors = this.getAnnotations();
     // By default CouchDB view functions don't pass lint
     return _.every(errors, function(error) {
      return this.isIgnorableError(error.raw);
      },this);
    },

    // List of JSHINT errors to ignore
    // Gets around problem of anonymous functions not being a valid statement
    excludedViewErrors: [
      "Missing name in function declaration.",
      "['{a}'] is better written in dot notation."
    ],

    isIgnorableError: function(msg) {
      return _.contains(this.excludedViewErrors, msg);
    }

  });

  //need to make this into a backbone view...
  var routeObjectSpinner;
  FauxtonAPI.RouteObject.on('beforeEstablish', function (routeObject) {
    if (!routeObject.disableLoader){
      var opts = {
        lines: 16, // The number of lines to draw
        length: 8, // The length of each line
        width: 4, // The line thickness
        radius: 12, // The radius of the inner circle
        color: '#333', // #rbg or #rrggbb
        speed: 1, // Rounds per second
        trail: 10, // Afterglow percentage
        shadow: false // Whether to render a shadow
     };

     if (routeObjectSpinner) { return; }

     if (!$('.spinner').length) {
       $('

')
        .appendTo('#app-container');
     }

     routeObjectSpinner = new Spinner(opts).spin();
     $('.spinner').append(routeObjectSpinner.el);
   }
  });

  var removeRouteObjectSpinner = function () {
    if (routeObjectSpinner) {
      routeObjectSpinner.stop();
      routeObjectSpinner = null;
      $('.spinner').remove();
    }
  };

  var removeViewSpinner = function (selector) {
    var viewSpinner = viewSpinners[selector];

    if (viewSpinner){
      viewSpinner.stop();
      $(selector).find('.spinner').remove();
      delete viewSpinners[selector];
    }
  };

  var viewSpinners = {};
  FauxtonAPI.RouteObject.on('beforeRender', function (routeObject, view, selector) {
    removeRouteObjectSpinner();

    if (!view.disableLoader){
      var opts = {
        lines: 16, // The number of lines to draw
        length: 8, // The length of each line
        width: 4, // The line thickness
        radius: 12, // The radius of the inner circle
        color: '#333', // #rbg or #rrggbb
        speed: 1, // Rounds per second
        trail: 10, // Afterglow percentage
        shadow: false // Whether to render a shadow
      };

      var viewSpinner = new Spinner(opts).spin();
      $('

')
        .appendTo(selector)
        .append(viewSpinner.el);

      viewSpinners[selector] = viewSpinner;
    }
  });

  FauxtonAPI.RouteObject.on('afterRender', function (routeObject, view, selector) {
    removeViewSpinner(selector);
  });

  FauxtonAPI.RouteObject.on('viewHasRendered', function (view, selector) {
    removeViewSpinner(selector);
    removeRouteObjectSpinner();
  });

  return Components;
});

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

define('ace_configuration', ["app", "ace/ace"], function (app, ace) {
  var path = app.host + app.root + 'js/ace';
  var config = require("ace/config");
  config.set("packaged", true);
  config.set("workerPath",path);
  config.set("modePath",path);
  config.set("themePath", path);
  return ace;
});

define([
  "app",
  // Libs
  "api",
  "ace_configuration",
  "spin"
],

function(app, FauxtonAPI, ace, spin) {
  var Components = FauxtonAPI.addon();

  Components.Pagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/pagination",

    initialize: function(options) {
      this.page = parseInt(options.page, 10);
      this.perPage = options.perPage;
      this.total = options.total;
      this.totalPages = Math.ceil(this.total / this.perPage);
      this.urlFun = options.urlFun;
    },

    serialize: function() {
      return {
        page: this.page,
        perPage: this.perPage,
        total: this.total,
        totalPages: this.totalPages,
        urlFun: this.urlFun
      };
    }
  });

  Components.IndexPagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/index_pagination",
    events: {
      "click a": 'scrollTo',
      "click a#next": 'nextClicked',
      "click a#previous": 'previousClicked'
    },

    scrollTo: function () {
      if (!this.scrollToSelector) { return; }
      $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow');
    },

    initialize: function (options) {
      this.previousUrlfn = options.previousUrlfn;
      this.nextUrlfn = options.nextUrlfn;
      this.canShowPreviousfn = options.canShowPreviousfn;
      this.canShowNextfn = options.canShowNextfn;
      this.scrollToSelector = options.scrollToSelector;
      _.bindAll(this);
      this.previousParams = [];
    },

    previousClicked: function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (!this.canShowPreviousfn()) { return; }
      FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'previous');
    },

    nextClicked: function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (!this.canShowNextfn()) { return; }

      var params = _.clone(this.collection.params);

      if (params) {
        this.previousParams.push(params);
      }

      FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'next');
    },

    serialize: function () {
      return {
        canShowNextfn: this.canShowNextfn,
        canShowPreviousfn: this.canShowPreviousfn,
      };
    },

    pageLimit: function () {
      var limit = 20;

      if (this.collection.params.limit && this.collection.skipFirstItem) {
        limit = parseInt(this.collection.params.limit, 10) - 1;
      } else if (this.collection.params.limit) {
        limit = parseInt(this.collection.params.limit, 10);
      }

      return limit;
    },

    pageStart: function () {
      return (this.previousParams.length * this.pageLimit()) + 1;

    },

    pageEnd: function () {
      if (this.collection.length < this.pageLimit()) {
        return (this.previousParams.length * this.pageLimit()) + this.collection.length;
      }

      return (this.previousParams.length * this.pageLimit()) + this.pageLimit();
    }

  });

  //TODO allow more of the typeahead options.
  //Current this just does what we need but we
  //need to support the other typeahead options.
  Components.Typeahead = FauxtonAPI.View.extend({

    initialize: function (options) {
      this.source = options.source;
      _.bindAll(this);
    },

    afterRender: function () {
      var onUpdate = this.onUpdate;

      this.$el.typeahead({
        source: this.source,
        updater: function (item) {
          if (onUpdate) {
            onUpdate(item);
          }

          return item;
        }
      });
    }

  });

  Components.ModalView = FauxtonAPI.View.extend({

    disableLoader: true,

    initialize: function (options) {
      _.bindAll(this);
    },

    showModal: function () {
      if (this._showModal){ this._showModal();}
      this.clear_error_msg();
      this.$('.modal').modal();
      // hack to get modal visible
      $('.modal-backdrop').css('z-index',1025);
    },

    hideModal: function () {
      this.$('.modal').modal('hide');
    },

    set_error_msg: function (msg) {
      var text;
      if (typeof(msg) == 'string') {
        text = msg;
      } else {
        text = JSON.parse(msg.responseText).reason;
      }
      this.$('#modal-error').text(text).removeClass('hide');
    },

    clear_error_msg: function () {
      this.$('#modal-error').text(' ').addClass('hide');
    },

    serialize: function () {
      if (this.model){
        return this.model.toJSON();
      }
      return {};
    }
  });

  Components.DbSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.dbLimit = options.dbLimit || 30;
      this.onUpdate = options.onUpdate;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/_all_dbs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.dbLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          process(data);
        }
      });
    }
  });

  Components.DocSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.docLimit = options.docLimit || 30;
      this.database = options.database;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/",
        this.database.id,
        "/_all_docs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.docLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          var ids = _.map(data.rows, function (row) {
            return row.id;
          });
          process(ids);
        }
      });
    }
  });

  Components.Editor = FauxtonAPI.View.extend({
    initialize: function (options) {
      this.editorId = options.editorId;
      this.mode = options.mode || "json";
      this.commands = options.commands;
      this.theme = options.theme || 'crimson_editor';
      this.couchJSHINT = options.couchJSHINT;
      this.edited = false;

      _.bindAll(this);
    },

    afterRender: function () {
      this.editor = ace.edit(this.editorId);
      this.setHeightToLineCount();

      this.editor.setTheme("ace/theme/" + this.theme);

      this.editor.getSession().setMode("ace/mode/" + this.mode);
      this.editor.setShowPrintMargin(false);
      this.addCommands();

      if (this.couchJSHINT) {
        this.removeIncorrectAnnotations();
      }

      var that = this;
      this.editor.getSession().on('change', function () {
        that.setHeightToLineCount();
        that.edited = true;
      });

      $(window).on('beforeunload.editor', function() {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });

      FauxtonAPI.beforeUnload("editor", function (deferred) {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });
    },

    cleanup: function () {
      $(window).off('beforeunload.editor');
      FauxtonAPI.removeBeforeUnload("editor");
    },

    setHeightToLineCount: function () {
      var lines = this.editor.getSession().getDocument().getLength();
      this.editor.setOptions({
        maxLines: lines
      });

      this.editor.resize();
    },

    getLines: function(){
     return this.editor.getSession().getDocument().getLength();
    },

    addCommands: function () {
      _.each(this.commands, function (command) {
        this.editor.commands.addCommand(command);
      }, this);
    },

    removeIncorrectAnnotations: function () {
      var editor = this.editor,
          isIgnorableError = this.isIgnorableError;

      this.editor.getSession().on("changeAnnotation", function () {
        var annotations = editor.getSession().getAnnotations();

        var newAnnotations = _.reduce(annotations, function (annotations, error) {
          if (!isIgnorableError(error.raw)) {
            annotations.push(error);
          }
          return annotations;
        }, []);

        if (annotations.length !== newAnnotations.length) {
          editor.getSession().setAnnotations(newAnnotations);
        }
      });
    },

    editSaved: function () {
      this.edited = false;
    },

    setReadOnly: function (value) {
      return this.editor.setReadOnly(value);
    },

    setValue: function (data, lineNumber) {
      lineNumber = lineNumber ? lineNumber : -1;
      this.editor.setValue(data, lineNumber);
    },

    getValue: function () {
      return this.editor.getValue();
    },

    getAnnotations: function () {
      return this.editor.getSession().getAnnotations();
    },

    hadValidCode: function () {
     var errors = this.getAnnotations();
     // By default CouchDB view functions don't pass lint
     return _.every(errors, function(error) {
      return this.isIgnorableError(error.raw);
      },this);
    },

    // List of JSHINT errors to ignore
    // Gets around problem of anonymous functions not being a valid statement
    excludedViewErrors: [
      "Missing name in function declaration.",
      "['{a}'] is better written in dot notation."
    ],

    isIgnorableError: function(msg) {
      return _.contains(this.excludedViewErrors, msg);
    }

  });

  //need to make this into a backbone view...
  var routeObjectSpinner;
  FauxtonAPI.RouteObject.on('beforeEstablish', function (routeObject) {
    if (!routeObject.disableLoader){
      var opts = {
        lines: 16, // The number of lines to draw
        length: 8, // The length of each line
        width: 4, // The line thickness
        radius: 12, // The radius of the inner circle
        color: '#333', // #rbg or #rrggbb
        speed: 1, // Rounds per second
        trail: 10, // Afterglow percentage
        shadow: false // Whether to render a shadow
     };

     if (routeObjectSpinner) { return; }

     if (!$('.spinner').length) {
       $('

')
        .appendTo('#app-container');
     }

     routeObjectSpinner = new Spinner(opts).spin();
     $('.spinner').append(routeObjectSpinner.el);
   }
  });

  var removeRouteObjectSpinner = function () {
    if (routeObjectSpinner) {
      routeObjectSpinner.stop();
      routeObjectSpinner = null;
      $('.spinner').remove();
    }
  };

  var removeViewSpinner = function (selector) {
    var viewSpinner = viewSpinners[selector];

    if (viewSpinner){
      viewSpinner.stop();
      $(selector).find('.spinner').remove();
      delete viewSpinners[selector];
    }
  };

  var viewSpinners = {};
  FauxtonAPI.RouteObject.on('beforeRender', function (routeObject, view, selector) {
    removeRouteObjectSpinner();

    if (!view.disableLoader){
      var opts = {
        lines: 16, // The number of lines to draw
        length: 8, // The length of each line
        width: 4, // The line thickness
        radius: 12, // The radius of the inner circle
        color: '#333', // #rbg or #rrggbb
        speed: 1, // Rounds per second
        trail: 10, // Afterglow percentage
        shadow: false // Whether to render a shadow
      };

      var viewSpinner = new Spinner(opts).spin();
      $('

')
        .appendTo(selector)
        .append(viewSpinner.el);

      viewSpinners[selector] = viewSpinner;
    }
  });

  FauxtonAPI.RouteObject.on('afterRender', function (routeObject, view, selector) {
    removeViewSpinner(selector);
  });

  FauxtonAPI.RouteObject.on('viewHasRendered', function (view, selector) {
    removeViewSpinner(selector);
    removeRouteObjectSpinner();
  });

  return Components;
});

<|endoftext|>


<commit_before>// Setup three.js WebGL renderer
var renderer = new THREE.WebGLRenderer( {antialias: true} );
renderer.setClearColor( 0xddddfd );

// Append the canvas element created by the renderer to document body element.
document.body.appendChild( renderer.domElement );

// Create a three.js scene
var scene = new THREE.Scene();

// Create a three.js camera
var camera = new THREE.PerspectiveCamera( 110, window.innerWidth / window.innerHeight, 0.01, 1000 );
scene.add(camera);
camera.position.set( 0, 3, 0 );

// Apply VR headset positional data to camera.
var controls = new THREE.VRControls( camera );

// Apply VR stereo rendering to renderer
var effect = new THREE.VREffect( renderer );
effect.setSize( window.innerWidth, window.innerHeight );

// VR Scene Below

var pi = 3.141592653589793238;

scene.fog = new THREE.FogExp2( 0xddddfd, 0.15 );

var everything = new THREE.Object3D();
scene.add( everything );

// ground
var groundGeometry = new THREE.PlaneGeometry( 100, 100, 50, 50 );
var groundMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, side: THREE.DoubleSide, wireframe: false } );
var ground = new THREE.Mesh( groundGeometry, groundMaterial );
ground.rotation.x = -pi/2;
everything.add( ground );
for (var i = 0; i < ground.geometry.vertices.length; i++){
  ground.geometry.vertices[i].z = 1.5 - 0.7*Math.sin(ground.geometry.vertices[i].y/2) - 1.3*Math.sin(ground.geometry.vertices[i].x/4) - 1.3*Math.cos(ground.geometry.vertices[i].y/4) - 0.8*Math.cos(ground.geometry.vertices[i].x/3) - 3*Math.sin(ground.geometry.vertices[1].x/25);
};

var snowFloor = 0;

// snow
var particles = new THREE.Geometry();
var partCount = 1000;
for (var p = 0; p<partCount; p++) {
  var part = new THREE.Vector3(
    24 * Math.random() - 12,
    16 * Math.random() + snowFloor,
    24 * Math.random() - 12
    );
  part.velocity = new THREE.Vector3(
    Math.random() * 0.1,
    -Math.random() * 0.5,
    Math.random() * 0.09
  );
  particles.vertices.push(part);
}
var partMat = new THREE.PointCloudMaterial( { color: 0xffffff, size: 0.07 } );
var partSystem = new THREE.PointCloud( particles, partMat );
partSystem.sortParticles = true;
partSystem.frustumCulled = false;
everything.add( partSystem );

// sky
var skyGeometry = new THREE.PlaneGeometry( 100, 100, 50, 50 );
var skyMaterial = new THREE.MeshLambertMaterial( { color: 0xbcbcbc, side: THREE.DoubleSide, wireframe: false } );
var sky = new THREE.Mesh( skyGeometry, skyMaterial );
sky.rotation.x = -pi/2;
sky.position.y = 16;
everything.add( sky );
for (var i = 0; i < sky.geometry.vertices.length; i++){
  sky.geometry.vertices[i].z = 1.5 - 1.3*Math.sin(sky.geometry.vertices[i].y/3) - Math.sin(sky.geometry.vertices[i].x/2.6) - 1.1*Math.cos(sky.geometry.vertices[i].y/3.8) - 2.1*Math.cos(sky.geometry.vertices[i].x/3.3);
};

var cubePosX = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0x00ff00 } ));
cubePosX.position.set( 1, 3, 0 );
everything.add( cubePosX );

var cubePosY = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0x0000ff } ));
cubePosY.position.set( 0, 4, 0 );
everything.add( cubePosY );

var cubePosZ = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0xff0000 } ));
cubePosZ.position.set( 0, 3, 1 );
everything.add( cubePosZ );

// light
var light = new THREE.PointLight( 0xffffff, 1, 100  );
light.position.set( -10, 4, -2 );
light.castShadow = true;
everything.add( light );

/* sled which I can't
  var sled = new THREE.Object3D();

  // var sledCenter = new THREE.Mesh(
  //  new THREE.TetrahedronGeometry(),
  //  new THREE.MeshLambertMaterial({color: 0xffff00})
  //  );
  // sledCenter.scale.set(0.1,0.1,0.1);
  // sled.add(sledCenter);

  var sledFront = new THREE.Mesh(
    new THREE.TetrahedronGeometry(),
    new THREE.MeshLambertMaterial({color: 0x550000})
    );
  sledFront.position.z = 0.5;
  sledFront.scale.set(0.1,0.1,0.1);
  sled.add(sledFront);

  var slat = new THREE.Mesh(
    new THREE.BoxGeometry(0.5,0.05,1),
    new THREE.MeshLambertMaterial({color: 0x330000})
    );
  sled.add(slat);

  scene.add(sled);

  // var headProjection = new THREE.Mesh(
  //  new THREE.IcosahedronGeometry(),
  //  new THREE.MeshLambertMaterial({color: 0x0000ff})
  // );
  // headProjection.scale.set(0.1,0.1,0.1);
  // scene.add(headProjection);

  var pos = new THREE.Vector2;
  var moveVector = new THREE.Vector2;
  var crouchHeight = 1.2;
  var crouchToggleHeight = 0.5;
  var sledDistance = 0.8;
  var speed = 0.2;
  var sledToggle = 0;
  var sledToggleDistance = 0.4;

  var t = 0;*/

/*
Request animation frame loop function
*/
function animate() {
  // Apply any desired changes for the next frame here.
  for (var p = 0; p<partCount; p++) {
    // check if we need to reset particles
    if (particles.vertices[p].y < snowFloor) {
      particles.vertices[p].set(
        24*Math.random() - 12 + camera.position.x,
        snowFloor + 16,
        24*Math.random() - 12 + camera.position.z);
      particles.vertices[p].velocity.y = -Math.random() + 0.0001;
    }

    particles.vertices[p].y += particles.vertices[p].velocity.y;
    particles.vertices[p].z += particles.vertices[p].velocity.z;
    particles.vertices[p].x += particles.vertices[p].velocity.x;
  }
  light.position.x = camera.position.x;
  light.position.y = camera.position.y;

  // Update VR headset position and apply to camera.
  controls.update();

  // Render the scene through the VREffect.
  effect.render( scene, camera );
  requestAnimationFrame( animate );
}

animate();	// Kick off animation loop

/*
Listen for click event to enter full-screen mode.
We listen for single click because that works best for mobile for now
*/
document.body.addEventListener( 'click', function(){
  effect.setFullScreen( true );
})

/*
Listen for keyboard events
*/
function onkey(event) {
  event.preventDefault();

  if (event.keyCode == 90) { // z
    controls.resetSensor(); //zero rotation
  } else if (event.keyCode == 70 || event.keyCode == 13) { //f or enter
    effect.setFullScreen(true) //fullscreen
  }
};
window.addEventListener("keydown", onkey, true);

/*
Handle window resizes
*/
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  effect.setSize( window.innerWidth, window.innerHeight );
}
window.addEventListener( 'resize', onWindowResize, false );
<commit_msg>it's my aesthetic<commit_after>// Setup three.js WebGL renderer
var renderer = new THREE.WebGLRenderer( {antialias: true} );
renderer.setClearColor( 0xddddfd );

// Append the canvas element created by the renderer to document body element.
document.body.appendChild( renderer.domElement );

// Create a three.js scene
var scene = new THREE.Scene();

// Create a three.js camera
var camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 1000 );
scene.add(camera);
camera.position.set( 0, 3, 0 );

// Apply VR headset positional data to camera.
var controls = new THREE.VRControls( camera );

// Apply VR stereo rendering to renderer
var effect = new THREE.VREffect( renderer );
effect.setSize( window.innerWidth, window.innerHeight );

// VR Scene Below

var pi = 3.141592653589793238;

scene.fog = new THREE.FogExp2( 0xddddfd, 0.15 );

var everything = new THREE.Object3D();
scene.add( everything );

// ground
var groundGeometry = new THREE.PlaneGeometry( 100, 100, 50, 50 );
var groundMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, side: THREE.DoubleSide, wireframe: false } );
var ground = new THREE.Mesh( groundGeometry, groundMaterial );
ground.rotation.x = -pi/2;
everything.add( ground );
for (var i = 0; i < ground.geometry.vertices.length; i++){
  ground.geometry.vertices[i].z = 1.5 - 0.7*Math.sin(ground.geometry.vertices[i].y/2) - 1.3*Math.sin(ground.geometry.vertices[i].x/4) - 1.3*Math.cos(ground.geometry.vertices[i].y/4) - 0.8*Math.cos(ground.geometry.vertices[i].x/3) - 3*Math.sin(ground.geometry.vertices[1].x/25);
};

var snowFloor = 0;

// snow
var particles = new THREE.Geometry();
var partCount = 10000;
for (var p = 0; p<partCount; p++) {
  var part = new THREE.Vector3(
    24 * Math.random() - 12,
    12 * Math.random() + snowFloor,
    24 * Math.random() - 12
    );
  part.velocity = new THREE.Vector3(
    Math.random() * 0.1,
    -Math.random() * 0.5,
    Math.random() * 0.09
  );
  particles.vertices.push(part);
}
var partMat = new THREE.PointCloudMaterial( { color: 0xffffff, size: 0.07 } );
var partSystem = new THREE.PointCloud( particles, partMat );
partSystem.sortParticles = true;
partSystem.frustumCulled = false;
everything.add( partSystem );

// sky
var skyGeometry = new THREE.PlaneGeometry( 100, 100, 50, 50 );
var skyMaterial = new THREE.MeshLambertMaterial( { color: 0xbcbcbc, side: THREE.DoubleSide, wireframe: false } );
var sky = new THREE.Mesh( skyGeometry, skyMaterial );
sky.rotation.x = -pi/2;
sky.position.y = 12;
everything.add( sky );
for (var i = 0; i < sky.geometry.vertices.length; i++){
  sky.geometry.vertices[i].z = 1.5 - 1.3*Math.sin(sky.geometry.vertices[i].y/3) - Math.sin(sky.geometry.vertices[i].x/2.6) - 1.1*Math.cos(sky.geometry.vertices[i].y/3.8) - 2.1*Math.cos(sky.geometry.vertices[i].x/3.3);
};

var cubePosX = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0x00ff00 } ));
cubePosX.position.set( 1, 3, 0 );
// everything.add( cubePosX );

var cubePosY = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0x0000ff } ));
cubePosY.position.set( 0, 4, 0 );
// everything.add( cubePosY );

var cubePosZ = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: 0xff0000 } ));
cubePosZ.position.set( 0, 3, 1 );
// everything.add( cubePosZ );

// lights
var light = new THREE.PointLight( 0xffffff, 1.25, 100  );
light.position.set( 0, 25, 0 );
light.castShadow = true;
everything.add( light );

/* sled which I can't
  var sled = new THREE.Object3D();

  // var sledCenter = new THREE.Mesh(
  //  new THREE.TetrahedronGeometry(),
  //  new THREE.MeshLambertMaterial({color: 0xffff00})
  //  );
  // sledCenter.scale.set(0.1,0.1,0.1);
  // sled.add(sledCenter);

  var sledFront = new THREE.Mesh(
    new THREE.TetrahedronGeometry(),
    new THREE.MeshLambertMaterial({color: 0x550000})
    );
  sledFront.position.z = 0.5;
  sledFront.scale.set(0.1,0.1,0.1);
  sled.add(sledFront);

  var slat = new THREE.Mesh(
    new THREE.BoxGeometry(0.5,0.05,1),
    new THREE.MeshLambertMaterial({color: 0x330000})
    );
  sled.add(slat);

  scene.add(sled);

  // var headProjection = new THREE.Mesh(
  //  new THREE.IcosahedronGeometry(),
  //  new THREE.MeshLambertMaterial({color: 0x0000ff})
  // );
  // headProjection.scale.set(0.1,0.1,0.1);
  // scene.add(headProjection);

  var pos = new THREE.Vector2;
  var moveVector = new THREE.Vector2;
  var crouchHeight = 1.2;
  var crouchToggleHeight = 0.5;
  var sledDistance = 0.8;
  var speed = 0.2;
  var sledToggle = 0;
  var sledToggleDistance = 0.4;

  var t = 0;*/

/*
Request animation frame loop function
*/
function animate() {
  // Apply any desired changes for the next frame here.
  for (var p = 0; p<partCount; p++) {
    // check if we need to reset particles
    if (particles.vertices[p].y < snowFloor) {
      particles.vertices[p].set(
        24*Math.random() - 12 + camera.position.x,
        snowFloor + 12,
        24*Math.random() - 12 + camera.position.z);
      particles.vertices[p].velocity.y = -Math.random() + 0.0001;
    }

    particles.vertices[p].y += particles.vertices[p].velocity.y;
    particles.vertices[p].z += particles.vertices[p].velocity.z;
    particles.vertices[p].x += particles.vertices[p].velocity.x;
  }
  light.position.x = camera.position.x - 10;
  light.position.z = camera.position.z + 6;

  // Update VR headset position and apply to camera.
  controls.update();

  // Render the scene through the VREffect.
  effect.render( scene, camera );
  requestAnimationFrame( animate );
}

animate();	// Kick off animation loop

/*
Listen for click event to enter full-screen mode.
We listen for single click because that works best for mobile for now
*/
document.body.addEventListener( 'click', function(){
  effect.setFullScreen( true );
})

/*
Listen for keyboard events
*/
function onkey(event) {
  event.preventDefault();

  if (event.keyCode == 90) { // z
    camera.rotation.z = 0; //zero rotation
  } else if (event.keyCode == 70 || event.keyCode == 13) { //f or enter
    effect.setFullScreen(true) //fullscreen
  }
};
window.addEventListener("keydown", onkey, true);

/*
Handle window resizes
*/
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  effect.setSize( window.innerWidth, window.innerHeight );
}
window.addEventListener( 'resize', onWindowResize, false );
<|endoftext|>