<commit_before>
function clearAll($elems) {
    _.each($elems, function($elem) {
        $elem.empty();
    });
};

function setTransformPos(elem, x, y) {
    var style = "translate(" + x + "px," + y + "px)";
    elem.style["-ms-transform"] = style;
    elem.style["-webkit-transform"] = style;
    elem.style.transform = style;
};

function updateUserState($user, elem_user, user) {
    setTransformPos(elem_user, user.worldX, user.worldY);
    if(user.done) { $user.addClass("leaving"); }
};

function presentStats($parent, world) {

    var elem_transportedcounter = $parent.find(".transportedcounter").get(0),
        elem_elapsedtime = $parent.find(".elapsedtime").get(0),
        elem_transportedpersec = $parent.find(".transportedpersec").get(0),
        elem_avgwaittime = $parent.find(".avgwaittime").get(0),
        elem_maxwaittime = $parent.find(".maxwaittime").get(0),
        elem_movecount = $parent.find(".movecount").get(0);

    world.on("stats_display_changed", function updateStats() {
        elem_transportedcounter.innerHTML = world.transportedCounter;
        elem_elapsedtime.innerHTML = world.elapsedTime.toFixed(0) + "s";
        elem_transportedpersec.innerHTML = world.transportedPerSec.toPrecision(3);
        elem_avgwaittime.innerHTML = world.avgWaitTime.toFixed(1) + "s";
        elem_maxwaittime.innerHTML = world.maxWaitTime.toFixed(1) + "s";
        elem_movecount.innerHTML = world.moveCount;
    });
    world.trigger("stats_display_changed");
};

function presentChallenge($parent, challenge, app, world, worldController, challengeNum, challengeTempl) {
    var $challenge = $(riot.render(challengeTempl, {
        challenge: challenge,
        num: challengeNum,
        timeScale: worldController.timeScale.toFixed(0) + "x",
        startButtonText: world.challengeEnded ? " Restart" : (worldController.isPaused ? "Start" : "Pause")
    }));
    $parent.html($challenge);

    $parent.find(".startstop").on("click", function() {
        app.startStopOrRestart();
    });
    $parent.find(".timescale_increase").on("click", function(e) {
        e.preventDefault();
        if(worldController.timeScale < 40) {
            var timeScale = Math.round(worldController.timeScale * 1.618);
            worldController.setTimeScale(timeScale);
        }
    });
    $parent.find(".timescale_decrease").on("click", function(e) {
        e.preventDefault();
        var timeScale = Math.round(worldController.timeScale / 1.618);
        worldController.setTimeScale(timeScale);
    });
};

function presentFeedback($parent, feedbackTempl, world, title, message, url) {
    $parent.html(riot.render(feedbackTempl, {title: title, message: message, url: url, paddingTop: world.floors.length * world.floorHeight * 0.2}));
    if(!url) {
        $parent.find("a").remove();
    }
};

function presentWorld($world, world, floorTempl, elevatorTempl, elevatorButtonTempl, userTempl) {
    $world.css("height", world.floorHeight * world.floors.length);

    $world.append(_.map(world.floors, function(f) {
        var $floor = $(riot.render(floorTempl, f));
        f.on("buttonstate_change", function(buttonStates) {
            $floor.find(".up").toggleClass("activated", buttonStates.up !== "");
            $floor.find(".down").toggleClass("activated", buttonStates.down !== "");
        });
        $floor.find(".up").on("click", function() {
            f.pressUpButton();
        });
        $floor.find(".down").on("click", function() {
            f.pressDownButton();
        });
        return $floor;
    }));
    $world.find(".floor").first().find(".down").addClass("invisible");
    $world.find(".floor").last().find(".up").addClass("invisible");

    function renderElevatorButtons(states) {
        // This is a rarely executed inner-inner loop, does not need efficiency
        return _.map(states, function(b, i) {
            return riot.render(elevatorButtonTempl, {floorNum: i});
        }).join("");
    };

    function setUpElevator(e) {
        var $elevator = $(riot.render(elevatorTempl, {e: e}));
        var elem_elevator = $elevator.get(0);
        $elevator.find(".buttonindicator").html(renderElevatorButtons(e.buttonStates));
        var $buttons = _.map($elevator.find(".buttonindicator").children(), function(c) { return $(c); });
        var elem_floorindicator = $elevator.find(".floorindicator > span").get(0);

        $elevator.on("click", ".buttonpress", function() {
            e.pressFloorButton(parseInt($(this).text()));
        });
        e.on("new_display_state", function updateElevatorPosition() {
            setTransformPos(elem_elevator, e.worldX, e.worldY);
        });
        e.on("new_current_floor", function update_current_floor(floor) {
            elem_floorindicator.className = "number" + floor;
        });
        e.on("floor_buttons_changed", function update_floor_buttons(states, indexChanged) {
            $buttons[indexChanged].toggleClass("activated", states[indexChanged]);
        });
        e.on("indicatorstate_change", function indicatorstate_change(indicatorStates) {
            $elevator.find(".up").toggleClass("activated", indicatorStates.up);
            $elevator.find(".down").toggleClass("activated", indicatorStates.down);
        });
        e.trigger("new_state", e);
        e.trigger("new_display_state", e);
        e.trigger("new_current_floor", e.currentFloor);
        return $elevator;
    }

    $world.append(_.map(world.elevators, function(e) {
        return setUpElevator(e);
    }));

    world.on("new_user", function(user) {
        var $user = $(riot.render(userTempl, {u: user, state: user.done ? "leaving" : ""}));
        var elem_user = $user.get(0);

        user.on("new_display_state", function() { updateUserState($user, elem_user, user); })
        user.on("removed", function() {
            $user.remove();
        });
        $world.append($user);
    });
};

function presentCodeStatus($parent, templ, error) {
    console.log(error);
    var errorDisplay = error ? "block" : "none";
    var successDisplay = error ? "none" : "block";
    var errorMessage = error;
    if(error && error.stack) {
        errorMessage = error.stack;
        errorMessage = errorMessage.replace(/\n/g, "
");
    }
    var status = riot.render(templ, {errorMessage: errorMessage, errorDisplay: errorDisplay, successDisplay: successDisplay});
    $parent.html(status);
};

function makeDemoFullscreen() {
    $("body .container > *").not(".world").css("visibility", "hidden");
    $("html, body, body .container, .world").css({width: "100%", margin: "0", "padding": 0});
};
<commit_msg>Improve stats performance by using textContent<commit_after>
function clearAll($elems) {
    _.each($elems, function($elem) {
        $elem.empty();
    });
};

function setTransformPos(elem, x, y) {
    var style = "translate(" + x + "px," + y + "px)";
    elem.style["-ms-transform"] = style;
    elem.style["-webkit-transform"] = style;
    elem.style.transform = style;
};

function updateUserState($user, elem_user, user) {
    setTransformPos(elem_user, user.worldX, user.worldY);
    if(user.done) { $user.addClass("leaving"); }
};

function presentStats($parent, world) {

    var elem_transportedcounter = $parent.find(".transportedcounter").get(0),
        elem_elapsedtime = $parent.find(".elapsedtime").get(0),
        elem_transportedpersec = $parent.find(".transportedpersec").get(0),
        elem_avgwaittime = $parent.find(".avgwaittime").get(0),
        elem_maxwaittime = $parent.find(".maxwaittime").get(0),
        elem_movecount = $parent.find(".movecount").get(0);

    world.on("stats_display_changed", function updateStats() {
        elem_transportedcounter.textContent = world.transportedCounter;
        elem_elapsedtime.textContent = world.elapsedTime.toFixed(0) + "s";
        elem_transportedpersec.textContent = world.transportedPerSec.toPrecision(3);
        elem_avgwaittime.textContent = world.avgWaitTime.toFixed(1) + "s";
        elem_maxwaittime.textContent = world.maxWaitTime.toFixed(1) + "s";
        elem_movecount.textContent = world.moveCount;
    });
    world.trigger("stats_display_changed");
};

function presentChallenge($parent, challenge, app, world, worldController, challengeNum, challengeTempl) {
    var $challenge = $(riot.render(challengeTempl, {
        challenge: challenge,
        num: challengeNum,
        timeScale: worldController.timeScale.toFixed(0) + "x",
        startButtonText: world.challengeEnded ? " Restart" : (worldController.isPaused ? "Start" : "Pause")
    }));
    $parent.html($challenge);

    $parent.find(".startstop").on("click", function() {
        app.startStopOrRestart();
    });
    $parent.find(".timescale_increase").on("click", function(e) {
        e.preventDefault();
        if(worldController.timeScale < 40) {
            var timeScale = Math.round(worldController.timeScale * 1.618);
            worldController.setTimeScale(timeScale);
        }
    });
    $parent.find(".timescale_decrease").on("click", function(e) {
        e.preventDefault();
        var timeScale = Math.round(worldController.timeScale / 1.618);
        worldController.setTimeScale(timeScale);
    });
};

function presentFeedback($parent, feedbackTempl, world, title, message, url) {
    $parent.html(riot.render(feedbackTempl, {title: title, message: message, url: url, paddingTop: world.floors.length * world.floorHeight * 0.2}));
    if(!url) {
        $parent.find("a").remove();
    }
};

function presentWorld($world, world, floorTempl, elevatorTempl, elevatorButtonTempl, userTempl) {
    $world.css("height", world.floorHeight * world.floors.length);

    $world.append(_.map(world.floors, function(f) {
        var $floor = $(riot.render(floorTempl, f));
        f.on("buttonstate_change", function(buttonStates) {
            $floor.find(".up").toggleClass("activated", buttonStates.up !== "");
            $floor.find(".down").toggleClass("activated", buttonStates.down !== "");
        });
        $floor.find(".up").on("click", function() {
            f.pressUpButton();
        });
        $floor.find(".down").on("click", function() {
            f.pressDownButton();
        });
        return $floor;
    }));
    $world.find(".floor").first().find(".down").addClass("invisible");
    $world.find(".floor").last().find(".up").addClass("invisible");

    function renderElevatorButtons(states) {
        // This is a rarely executed inner-inner loop, does not need efficiency
        return _.map(states, function(b, i) {
            return riot.render(elevatorButtonTempl, {floorNum: i});
        }).join("");
    };

    function setUpElevator(e) {
        var $elevator = $(riot.render(elevatorTempl, {e: e}));
        var elem_elevator = $elevator.get(0);
        $elevator.find(".buttonindicator").html(renderElevatorButtons(e.buttonStates));
        var $buttons = _.map($elevator.find(".buttonindicator").children(), function(c) { return $(c); });
        var elem_floorindicator = $elevator.find(".floorindicator > span").get(0);

        $elevator.on("click", ".buttonpress", function() {
            e.pressFloorButton(parseInt($(this).text()));
        });
        e.on("new_display_state", function updateElevatorPosition() {
            setTransformPos(elem_elevator, e.worldX, e.worldY);
        });
        e.on("new_current_floor", function update_current_floor(floor) {
            elem_floorindicator.className = "number" + floor;
        });
        e.on("floor_buttons_changed", function update_floor_buttons(states, indexChanged) {
            $buttons[indexChanged].toggleClass("activated", states[indexChanged]);
        });
        e.on("indicatorstate_change", function indicatorstate_change(indicatorStates) {
            $elevator.find(".up").toggleClass("activated", indicatorStates.up);
            $elevator.find(".down").toggleClass("activated", indicatorStates.down);
        });
        e.trigger("new_state", e);
        e.trigger("new_display_state", e);
        e.trigger("new_current_floor", e.currentFloor);
        return $elevator;
    }

    $world.append(_.map(world.elevators, function(e) {
        return setUpElevator(e);
    }));

    world.on("new_user", function(user) {
        var $user = $(riot.render(userTempl, {u: user, state: user.done ? "leaving" : ""}));
        var elem_user = $user.get(0);

        user.on("new_display_state", function() { updateUserState($user, elem_user, user); })
        user.on("removed", function() {
            $user.remove();
        });
        $world.append($user);
    });
};

function presentCodeStatus($parent, templ, error) {
    console.log(error);
    var errorDisplay = error ? "block" : "none";
    var successDisplay = error ? "none" : "block";
    var errorMessage = error;
    if(error && error.stack) {
        errorMessage = error.stack;
        errorMessage = errorMessage.replace(/\n/g, "
");
    }
    var status = riot.render(templ, {errorMessage: errorMessage, errorDisplay: errorDisplay, successDisplay: successDisplay});
    $parent.html(status);
};

function makeDemoFullscreen() {
    $("body .container > *").not(".world").css("visibility", "hidden");
    $("html, body, body .container, .world").css({width: "100%", margin: "0", "padding": 0});
};
<|endoftext|>


<commit_before>// ProcessImage utilities and helper methods

var fs = require('fs'),
    gm = require('gm').subClass({ imageMagick: true }),
    exec = require('child_process').exec;

exports.generateThumb = function (originalPath, cb) {

    var UPLOAD_THUMB_PATH = 'upload/thumb';
    var UPLOAD_DETAIL_PATH = 'upload/detail';

    //create repositories
    try {
        mkdirp.sync(UPLOAD_THUMB_PATH, 0755);
    } catch (e) {
        console.log(e);
    }

    try {
        mkdirp.sync(UPLOAD_DETAIL_PATH, 0755);
    } catch (e) {
        console.log(e);
    }

    //settings size and path
    var originalFileName = originalPath.replace(/^.*[\\\/]/, ''),
        thumbSize = ['460', '286'],
        detailSize = ['1024', '580'];

    gm(originalPath).thumb(thumbSize[0], thumbSize[1], UPLOAD_THUMB_PATH + '/' + originalFileName, 100, function (err) {
        if (!err) {
            console.log(' Thumb Resize Ok! ');
            gm(originalPath).thumb(detailSize[0], detailSize[1], UPLOAD_DETAIL_PATH  + '/' +  originalFileName,100, function (err) {
                if (!err) {
                    console.log('Detail resize Ok !');
                    cb(null, {
                        'result': 'success',
                        'originalFileName': originalFileName,
                        'originalPath': '/' + originalPath,
                        'thumbPath': '/' + UPLOAD_THUMB_PATH + '/' + originalFileName,
                        'detailPath': '/' + UPLOAD_DETAIL_PATH  + '/' +  originalFileName
                    });
                }
                else  console.log(err);
            });
        }
        else console.log(err);
    });

}<commit_msg>correct repository creation<commit_after>// ProcessImage utilities and helper methods

var fs = require('fs'),
    gm = require('gm').subClass({ imageMagick: true }),
    mkdirp = require('mkdirp'),
    exec = require('child_process').exec;

exports.generateThumb = function (originalPath, cb) {

    var UPLOAD_THUMB_PATH = 'upload/thumb';
    var UPLOAD_DETAIL_PATH = 'upload/detail';

    //create repositories
    try {
        mkdirp.sync(UPLOAD_THUMB_PATH, 0755);
    } catch (e) {
        console.log(e);
    }

    try {
        mkdirp.sync(UPLOAD_DETAIL_PATH, 0755);
    } catch (e) {
        console.log(e);
    }

    //settings size and path
    var originalFileName = originalPath.replace(/^.*[\\\/]/, ''),
        thumbSize = ['460', '286'],
        detailSize = ['1024', '580'];

    gm(originalPath).thumb(thumbSize[0], thumbSize[1], UPLOAD_THUMB_PATH + '/' + originalFileName, 100, function (err) {
        if (!err) {
            console.log(' Thumb Resize Ok! ');
            gm(originalPath).thumb(detailSize[0], detailSize[1], UPLOAD_DETAIL_PATH  + '/' +  originalFileName,100, function (err) {
                if (!err) {
                    console.log('Detail resize Ok !');
                    cb(null, {
                        'result': 'success',
                        'originalFileName': originalFileName,
                        'originalPath': '/' + originalPath,
                        'thumbPath': '/' + UPLOAD_THUMB_PATH + '/' + originalFileName,
                        'detailPath': '/' + UPLOAD_DETAIL_PATH  + '/' +  originalFileName
                    });
                }
                else  console.log(err);
            });
        }
        else console.log(err);
    });

}<|endoftext|>


<commit_before>var jsdom = require("jsdom");
var nodeURL = require("url");
var jsonUtils = require('../utils/json');

var outputType;
var total;
var numberSubsHTML;
var numberSubsNoDigest;
var numberSubsDigest;

var requestCount;
var urls = [];
var data = [];

var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var month;
var year;
var arrayPos;

function mailingListReporter (request, response) {

if(nodeURL.parse(request.url,false,true).pathname.split(".").pop() == "json")
    outputType = "JSON";
else
    outputType = "HTML";

urls = [];
data = [];
requestCount = 0;

urls.push({"url":"http://lists.numenta.org/mailman/roster/nupic_lists.numenta.org"});

month = 4;    //Start in May
year = 2013;  //Start in 2013
var date = new Date();
arrayPos = 1;
while (year <= date.getYear() || month <= date.getMonth()) {

    urls.push({"url":"http://lists.numenta.org/pipermail/nupic_lists.numenta.org/"+year+"-"+monthNames[month]+"/date.html","month":month,"year":year,"arrayPos":arrayPos});

    arrayPos++;
    month++;
    if(month == 12) {

        month = 0;
        year++;

    }

}

jsdom.env(urls.shift().url,["http://code.jquery.com/jquery.js"], function (errors, window) {

    numberSubsHTML = window.$("center b font");
    numberSubsNoDigest = parseInt((numberSubsHTML[0]).innerHTML.split(" ").shift());
    numberSubsDigest = parseInt((numberSubsHTML[1]).innerHTML.split(" ").shift());
    var object = {};
    object["name"] = "subscribers";
    object["month"] = -1;
    object["year"] = -1;
    object["number"] = numberSubsNoDigest + numberSubsDigest;
    data[0] = object;
    requestCount++;
    checkIfLastRequestAndBuildOutput(response);

});

urls.forEach(function(url) {

    jsdom.env(url.url,["http://code.jquery.com/jquery.js"], function (errors, window) {

        var object = {};
        object["name"] = monthNames[url.month] + " " + url.year;
        object["month"] = url.month;
        object["year"] = url.year;
        object["number"] = (window.$("a").length-10)/2;
        data[url.arrayPos] = object;
        requestCount++;
        checkIfLastRequestAndBuildOutput(response);

    });

});

}

function checkIfLastRequestAndBuildOutput (response)  {

    if (requestCount >= urls.length + 1) {

        if(outputType == "HTML")    {

            response.write("<title>Mailing List Statistics</title>
Mailing List Statistics
Total Subscribers: ");
            response.write(data.shift().number.toString());
            response.write("
Number of messages by month:
");
            total = 0;
            data.forEach(function(nextMonthData) {

                response.write("
");
                response.write(nextMonthData.name);
                response.write("	");
                response.write(nextMonthData.number.toString());
                response.write("
");

                total += nextMonthData.number;

            });
            response.write("
TOTAL	");
            response.write(total.toString());
            response.write("

");

            response.end();

        } else if (outputType == "JSON") {

            console.log(data);

            jsonUtils.render(data,response);

            response.end();

        }

    }

}

mailingListReporter.name = 'Mailing List Reporter';
mailingListReporter.description = 'Provides statistics about the mailing list. (Outputs HTML or JSON depending on extention [*.html or *.json].)';

module.exports = {
    '/maillist': function() {
        return mailingListReporter;
    }
};<commit_msg>removing unnecessary functions.<commit_after>var jsdom = require("jsdom");
var nodeURL = require("url");
var jsonUtils = require('../utils/json');

var outputType;
var total;
var numberSubsHTML;
var numberSubsNoDigest;
var numberSubsDigest;

var requestCount;
var urls = [];
var data = [];

var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var month;
var year;
var arrayPos;

function mailingListReporter (request, response) {

if(nodeURL.parse(request.url,false,true).pathname.split(".").pop() == "json")
    outputType = "JSON";
else
    outputType = "HTML";

urls = [];
data = [];
requestCount = 0;

urls.push({"url":"http://lists.numenta.org/mailman/roster/nupic_lists.numenta.org"});

month = 4;    //Start in May
year = 2013;  //Start in 2013
var date = new Date();
arrayPos = 1;
while (year <= date.getYear() || month <= date.getMonth()) {

    urls.push({"url":"http://lists.numenta.org/pipermail/nupic_lists.numenta.org/"+year+"-"+monthNames[month]+"/date.html","month":month,"year":year,"arrayPos":arrayPos});

    arrayPos++;
    month++;
    if(month == 12) {

        month = 0;
        year++;

    }

}

jsdom.env(urls.shift().url,["http://code.jquery.com/jquery.js"], function (errors, window) {

    numberSubsHTML = window.$("center b font");
    numberSubsNoDigest = parseInt((numberSubsHTML[0]).innerHTML.split(" ").shift());
    numberSubsDigest = parseInt((numberSubsHTML[1]).innerHTML.split(" ").shift());
    var object = {};
    object["name"] = "subscribers";
    object["month"] = -1;
    object["year"] = -1;
    object["number"] = numberSubsNoDigest + numberSubsDigest;
    data[0] = object;
    requestCount++;
    checkIfLastRequestAndBuildOutput(response);

});

urls.forEach(function(url) {

    jsdom.env(url.url,["http://code.jquery.com/jquery.js"], function (errors, window) {

        var object = {};
        object["name"] = monthNames[url.month] + " " + url.year;
        object["month"] = url.month;
        object["year"] = url.year;
        object["number"] = (window.$("a").length-10)/2;
        data[url.arrayPos] = object;
        requestCount++;
        checkIfLastRequestAndBuildOutput(response);

    });

});

}

function checkIfLastRequestAndBuildOutput (response)  {

    if (requestCount >= urls.length + 1) {

        if(outputType == "HTML")    {

            response.write("<title>Mailing List Statistics</title>
Mailing List Statistics
Total Subscribers: ");
            response.write(data.shift().number.toString());
            response.write("
Number of messages by month:
");
            total = 0;
            data.forEach(function(nextMonthData) {

                response.write("
");
                response.write(nextMonthData.name);
                response.write("	");
                response.write(nextMonthData.number.toString());
                response.write("
");

                total += nextMonthData.number;

            });
            response.write("
TOTAL	");
            response.write(total.toString());
            response.write("

");

            response.end();

        } else if (outputType == "JSON") {

            jsonUtils.render(data,response);

        }

    }

}

mailingListReporter.name = 'Mailing List Reporter';
mailingListReporter.description = 'Provides statistics about the mailing list. (Outputs HTML or JSON depending on extention [*.html or *.json].)';

module.exports = {
    '/maillist': function() {
        return mailingListReporter;
    }
};<|endoftext|>


<commit_before>var util = require('util'),
    sha = require('sha1'),
    utility = require('../../util'),
    nodes = require('./index'),

  /**
   * Subclass of dynamic nodes which describe library blocks
   * @param {LevelNode} parent node
   * @param {Object} version of library
   * @param {Object} level of library blocks
   * @param {Object} block data
   * @constructor
   */
    BlockNode = function (parent, version, level, block) {
        this.setTitle(block)
            .setSource(version, level, block)
            .processRoute(parent, {
                conditions: {
                    lib: version.repo,
                    version: version.ref.replace(/\//g, '-'),
                    level: level.name,
                    block: block.name
                }
            })
            .init(parent)
            .createBreadcrumbs();
        this.createMeta(version);
    };

BlockNode.prototype = Object.create(nodes.dynamic.DynamicNode.prototype);

/**
 * Sets title for node
 * @param {Object} block
 * @returns {BlockNode}
 */
BlockNode.prototype.setTitle = function (block) {
    this.title = utility.getLanguages().reduce(function (prev, lang) {
        prev[lang] = block.name;
        return prev;
    }, {});
    return this;
};

/**
 * Sets source for node
 * @param {Object} version of library
 * @param {Object} level of library blocks
 * @param {Object} block data
 * @returns {BlockNode}
 */
BlockNode.prototype.setSource = function (version, level, block) {
    this.source = {
        data: block.data,
        jsdoc: block.jsdoc,
        enb: version.enb,
        prefix: version.enb ?
            util.format('/__example/%s/%s', version.repo, version.ref) :
            util.format('/__example/%s/%s/%s.sets/%s', version.repo, version.ref, level.name, block.name)
    };

    return this;
};

/**
 * Sets view for node
 * @returns {BlockNode}
 */
BlockNode.prototype.setView = function () {
    this.view = this.VIEW.BLOCK;
    return this;
};

/**
 * Sets class for node
 * @returns {BlockNode}
 */
BlockNode.prototype.setClass = function () {
    this.class = 'block';
    return this;
};

/**
 * Creates meta-information for search engines
 * @returns {BlockNode}
 */
BlockNode.prototype.createMeta = function (version) {
    nodes.base.BaseNode.prototype.createMeta.apply(this);
    var _this = this,
        conditions = this.route.conditions;

    this.meta.fields = utility.getLanguages().reduce(function (prev, item) {
        prev[item] = {
            type: 'block',
            keywords: [
                'bem',
                'block',
                // islands button
                [conditions.lib, _this.title[item]].join(' '),
                // islands v2.0.0 button
                [conditions.lib, conditions.version, _this.title[item]].join(' '),
                // islands v2.0.0 button desktop
                [conditions.lib, conditions.version, _this.title[item], conditions.level].join(' ')
            ],
            block: {
                name: _this.title[item],
                library: conditions.lib,
                version: conditions.version,
                level: conditions.level,
                status: version.isCurrent ? 'current' : 'default'
            }
        };
        return prev;
    }, {});
    return this;
};

BlockNode.prototype.saveToDb = function () {
    var dataValue = this.source.data,
        jsdocValue = this.source.jsdoc,
        dataKey,
        jsdocKey,
        batchOperations = [];

    if (dataValue) {
        dataKey = util.format('blocks:data:%s', sha(JSON.stringify(dataValue)))
    }

    if (jsdocValue) {
        jsdocKey = util.format('blocks:jsdoc:%s', sha(JSON.stringify(jsdocValue)))
    }

    if (this.source.data) {
        batchOperations.push({
            type: 'put',
            key: dataKey,
            value: dataValue
        });
    }

    if (this.source.jsdoc) {
        batchOperations.push({
            type: 'put',
            key: jsdocKey,
            value: jsdocValue
        });
    }

    this.source.data = dataKey;
    this.source.jsdoc = jsdocKey;
    this.markAsHasSource();

    // var conditions = this.route.conditions;
    // logger.verbose(util.format('save lib: %s version: %s, level: %s block: %s',
    //    conditions.lib, conditions.version, conditions.level, conditions.block), module);

    this.parent = this.parent.id;
    return batchOperations.concat({
        type: 'put',
        key: this.generateKey(),
        value: this
    });
};

exports.BlockNode = BlockNode;
<commit_msg>model/nodes/block.js: refactoring<commit_after>var util = require('util'),
    sha = require('sha1'),
    utility = require('../../util'),
    nodes = require('./index'),

  /**
   * Subclass of dynamic nodes which describe library blocks
   * @param {LevelNode} parent node
   * @param {Object} version of library
   * @param {Object} level of library blocks
   * @param {Object} block data
   * @constructor
   */
    BlockNode = function (parent, version, level, block) {
        this.setTitle(block)
            .setSource(version, level, block)
            .processRoute(parent, {
                conditions: {
                    lib: version.repo,
                    version: version.ref.replace(/\//g, '-'),
                    level: level.name,
                    block: block.name
                }
            })
            .init(parent)
            .createBreadcrumbs();
        this.createMeta(version);
    };

BlockNode.prototype = Object.create(nodes.dynamic.DynamicNode.prototype);

/**
 * Sets title for node
 * @param {Object} block
 * @returns {BlockNode}
 */
BlockNode.prototype.setTitle = function (block) {
    this.title = utility.getLanguages().reduce(function (prev, lang) {
        prev[lang] = block.name;
        return prev;
    }, {});
    return this;
};

/**
 * Sets source for node
 * @param {Object} version of library
 * @param {Object} level of library blocks
 * @param {Object} block data
 * @returns {BlockNode}
 */
BlockNode.prototype.setSource = function (version, level, block) {
    this.source = {
        data: block.data,
        jsdoc: block.jsdoc,
        enb: version.enb,
        prefix: version.enb ?
            util.format('/__example/%s/%s', version.repo, version.ref) :
            util.format('/__example/%s/%s/%s.sets/%s', version.repo, version.ref, level.name, block.name)
    };

    return this;
};

/**
 * Sets view for node
 * @returns {BlockNode}
 */
BlockNode.prototype.setView = function () {
    this.view = this.VIEW.BLOCK;
    return this;
};

/**
 * Sets class for node
 * @returns {BlockNode}
 */
BlockNode.prototype.setClass = function () {
    this.class = 'block';
    return this;
};

/**
 * Creates meta-information for search engines
 * @returns {BlockNode}
 */
BlockNode.prototype.createMeta = function (version) {
    nodes.base.BaseNode.prototype.createMeta.apply(this);
    var _this = this,
        conditions = this.route.conditions;

    this.meta.fields = utility.getLanguages().reduce(function (prev, item) {
        prev[item] = {
            type: 'block',
            keywords: [
                'bem',
                'block',
                // islands button
                [conditions.lib, _this.title[item]].join(' '),
                // islands v2.0.0 button
                [conditions.lib, conditions.version, _this.title[item]].join(' '),
                // islands v2.0.0 button desktop
                [conditions.lib, conditions.version, _this.title[item], conditions.level].join(' ')
            ],
            block: {
                name: _this.title[item],
                library: conditions.lib,
                version: conditions.version,
                level: conditions.level,
                status: version.isCurrent ? 'current' : 'default'
            }
        };
        return prev;
    }, {});
    return this;
};

BlockNode.prototype.saveToDb = function () {
    var batchOperations = [];

    ['data', 'jsdoc'].forEach(function(field) {
        var val = this.source[field];

        if (!val) return;

        var key = util.format('blocks:' + field + ':%s', sha(JSON.stringify(val)));

        batchOperations.push({
            type: 'put',
            key: key,
            value: val
        });

        this.source[field] = key;
    }, this);

    this.markAsHasSource();

    // var conditions = this.route.conditions;
    // logger.verbose(util.format('save lib: %s version: %s, level: %s block: %s',
    //    conditions.lib, conditions.version, conditions.level, conditions.block), module);

    this.parent = this.parent.id;
    return batchOperations.concat({
        type: 'put',
        key: this.generateKey(),
        value: this
    });
};

exports.BlockNode = BlockNode;
<|endoftext|>


<commit_before>/* global exports */
/* global XMLHttpRequest */
/* global module */
"use strict";

// module Network.HTTP.Affjax

// jshint maxparams: 5
exports._ajax = function (mkHeader, options, canceler, errback, callback) {
  var platformSpecific = { };
  if (typeof module !== "undefined" && module.require) {
    // We are on node.js
    platformSpecific.newXHR = function () {
      var XHR = module.require("xhr2");
      return new XHR();
    };

    platformSpecific.fixupUrl = function (url) {
      var urllib = module.require("url");
      var u = urllib.parse(url);
      u.protocol = u.protocol || "http:";
      u.hostname = u.hostname || "localhost";
      return urllib.format(u);
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  } else {
    // We are in the browser
    platformSpecific.newXHR = function () {
      return new XMLHttpRequest();
    };

    platformSpecific.fixupUrl = function (url) {
      return url || "/";
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  }

  return function () {
    var xhr = platformSpecific.newXHR();
    var fixedUrl = platformSpecific.fixupUrl(options.url);
    xhr.open(options.method || "GET", fixedUrl, true, options.username, options.password);
    if (options.headers) {
      for (var i = 0, header; (header = options.headers[i]) != null; i++) {
        xhr.setRequestHeader(header.field, header.value);
      }
    }
    xhr.onerror = function () {
      errback(new Error("AJAX request failed: " + options.method + " " + options.url))();
    };
    xhr.onload = function () {
      callback({
        status: xhr.status,
        headers: xhr.getAllResponseHeaders().split("\n")
          .filter(function (header) {
            return header.length > 0;
          })
          .map(function (header) {
            var i = header.indexOf(":");
            return mkHeader(header.substring(0, i))(header.substring(i + 2));
          }),
        response: platformSpecific.getResponse(xhr)
      })();
    };
    xhr.responseType = options.responseType;
    xhr.send(options.content);
    return canceler(xhr);
  };
};

// jshint maxparams: 4
exports._cancelAjax = function (xhr, cancelError, errback, callback) {
  return function () {
    try { xhr.abort(); } catch (e) { return callback(false)(); }
    return callback(true)();
  };
};

<commit_msg>catch errors in setRequestHeader, Fixes #58<commit_after>/* global exports */
/* global XMLHttpRequest */
/* global module */
"use strict";

// module Network.HTTP.Affjax

// jshint maxparams: 5
exports._ajax = function (mkHeader, options, canceler, errback, callback) {
  var platformSpecific = { };
  if (typeof module !== "undefined" && module.require) {
    // We are on node.js
    platformSpecific.newXHR = function () {
      var XHR = module.require("xhr2");
      return new XHR();
    };

    platformSpecific.fixupUrl = function (url) {
      var urllib = module.require("url");
      var u = urllib.parse(url);
      u.protocol = u.protocol || "http:";
      u.hostname = u.hostname || "localhost";
      return urllib.format(u);
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  } else {
    // We are in the browser
    platformSpecific.newXHR = function () {
      return new XMLHttpRequest();
    };

    platformSpecific.fixupUrl = function (url) {
      return url || "/";
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  }

  return function () {
    var xhr = platformSpecific.newXHR();
    var fixedUrl = platformSpecific.fixupUrl(options.url);
    xhr.open(options.method || "GET", fixedUrl, true, options.username, options.password);
    if (options.headers) {
      try {
        for (var i = 0, header; (header = options.headers[i]) != null; i++) {
          xhr.setRequestHeader(header.field, header.value);
        }
      }
      catch (e) {
        errback(e)();
      }
    }
    xhr.onerror = function () {
      errback(new Error("AJAX request failed: " + options.method + " " + options.url))();
    };
    xhr.onload = function () {
      callback({
        status: xhr.status,
        headers: xhr.getAllResponseHeaders().split("\n")
          .filter(function (header) {
            return header.length > 0;
          })
          .map(function (header) {
            var i = header.indexOf(":");
            return mkHeader(header.substring(0, i))(header.substring(i + 2));
          }),
        response: platformSpecific.getResponse(xhr)
      })();
    };
    xhr.responseType = options.responseType;
    xhr.send(options.content);
    return canceler(xhr);
  };
};

// jshint maxparams: 4
exports._cancelAjax = function (xhr, cancelError, errback, callback) {
  return function () {
    try { xhr.abort(); } catch (e) { return callback(false)(); }
    return callback(true)();
  };
};

<|endoftext|>


<commit_before><commit_msg>bug fix: scroll distance<commit_after><|endoftext|>


<commit_before>elation.require([ "ui.panel", "share.picker", "share.targets.imgur", "share.targets.dropbox", "share.targets.googledrive", "share.targets.youtube", "share.targets.file", "share.targets.facebook"], function() {
  elation.requireCSS(["engine.sharing"]);

  elation.component.add('engine.sharing', function() {
    this.init = function() {
      elation.engine.sharing.extendclass.init.call(this);
      this.client = this.args.client;
    }
    this.showShareDialog = function() {
      if (!this.dialog) {
        this.dialog = elation.engine.sharing.dialog({append: document.body, client: this.client, anchor: this.sharebutton});
        elation.events.add(this.dialog, 'ui_window_close', elation.bind(this, function() { this.sharebutton.show(); }));
      } else {
        this.dialog.show();
      }
    }
    this.share = function(data) {
      this.showShareDialog();
      this.dialog.share(data);
    }
  }, elation.ui.base);
  elation.component.add('engine.sharing.dialog', function() {
    this.init = function() {
      this.client = this.args.client;

      this.args.title = 'Sharing Options';
      this.args.right = true;
      this.args.bottom = 60;
      this.args.minimize = false;
      this.args.maximize = false;
      this.args.resizable = false;
      elation.engine.sharing.dialog.extendclass.init.call(this);
      this.addclass('engine_sharing');

      this.initPicker();

      this.sharetypes = {
        link: elation.engine.sharing.share_link({client: this.client, picker: this.sharepicker}),
        screenshot: elation.engine.sharing.share_screenshot({client: this.client, picker: this.sharepicker}),
        screenshot360: elation.engine.sharing.share_screenshot360({client: this.client, picker: this.sharepicker}),
        video: elation.engine.sharing.share_video({client: this.client, picker: this.sharepicker}),
      };
      this.selected = 'screenshot';

      this.tabs = elation.ui.tabbedcontent({
        append: this,
        items: [
          { name: 'link', label: 'Link', content: this.sharetypes.link },
          { name: 'screenshot', label: 'Screenshot', content: this.sharetypes.screenshot },
          { name: 'screenshot360', label: '360 Screenshot', content: this.sharetypes.screenshot360 },
          { name: 'video', label: 'Video', content: this.sharetypes.video, disabled: true },
        ],
        selected: this.selected,
        events: {
          tab_change: elation.bind(this, function(ev) { this.selected = ev.data.name; })
        }
      });
      this.setcontent(this.tabs);
    }
    this.initPicker = function() {
      this.sharepicker = elation.share.picker({append: document.body});
      var share = elation.config.get('share'),
          targets = share.targets || {};

      for (var k in targets) {
        var target = targets[k];
        if (!target.disabled && elation.share.targets[k]) {
          this.sharepicker.addShareTarget(elation.share.targets[k](target));
        }
      }
      console.log('did the picker', this.sharepicker);
    }
    this.share = function(data) {
      var type = this.selected;
      console.log('sharetype', type, this.sharetypes[type], this.tabs)
      if (this.sharetypes[type]) {
        this.sharetypes[type].share(data);
      }
    }
  }, elation.ui.window);
  elation.component.add('engine.sharing.share_link', function() {
    this.init = function() {
      elation.engine.sharing.share_link.extendclass.init.call(this);
      this.client = this.args.client;
      this.janusweb = this.client.janusweb;

      this.link = elation.ui.input({
        append: this,
        label: 'URL',
        value: this.janusweb.currentroom.url
      });
      this.button = elation.ui.button({
        append: this,
        label: 'Share'
      });
      this.addclass('engine_sharing_link');
    }
    this.share = function(data) {
    }
  }, elation.ui.panel_horizontal);
  elation.component.add('engine.sharing.share_screenshot', function() {
    this.init = function() {
      elation.engine.sharing.share_screenshot.extendclass.init.call(this);

      this.client = this.args.client;
      this.picker = this.args.picker;

      var resolutions = ['(window)', '512 x 256', '1280 x 720', '1920 x 1080', '3840 x ', '8k'];
      var formats = ['PNG', 'JPEG'];

      var panel = elation.ui.panel_horizontal({
        append: this
      });
      this.resolution = elation.ui.select({
        append: panel,
        label: 'Resolution',
        classname: 'engine_sharing_screenshot_resolution',
        items: resolutions
      });
      this.format = elation.ui.select({
        append: panel,
        label: 'Format',
        items: formats
      });
      this.button = elation.ui.button({
        append: panel,
        label: 'Share',
        events: {
          click: elation.bind(this, this.share)
        }
      });

      this.addclass('engine_sharing_screenshot');
    }
    this.share = function() {
      var client = this.client;
      client.screenshot({format: 'png'}).then(elation.bind(this, function(data) {
console.log('done');
        var imgdata = data.split(',')[1]; //data.image.data;

        var bytestr = atob(imgdata);
        var img = new Uint8Array(bytestr.length);
        for (var i = 0; i < bytestr.length; i++) {
          img[i] = bytestr.charCodeAt(i);
        }

        client.player.disable();
        this.picker.share({
          name: this.getScreenshotFilename('png'),
          type: 'image/png',
          image: img,
        }).then(elation.bind(this, function(upload) {
          //this.player.enable();
        }));
        var now = new Date().getTime();
        //console.log('finished png in ' + data.time.toFixed(2) + 'ms');
        console.log('finished png');
      }));
    }
    this.getScreenshotFilename = function(extension) {
      if (!extension) extension = 'png';
      var now = new Date();
      function pad(n) {
        if (n < 10) return '0' + n;
        return n;
      }
      var prefix = elation.config.get('engine.screenshot.prefix', 'screenshot');
      var date = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate());
      var time = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
      var filename = prefix + '-' + date + ' ' + time + '.' + extension
      return filename;
    }
  }, elation.ui.panel_vertical);
  elation.component.add('engine.sharing.share_screenshot360', function() {
    this.init = function() {
      elation.engine.sharing.share_screenshot360.extendclass.init.call(this);
      this.client = this.args.client;

      var mappings = ['equirectangular', 'cubemap'],
          resolutions = ['512', '1024', '2048', '4096', '8192'],
          formats = ['PNG', 'JPEG'];

      var panel = elation.ui.panel_horizontal({
        append: this
      });
      this.mapping = elation.ui.select({
        append: panel,
        label: 'Type',
        items: mappings
      });
      this.resolution = elation.ui.select({
        append: panel,
        label: 'Resolution',
        default: '4096',
        items: resolutions
      });
      this.format = elation.ui.select({
        append: panel,
        label: 'Format',
        items: formats
      });
      this.button = elation.ui.button({
        append: panel,
        label: 'Share'
      });

      this.addclass('engine_sharing_screenshot360');
    }
    this.share = function(data) {
    }
  }, elation.ui.panel);
  elation.component.add('engine.sharing.share_video', function() {
    this.init = function() {
      elation.engine.sharing.share_video.extendclass.init.call(this);
      this.client = this.args.client;

      this.addclass('engine_sharing_video');
    }
    this.share = function(data) {
    }
  }, elation.ui.panel);

  elation.component.add('engine.sharing.sharebutton', function() {
    this.init = function() {
      var type = this.args.type,
          picker = this.args.picker;

      var targets = picker.getTargetsForType(type);

      var button = elation.ui.button({
        append: this,
        label: 'Share on'
      });
      this.targets = elation.ui.select({
        append: this,
        items: targets
      });
    }
  }, elation.ui.panel_horizontal);

  elation.component.add('engine.sharing.config', function() {
    this.init = function() {
        this.args.orientation = 'vertical'
        elation.engine.sharing.config.extendclass.init.call(this);

        this.client = this.args.client;
        this.engine = this.client.engine;
        this.view = this.client.view;

        var sharepanel = elation.ui.panel({
          orientation: 'vertical',
          classname: 'engine_config_section',
          append: this
        });

        var sharepicker = this.client.sharepicker;
        if (!sharepicker) {
          this.client.createSharePicker();
          sharepicker = this.client.sharepicker;
        }
        var foo = sharepicker.showTargetSelector('image/png', sharepanel).then(function(f) {
          console.log('mfing ya', f);
        });

      // Capture Settings
/*
      var capturelabel = elation.ui.labeldivider({
        append: capturepanel,
        label: 'Capture Settings'
      });
      var codec = elation.ui.select({
        append: capturepanel,
        label: 'Codec',
        items: ['h264','gif']
      });
      var fps = elation.ui.select({
        append: capturepanel,
        label: 'FPS',
        items: [5,10,25,30,45,60]
      });
*/
    }
  }, elation.ui.panel);
});

<commit_msg>Improved screenshot and equirectangular screenshots<commit_after>elation.require([ "ui.panel", "share.picker", "share.targets.imgur", "share.targets.dropbox", "share.targets.googledrive", "share.targets.youtube", "share.targets.file", "share.targets.facebook"], function() {
  elation.requireCSS(["engine.sharing"]);

  elation.component.add('engine.sharing', function() {
    this.init = function() {
      elation.engine.sharing.extendclass.init.call(this);
      this.client = this.args.client;
    }
    this.showShareDialog = function() {
      if (!this.dialog) {
        this.dialog = elation.engine.sharing.dialog({append: document.body, client: this.client, anchor: this.args.anchor});
      } else {
        this.dialog.show();
      }
    }
    this.share = function(data) {
      this.showShareDialog();
      this.dialog.share(data);
    }
  }, elation.ui.base);
  elation.component.add('engine.sharing.dialog', function() {
    this.init = function() {
      this.client = this.args.client;

      this.anchor = this.args.anchor;

      var bottom = 100;

      this.args.title = 'Sharing Options';
      this.args.right = true;
      this.args.bottom = bottom;
      this.args.minimize = false;
      this.args.maximize = false;
      this.args.resizable = false;
      elation.engine.sharing.dialog.extendclass.init.call(this);
      this.addclass('engine_sharing');

      this.initPicker();

      this.sharetypes = {
        link: elation.engine.sharing.share_link({client: this.client, picker: this.sharepicker}),
        screenshot: elation.engine.sharing.share_screenshot({client: this.client, picker: this.sharepicker}),
        screenshot360: elation.engine.sharing.share_screenshot360({client: this.client, picker: this.sharepicker}),
        video: elation.engine.sharing.share_video({client: this.client, picker: this.sharepicker}),
      };
      this.selected = 'screenshot';

      this.tabs = elation.ui.tabbedcontent({
        append: this,
        items: [
          { name: 'link', label: 'Link', content: this.sharetypes.link },
          { name: 'screenshot', label: 'Screenshot', content: this.sharetypes.screenshot },
          { name: 'screenshot360', label: '360 Screenshot', content: this.sharetypes.screenshot360 },
          { name: 'video', label: 'Video', content: this.sharetypes.video, disabled: true },
        ],
        selected: this.selected,
        events: {
          tab_change: elation.bind(this, function(ev) { this.selected = ev.data.name; })
        }
      });
      this.setcontent(this.tabs);
    }
    this.initPicker = function() {
      this.sharepicker = elation.share.picker({append: document.body});
      var share = elation.config.get('share'),
          targets = share.targets || {};

      for (var k in targets) {
        var target = targets[k];
        if (!target.disabled && elation.share.targets[k]) {
          this.sharepicker.addShareTarget(elation.share.targets[k](target));
        }
      }
      console.log('did the picker', this.sharepicker);
    }
    this.share = function(data) {
      var type = this.selected;
      console.log('sharetype', type, this.sharetypes[type], this.tabs)
      if (this.sharetypes[type]) {
        this.sharetypes[type].share(data);
      }
    }
  }, elation.ui.window);
  elation.component.add('engine.sharing.share_link', function() {
    this.init = function() {
      elation.engine.sharing.share_link.extendclass.init.call(this);
      this.client = this.args.client;
      this.janusweb = this.client.janusweb;

      this.link = elation.ui.input({
        append: this,
        label: 'URL',
        value: this.janusweb.currentroom.url
      });
      this.button = elation.ui.button({
        append: this,
        label: 'Share'
      });
      this.addclass('engine_sharing_link');
    }
    this.share = function(data) {
    }
  }, elation.ui.panel_horizontal);
  elation.component.add('engine.sharing.share_screenshot', function() {
    this.init = function() {
      elation.engine.sharing.share_screenshot.extendclass.init.call(this);

      this.client = this.args.client;
      this.picker = this.args.picker;

      var resolutions = ['(window)', '512x256', '1280x720', '1920x1080', '3840x2160', '7680x4320'];
      var formats = ['png', 'jpg'];

      var panel = elation.ui.panel_horizontal({
        append: this
      });
      this.resolution = elation.ui.select({
        append: panel,
        label: 'Resolution',
        classname: 'engine_sharing_screenshot_resolution',
        items: resolutions,
        selected: resolutions[0]
      });
      this.format = elation.ui.select({
        append: panel,
        label: 'Format',
        items: formats,
        selected: 'png'
      });
      this.button = elation.ui.button({
        append: panel,
        label: 'Capture',
        events: {
          click: elation.bind(this, this.share)
        }
      });

      this.addclass('engine_sharing_screenshot');
    }
    this.share = function() {
      var client = this.client;
      var width = window.innerWidth,
          height = window.innerHeight;
      if (this.resolution.value != '(window)') {
        var size = this.resolution.value.split('x');
        width = size[0];
        height = size[1];
        client.view.setrendersize(width, height);
        // Force a render after resizing
        client.view.render(0);
      }

      client.screenshot({width: width, height: height, format: this.format.value}).then(elation.bind(this, function(data) {
        var imgdata = data.split(',')[1]; //data.image.data;

        var bytestr = atob(imgdata);
        var img = new Uint8Array(bytestr.length);
        for (var i = 0; i < bytestr.length; i++) {
          img[i] = bytestr.charCodeAt(i);
        }

        var mimes = {
          png: 'image/png',
          jpg: 'image/jpeg'
        };
        client.player.disable();
        this.picker.share({
          name: this.getScreenshotFilename(this.format.value),
          type: mimes[this.format.value],
          image: img,
        }).then(elation.bind(this, function(upload) {
          //this.player.enable();
        }));
        var now = new Date().getTime();
        //console.log('finished png in ' + data.time.toFixed(2) + 'ms');
        console.log('finished screenshot');
        client.view.setrendersize(window.innerWidth, window.innerHeight);
      }));
    }
    this.getScreenshotFilename = function(extension) {
      if (!extension) extension = 'png';
      var now = new Date();
      function pad(n) {
        if (n < 10) return '0' + n;
        return n;
      }
      var prefix = elation.config.get('engine.screenshot.prefix', 'screenshot');
      var date = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate());
      var time = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
      var filename = prefix + '-' + date + ' ' + time + '.' + extension
      return filename;
    }
  }, elation.ui.panel_vertical);
  elation.component.add('engine.sharing.share_screenshot360', function() {
    this.init = function() {
      elation.engine.sharing.share_screenshot360.extendclass.init.call(this);
      this.client = this.args.client;
      this.picker = this.args.picker;

      this.xmlns = {
        'GPano': 'http://ns.google.com/photos/1.0/panorama/'
      };

      var mappings = ['equirectangular', 'cubemap'],
          resolutions = ['512', '1024', '2048', '4096', '8192'],
          formats = ['PNG', 'JPEG'];

      var panel = elation.ui.panel_horizontal({
        append: this
      });

      this.mapping = elation.ui.select({
        append: panel,
        label: 'Type',
        items: mappings
      });
      this.resolution = elation.ui.select({
        append: panel,
        label: 'Resolution',
        selected: '4096',
        items: resolutions
      });
      this.format = elation.ui.select({
        append: panel,
        label: 'Format',
        items: formats
      });

      this.button = elation.ui.button({
        append: panel,
        label: 'Capture',
        events: {
          click: elation.bind(this, this.share)
        }
      });

      this.addclass('engine_sharing_screenshot360');
    }
    this.share = function() {
      var client = this.client;
      var width = this.resolution.value,
          height = this.resolution.value / 2;
      client.screenshot({type: 'equirectangular', format: 'jpg'}).then(elation.bind(this, function(data) {
        var imgdata = data.split(',')[1]; //data.image.data;

        var bytestr = atob(imgdata);
        var img = new Uint8Array(bytestr.length);
        var lastbyte = null;
        var inject = false;

        // merge the panorama exif data inito image binary data
        // FIXME - could be made more efficient!

        var offset = 0;
        for (var i = 0; i < bytestr.length; i++) {
          var byte = img[i+offset] = bytestr.charCodeAt(i);
          if (lastbyte == 0xff && (byte == 0xc0 || byte == 0xc2 || byte == 0xda)) {
            console.log('found exif thing', i);
            if (!inject) {
              inject = i-1;
            }
          }
          lastbyte = byte;
        }
        if (inject) {
          var xmp = this.getXMPBytes(data);
          offset = xmp.length;
          var newimg = new Uint8Array(bytestr.length + xmp.length);
          newimg.set(img.subarray(0, inject, 0));
          newimg.set(xmp, inject);
          newimg.set(img.subarray(inject), inject + offset);
          img = newimg;
        }

        client.player.disable();
        this.picker.share({
          name: this.getScreenshotFilename('jpg'),
          type: 'image/jpg',
          image: img,
          //imageb64: data,
          width: width,
          height: height,
        }).then(elation.bind(this, function(upload) {
          //this.player.enable();
        }));
      }));
    }
    this.getXMPBytes = function(data) {
      var xmp = {
        'GPano:ProjectionType': 'equirectangular',
      };
      var xmpStr = this.getXMPString(xmp);
      var xmpData= this.buildXMPsegments(xmpStr);

      var len = 0;
      for (var i = 0; i < xmpData.length; i++) {
        len += xmpData[i].length;
      }
      var bytes = new Uint8Array(len);
      var offset = 0;
      for (var i = 0; i < xmpData.length; i++) {
        var d = xmpData[i];
        for (var j = 0; j < d.length; j++) {
          bytes[offset++] = d[j];
        }
      }

      return bytes;
    }
    this.getXMPString = function(props, xmlns) {
      var xmp = [], k;
      xmlns = xmlns || this.xmlns;
      xmp.push('<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.1.0-jc003">');
      xmp.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">');
      xmp.push('<rdf:Description rdf:about=""');
      for (k in xmlns) {
        xmp.push(' xmlns:', k, '="', xmlns[k], '"');
      }
      for (k in props) {
        // TODO html entities escaping
        xmp.push(' ', k, '="' + props[k] + '"');
      }
      xmp.push(' /></rdf:RDF></x:xmpmeta>');
      return xmp.join('');
    }

    this.buildXMPsegments = function(standardXMP) {
      var extendedUid, parts = [];
      console.log('StandardXMP: ', standardXMP.length);

      var xmpHeader = 'http://ns.adobe.com/xap/1.0/';

      parts.push(new Uint8Array([0xFF, 0xE1]));
      parts.push(this.makeUint16Buffer([2 + xmpHeader.length + 1 + standardXMP.length]));
      parts.push(this.stringToUint8Array(xmpHeader), new Uint8Array([0x00]));
      parts.push(this.stringToUint8Array(standardXMP));
      console.log('Written standardXMP');
      return parts;
    },

    this.makeUint16Buffer = function(arr, littleEndian) {
      var ab = new ArrayBuffer(arr.length * 2),
          dv = new DataView(ab);
      for (var i = 0; i < arr.length; ++i) {
        dv.setUint16(i * 2, arr[i], littleEndian);
      }
      return new Uint8Array(ab);
    }
    this.stringToUint8Array = function(str) {
      var arr = new Uint8Array(str.length);
      for (var i = 0; i < str.length; i++) {
        arr[i] = str.charCodeAt(i);
      }
      return arr;
    }

    this.getScreenshotFilename = function(extension) {
      if (!extension) extension = 'jpg';
      var now = new Date();
      function pad(n) {
        if (n < 10) return '0' + n;
        return n;
      }
      var prefix = elation.config.get('engine.screenshot.prefix', 'screenshot');
      var date = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate());
      var time = pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());
      var filename = prefix + '-equirectangular-' + date + ' ' + time + '.' + extension
      return filename;
    }
  }, elation.ui.panel);
  elation.component.add('engine.sharing.share_video', function() {
    this.init = function() {
      elation.engine.sharing.share_video.extendclass.init.call(this);
      this.client = this.args.client;

      this.addclass('engine_sharing_video');
    }
    this.share = function(data) {
    }
  }, elation.ui.panel);

  elation.component.add('engine.sharing.sharebutton', function() {
    this.init = function() {
      var type = this.args.type,
          picker = this.args.picker;

      var targets = picker.getTargetsForType(type);

      var button = elation.ui.button({
        append: this,
        label: 'Share on'
      });
      this.targets = elation.ui.select({
        append: this,
        items: targets
      });
    }
  }, elation.ui.panel_horizontal);

  elation.component.add('engine.sharing.config', function() {
    this.init = function() {
        this.args.orientation = 'vertical'
        elation.engine.sharing.config.extendclass.init.call(this);

        this.client = this.args.client;
        this.engine = this.client.engine;
        this.view = this.client.view;

        var sharepanel = elation.ui.panel({
          orientation: 'vertical',
          classname: 'engine_config_section',
          append: this
        });

        var sharepicker = this.client.sharepicker;
        if (!sharepicker) {
          this.client.createSharePicker();
          sharepicker = this.client.sharepicker;
        }
        var foo = sharepicker.showTargetSelector('image/png', sharepanel).then(function(f) {
          console.log('mfing ya', f);
        });

      // Capture Settings
/*
      var capturelabel = elation.ui.labeldivider({
        append: capturepanel,
        label: 'Capture Settings'
      });
      var codec = elation.ui.select({
        append: capturepanel,
        label: 'Codec',
        items: ['h264','gif']
      });
      var fps = elation.ui.select({
        append: capturepanel,
        label: 'FPS',
        items: [5,10,25,30,45,60]
      });
*/
    }
  }, elation.ui.panel);
});

<|endoftext|>


<commit_before><commit_msg>Update variable-data-types.js<commit_after><|endoftext|>


<commit_before>'use strict';

/**
 * ButtressJS - Realtime datastore for software
 *
 * @file schemaModel.js
 * @description A default model for schemas
 * @module Model
 * @exports model, schema, constants
 * @author Chris Bates-Keegan
 *
 */

const ObjectId = require('mongodb').ObjectId;
// const Logging = require('../logging');
const Shared = require('./shared');
const Sugar = require('sugar');
const Helpers = require('../helpers');
const shortId = require('../helpers').shortId;

/* ********************************************************************************
 *
 * LOCALS
 *
 **********************************************************************************/

class SchemaModel {
	constructor(MongoDb, schemaData, app) {
		this.schemaData = schemaData;
		this.flatSchemaData = Helpers.getFlattenedSchema(this.schemaData);

		this.app = app || null;

		this.appShortId = (app) ? shortId(app._id) : null;
		this.collectionName = `${schemaData.collection}`;

		if (this.appShortId) {
			this.collectionName = `${this.appShortId}-${this.collectionName}`;
		}

		this.collection = MongoDb.collection(this.collectionName);
	}

	__doValidation(body) {
		const res = {
			isValid: true,
			missing: [],
			invalid: [],
		};

		const app = Shared.validateAppProperties(this.schemaData, body);
		if (app.isValid === false) {
			res.isValid = false;
			res.invalid = res.invalid.concat(app.invalid);
			res.missing = res.missing.concat(app.missing);
		}

		return res;
	}
	validate(body) {
		if (body instanceof Array === false) {
			body = [body];
		}
		const validation = body.map((b) => this.__doValidation(b)).filter((v) => v.isValid === false);

		return validation.length >= 1 ? validation[0] : {isValid: true};
	}

	static parseQuery(query, envFlat = {}, schemaFlat = {}) {
		const output = {};

		for (const property in query) {
			if (!{}.hasOwnProperty.call(query, property)) continue;
			const command = query[property];

			if (property === '$or' && Array.isArray(command)) {
				output['$or'] = command.map((q) => SchemaModel.parseQuery(q, envFlat, schemaFlat));
			} else if (property === '$and' && Array.isArray(command)) {
				output['$and'] = command.map((q) => SchemaModel.parseQuery(q, envFlat, schemaFlat));
			} else {
				for (let operator in command) {
					if (!{}.hasOwnProperty.call(command, operator)) continue;
					let operand = command[operator];
					switch (operator) {
					case '$not':
						operator = '$ne';
						break;

					case '$elMatch':
						operator = '$elemMatch';
						break;

					default:
					}
					// operator = (operator === '$not')? '$ne' : operator;
					// operator = (operator === '$elMatch')? '$elemMatch' : operator;

					// Check to see if operand is a path and fetch value
					if (operand && operand.indexOf && operand.indexOf('.') !== -1) {
						let path = operand.split('.');
						const key = path.shift();

						path = path.join('.');

						if (key === 'env' && envFlat[path]) {
							operand = envFlat[path];
						} else {
							// throw new Error(`Unable to find ${path} in schema.authFilter.env`);
						}
					}

					// Check the property type of what we are trying to fetch
					if (!schemaFlat[property]) {
						// TODO: Should maybe reject
					}

					if (schemaFlat[property]) {
						if (schemaFlat[property].__type === 'array' && schemaFlat[property].__schema) {
							Object.keys(operand).forEach((op) => {
								if (schemaFlat[property].__schema[op].__type === 'id') {
									Object.keys(operand[op]).forEach((key) => {
										operand[op][key] = new ObjectId(operand[op][key]);
									});
								}
							});
						}

						if ((schemaFlat[property].__type === 'id' || schemaFlat[property].__itemtype === 'id') && typeof operand === 'string') {
							operand = new ObjectId(operand);
						}
						if (schemaFlat[property].__type === 'id' && Array.isArray(operand)) {
							operand = operand.map((o) => new ObjectId(o));
						}
					}

					// Check the property type of what we are trying to fetch
					if (!schemaFlat[property]) {
						// TODO: Should maybe reject
					}

					if (schemaFlat[property]) {
						if (schemaFlat[property].__type === 'id' && typeof operand === 'string') {
							operand = new ObjectId(operand);
						}
					}

					if (!output[property]) {
						output[property] = {};
					}

					if (operator.indexOf('$') !== 0) {
						output[property][`$${operator}`] = operand;
					} else {
						output[property][`${operator}`] = operand;
					}
				}
			}
		}

		return output;
	}

	generateRoleFilterQuery(token, roles, Model) {
		if (!roles.schema || !roles.schema.authFilter) {
			return Promise.resolve({});
		}

		const env = {
			authUserId: token._user,
		};

		const tasks = [];

		if (roles.schema.authFilter.env) {
			for (const property in roles.schema.authFilter.env) {
				if (!{}.hasOwnProperty.call(roles.schema.authFilter.env, property)) continue;
				const query = roles.schema.authFilter.env[property];

				let propertyMap = '_id';
				if (query.map) {
					propertyMap = query.map;
				}
				for (const command in query) {
					if (!{}.hasOwnProperty.call(query, command)) continue;

					if (command.includes('schema.')) {
						const commandPath = command.split('.');
						commandPath.shift(); // Remove "schema"
						const collectionName = commandPath.shift();
						const collectionPath = `${this.appShortId}-${collectionName}`;
						const collection = Model[collectionPath];

						if (!collection) {
							throw new Error(`Unable to find a collection named ${collectionName} while building authFilter.env`);
						}

						const propertyPath = commandPath.join('.');

						let propertyQuery = {};
						propertyQuery[propertyPath] = query[command];
						propertyQuery = SchemaModel.parseQuery(propertyQuery, env);

						const fields = {};
						fields[propertyPath] = true;

						tasks.push(() => {
							return collection.find(propertyQuery, fields)
								.then((res) => {
									// Map fetched properties into a array.
									env[property] = res.map((i) => i[propertyMap]);
									// Hack - Flattern any sub arrays down to the single level.
									env[property] = [].concat(...env[property]);
								});
						});
					} else {
						// Unknown operation
					}
				}
			}
		}

		// Engage.
		return tasks.reduce((prev, task) => prev.then(() => task()), Promise.resolve())
			.then(() => SchemaModel.parseQuery(roles.schema.authFilter.query, env, this.flatSchemaData));
	}

	/*
	* @param {Object} body - body passed through from a POST request
	* @return {Promise} - returns a promise that is fulfilled when the database request is completed
	*/
	__add(body, internals) {
		return (prev) => {
			const entity = Object.assign({}, internals);

			if (body.id) {
				entity._id = new ObjectId(body.id);
			}

			if (this.schemaData.extends && this.schemaData.extends.includes('timestamps')) {
				entity.createdAt = Sugar.Date.create();
				entity.updatedAt = (body.updatedAt) ? Sugar.Date.create(body.updatedAt) : null;
			}

			const validated = Shared.applyAppProperties(this.schemaData, body);
			return prev.concat([Object.assign(validated, entity)]);
		};
	}
	add(body, internals) {
		const sharedAddFn = Shared.add(this.collection, (item) => this.__add(item, internals));
		return sharedAddFn(body);
	}

	update(query, id) {
		// Logging.logSilly(`update: ${this.collectionName} ${id} ${query}`);

		return new Promise((resolve, reject) => {
			this.collection.updateOne({_id: id}, {
				$set: query,
			}, (err, object) => {
				if (err) throw new Error(err);

				resolve(object);
			});
		});
	}
	validateUpdate(body) {
		const sharedFn = Shared.validateUpdate({}, this.schemaData);
		return sharedFn(body);
	}
	updateByPath(body, id) {
		const sharedFn = Shared.updateByPath({}, this.schemaData, this.collection);

		if (body instanceof Array === false) {
			body = [body];
		}

		if (this.schemaData.extends && this.schemaData.extends.includes('timestamps')) {
			body.push({
				path: 'updatedAt',
				value: new Date(),
				contextPath: '^updatedAt$',
			});
		}

		return sharedFn(body, id);
	}

	exists(id) {
		// Logging.logSilly(`exists: ${this.collectionName} ${id}`);

		return this.collection.find({_id: new ObjectId(id)})
			.limit(1)
			.count()
			.then((count) => count > 0);
	}

	/*
	* @return {Promise} - returns a promise that is fulfilled when the database request is completed
	*/
	isDuplicate(details) {
		return Promise.resolve(false);
	}

	/**
	 * @param {App} entity - entity object to be deleted
	 * @return {Promise} - returns a promise that is fulfilled when the database request is completed
	 */
	rm(entity) {
		// Logging.log(`DELETING: ${entity._id}`, Logging.Constants.LogLevel.DEBUG);
		return new Promise((resolve) => {
			this.collection.deleteOne({_id: new ObjectId(entity._id)}, (err, cursor) => {
				if (err) throw err;
				resolve(cursor);
			});
		});
	}

	/**
	 * @param {Array} ids - Array of entity ids to delete
	 * @return {Promise} - returns a promise that is fulfilled when the database request is completed
	 */
	rmBulk(ids) {
		// Logging.log(`rmBulk: ${this.collectionName} ${ids}`, Logging.Constants.LogLevel.SILLY);
		return this.rmAll({_id: {$in: ids}});
	}

	/*
	 * @param {Object} query - mongoDB query
	 * @return {Promise} - returns a promise that is fulfilled when the database request is completed
	 */
	rmAll(query) {
		if (!query) query = {};
		// Logging.logSilly(`rmAll: ${this.collectionName} ${query}`);

		return new Promise((resolve) => {
			this.collection.deleteMany(query, (err, doc) => {
				if (err) throw err;
				resolve(doc);
			});
		});
	}

	/**
	 * @param {String} id - entity id to get
	 * @return {Promise} - resolves to an array of Companies
	 */
	findById(id) {
		// Logging.logSilly(`Schema:findById: ${this.collectionName} ${id}`);

		return new Promise((resolve) => {
			this.collection.findOne({_id: new ObjectId(id)}, {}, (err, doc) => {
				if (err) throw err;
				resolve(doc);
			});
		});
	}

	/**
	 * @param {Object} query - mongoDB query
	 * @param {Object} excludes - mongoDB query excludes
	 * @param {Boolean} stream - should return a stream
	 * @return {Promise} - resolves to an array of docs
	 */
	find(query, excludes = {}, stream = false) {
		// Logging.logSilly(`find: ${this.collectionName} ${query}`);

		if (stream) {
			return this.collection.find(query, excludes);
		}

		return new Promise((resolve) => {
			this.collection.find(query, excludes).toArray((err, doc) => {
				if (err) throw err;
				resolve(doc);
			});
		});
	}

	/**
	 * @param {Object} query - mongoDB query
	 * @param {Object} excludes - mongoDB query excludes
	 * @return {Promise} - resolves to an array of docs
	 */
	findOne(query, excludes = {}) {
		// Logging.logSilly(`findOne: ${this.collectionName} ${query}`);

		return new Promise((resolve) => {
			this.collection.find(query, excludes).toArray((err, doc) => {
				if (err) throw err;
				resolve(doc[0]);
			});
		});
	}

	/**
	 * @return {Promise} - resolves to an array of Companies
	 */
	findAll() {
		// Logging.logSilly(`findAll: ${this.collectionName}`);

		return this.collection.find({});
	}

	/**
	 * @param {Array} ids - Array of entities ids to get
	 * @return {Promise} - resolves to an array of Companies
	 */
	findAllById(ids) {
		// Logging.logSilly(`update: ${this.collectionName} ${ids}`);

		return this.collection.find({_id: {$in: ids.map((id) => new ObjectId(id))}}, {});
	}
}

module.exports = SchemaModel;
<commit_msg>TWEAK: convert $rex Buttress to $regex mongo<commit_after>'use strict';

/**
 * ButtressJS - Realtime datastore for software
 *
 * @file schemaModel.js
 * @description A default model for schemas
 * @module Model
 * @exports model, schema, constants
 * @author Chris Bates-Keegan
 *
 */

const ObjectId = require('mongodb').ObjectId;
// const Logging = require('../logging');
const Shared = require('./shared');
const Sugar = require('sugar');
const Helpers = require('../helpers');
const shortId = require('../helpers').shortId;

/* ********************************************************************************
 *
 * LOCALS
 *
 **********************************************************************************/

class SchemaModel {
	constructor(MongoDb, schemaData, app) {
		this.schemaData = schemaData;
		this.flatSchemaData = Helpers.getFlattenedSchema(this.schemaData);

		this.app = app || null;

		this.appShortId = (app) ? shortId(app._id) : null;
		this.collectionName = `${schemaData.collection}`;

		if (this.appShortId) {
			this.collectionName = `${this.appShortId}-${this.collectionName}`;
		}

		this.collection = MongoDb.collection(this.collectionName);
	}

	__doValidation(body) {
		const res = {
			isValid: true,
			missing: [],
			invalid: [],
		};

		const app = Shared.validateAppProperties(this.schemaData, body);
		if (app.isValid === false) {
			res.isValid = false;
			res.invalid = res.invalid.concat(app.invalid);
			res.missing = res.missing.concat(app.missing);
		}

		return res;
	}
	validate(body) {
		if (body instanceof Array === false) {
			body = [body];
		}
		const validation = body.map((b) => this.__doValidation(b)).filter((v) => v.isValid === false);

		return validation.length >= 1 ? validation[0] : {isValid: true};
	}

	static parseQuery(query, envFlat = {}, schemaFlat = {}) {
		const output = {};

		for (const property in query) {
			if (!{}.hasOwnProperty.call(query, property)) continue;
			const command = query[property];

			if (property === '$or' && Array.isArray(command)) {
				output['$or'] = command.map((q) => SchemaModel.parseQuery(q, envFlat, schemaFlat));
			} else if (property === '$and' && Array.isArray(command)) {
				output['$and'] = command.map((q) => SchemaModel.parseQuery(q, envFlat, schemaFlat));
			} else {
				for (let operator in command) {
					if (!{}.hasOwnProperty.call(command, operator)) continue;
					let operand = command[operator];
					switch (operator) {
					case '$not':
						operator = '$ne';
						break;

					case '$elMatch':
						operator = '$elemMatch';
						break;

					case '$rex':
						operator = '$regex';
						break;

					default:
					}

					// Check to see if operand is a path and fetch value
					if (operand && operand.indexOf && operand.indexOf('.') !== -1) {
						let path = operand.split('.');
						const key = path.shift();

						path = path.join('.');

						if (key === 'env' && envFlat[path]) {
							operand = envFlat[path];
						} else {
							// throw new Error(`Unable to find ${path} in schema.authFilter.env`);
						}
					}

					// Check the property type of what we are trying to fetch
					if (!schemaFlat[property]) {
						// TODO: Should maybe reject
					}

					if (schemaFlat[property]) {
						if (schemaFlat[property].__type === 'array' && schemaFlat[property].__schema) {
							Object.keys(operand).forEach((op) => {
								if (schemaFlat[property].__schema[op].__type === 'id') {
									Object.keys(operand[op]).forEach((key) => {
										operand[op][key] = new ObjectId(operand[op][key]);
									});
								}
							});
						}

						if ((schemaFlat[property].__type === 'id' || schemaFlat[property].__itemtype === 'id') && typeof operand === 'string') {
							operand = new ObjectId(operand);
						}
						if (schemaFlat[property].__type === 'id' && Array.isArray(operand)) {
							operand = operand.map((o) => new ObjectId(o));
						}
					}

					// Check the property type of what we are trying to fetch
					if (!schemaFlat[property]) {
						// TODO: Should maybe reject
					}

					if (schemaFlat[property]) {
						if (schemaFlat[property].__type === 'id' && typeof operand === 'string') {
							operand = new ObjectId(operand);
						}
					}

					if (!output[property]) {
						output[property] = {};
					}

					if (operator.indexOf('$') !== 0) {
						output[property][`$${operator}`] = operand;
					} else {
						output[property][`${operator}`] = operand;
					}
				}
			}
		}

		return output;
	}

	generateRoleFilterQuery(token, roles, Model) {
		if (!roles.schema || !roles.schema.authFilter) {
			return Promise.resolve({});
		}

		const env = {
			authUserId: token._user,
		};

		const tasks = [];

		if (roles.schema.authFilter.env) {
			for (const property in roles.schema.authFilter.env) {
				if (!{}.hasOwnProperty.call(roles.schema.authFilter.env, property)) continue;
				const query = roles.schema.authFilter.env[property];

				let propertyMap = '_id';
				if (query.map) {
					propertyMap = query.map;
				}
				for (const command in query) {
					if (!{}.hasOwnProperty.call(query, command)) continue;

					if (command.includes('schema.')) {
						const commandPath = command.split('.');
						commandPath.shift(); // Remove "schema"
						const collectionName = commandPath.shift();
						const collectionPath = `${this.appShortId}-${collectionName}`;
						const collection = Model[collectionPath];

						if (!collection) {
							throw new Error(`Unable to find a collection named ${collectionName} while building authFilter.env`);
						}

						const propertyPath = commandPath.join('.');

						let propertyQuery = {};
						propertyQuery[propertyPath] = query[command];
						propertyQuery = SchemaModel.parseQuery(propertyQuery, env);

						const fields = {};
						fields[propertyPath] = true;

						tasks.push(() => {
							return collection.find(propertyQuery, fields)
								.then((res) => {
									// Map fetched properties into a array.
									env[property] = res.map((i) => i[propertyMap]);
									// Hack - Flattern any sub arrays down to the single level.
									env[property] = [].concat(...env[property]);
								});
						});
					} else {
						// Unknown operation
					}
				}
			}
		}

		// Engage.
		return tasks.reduce((prev, task) => prev.then(() => task()), Promise.resolve())
			.then(() => SchemaModel.parseQuery(roles.schema.authFilter.query, env, this.flatSchemaData));
	}

	/*
	* @param {Object} body - body passed through from a POST request
	* @return {Promise} - returns a promise that is fulfilled when the database request is completed
	*/
	__add(body, internals) {
		return (prev) => {
			const entity = Object.assign({}, internals);

			if (body.id) {
				entity._id = new ObjectId(body.id);
			}

			if (this.schemaData.extends && this.schemaData.extends.includes('timestamps')) {
				entity.createdAt = Sugar.Date.create();
				entity.updatedAt = (body.updatedAt) ? Sugar.Date.create(body.updatedAt) : null;
			}

			const validated = Shared.applyAppProperties(this.schemaData, body);
			return prev.concat([Object.assign(validated, entity)]);
		};
	}
	add(body, internals) {
		const sharedAddFn = Shared.add(this.collection, (item) => this.__add(item, internals));
		return sharedAddFn(body);
	}

	update(query, id) {
		// Logging.logSilly(`update: ${this.collectionName} ${id} ${query}`);

		return new Promise((resolve, reject) => {
			this.collection.updateOne({_id: id}, {
				$set: query,
			}, (err, object) => {
				if (err) throw new Error(err);

				resolve(object);
			});
		});
	}
	validateUpdate(body) {
		const sharedFn = Shared.validateUpdate({}, this.schemaData);
		return sharedFn(body);
	}
	updateByPath(body, id) {
		const sharedFn = Shared.updateByPath({}, this.schemaData, this.collection);

		if (body instanceof Array === false) {
			body = [body];
		}

		if (this.schemaData.extends && this.schemaData.extends.includes('timestamps')) {
			body.push({
				path: 'updatedAt',
				value: new Date(),
				contextPath: '^updatedAt$',
			});
		}

		return sharedFn(body, id);
	}

	exists(id) {
		// Logging.logSilly(`exists: ${this.collectionName} ${id}`);

		return this.collection.find({_id: new ObjectId(id)})
			.limit(1)
			.count()
			.then((count) => count > 0);
	}

	/*
	* @return {Promise} - returns a promise that is fulfilled when the database request is completed
	*/
	isDuplicate(details) {
		return Promise.resolve(false);
	}

	/**
	 * @param {App} entity - entity object to be deleted
	 * @return {Promise} - returns a promise that is fulfilled when the database request is completed
	 */
	rm(entity) {
		// Logging.log(`DELETING: ${entity._id}`, Logging.Constants.LogLevel.DEBUG);
		return new Promise((resolve) => {
			this.collection.deleteOne({_id: new ObjectId(entity._id)}, (err, cursor) => {
				if (err) throw err;
				resolve(cursor);
			});
		});
	}

	/**
	 * @param {Array} ids - Array of entity ids to delete
	 * @return {Promise} - returns a promise that is fulfilled when the database request is completed
	 */
	rmBulk(ids) {
		// Logging.log(`rmBulk: ${this.collectionName} ${ids}`, Logging.Constants.LogLevel.SILLY);
		return this.rmAll({_id: {$in: ids}});
	}

	/*
	 * @param {Object} query - mongoDB query
	 * @return {Promise} - returns a promise that is fulfilled when the database request is completed
	 */
	rmAll(query) {
		if (!query) query = {};
		// Logging.logSilly(`rmAll: ${this.collectionName} ${query}`);

		return new Promise((resolve) => {
			this.collection.deleteMany(query, (err, doc) => {
				if (err) throw err;
				resolve(doc);
			});
		});
	}

	/**
	 * @param {String} id - entity id to get
	 * @return {Promise} - resolves to an array of Companies
	 */
	findById(id) {
		// Logging.logSilly(`Schema:findById: ${this.collectionName} ${id}`);

		return new Promise((resolve) => {
			this.collection.findOne({_id: new ObjectId(id)}, {}, (err, doc) => {
				if (err) throw err;
				resolve(doc);
			});
		});
	}

	/**
	 * @param {Object} query - mongoDB query
	 * @param {Object} excludes - mongoDB query excludes
	 * @param {Boolean} stream - should return a stream
	 * @return {Promise} - resolves to an array of docs
	 */
	find(query, excludes = {}, stream = false) {
		// Logging.logSilly(`find: ${this.collectionName} ${query}`);

		if (stream) {
			return this.collection.find(query, excludes);
		}

		return new Promise((resolve) => {
			this.collection.find(query, excludes).toArray((err, doc) => {
				if (err) throw err;
				resolve(doc);
			});
		});
	}

	/**
	 * @param {Object} query - mongoDB query
	 * @param {Object} excludes - mongoDB query excludes
	 * @return {Promise} - resolves to an array of docs
	 */
	findOne(query, excludes = {}) {
		// Logging.logSilly(`findOne: ${this.collectionName} ${query}`);

		return new Promise((resolve) => {
			this.collection.find(query, excludes).toArray((err, doc) => {
				if (err) throw err;
				resolve(doc[0]);
			});
		});
	}

	/**
	 * @return {Promise} - resolves to an array of Companies
	 */
	findAll() {
		// Logging.logSilly(`findAll: ${this.collectionName}`);

		return this.collection.find({});
	}

	/**
	 * @param {Array} ids - Array of entities ids to get
	 * @return {Promise} - resolves to an array of Companies
	 */
	findAllById(ids) {
		// Logging.logSilly(`update: ${this.collectionName} ${ids}`);

		return this.collection.find({_id: {$in: ids.map((id) => new ObjectId(id))}}, {});
	}
}

module.exports = SchemaModel;
<|endoftext|>


<commit_before><commit_msg>Update share header text<commit_after><|endoftext|>


<commit_before>// most of this code is taken from here:
// https://github.com/snorpey/CirclePackingJS/blob/master/js-module/web/js/PackedCircleManager.js
// by @onedayitwillmake / Mario Gonzalez with some changes by @snorpey

import PackedCircle from './PackedCircle.js';
import Vector from './Vector.js';

export default class PackedCircleManager {
	constructor () {
		this.allCircles = [ ];
		this.desiredTarget = new Vector( 0, 0 );
		this.bounds = { left: 0, top: 0, right: 0, bottom: 0 };

		// Number of passes for the centering and collision
		// algorithms - it's (O)logN^2 so use increase at your own risk!
		// Play with these numbers - see what works best for your project
		this.numberOfCenteringPasses = 1;
		this.numberOfCollisionPasses = 3;
	}

	/**
	 * Set the boundary rectangle for the circle packing.
	 * This is used to locate the 'center'
	 * @param aBoundaryObject
	 */
	setBounds ( aBoundaryObject ) {
		if ( typeof aBoundaryObject.left === 'number' ) {
			this.bounds.left = aBoundaryObject.left;
		}

		if ( typeof aBoundaryObject.right === 'number' ) {
			this.bounds.right = aBoundaryObject.right;
		}

		if ( typeof aBoundaryObject.top === 'number' ) {
			this.bounds.top = aBoundaryObject.top;
		}

		if ( typeof aBoundaryObject.bottom === 'number' ) {
			this.bounds.bottom = aBoundaryObject.bottom;
		}

		if ( typeof aBoundaryObject.width === 'number' ) {
			this.bounds.right = this.bounds.left + aBoundaryObject.width;
		}

		if ( typeof aBoundaryObject.height === 'number' ) {
			this.bounds.bottom = this.bounds.top + aBoundaryObject.height;
		}
	}

	/**
	 * Add a circle
	 * @param aCircle A Circle to add, should already be created.
	 */
	addCircle ( aCircle ) {
		if ( ! ( aCircle instanceof PackedCircle ) ) {
			aCircle = new PackedCircle( aCircle.id, aCircle.radius, aCircle.position.x, aCircle.position.y );
		}

		this.allCircles.push( aCircle );
		aCircle.targetPosition = this.desiredTarget.cp();
	}

	/**
	 * Remove a circle
	 * @param circleToRemoveId Id of the circle to remove
	 */
	removeCircle ( circleToRemoveId ) {
		const indicesToRemove = this.allCircles.reduce( ( indices, circle, index ) => {
			if ( circle.id === circleToRemoveId ) {
				indices.push( index );
			}

			return indices;
		}, [ ] );

		for ( let n = indicesToRemove.length - 1; n >= 0; n-- ) {
			this.allCircles.splice( indicesToRemove[n], 1 );
		}
	}

	/**
	 * Recalculate all circle positions
	 */
	updatePositions () {
		var circleList = this.allCircles;
		var circleCount = circleList.length;

		// store information about the previous position
		for ( let i = 0; i < circleCount; ++i ) {
			const circle = circleList[i];

			circle.previousPosition = circle.position.cp();
		}

		if ( this.desiredTarget ) {
			// Push all the circles to the target - in my case the center of the bounds
			this.pushAllCirclesTowardTarget( this.desiredTarget );
		}

		// Make the circles collide and adjust positions to move away from each other
		this.handleCollisions();

		// store information about the previous position
		for ( let i = 0; i < circleCount; ++i ) {
			const circle = circleList[i];

			this.handleBoundaryForCircle( circle );
		}
	}

	pushAllCirclesTowardTarget ( aTarget ) {
		var v = new Vector( 0, 0 );

		var dragCircle = this.draggedCircle;
		var circleList = this.allCircles;
		var circleCount = circleList.length;

		for ( var n = 0; n < this.numberOfCenteringPasses; n++ ) {
			var damping = 0.025;

			for ( var i = 0; i < circleCount; i++ ) {
				var circle = circleList[i];

				if ( circle === dragCircle ) {
					continue;
				}

				v.x = circle.position.x - aTarget.x;
				v.y = circle.position.y - aTarget.y;
				v.mul ( damping );

				circle.position.x -= v.x;
				circle.position.y -= v.y;
			}
		}
	}

	/**
	 * Packs the circles towards the center of the bounds.
	 * Each circle will have it's own 'targetPosition' later on
	 */
	handleCollisions () {
		var v = new Vector( 0, 0 );

		var dragCircle = this.draggedCircle;
		var circleList = this.allCircles;
		var circleCount = circleList.length;

		// Collide circles
		for ( var n = 0; n < this.numberOfCollisionPasses; n++ ) {
			for ( var i = 0; i < circleCount; i++ ) {
				var circleA = circleList[i];

				for ( var j = i + 1; j < circleCount; j++ ) {
					var circleB = circleList[j];

					if ( circleA === circleB ) {
						continue; // It's us!
					}

					var dx = circleB.position.x - circleA.position.x;
					var dy = circleB.position.y - circleA.position.y;

					// The distance between the two circles radii,
					// but we're also gonna pad it a tiny bit
					var r = ( circleA.radius + circleB.radius ) * 1.08;
					var d = circleA.position.distanceSquared( circleB.position );

					if ( d < ( r * r ) - 0.02 ) {
						v.x = dx;
						v.y = dy;
						v.normalize();

						var inverseForce = ( r - Math.sqrt( d ) ) * 0.5;
						v.mul( inverseForce );

						if ( circleB !== dragCircle ) {
							if ( circleA === dragCircle ) {
								// Double inverse force to make up
								// for the fact that the other object is fixed
								v.mul( 2.2 );
							}

							circleB.position.x += v.x;
							circleB.position.y += v.y;
						}

						if ( circleA !== dragCircle ) {
							if ( circleB === dragCircle ) {
								// Double inverse force to make up
								// for the fact that the other object is fixed
								v.mul( 2.2 );
							}

							circleA.position.x -= v.x;
							circleA.position.y -= v.y;
						}
					}
				}
			}
		}
	}

	handleBoundaryForCircle ( aCircle ) {
		let x = aCircle.position.x;
		let y = aCircle.position.y;

		const radius = aCircle.radius;
		let overEdge = false;

		if ( x + radius >= this.bounds.right ) {
			x = this.bounds.right - radius;
			overEdge = true;
		} else if ( x - radius < this.bounds.left ) {
			x = this.bounds.left + radius;
			overEdge = true;
		}

		if ( y + radius > this.bounds.bottom ) {
			y = this.bounds.bottom - radius;
			overEdge = true;
		} else if ( y - radius < this.bounds.top ) {
			y = this.bounds.top + radius;
			overEdge = true;
		}

		// end dragging if user dragged over edge
		if ( overEdge && aCircle === this.draggedCircle ) {
			this.draggedCircle = null;
		}
	}

	/**
	 * Force a certain circle to be the 'draggedCircle'.
	 * Can be used to undrag a circle by calling setDraggedCircle(null)
	 * @param aCircle  Circle to start dragging. It's assumed to be part of our list. No checks in place currently.
	 */
	setDraggedCircle ( aCircle ) {
		// Setting to null, and we had a circle before.
		// Restore the radius of the circle as it was previously
		if ( this.draggedCircle && this.draggedCircle !== aCircle ) {
			this.draggedCircle.radius = this.draggedCircle.originalRadius;
		}

		this.draggedCircle = aCircle;
	}

	dragStart ( id ) {
		const draggedCircle = this.allCircles.filter( c => { return c.id === id; } )[0];
		this.setDraggedCircle( draggedCircle );
	}

	dragEnd ( id ) {
		if ( this.draggedCircle ) {
			this.setDraggedCircle( null );
		}
	}

	drag ( id, position ) {
		if ( this.draggedCircle && position ) {
			this.draggedCircle.position.x = position.x;
			this.draggedCircle.position.y = position.y;
		}
	}

	/**
	 * Sets the target position where the circles want to be
	 * @param aPosition
	 */
	setTarget ( aPosition ) {
		this.desiredTarget = aPosition;
	}
}<commit_msg>some more boundary fixes<commit_after>// most of this code is taken from here:
// https://github.com/snorpey/CirclePackingJS/blob/master/js-module/web/js/PackedCircleManager.js
// by @onedayitwillmake / Mario Gonzalez with some changes by @snorpey

import PackedCircle from './PackedCircle.js';
import Vector from './Vector.js';

export default class PackedCircleManager {
	constructor () {
		this.allCircles = [ ];
		this.desiredTarget = new Vector( 0, 0 );
		this.bounds = { left: 0, top: 0, right: 0, bottom: 0 };

		// Number of passes for the centering and collision
		// algorithms - it's (O)logN^2 so use increase at your own risk!
		// Play with these numbers - see what works best for your project
		this.numberOfCenteringPasses = 1;
		this.numberOfCollisionPasses = 3;
	}

	/**
	 * Set the boundary rectangle for the circle packing.
	 * This is used to locate the 'center'
	 * @param aBoundaryObject
	 */
	setBounds ( aBoundaryObject ) {
		if ( typeof aBoundaryObject.left === 'number' ) {
			this.bounds.left = aBoundaryObject.left;
		}

		if ( typeof aBoundaryObject.right === 'number' ) {
			this.bounds.right = aBoundaryObject.right;
		}

		if ( typeof aBoundaryObject.top === 'number' ) {
			this.bounds.top = aBoundaryObject.top;
		}

		if ( typeof aBoundaryObject.bottom === 'number' ) {
			this.bounds.bottom = aBoundaryObject.bottom;
		}

		if ( typeof aBoundaryObject.width === 'number' ) {
			this.bounds.right = this.bounds.left + aBoundaryObject.width;
		}

		if ( typeof aBoundaryObject.height === 'number' ) {
			this.bounds.bottom = this.bounds.top + aBoundaryObject.height;
		}
	}

	/**
	 * Add a circle
	 * @param aCircle A Circle to add, should already be created.
	 */
	addCircle ( aCircle ) {
		if ( ! ( aCircle instanceof PackedCircle ) ) {
			aCircle = new PackedCircle( aCircle.id, aCircle.radius, aCircle.position.x, aCircle.position.y );
		}

		this.allCircles.push( aCircle );
		aCircle.targetPosition = this.desiredTarget.cp();
	}

	/**
	 * Remove a circle
	 * @param circleToRemoveId Id of the circle to remove
	 */
	removeCircle ( circleToRemoveId ) {
		const indicesToRemove = this.allCircles.reduce( ( indices, circle, index ) => {
			if ( circle.id === circleToRemoveId ) {
				indices.push( index );
			}

			return indices;
		}, [ ] );

		for ( let n = indicesToRemove.length - 1; n >= 0; n-- ) {
			this.allCircles.splice( indicesToRemove[n], 1 );
		}
	}

	/**
	 * Recalculate all circle positions
	 */
	updatePositions () {
		var circleList = this.allCircles;
		var circleCount = circleList.length;

		// store information about the previous position
		for ( let i = 0; i < circleCount; ++i ) {
			const circle = circleList[i];

			circle.previousPosition = circle.position.cp();
		}

		if ( this.desiredTarget ) {
			// Push all the circles to the target - in my case the center of the bounds
			this.pushAllCirclesTowardTarget( this.desiredTarget );
		}

		// Make the circles collide and adjust positions to move away from each other
		this.handleCollisions();

		// store information about the previous position
		for ( let i = 0; i < circleCount; ++i ) {
			const circle = circleList[i];

			this.handleBoundaryForCircle( circle );
		}
	}

	pushAllCirclesTowardTarget ( aTarget ) {
		var v = new Vector( 0, 0 );

		var dragCircle = this.draggedCircle;
		var circleList = this.allCircles;
		var circleCount = circleList.length;

		for ( var n = 0; n < this.numberOfCenteringPasses; n++ ) {
			var damping = 0.025;

			for ( var i = 0; i < circleCount; i++ ) {
				var circle = circleList[i];

				if ( circle === dragCircle ) {
					continue;
				}

				v.x = circle.position.x - aTarget.x;
				v.y = circle.position.y - aTarget.y;
				v.mul ( damping );

				circle.position.x -= v.x;
				circle.position.y -= v.y;
			}
		}
	}

	/**
	 * Packs the circles towards the center of the bounds.
	 * Each circle will have it's own 'targetPosition' later on
	 */
	handleCollisions () {
		var v = new Vector( 0, 0 );

		var dragCircle = this.draggedCircle;
		var circleList = this.allCircles;
		var circleCount = circleList.length;

		// Collide circles
		for ( var n = 0; n < this.numberOfCollisionPasses; n++ ) {
			for ( var i = 0; i < circleCount; i++ ) {
				var circleA = circleList[i];

				for ( var j = i + 1; j < circleCount; j++ ) {
					var circleB = circleList[j];

					if ( circleA === circleB ) {
						continue; // It's us!
					}

					var dx = circleB.position.x - circleA.position.x;
					var dy = circleB.position.y - circleA.position.y;

					// The distance between the two circles radii,
					// but we're also gonna pad it a tiny bit
					var r = ( circleA.radius + circleB.radius ) * 1.08;
					var d = circleA.position.distanceSquared( circleB.position );

					if ( d < ( r * r ) - 0.02 ) {
						v.x = dx;
						v.y = dy;
						v.normalize();

						var inverseForce = ( r - Math.sqrt( d ) ) * 0.5;
						v.mul( inverseForce );

						if ( circleB !== dragCircle ) {
							if ( circleA === dragCircle ) {
								// Double inverse force to make up
								// for the fact that the other object is fixed
								v.mul( 2.2 );
							}

							circleB.position.x += v.x;
							circleB.position.y += v.y;
						}

						if ( circleA !== dragCircle ) {
							if ( circleB === dragCircle ) {
								// Double inverse force to make up
								// for the fact that the other object is fixed
								v.mul( 2.2 );
							}

							circleA.position.x -= v.x;
							circleA.position.y -= v.y;
						}
					}
				}
			}
		}
	}

	handleBoundaryForCircle ( aCircle ) {
		const x = aCircle.position.x;
		const y = aCircle.position.y;
		const radius = aCircle.radius;

		let overEdge = false;

		if ( x + radius >= this.bounds.right ) {
			aCircle.position.x = this.bounds.right - radius;
			overEdge = true;
		} else if ( x - radius < this.bounds.left ) {
			aCircle.position.x = this.bounds.left + radius;
			overEdge = true;
		}

		if ( y + radius > this.bounds.bottom ) {
			aCircle.position.y = this.bounds.bottom - radius;
			overEdge = true;
		} else if ( y - radius < this.bounds.top ) {
			aCircle.position.y = this.bounds.top + radius;
			overEdge = true;
		}

		// end dragging if user dragged over edge
		if ( overEdge && aCircle === this.draggedCircle ) {
			this.draggedCircle = null;
		}
	}

	/**
	 * Force a certain circle to be the 'draggedCircle'.
	 * Can be used to undrag a circle by calling setDraggedCircle(null)
	 * @param aCircle  Circle to start dragging. It's assumed to be part of our list. No checks in place currently.
	 */
	setDraggedCircle ( aCircle ) {
		// Setting to null, and we had a circle before.
		// Restore the radius of the circle as it was previously
		if ( this.draggedCircle && this.draggedCircle !== aCircle ) {
			this.draggedCircle.radius = this.draggedCircle.originalRadius;
		}

		this.draggedCircle = aCircle;
	}

	dragStart ( id ) {
		const draggedCircle = this.allCircles.filter( c => { return c.id === id; } )[0];
		this.setDraggedCircle( draggedCircle );
	}

	dragEnd ( id ) {
		if ( this.draggedCircle ) {
			this.setDraggedCircle( null );
		}
	}

	drag ( id, position ) {
		if ( this.draggedCircle && position ) {
			this.draggedCircle.position.x = position.x;
			this.draggedCircle.position.y = position.y;
		}
	}

	/**
	 * Sets the target position where the circles want to be
	 * @param aPosition
	 */
	setTarget ( aPosition ) {
		this.desiredTarget = aPosition;
	}
}<|endoftext|>