<commit_before>define(["github/adioo/bind/v0.2.0/bind", "github/adioo/events/v0.1.0/events", "/jquery.js"], function(Bind, Events) {

    function Cart(module) {

        var self;
        var config;
        var container;
        var template;
        var items = [];

        function processConfig(config) {
            config.options = config.options || {};
            config.options.type = config.options.type || "cookie";

            if (config.options.type === "cookie") {
                config.options.cookie = "cart";
            }

            config.template.binds = config.template.binds || [];

            var optClasses = config.options.classes || {}
            optClasses.item = optClasses.item || "item";
            optClasses.empty = optClasses.empty || "empty";
            optClasses.content = optClasses.content || "content";
            optClasses.confirm = optClasses.config || "confirm";
            config.options.classes = optClasses;

            return config;
        }

        function init(conf) {

            // initialize the globals
            self = this;
            config = processConfig(conf);
            if (config.container) {
                container = $(config.container, module.dom);
            } else {
                container = module.dom;
            }
            template = $(config.template.value, module.dom);

            // **************************************
            // generate general binds from the config
            var binds = [];

            for (var i in config.controls) {
                switch (i) {
                    case "add":
                        binds.push({
                            target: config.controls[i],
                            context: ".controls",
                            on: [{
                                name: "click",
                                emit: "requestNewItem"
                            }]
                        });
                        break;
                    case "delete":
                        binds.push({
                            target: config.controls[i],
                            context: ".controls",
                            on: [{
                                name: "click",
                                handler: "removeSelected"
                            }]
                        });
                        break;
                }
            }

            // run the internal binds
            for (var i in binds) {
                Bind.call(self, binds[i]);
            }

            // run the binds
            for (var i in config.binds) {
                Bind.call(self, config.binds[i]);
            }

            Events.call(self, config);

            showEmpty(true);

            self.read();
        }

        // TODO call this from a checkout operation link response if success
        function checkoutDone() {
            clearList();
            items = [];
            if (config.options.type === "cookie") {
                $.cookie.json = true;
                $.cookie("cart", items, { path: "/" });
            }

            showError();
            showOrdered();
        }

        function checkout() {

            var agb = $(".agb", self.dom).find("input").andSelf().find("input[type='checkbox']");
            if (agb.length) {
                if (agb.is(":checked")) {
                    agb.get(0).checked = false;
                    checkoutDone();
                }
                else {
                    showError("Please agree to the terms and conditions");
                }
                return;
            }
            checkoutDone();
        }

        var renderers = {
            selector: function(item) {
                // TODO where do we know the key is the _id
                var existingItem = container.find("#" + item._id);

                // we only need an increment
                if (!existingItem.length) {

                    var newItem = $(template).clone();
                    newItem
                        .removeClass("template")
                        .addClass(config.options.classes.item)
                        .appendTo(container)
                        .show();

                    for (var i in config.template.binds) {
                        var bindObj = config.template.binds[i];
                        bindObj.context = newItem;
                        Bind.call(self, bindObj, item);
                    }

                    // now there should be an element with this id
                    existingItem = container.find("#" + item._id);
                }

                existingItem.find(".quantity").each(function() {

                    var elem = $(this);

                    switch (this.tagName) {
                        case "INPUT":
                            elem.attr("value", item.quantity);
                            elem.val(item.quantity);
                            break;
                        default:
                            elem.text(quantity);
                    }
                });

                return;
            }
        };

        function render(items) {
            if (!items || !items.length) {
                showEmpty(true);
                return;
            }

            showEmpty(false);

            var renderer = renderers[config.template.type];
            if (!renderer) {
                showError("No renderer found for templates of type: " + config.template.type);
            }
            for (var i in items) {
                renderer.call(self, items[i]);
            }
        }

        function renderItem(item) {

            if (!item) {
                return;
            }

            var renderer = renderers[config.template.type];
            if (!renderer) {
                showError("No renderer found for templates of type: " + config.template.type);
            }
            showEmpty(false);
            renderer.call(self, item);
        }

        function clearList() {
            $("." + config.options.classes.item, container).remove();
        }

        // ********************************
        // Public functions ***************
        // ********************************

        var readFrom = {
            memory: function(callback) {
                callback(null, items);
            },
            cookie: function(callback) {
                $.cookie.json = true;
                items = $.cookie(config.options.cookie) || [];
                callback(null, items);
            },
            server: function(callback) {
                self.link(config.crud.read, function(err, data) {
                    if (err) { return callback(err); }
                    items = [];
                    for (var i in data) {
                        items.push(data[i]);
                    }
                    callback(null, items);
                });
            }
        }

        function read() {

            clearList();

            var reader = readFrom[config.options.type];
            if (render) {
                reader.call(self, function(err, items) {
                    if (err) {
                        showError(JSON.stringify(err));
                        return;
                    }
                    render.call(self, items);
                });
            }
        }

        function showEmpty(empty) {
            if (empty) {
                $("." + config.options.classes.empty, self.dom).show();
                $("." + config.options.classes.content, self.dom).hide();
                $("." + config.options.classes.confirm, self.dom).hide();
            } else {
                $("." + config.options.classes.empty, self.dom).hide();
                $("." + config.options.classes.content, self.dom).show();
                $("." + config.options.classes.confirm, self.dom).hide();
            }
        }

        function showOrdered() {
            $("." + config.options.classes.empty, self.dom).hide();
            $("." + config.options.classes.content, self.dom).hide();
            $("." + config.options.classes.confirm, self.dom).show();
        }

        function showError(message) {
            if (!message) {
                $(".error").text("").hide();
            } else {
                $(".error").text(message).show();
            }
        }

        var adders = {
            cookie: function(item, callback) {
                $.cookie.json = true;
                var cart = $.cookie("cart") || [];
                var found = false;
                for (var i in cart) {
                    if (cart[i]._id === item._id) {
                        // TODO support incomming item.quantity
                        ++(cart[i].quantity);
                        item = cart[i];
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    item.quantity = 1;
                    cart.push(item);
                    item = cart[cart.length - 1];
                }

                $.cookie.json = true;
                $.cookie("cart", cart, { path: "/" });
                items = cart;

                callback(null, item);
            },

            server: function(item, callback) {
                self.link(config.crud.create, { data: item }, function(err, confirmedItem) {
                    if (err) { return callback(err); }

                    var found = false;
                    for (var i in items) {
                        if (items[i]._id === confirmedItem._id) {
                            items[i].confirmedItem;
                            found = true;
                        }
                    }

                    if (!found) {
                        items.push(confirmedItem);
                    }

                    callback(null, confirmedItem);
                });
            },

            memory: function(item, callback) {
                // TODO in memory type the quantity is saved in the memory object and will
                // be reused later, which is wrong
                var newItem = {};
                for (var i in item) {
                    newItem[i] = item[i];
                }
                item = newItem;

                var found = false;
                for (var i in items) {
                    if (items[i]._id === item._id) {
                        item = items[i];
                        ++(item.quantity);
                        found = true;
                    }
                }

                if (!found) {
                    item.quantity = 1;
                    items.push(item);
                }

                callback(null, item);
            }
        };

        function addItem(itemData) {
            showError();

            var adder = adders[config.options.type];
            if (!adder) {
                showError("No item adder was found for cart type: " + config.options.type);
                return;
            }
            adder.call(self, itemData, function(err, item) {
                if (err) {
                    showError(JSON.stringify(err));
                    return;
                }
                renderItem(item);
            });
        }

        function readQuantityFromItem(elem) {

            var quantityElem = elem.find(".quantity").first();
            if (!quantityElem.length) {
                return 1;
            }

            var value = 1;
            var textVal = null;

            switch (quantityElem[0].tagName) {
                case "INPUT":
                    textVal = quantityElem.val();
                    break;
                default:
                    textVal = quantityElem.text();
            }
            var parsedVal = parseInt(textVal);
            if (!isNaN(parsedVal)) {
                value = parsedVal + 1;
            }

            return value;
        }

        function removeItem(itemData) {
            showError();

            function removeUiItem() {
                // TODO where do we get the _id key from?
                container.find("#" + itemData._id).remove();

                // if no more items, show empty cart
                if (container.find("." + config.options.classes.item).length == 0) {
                    showEmpty(true);
                }
            }

            switch (config.options.type) {
                case "server":
                    self.link(config.crud.delete, { data: { _id: itemData._id } }, function(err, data) {
                        if (err) { return; }
                        removeUiItem();
                    });
                    break;

                case "memory":
                    // a memory-based cart should not make any requests, just remove the item
                    removeUiItem();
                    // and show an empty cart when no more items in it
                    var items = container.find("." + config.options.classes.item);
                    showEmpty(!items.length);
                    break;

                case "cookie":
                    // search in the cart cookie for the item with this ID and remove it
                    var cart = $.cookie("cart");
                    for (var i in cart) {
                        if (cart[i]._id === itemData._id) {
                            cart.splice(i, 1);
                            break;
                        }
                    }
                    // if the cart is already empty it should be displayed as so
                    showEmpty(!cart || !cart.length);
                    // save back the updated cart in the cookie
                    $.cookie("cart", cart, { path: "/"});
                    // and also remove the item from the UI
                    removeUiItem();
                    break;
            }
        }

        function show() {
            $(self.dom).parent().show();
        }

        function hide() {
            $(self.dom).parent().hide();
        }

         return {
            init: init,
            read: read,
            addItem: addItem,
            removeItem: removeItem,
            checkout: checkout,
            show: show,
            hide: hide
        };
    }

    return function(module, config) {

        var cart = new Cart(module);
        for (var i in cart) {
            cart[i] = module[i] || cart[i];
        }
        cart = Object.extend(cart, module);

        cart.init(config);

        return cart;
    }
});

<commit_msg>Forgot core version reference updates. Damn\! This is becomming annoying and needs a solution\!<commit_after>define(["github/adioo/bind/v0.2.1/bind", "github/adioo/events/v0.1.2/events", "/jquery.js"], function(Bind, Events) {

    function Cart(module) {

        var self;
        var config;
        var container;
        var template;
        var items = [];

        function processConfig(config) {
            config.options = config.options || {};
            config.options.type = config.options.type || "cookie";

            if (config.options.type === "cookie") {
                config.options.cookie = "cart";
            }

            config.template.binds = config.template.binds || [];

            var optClasses = config.options.classes || {}
            optClasses.item = optClasses.item || "item";
            optClasses.empty = optClasses.empty || "empty";
            optClasses.content = optClasses.content || "content";
            optClasses.confirm = optClasses.config || "confirm";
            config.options.classes = optClasses;

            return config;
        }

        function init(conf) {

            // initialize the globals
            self = this;
            config = processConfig(conf);
            if (config.container) {
                container = $(config.container, module.dom);
            } else {
                container = module.dom;
            }
            template = $(config.template.value, module.dom);

            // **************************************
            // generate general binds from the config
            var binds = [];

            for (var i in config.controls) {
                switch (i) {
                    case "add":
                        binds.push({
                            target: config.controls[i],
                            context: ".controls",
                            on: [{
                                name: "click",
                                emit: "requestNewItem"
                            }]
                        });
                        break;
                    case "delete":
                        binds.push({
                            target: config.controls[i],
                            context: ".controls",
                            on: [{
                                name: "click",
                                handler: "removeSelected"
                            }]
                        });
                        break;
                }
            }

            // run the internal binds
            for (var i in binds) {
                Bind.call(self, binds[i]);
            }

            // run the binds
            for (var i in config.binds) {
                Bind.call(self, config.binds[i]);
            }

            Events.call(self, config);

            showEmpty(true);

            self.read();
        }

        // TODO call this from a checkout operation link response if success
        function checkoutDone() {
            clearList();
            items = [];
            if (config.options.type === "cookie") {
                $.cookie.json = true;
                $.cookie("cart", items, { path: "/" });
            }

            showError();
            showOrdered();
        }

        function checkout() {

            var agb = $(".agb", self.dom).find("input").andSelf().find("input[type='checkbox']");
            if (agb.length) {
                if (agb.is(":checked")) {
                    agb.get(0).checked = false;
                    checkoutDone();
                }
                else {
                    showError("Please agree to the terms and conditions");
                }
                return;
            }
            checkoutDone();
        }

        var renderers = {
            selector: function(item) {
                // TODO where do we know the key is the _id
                var existingItem = container.find("#" + item._id);

                // we only need an increment
                if (!existingItem.length) {

                    var newItem = $(template).clone();
                    newItem
                        .removeClass("template")
                        .addClass(config.options.classes.item)
                        .appendTo(container)
                        .show();

                    for (var i in config.template.binds) {
                        var bindObj = config.template.binds[i];
                        bindObj.context = newItem;
                        Bind.call(self, bindObj, item);
                    }

                    // now there should be an element with this id
                    existingItem = container.find("#" + item._id);
                }

                existingItem.find(".quantity").each(function() {

                    var elem = $(this);

                    switch (this.tagName) {
                        case "INPUT":
                            elem.attr("value", item.quantity);
                            elem.val(item.quantity);
                            break;
                        default:
                            elem.text(quantity);
                    }
                });

                return;
            }
        };

        function render(items) {
            if (!items || !items.length) {
                showEmpty(true);
                return;
            }

            showEmpty(false);

            var renderer = renderers[config.template.type];
            if (!renderer) {
                showError("No renderer found for templates of type: " + config.template.type);
            }
            for (var i in items) {
                renderer.call(self, items[i]);
            }
        }

        function renderItem(item) {

            if (!item) {
                return;
            }

            var renderer = renderers[config.template.type];
            if (!renderer) {
                showError("No renderer found for templates of type: " + config.template.type);
            }
            showEmpty(false);
            renderer.call(self, item);
        }

        function clearList() {
            $("." + config.options.classes.item, container).remove();
        }

        // ********************************
        // Public functions ***************
        // ********************************

        var readFrom = {
            memory: function(callback) {
                callback(null, items);
            },
            cookie: function(callback) {
                $.cookie.json = true;
                items = $.cookie(config.options.cookie) || [];
                callback(null, items);
            },
            server: function(callback) {
                self.link(config.crud.read, function(err, data) {
                    if (err) { return callback(err); }
                    items = [];
                    for (var i in data) {
                        items.push(data[i]);
                    }
                    callback(null, items);
                });
            }
        }

        function read() {

            clearList();

            var reader = readFrom[config.options.type];
            if (render) {
                reader.call(self, function(err, items) {
                    if (err) {
                        showError(JSON.stringify(err));
                        return;
                    }
                    render.call(self, items);
                });
            }
        }

        function showEmpty(empty) {
            if (empty) {
                $("." + config.options.classes.empty, self.dom).show();
                $("." + config.options.classes.content, self.dom).hide();
                $("." + config.options.classes.confirm, self.dom).hide();
            } else {
                $("." + config.options.classes.empty, self.dom).hide();
                $("." + config.options.classes.content, self.dom).show();
                $("." + config.options.classes.confirm, self.dom).hide();
            }
        }

        function showOrdered() {
            $("." + config.options.classes.empty, self.dom).hide();
            $("." + config.options.classes.content, self.dom).hide();
            $("." + config.options.classes.confirm, self.dom).show();
        }

        function showError(message) {
            if (!message) {
                $(".error").text("").hide();
            } else {
                $(".error").text(message).show();
            }
        }

        var adders = {
            cookie: function(item, callback) {
                $.cookie.json = true;
                var cart = $.cookie("cart") || [];
                var found = false;
                for (var i in cart) {
                    if (cart[i]._id === item._id) {
                        // TODO support incomming item.quantity
                        ++(cart[i].quantity);
                        item = cart[i];
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    item.quantity = 1;
                    cart.push(item);
                    item = cart[cart.length - 1];
                }

                $.cookie.json = true;
                $.cookie("cart", cart, { path: "/" });
                items = cart;

                callback(null, item);
            },

            server: function(item, callback) {
                self.link(config.crud.create, { data: item }, function(err, confirmedItem) {
                    if (err) { return callback(err); }

                    var found = false;
                    for (var i in items) {
                        if (items[i]._id === confirmedItem._id) {
                            items[i].confirmedItem;
                            found = true;
                        }
                    }

                    if (!found) {
                        items.push(confirmedItem);
                    }

                    callback(null, confirmedItem);
                });
            },

            memory: function(item, callback) {
                // TODO in memory type the quantity is saved in the memory object and will
                // be reused later, which is wrong
                var newItem = {};
                for (var i in item) {
                    newItem[i] = item[i];
                }
                item = newItem;

                var found = false;
                for (var i in items) {
                    if (items[i]._id === item._id) {
                        item = items[i];
                        ++(item.quantity);
                        found = true;
                    }
                }

                if (!found) {
                    item.quantity = 1;
                    items.push(item);
                }

                callback(null, item);
            }
        };

        function addItem(itemData) {
            showError();

            var adder = adders[config.options.type];
            if (!adder) {
                showError("No item adder was found for cart type: " + config.options.type);
                return;
            }
            adder.call(self, itemData, function(err, item) {
                if (err) {
                    showError(JSON.stringify(err));
                    return;
                }
                renderItem(item);
            });
        }

        function readQuantityFromItem(elem) {

            var quantityElem = elem.find(".quantity").first();
            if (!quantityElem.length) {
                return 1;
            }

            var value = 1;
            var textVal = null;

            switch (quantityElem[0].tagName) {
                case "INPUT":
                    textVal = quantityElem.val();
                    break;
                default:
                    textVal = quantityElem.text();
            }
            var parsedVal = parseInt(textVal);
            if (!isNaN(parsedVal)) {
                value = parsedVal + 1;
            }

            return value;
        }

        function removeItem(itemData) {
            showError();

            function removeUiItem() {
                // TODO where do we get the _id key from?
                container.find("#" + itemData._id).remove();

                // if no more items, show empty cart
                if (container.find("." + config.options.classes.item).length == 0) {
                    showEmpty(true);
                }
            }

            switch (config.options.type) {
                case "server":
                    self.link(config.crud.delete, { data: { _id: itemData._id } }, function(err, data) {
                        if (err) { return; }
                        removeUiItem();
                    });
                    break;

                case "memory":
                    // a memory-based cart should not make any requests, just remove the item
                    removeUiItem();
                    // and show an empty cart when no more items in it
                    var items = container.find("." + config.options.classes.item);
                    showEmpty(!items.length);
                    break;

                case "cookie":
                    // search in the cart cookie for the item with this ID and remove it
                    var cart = $.cookie("cart");
                    for (var i in cart) {
                        if (cart[i]._id === itemData._id) {
                            cart.splice(i, 1);
                            break;
                        }
                    }
                    // if the cart is already empty it should be displayed as so
                    showEmpty(!cart || !cart.length);
                    // save back the updated cart in the cookie
                    $.cookie("cart", cart, { path: "/"});
                    // and also remove the item from the UI
                    removeUiItem();
                    break;
            }
        }

        function show() {
            $(self.dom).parent().show();
        }

        function hide() {
            $(self.dom).parent().hide();
        }

         return {
            init: init,
            read: read,
            addItem: addItem,
            removeItem: removeItem,
            checkout: checkout,
            show: show,
            hide: hide
        };
    }

    return function(module, config) {

        var cart = new Cart(module);
        for (var i in cart) {
            cart[i] = module[i] || cart[i];
        }
        cart = Object.extend(cart, module);

        cart.init(config);

        return cart;
    }
});

<|endoftext|>


<commit_before>'use strict';
module.exports = function() {

  const dotenv = require('dotenv').load();
  const Sequelize = require('sequelize');
  const mysql = require('mysql');

  const _sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
    host: process.env.DB_HOST,
    dialect: 'mysql',
    port: process.env.DB_PORT,
    pool: {
      max: 5,
      min: 0,
      idle: 10000
    }
  });

  const _users = _sequelize.define('users', {
    userId: {
      type: Sequelize.STRING,
      primaryKey: true
    },
    email: {
      type: Sequelize.STRING
    },
    token: {
      type: Sequelize.STRING
    }
  });

  const _meals = _sequelize.define('meals', {
    mealId: {
      type: Sequelize.INTEGER,
      primaryKey: true
    },
    name: {
      type: Sequelize.STRING
    },
    image: {
      type: Sequelize.STRING
    }
  });

  const _userMeals = _sequelize.define('userMeals', {
    date: {
      type: Sequelize.STRING
    },
    mealType: {
      type: Sequelize.STRING
    }
  });

  const _groceryLists = _sequelize.define('groceryLists', {
    listId: {
      type: Sequelize.UUID,
      primaryKey: true
    },
  });

  const _userGroceryLists = _sequelize.define('userGroceryLists', {

  });

  const _ingredients = _sequelize.define('ingredients', {
    ingredientId: {
      type: Sequelize.UUID,
      primaryKey: true
    },
    name: {
      type: Sequelize.STRING
    },
    completed: {
      type: Sequelize.BOOLEAN
    }
  });

  const _intolerances = _sequelize.define('intolerances', {
    intoleranceId: {
      type: Sequelize.UUID,
      primaryKey: true
    },
    name: {
      type: Sequelize.STRING
    }
  });

  const _userIntolerances = _sequelize.define('userIntolerances', {
    status: {
      type: Sequelize.BOOLEAN
    }
  });

  //Relationships
  _users.belongsToMany(_meals, { through: _userMeals, foreignKey: 'userId', constraints: false });
  _users.belongsToMany(_groceryLists, { through: _userGroceryLists, foreignKey: 'userId', constraints: false });
  _users.belongsToMany(_intolerances, { through: _userIntolerances, foreignKey: 'userId', constraints: false });
  _meals.belongsToMany(_users, { through: _userMeals, foreignKey: 'mealId', constraints: false });
  _groceryLists.belongsToMany(_users, { through: _userGroceryLists, foreignKey: 'listId', constraints: false });
  _groceryLists.hasMany(_ingredients, { foreignKey: 'listId', constraints: false });
  _intolerances.belongsToMany(_users, { through: _userIntolerances, foreignKey: 'intoleranceId', constraints: false });

  //Syncs newly created tables and datatypes inside.
  _sequelize.sync();

  return {
    connection: _sequelize,
    groceryLists: _groceryLists,
    userGroceryLists: _userGroceryLists,
    ingredients: _ingredients,
    meals: _meals,
    userMeals: _userMeals,
    intolerances: _intolerances,
    userIntolerances: _userIntolerances,
    users: _users,
  };

}();
<commit_msg>added constraints false<commit_after>'use strict';
module.exports = function() {

  const dotenv = require('dotenv').load();
  const Sequelize = require('sequelize');
  const mysql = require('mysql');

  const _sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
    host: process.env.DB_HOST,
    dialect: 'mysql',
    port: process.env.DB_PORT,
    pool: {
      max: 5,
      min: 0,
      idle: 10000
    }
  });

  const _users = _sequelize.define('users', {
    userId: {
      type: Sequelize.STRING,
      primaryKey: true,
      constraints: false
    },
    email: {
      type: Sequelize.STRING
    },
    token: {
      type: Sequelize.STRING
    }
  });

  const _meals = _sequelize.define('meals', {
    mealId: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      constraints: false
    },
    name: {
      type: Sequelize.STRING
    },
    image: {
      type: Sequelize.STRING
    }
  });

  const _userMeals = _sequelize.define('userMeals', {
    date: {
      type: Sequelize.STRING
    },
    mealType: {
      type: Sequelize.STRING
    }
  });

  const _groceryLists = _sequelize.define('groceryLists', {
    listId: {
      type: Sequelize.UUID,
      primaryKey: true,
      constraints: false
    },
  });

  const _userGroceryLists = _sequelize.define('userGroceryLists', {

  });

  const _ingredients = _sequelize.define('ingredients', {
    ingredientId: {
      type: Sequelize.UUID,
      primaryKey: true,
      constraints: false
    },
    name: {
      type: Sequelize.STRING
    },
    completed: {
      type: Sequelize.BOOLEAN
    }
  });

  const _intolerances = _sequelize.define('intolerances', {
    intoleranceId: {
      type: Sequelize.UUID,
      primaryKey: true,
      constraints: false
    },
    name: {
      type: Sequelize.STRING
    }
  });

  const _userIntolerances = _sequelize.define('userIntolerances', {
    status: {
      type: Sequelize.BOOLEAN
    }
  });

  //Relationships
  _users.belongsToMany(_meals, { through: _userMeals, foreignKey: 'userId', constraints: false });
  _users.belongsToMany(_groceryLists, { through: _userGroceryLists, foreignKey: 'userId', constraints: false });
  _users.belongsToMany(_intolerances, { through: _userIntolerances, foreignKey: 'userId', constraints: false });
  _meals.belongsToMany(_users, { through: _userMeals, foreignKey: 'mealId', constraints: false });
  _groceryLists.belongsToMany(_users, { through: _userGroceryLists, foreignKey: 'listId', constraints: false });
  _groceryLists.hasMany(_ingredients, { foreignKey: 'listId', constraints: false });
  _intolerances.belongsToMany(_users, { through: _userIntolerances, foreignKey: 'intoleranceId', constraints: false });

  //Syncs newly created tables and datatypes inside.
  _sequelize.sync();

  return {
    connection: _sequelize,
    groceryLists: _groceryLists,
    userGroceryLists: _userGroceryLists,
    ingredients: _ingredients,
    meals: _meals,
    userMeals: _userMeals,
    intolerances: _intolerances,
    userIntolerances: _userIntolerances,
    users: _users,
  };

}();
<|endoftext|>


<commit_before>'use strict'

class Protocol {
  constructor(initialAddress) {
    this.initialAddress = initialAddress
  }
}

let init = address => {

}

// Save on Exit

process.stdin.resume()

let quit = () => {
  console.log('saving protocol...')
  // TODO: save protocol
  process.exit()
}

process.on('exit', quit)
process.on('SIGINT', quit)
process.on('uncaughtException', quit)<commit_msg>Remove Save on Quit Logic<commit_after>'use strict'

class Protocol {
  constructor(initialAddress) {
    this.initialAddress = initialAddress
  }
}

let init = address => {

}

<|endoftext|>


<commit_before>( function ( undefined ) {

var	global = this,

	exports = {
		version: '0.1.1',
		env: {
			server: typeof module !== 'undefined' && !!( module.require && module.exports ),
			client: typeof window !== 'undefined' && window === global
		}
	},

	toString = exports.toString =
		Object.prototype.toString,

	hasOwn = exports.hasOwn =
		Object.prototype.hasOwnProperty,

	/** jQuery-style "trim", using native method on `String.prototype` if available. */
	trim = exports.trim =
		String.prototype.trim ?
			function ( text ) { return text == null ? '' : String.prototype.trim.call( text ); } :
			function ( text ) { return text == null ? '' : text.toString().replace( /^\s+/, '' ).replace( /\s+$/, '' ); },

	slice = exports.slice =
		Array.prototype.slice;

exports.noConflict = ( function () {
	var autochthon = global.Z;
	return function () {
		global.Z = autochthon;
		return this;
	};
})();

/**
 * General-purpose empty function. May also be deemed suitable as a unique alternative "nil" type for
 * strict-equal matches whenever it's desirable to avoid traditional `null` and `undefined`.
 */
function noop () {}
exports.noop = noop;

/**
 * Like `noop`, except suited for substitution on methods designed to be chainable.
 */
function getThis () { return this; }
exports.getThis = getThis;

/**
 * Calls the specified native function if it exists and returns its result; if no such function exists on
 * `obj` as registered in `__native.fn`, returns our unique `noop` (as opposed to `null` or `undefined`,
 * which may be a valid result from the native function itself).
 */
function __native ( item, obj /* , ... */ ) {
	var n = __native.fn[item];
	return n && obj[item] === n ? n.apply( obj, slice.call( arguments, 2 ) ) : noop;
}
( exports.__native = __native ).fn = {
	forEach: Array.prototype.forEach
};

/**
 * A more browser-safe alternative to `typeof`, implemented similarly to jQuery and elsewhere, which
 * checks the string output returned by a plain `toString()` call.
 */
function type ( obj ) {
	return obj == null ? String( obj ) : type.map[ toString.call( obj ) ] || 'object';
}
type.map = {};
each( 'Array Boolean Date Function Number Object RegExp String'.split(' '), function( i, name ) {
	type.map[ "[object " + name + "]" ] = name.toLowerCase();
});
exports.type = type;

/** isBoolean */
function isBoolean ( obj ) { return type( obj ) === 'boolean'; }
exports.isBoolean = isBoolean;

/** isString */
function isString ( obj ) { return type( obj ) === 'string'; }
exports.isString = isString;

/** isNumber */
function isNumber ( n ) { return !isNaN( parseFloat( n ) ) && isFinite( n ); }
exports.isNumber = isNumber;

/** isArray */
function isArray ( obj ) { return type( obj ) === 'array'; }
exports.isArray = isArray;

/** isFunction */
function isFunction ( obj ) { return type( obj ) === 'function'; }
exports.isFunction = isFunction;

/**
 * Near-straight port of jQuery `isPlainObject`
 */
function isPlainObject ( obj ) {
	var key;
	if ( !obj || type( obj ) !== 'object' || obj.nodeType || obj === global ||
		obj.constructor &&
		!hasOwn.call( obj, 'constructor' ) &&
		!hasOwn.call( obj.constructor.prototype, 'isPrototypeOf' )
	) {
		return false;
	}
	for ( key in obj ) {}
	return key === undefined || hasOwn.call( obj, key );
}
exports.isPlainObject = isPlainObject;

/**
 * Returns a boolean indicating whether the object or array at `obj` contains any members. For an
 * `Object` type, if `andPrototype` is included and truthy, `obj` must be empty throughout its
 * prototype chain as well.
 */
function isEmpty ( obj, andPrototype ) {
	var key;
	if ( isArray( obj ) && obj.length ) {
		return false;
	}
	for ( key in obj ) {
		if ( andPrototype || hasOwn.call( obj, key ) ) {
			return false;
		}
	}
	return true;
}
exports.isEmpty = isEmpty;

/**
 * jQuery-style `$.each`, with callback signature of `key, value, object`.
 */
function each ( obj, fn ) {
	if ( !obj ) { return; }
	var	key, i, l = obj.length;
	if ( l === undefined || isFunction( obj ) ) {
		for ( key in obj ) {
			if ( fn.call( obj[key], key, obj[key], obj ) === false ) {
				break;
			}
		}
	} else {
		for ( i = 0, l = obj.length; i < l; ) {
			if ( fn.call( obj[i], i, obj[i++], obj ) === false ) {
				break;
			}
		}
	}
	return obj;
}
exports.each = each;

/**
 * ES5-style `Array.prototype.forEach`, with callback signature of `value, key, object`.
 */
function forEach ( obj, fn, context ) {
	var	n, l, key, i;
	if ( obj == null ) { return; }
	if ( ( n = __native( 'forEach', obj, fn, context ) ) !== noop ) { return n; }
	if ( ( l = obj.length ) === undefined || isFunction( obj ) ) {
		for ( key in obj ) {
			if ( fn.call( context || obj[key], obj[key], key, obj ) === false ) {
				break;
			}
		}
	} else {
		for ( i = 0, l = obj.length; i < l; ) {
			if ( fn.call( context || obj[i], obj[i], i++, obj ) === false ) {
				break;
			}
		}
	}
	return obj;
}
exports.forEach = forEach;

/**
 * Based on jQuery `$.extend` method. Optional first argument may be Boolean `deep`, and may also
 * accept a `flags` String:
 *     'deep' : Same as the optional Boolean flag in jQuery
 *     'own' : Restricts extended properties to those filtered by `Object.hasOwnProperty`
 *     'all' : Includes keys with undefined values
 */
function extend () {
	var	args = slice.call( arguments ),
		t = type( args[0] ),
		flags =
			t === 'boolean' ? { deep: args.shift() } :
			t === 'string' ? splitToHash( args.shift(), ' ' ) :
			{},
		subject = args.shift(),
		i = 0, l = args.length,
		obj, key, value, valueIsArray, target, clone;

	typeof subject === 'object' || isFunction( subject ) || ( subject = {} );
	for ( ; i < l && ( obj = args[i] ) != null; i++ ) {
		for ( key in obj ) if ( !flags.own || hasOwn.call( obj, key ) ) {
			value = obj[ key ];
			if ( value === subject ) {
				continue;
			}
			if ( flags.deep && value && ( isPlainObject( value ) || ( valueIsArray = isArray( value ) ) ) ) {
				target = subject[ key ];
				if ( valueIsArray ) {
					valueIsArray = false;
					clone = target && isArray( target ) ? target : [];
				} else {
					clone = target && ( isFunction( target ) || type( target ) === 'object' ) ? target : {};
				}
				subject[ key ] = extend( keys( flags ).join(' '), clone, value );
			} else if ( flags.all || value !== undefined ) {
				subject[ key ] = value;
			}
		}
	}
	return subject;
}
exports.extend = extend;

/**
 * Extracts elements of nested arrays
 */
function flatten ( array ) {
	isArray( array ) || ( array = [ array ] );
	var	i = 0,
		l = array.length,
		item,
		result = [];
	while ( i < l ) {
		item = array[i++];
		isArray( item ) ? ( result = result.concat( flatten( item ) ) ) : result.push( item );
	}
	return result;
}
exports.flatten = flatten;

/**
 * Returns an array containing the keys of a hashmap
 */
function keys ( obj ) {
	var key, result = [];
	if ( !( isPlainObject( obj ) || isFunction( obj ) ) ) { throw new TypeError; }
	for ( key in obj ) { hasOwn.call( obj, key ) && result.push( key ); }
	return result;
}
exports.keys = keys = isFunction( Object.keys ) ? Object.keys : keys;

/**
 * Returns a hashmap that is the key-value inversion of the supplied string array
 */
function invert ( array ) {
	for ( var i = 0, l = array.length, map = {}; i < l; ) {
		map[ array[i] ] = i++;
	}
	return map;
}
exports.invert = invert;

/**
 * Sets all of an object's values to a specified value
 */
function setAll ( obj, value ) {
	for ( var i in obj ) if ( hasOwn.call( obj, i ) ) {
		obj[i] = value;
	}
	return obj;
}
exports.setAll = setAll;

/**
 * Sets all of an object's values to `null`
 */
function nullify ( obj ) {
	for ( var i in obj ) if ( hasOwn.call( obj, i ) ) {
		obj[i] = null;
	}
	return obj;
}
exports.nullify = nullify;

/**
 * Returns an object whose keys are the elements of `string.split()` and whose values are all `true`.
 */
function splitToHash ( string, delimiter, value ) {
	return setAll( invert( string.split( delimiter || (/\s+/) ) ), value !== undefined ? value : true );
}
exports.splitToHash = splitToHash;

/**
 * Lazy evaluator; returns a function that returns the enclosed argument
 */
function thunk ( obj ) {
	return function () { return obj; };
}
exports.thunk = thunk;

/**
 * Retrieves the value at the location indicated by the provided `path` string inside a
 * nested object `obj`.
 *
 * E.g.:
 * 	var x = { a: { b: 42 } };
 *  lookup( x, 'a' ) // => { "b": 42 }
 * 	lookup( x, 'a.b' ) // => 42
 * 	lookup( x, 'a.b.c' ) // => undefined
 */
function lookup ( obj, path, separator ) {
	var cursor = obj, i = 0, l = ( path = path.split( separator || '.' ) ).length, name;
	while ( i < l && cursor != null ) {
		if ( hasOwn.call( cursor, name = path[ i++ ] ) ) {
			cursor = cursor[ name ];
		} else {
			return undefined;
		}
	}
	return cursor;
}
exports.lookup = lookup;

/**
 * Reference to or shim for Object.create
 */
function create ( prototype, properties ) {
	var object, constructor;
	( constructor = function () {} ).prototype = prototype;
	( object = new constructor ).constructor = constructor;
	return properties ? extend( object, properties ) : object;
}
exports.create = isFunction( Object.create ) ? ( create = Object.create ) : create;

/**
 * Prototypal inheritance facilitator
 *
 * inherit( Function child, [ Function parent ], [ Object properties ], [ Object statics ] )
 *
 *   * `child` and `parent` are constructor functions, such that
 *         `new child instanceof parent === true`
 *   * `child` also inherits static members that are direct properties of `parent`
 *   * `properties` is an object containing properties to be added to the prototype of `child`
 *   * `statics` is an object containing properties to be added to `child` itself.
 */
function inherit ( child, parent, properties, statics ) {
	isFunction( parent ) ?
		( ( extend( child, parent ).prototype = create( parent.prototype ) ).constructor = child ) :
		( statics = properties, properties = parent );
	properties && extend( child.prototype, properties );
	statics && extend( child, statics );
	return child;
}
exports.inherit = inherit;

/**
 * Returns an object's prototype. In environments without native support, this may only work if
 * the object's constructor and its prototype are properly associated, e.g., as facilitated by
 * the `create` function.
 */
function getPrototypeOf ( obj ) {
	return obj.__proto__ || obj.constructor.prototype;
}
exports.getPrototypeOf = isFunction( Object.getPrototypeOf ) ?
	( getPrototypeOf = Object.getPrototypeOf ) : getPrototypeOf;

/**
 * Produces a hashmap whose keys are the supplied string array, with values all set to `null`
 */
function nullHash( keys ) { return nullify( invert( keys ) ); }
exports.nullHash = nullHash;

/**
 * Mirrors a function's output as the function's `valueOf`, occasionally useful in debugging/devtools
 */
function valueFunction ( fn ) { return fn.valueOf = fn; }
exports.valueFunction = valueFunction;

/**
 * Mirrors a function's output as the function's `toString`, occasionally useful in debugging/devtools
 */
function stringFunction ( fn ) { return fn.toString = fn; }
exports.stringFunction = stringFunction;

exports.env.server && ( module.exports = exports );
exports.env.client && ( global['Z'] = extend( global['Z'] || {}, exports ) );

})();<commit_msg>fix `create` to use `prototype.constructor`<commit_after>( function ( undefined ) {

var	global = this,

	exports = {
		version: '0.1.1',
		env: {
			server: typeof module !== 'undefined' && !!( module.require && module.exports ),
			client: typeof window !== 'undefined' && window === global
		}
	},

	toString = exports.toString =
		Object.prototype.toString,

	hasOwn = exports.hasOwn =
		Object.prototype.hasOwnProperty,

	/** jQuery-style "trim", using native method on `String.prototype` if available. */
	trim = exports.trim =
		String.prototype.trim ?
			function ( text ) { return text == null ? '' : String.prototype.trim.call( text ); } :
			function ( text ) { return text == null ? '' : text.toString().replace( /^\s+/, '' ).replace( /\s+$/, '' ); },

	slice = exports.slice =
		Array.prototype.slice;

exports.noConflict = ( function () {
	var autochthon = global.Z;
	return function () {
		global.Z = autochthon;
		return this;
	};
})();

/**
 * General-purpose empty function. May also be deemed suitable as a unique alternative "nil" type for
 * strict-equal matches whenever it's desirable to avoid traditional `null` and `undefined`.
 */
function noop () {}
exports.noop = noop;

/**
 * Like `noop`, except suited for substitution on methods designed to be chainable.
 */
function getThis () { return this; }
exports.getThis = getThis;

/**
 * Calls the specified native function if it exists and returns its result; if no such function exists on
 * `obj` as registered in `__native.fn`, returns our unique `noop` (as opposed to `null` or `undefined`,
 * which may be a valid result from the native function itself).
 */
function __native ( item, obj /* , ... */ ) {
	var n = __native.fn[item];
	return n && obj[item] === n ? n.apply( obj, slice.call( arguments, 2 ) ) : noop;
}
( exports.__native = __native ).fn = {
	forEach: Array.prototype.forEach
};

/**
 * A more browser-safe alternative to `typeof`, implemented similarly to jQuery and elsewhere, which
 * checks the string output returned by a plain `toString()` call.
 */
function type ( obj ) {
	return obj == null ? String( obj ) : type.map[ toString.call( obj ) ] || 'object';
}
type.map = {};
each( 'Array Boolean Date Function Number Object RegExp String'.split(' '), function( i, name ) {
	type.map[ "[object " + name + "]" ] = name.toLowerCase();
});
exports.type = type;

/** isBoolean */
function isBoolean ( obj ) { return type( obj ) === 'boolean'; }
exports.isBoolean = isBoolean;

/** isString */
function isString ( obj ) { return type( obj ) === 'string'; }
exports.isString = isString;

/** isNumber */
function isNumber ( n ) { return !isNaN( parseFloat( n ) ) && isFinite( n ); }
exports.isNumber = isNumber;

/** isArray */
function isArray ( obj ) { return type( obj ) === 'array'; }
exports.isArray = isArray;

/** isFunction */
function isFunction ( obj ) { return type( obj ) === 'function'; }
exports.isFunction = isFunction;

/**
 * Near-straight port of jQuery `isPlainObject`
 */
function isPlainObject ( obj ) {
	var key;
	if ( !obj || type( obj ) !== 'object' || obj.nodeType || obj === global ||
		obj.constructor &&
		!hasOwn.call( obj, 'constructor' ) &&
		!hasOwn.call( obj.constructor.prototype, 'isPrototypeOf' )
	) {
		return false;
	}
	for ( key in obj ) {}
	return key === undefined || hasOwn.call( obj, key );
}
exports.isPlainObject = isPlainObject;

/**
 * Returns a boolean indicating whether the object or array at `obj` contains any members. For an
 * `Object` type, if `andPrototype` is included and truthy, `obj` must be empty throughout its
 * prototype chain as well.
 */
function isEmpty ( obj, andPrototype ) {
	var key;
	if ( isArray( obj ) && obj.length ) {
		return false;
	}
	for ( key in obj ) {
		if ( andPrototype || hasOwn.call( obj, key ) ) {
			return false;
		}
	}
	return true;
}
exports.isEmpty = isEmpty;

/**
 * jQuery-style `$.each`, with callback signature of `key, value, object`.
 */
function each ( obj, fn ) {
	if ( !obj ) { return; }
	var	key, i, l = obj.length;
	if ( l === undefined || isFunction( obj ) ) {
		for ( key in obj ) {
			if ( fn.call( obj[key], key, obj[key], obj ) === false ) {
				break;
			}
		}
	} else {
		for ( i = 0, l = obj.length; i < l; ) {
			if ( fn.call( obj[i], i, obj[i++], obj ) === false ) {
				break;
			}
		}
	}
	return obj;
}
exports.each = each;

/**
 * ES5-style `Array.prototype.forEach`, with callback signature of `value, key, object`.
 */
function forEach ( obj, fn, context ) {
	var	n, l, key, i;
	if ( obj == null ) { return; }
	if ( ( n = __native( 'forEach', obj, fn, context ) ) !== noop ) { return n; }
	if ( ( l = obj.length ) === undefined || isFunction( obj ) ) {
		for ( key in obj ) {
			if ( fn.call( context || obj[key], obj[key], key, obj ) === false ) {
				break;
			}
		}
	} else {
		for ( i = 0, l = obj.length; i < l; ) {
			if ( fn.call( context || obj[i], obj[i], i++, obj ) === false ) {
				break;
			}
		}
	}
	return obj;
}
exports.forEach = forEach;

/**
 * Based on jQuery `$.extend` method. Optional first argument may be Boolean `deep`, and may also
 * accept a `flags` String:
 *     'deep' : Same as the optional Boolean flag in jQuery
 *     'own' : Restricts extended properties to those filtered by `Object.hasOwnProperty`
 *     'all' : Includes keys with undefined values
 */
function extend () {
	var	args = slice.call( arguments ),
		t = type( args[0] ),
		flags =
			t === 'boolean' ? { deep: args.shift() } :
			t === 'string' ? splitToHash( args.shift(), ' ' ) :
			{},
		subject = args.shift(),
		i = 0, l = args.length,
		obj, key, value, valueIsArray, target, clone;

	typeof subject === 'object' || isFunction( subject ) || ( subject = {} );
	for ( ; i < l && ( obj = args[i] ) != null; i++ ) {
		for ( key in obj ) if ( !flags.own || hasOwn.call( obj, key ) ) {
			value = obj[ key ];
			if ( value === subject ) {
				continue;
			}
			if ( flags.deep && value && ( isPlainObject( value ) || ( valueIsArray = isArray( value ) ) ) ) {
				target = subject[ key ];
				if ( valueIsArray ) {
					valueIsArray = false;
					clone = target && isArray( target ) ? target : [];
				} else {
					clone = target && ( isFunction( target ) || type( target ) === 'object' ) ? target : {};
				}
				subject[ key ] = extend( keys( flags ).join(' '), clone, value );
			} else if ( flags.all || value !== undefined ) {
				subject[ key ] = value;
			}
		}
	}
	return subject;
}
exports.extend = extend;

/**
 * Extracts elements of nested arrays
 */
function flatten ( array ) {
	isArray( array ) || ( array = [ array ] );
	var	i = 0,
		l = array.length,
		item,
		result = [];
	while ( i < l ) {
		item = array[i++];
		isArray( item ) ? ( result = result.concat( flatten( item ) ) ) : result.push( item );
	}
	return result;
}
exports.flatten = flatten;

/**
 * Returns an array containing the keys of a hashmap
 */
function keys ( obj ) {
	var key, result = [];
	if ( !( isPlainObject( obj ) || isFunction( obj ) ) ) { throw new TypeError; }
	for ( key in obj ) { hasOwn.call( obj, key ) && result.push( key ); }
	return result;
}
exports.keys = keys = isFunction( Object.keys ) ? Object.keys : keys;

/**
 * Returns a hashmap that is the key-value inversion of the supplied string array
 */
function invert ( array ) {
	for ( var i = 0, l = array.length, map = {}; i < l; ) {
		map[ array[i] ] = i++;
	}
	return map;
}
exports.invert = invert;

/**
 * Sets all of an object's values to a specified value
 */
function setAll ( obj, value ) {
	for ( var i in obj ) if ( hasOwn.call( obj, i ) ) {
		obj[i] = value;
	}
	return obj;
}
exports.setAll = setAll;

/**
 * Sets all of an object's values to `null`
 */
function nullify ( obj ) {
	for ( var i in obj ) if ( hasOwn.call( obj, i ) ) {
		obj[i] = null;
	}
	return obj;
}
exports.nullify = nullify;

/**
 * Returns an object whose keys are the elements of `string.split()` and whose values are all `true`.
 */
function splitToHash ( string, delimiter, value ) {
	return setAll( invert( string.split( delimiter || (/\s+/) ) ), value !== undefined ? value : true );
}
exports.splitToHash = splitToHash;

/**
 * Lazy evaluator; returns a function that returns the enclosed argument
 */
function thunk ( obj ) {
	return function () { return obj; };
}
exports.thunk = thunk;

/**
 * Retrieves the value at the location indicated by the provided `path` string inside a
 * nested object `obj`.
 *
 * E.g.:
 * 	var x = { a: { b: 42 } };
 *  lookup( x, 'a' ) // => { "b": 42 }
 * 	lookup( x, 'a.b' ) // => 42
 * 	lookup( x, 'a.b.c' ) // => undefined
 */
function lookup ( obj, path, separator ) {
	var cursor = obj, i = 0, l = ( path = path.split( separator || '.' ) ).length, name;
	while ( i < l && cursor != null ) {
		if ( hasOwn.call( cursor, name = path[ i++ ] ) ) {
			cursor = cursor[ name ];
		} else {
			return undefined;
		}
	}
	return cursor;
}
exports.lookup = lookup;

/**
 * Reference to or shim for Object.create
 */
function create ( prototype, properties ) {
	var object, constructor;
	( constructor = function () {} ).prototype = prototype;
	( object = new constructor ).constructor = prototype.constructor;
	return properties ? extend( object, properties ) : object;
}
exports.create = isFunction( Object.create ) ? ( create = Object.create ) : create;

/**
 * Prototypal inheritance facilitator
 *
 * inherit( Function child, [ Function parent ], [ Object properties ], [ Object statics ] )
 *
 *   * `child` and `parent` are constructor functions, such that
 *         `new child instanceof parent === true`
 *   * `child` also inherits static members that are direct properties of `parent`
 *   * `properties` is an object containing properties to be added to the prototype of `child`
 *   * `statics` is an object containing properties to be added to `child` itself.
 */
function inherit ( child, parent, properties, statics ) {
	isFunction( parent ) ?
		( ( extend( child, parent ).prototype = create( parent.prototype ) ).constructor = child ) :
		( statics = properties, properties = parent );
	properties && extend( child.prototype, properties );
	statics && extend( child, statics );
	return child;
}
exports.inherit = inherit;

/**
 * Returns an object's prototype. In environments without native support, this may only work if
 * the object's constructor and its prototype are properly associated, e.g., as facilitated by
 * the `create` function.
 */
function getPrototypeOf ( obj ) {
	return obj.__proto__ || obj.constructor.prototype;
}
exports.getPrototypeOf = isFunction( Object.getPrototypeOf ) ?
	( getPrototypeOf = Object.getPrototypeOf ) : getPrototypeOf;

/**
 * Produces a hashmap whose keys are the supplied string array, with values all set to `null`
 */
function nullHash( keys ) { return nullify( invert( keys ) ); }
exports.nullHash = nullHash;

/**
 * Mirrors a function's output as the function's `valueOf`, occasionally useful in debugging/devtools
 */
function valueFunction ( fn ) { return fn.valueOf = fn; }
exports.valueFunction = valueFunction;

/**
 * Mirrors a function's output as the function's `toString`, occasionally useful in debugging/devtools
 */
function stringFunction ( fn ) { return fn.toString = fn; }
exports.stringFunction = stringFunction;

exports.env.server && ( module.exports = exports );
exports.env.client && ( global['Z'] = extend( global['Z'] || {}, exports ) );

})();<|endoftext|>


<commit_before>var os = require('os');
var uuid = require('node-uuid');
var async = require('async');
var scientist = require('./lib/scientist');
var Runtime = require('./lib/runtime');
var HttpServer = require('./lib/http_server');
var PeerClient = require('./lib/peer_client');
var PeerRegistry = require('./lib/peer_registry');
var PubSub = require('./lib/pubsub_service');
var Logger = require('./lib/logger');
var HttpScout = require('./lib/http_scout');

var Zetta = module.exports = function(opts) {
  if (!(this instanceof Zetta)) {
    return new Zetta(opts);
  }

  opts = opts || {};

  this.id = uuid.v4(); // unique id of server
  this._name = os.hostname(); // optional name, defaults to OS hostname

  this._exposeQuery = '';
  this._scouts = [];
  this._apps = [];
  this._peers = [];

  this.peerRegistry = opts.peerRegistry || new PeerRegistry();

  this.pubsub = opts.pubsub || new PubSub();
  this.log = opts.log || new Logger({ pubsub: this.pubsub });

  var runtimeOpts = { pubsub: this.pubsub, log: this.log };
  if (opts && opts.registry) {
    runtimeOpts.registry = opts.registry;
  }
  this.runtime = new Runtime(runtimeOpts);
  this.httpServer = new HttpServer(this);

  var httpScout = scientist.create.apply(null, [HttpScout]);
  httpScout.server = this.runtime;
  this.httpScout = httpScout;
  this._scouts.push(httpScout);

  this._wireUpDatabaseCleanup();
};

Zetta.prototype._wireUpDatabaseCleanup = function() {
  var self = this;
  ['SIGINT', 'SIGTERM'].forEach(function(signal) {
    process.on(signal, function() {
      self.runtime.registry.close(function() {
        self.peerRegistry.close(function() {
          process.exit();
        });
      });
    });
  });
};

Zetta.prototype.name = function(name) {
  this._name = name;
  return this;
};

Zetta.prototype.use = function() {
  var opts = arguments[arguments.length - 1];
  if(opts && opts.http_device && opts.http_device === true) {
    var driver = arguments[0];
    var instance = new driver();
    instance = scientist.init(instance);
    this.httpScout.driverFunctions[instance.type] = driver;
  } else {
    var scout = scientist.create.apply(null, arguments);
    scout.server = this.runtime;
    this._scouts.push(scout);
  }
  return this;
};

Zetta.prototype.expose = function(query) {
  this._exposeQuery = query;
  this.runtime.expose(query);
  return this;
};

Zetta.prototype.load = function(app) {
  this._apps.push(app);
  return this;
};

Zetta.prototype.link = function(peers) {
  var self = this;
  if(!Array.isArray(peers)) {
    peers = [peers];
  }

  peers.forEach(function(peer) {
    //self._peers.push(new PeerClient(peer, self));
    self._peers.push(peer);
  });

  return this;
};

Zetta.prototype.listen = function(port, callback) {
  var self = this;

  if(!callback) {
    callback = function() {};
  }

  this._run(function(err){
    if(err) {
      return callback(err);
    }

    self.httpServer.listen(port, callback);
  });

  return this;
};

// run scouts/apps init server but do not listening on http port
Zetta.prototype._run = function(callback) {
  var self = this;

  if(!callback) {
    callback = function(){};
  }

  async.series([
    function(next) {
      self._initScouts(next);
    },
    function(next) {
      self._initApps(next);
    },
    function(next) {
      self._initHttpServer(next);
    },
    function(next) {
      self._initPeers(next);
    }

  ], function(err){
    setImmediate(function() {
      callback(err);
    });
  });

  return this;
};

Zetta.prototype._initScouts = function(callback) {
  async.each(this._scouts, function(scout, next) {
    scout.init(next);
  }, function(err) {
    callback(err);
  });

  return this;
};

Zetta.prototype._initApps = function(callback) {
  var self = this;
  this._apps.forEach(function(app) {
    app(self.runtime);
  });
  callback();

  return this;
};

Zetta.prototype._initHttpServer = function(callback) {
  this.httpServer.init();
  callback();

  return this;
};

Zetta.prototype._initPeers = function(callback) {
  var self = this;
  var existingUrls = [];
  var allPeers = [];

  this.peerRegistry.find({ match: function() { return true; } }, function(err, results) {
    results.forEach(function(peer) {
      peer.status = 'disconnected';
      if (peer.direction === 'initiator' && peer.url) {
        allPeers.push(peer);
        existingUrls.push(peer.url);
        return;
      }
    });

    // peers added through js api to registry peers if they don't already exist
    allPeers = allPeers.concat(self._peers.filter(function(peer) {
      return existingUrls.indexOf(peer) === -1;
    }));

    allPeers.forEach(function(obj) {
      var existing = (typeof obj === 'object');
      if (existing) {
        self.peerRegistry.save(obj, function() {
          runPeer(obj);
        });
      } else {
        var peerData = {
          url: obj,
          direction: 'initiator'
        };
        self.peerRegistry.add(peerData, function(err, newPeer) {
          console.log(err, newPeer)
          runPeer(newPeer);
        });
      }

      function runPeer(peer) {
        var peerClient = new PeerClient(peer.url, self);
        peerClient.on('connected', function() {
          peer.status = 'connected';
          self.peerRegistry.save(peer);
        });

        peerClient.on('error', function(error) {
          self.peerRegistry.get(peer.id, function(err, result) {
            result = JSON.parse(result);
            result.status = 'failed';
            result.error = error;
            self.peerRegistry.save(result);
          });
        });

        peerClient.on('closed', function(reconnect) {
          self.peerRegistry.get(peer.id, function(err, result) {
            result = JSON.parse(result);
            result.status = 'connecting';
            self.peerRegistry.save(result, function() {
              peerClient.start();
            });
          });
        });

        peerClient.start();
      }
    });

    // end after db read
    callback();
  });

  return this;
};
<commit_msg>Removed console.log in zetta<commit_after>var os = require('os');
var uuid = require('node-uuid');
var async = require('async');
var scientist = require('./lib/scientist');
var Runtime = require('./lib/runtime');
var HttpServer = require('./lib/http_server');
var PeerClient = require('./lib/peer_client');
var PeerRegistry = require('./lib/peer_registry');
var PubSub = require('./lib/pubsub_service');
var Logger = require('./lib/logger');
var HttpScout = require('./lib/http_scout');

var Zetta = module.exports = function(opts) {
  if (!(this instanceof Zetta)) {
    return new Zetta(opts);
  }

  opts = opts || {};

  this.id = uuid.v4(); // unique id of server
  this._name = os.hostname(); // optional name, defaults to OS hostname

  this._exposeQuery = '';
  this._scouts = [];
  this._apps = [];
  this._peers = [];

  this.peerRegistry = opts.peerRegistry || new PeerRegistry();

  this.pubsub = opts.pubsub || new PubSub();
  this.log = opts.log || new Logger({ pubsub: this.pubsub });

  var runtimeOpts = { pubsub: this.pubsub, log: this.log };
  if (opts && opts.registry) {
    runtimeOpts.registry = opts.registry;
  }
  this.runtime = new Runtime(runtimeOpts);
  this.httpServer = new HttpServer(this);

  var httpScout = scientist.create.apply(null, [HttpScout]);
  httpScout.server = this.runtime;
  this.httpScout = httpScout;
  this._scouts.push(httpScout);

  this._wireUpDatabaseCleanup();
};

Zetta.prototype._wireUpDatabaseCleanup = function() {
  var self = this;
  ['SIGINT', 'SIGTERM'].forEach(function(signal) {
    process.on(signal, function() {
      self.runtime.registry.close(function() {
        self.peerRegistry.close(function() {
          process.exit();
        });
      });
    });
  });
};

Zetta.prototype.name = function(name) {
  this._name = name;
  return this;
};

Zetta.prototype.use = function() {
  var opts = arguments[arguments.length - 1];
  if(opts && opts.http_device && opts.http_device === true) {
    var driver = arguments[0];
    var instance = new driver();
    instance = scientist.init(instance);
    this.httpScout.driverFunctions[instance.type] = driver;
  } else {
    var scout = scientist.create.apply(null, arguments);
    scout.server = this.runtime;
    this._scouts.push(scout);
  }
  return this;
};

Zetta.prototype.expose = function(query) {
  this._exposeQuery = query;
  this.runtime.expose(query);
  return this;
};

Zetta.prototype.load = function(app) {
  this._apps.push(app);
  return this;
};

Zetta.prototype.link = function(peers) {
  var self = this;
  if(!Array.isArray(peers)) {
    peers = [peers];
  }

  peers.forEach(function(peer) {
    //self._peers.push(new PeerClient(peer, self));
    self._peers.push(peer);
  });

  return this;
};

Zetta.prototype.listen = function(port, callback) {
  var self = this;

  if(!callback) {
    callback = function() {};
  }

  this._run(function(err){
    if(err) {
      return callback(err);
    }

    self.httpServer.listen(port, callback);
  });

  return this;
};

// run scouts/apps init server but do not listening on http port
Zetta.prototype._run = function(callback) {
  var self = this;

  if(!callback) {
    callback = function(){};
  }

  async.series([
    function(next) {
      self._initScouts(next);
    },
    function(next) {
      self._initApps(next);
    },
    function(next) {
      self._initHttpServer(next);
    },
    function(next) {
      self._initPeers(next);
    }

  ], function(err){
    setImmediate(function() {
      callback(err);
    });
  });

  return this;
};

Zetta.prototype._initScouts = function(callback) {
  async.each(this._scouts, function(scout, next) {
    scout.init(next);
  }, function(err) {
    callback(err);
  });

  return this;
};

Zetta.prototype._initApps = function(callback) {
  var self = this;
  this._apps.forEach(function(app) {
    app(self.runtime);
  });
  callback();

  return this;
};

Zetta.prototype._initHttpServer = function(callback) {
  this.httpServer.init();
  callback();

  return this;
};

Zetta.prototype._initPeers = function(callback) {
  var self = this;
  var existingUrls = [];
  var allPeers = [];

  this.peerRegistry.find({ match: function() { return true; } }, function(err, results) {
    results.forEach(function(peer) {
      peer.status = 'disconnected';
      if (peer.direction === 'initiator' && peer.url) {
        allPeers.push(peer);
        existingUrls.push(peer.url);
        return;
      }
    });

    // peers added through js api to registry peers if they don't already exist
    allPeers = allPeers.concat(self._peers.filter(function(peer) {
      return existingUrls.indexOf(peer) === -1;
    }));

    allPeers.forEach(function(obj) {
      var existing = (typeof obj === 'object');
      if (existing) {
        self.peerRegistry.save(obj, function() {
          runPeer(obj);
        });
      } else {
        var peerData = {
          url: obj,
          direction: 'initiator'
        };
        self.peerRegistry.add(peerData, function(err, newPeer) {
          runPeer(newPeer);
        });
      }

      function runPeer(peer) {
        var peerClient = new PeerClient(peer.url, self);
        peerClient.on('connected', function() {
          peer.status = 'connected';
          self.peerRegistry.save(peer);
        });

        peerClient.on('error', function(error) {
          self.peerRegistry.get(peer.id, function(err, result) {
            result = JSON.parse(result);
            result.status = 'failed';
            result.error = error;
            self.peerRegistry.save(result);
          });
        });

        peerClient.on('closed', function(reconnect) {
          self.peerRegistry.get(peer.id, function(err, result) {
            result = JSON.parse(result);
            result.status = 'connecting';
            self.peerRegistry.save(result, function() {
              peerClient.start();
            });
          });
        });

        peerClient.start();
      }
    });

    // end after db read
    callback();
  });

  return this;
};
<|endoftext|>


<commit_before>const SEARCH_RADIUS = .5;

var firebaseAuth = firebase.auth();
var firebaseDatabase = firebase.database();

// Setup commonly used refs
var usersRef = firebaseDatabase.ref("users");
var chatMessagesRef = firebaseDatabase.ref("chat-messages");
var messageLocationsRef = firebaseDatabase.ref("message-locations");

// Create a geofire object for the message locations
var messageLocationsGeoFire = new GeoFire(messageLocationsRef);
var currentLocationQuery = null;

var loginButton = $("#login-button");
var chatbox = $("#chatbox");
var messages = $("#messages");
var messageTextBox = $("#message-textbox");
messageTextBox.keypress(function(event) {
   if (event.which==13) {
       event.preventDefault();
       send();
   }
});

var currentLocation = null;
var locationWatchId = null;

var messageEnteredAreaEvent = null;
var messageExitedAreaEvent = null;

firebaseAuth.onAuthStateChanged(function(user) {
    signedInUser = user;
    if (signedInUser) {
        createUserProfileIfNotExist();
    }

    toggleLoginAndUserList();
});

function toggleLoginAndUserList() {
    if (signedInUser) {
        loginButton.val("Logout").on("click", logout);
        chatbox.fadeIn();

        // First get the current location so that we can
        // start querying the surrounding area
        getCurrentLocation(function() {
            // Start monitoring our current location and updating
            // the search query whenever our location changes
            startMonitoringLocation();
            bindChatbox();
        });
    } else {
        loginButton.val("Sign in with Google").on("click", signInWithGoogle);
        chatbox.fadeOut();
        unbindChatbox();
        stopMonitoringLocation();
    }
}

function createUserProfileIfNotExist() {
    if (!signedInUser)
        return;

    usersRef.child(signedInUser.uid).once("value", function(snapshot) {
        // User entry already exists
        if (snapshot.exists())
            return;

        // Create the user entry for the user
        usersRef.child(signedInUser.uid).set({
            name: signedInUser.displayName
        });
    });
}

function send() {
    var message = messageTextBox.val();
    if (!message || message.length==0)
        return;

    // Post the message
    chatMessagesRef.push({uid:signedInUser.uid, text:message}).then(function(snapshot) {
        // Set the messages location (notifies clients)
        messageLocationsGeoFire.set(snapshot.key, currentLocation);

        messageTextBox.val("");
        messageTextBox.focus();
    })
    .catch(function(error) {
        console.log(error);
    });
}

function bindChatbox() {
    // Wait for new messages to enter the area
    messageEnteredAreaEvent = currentLocationQuery.on("key_entered", function(key, location, distance) {

        var distanceValueElement = $("<span/>", {id:"distanceValue"}).text(distance.toFixed(2) + "km ");
        var distanceElement =  $("<span/>", {id:"distance"}).text(" - Distance: ").append(distanceValueElement);

        // Get the message for the key
        chatMessagesRef.child(key).once("value", function(snapshot) {
            var message = snapshot.val();
            if (!message)
                return;

			var messageKey = snapshot.key;
            var messageElement = $("<div />", {id: messageKey});
            var textElement =  $("<span />", {id:"text"}).text(message.text);

            // Get the posting users name
            usersRef.child(message.uid).child("name").once("value", function(snapshot) {
                var name = snapshot.val();

                // Build the message element
                messageElement
                    .append($("<span />", {id:"name"}).text(name + ": "))
                    .append(textElement)
                    .append(distanceElement);

                    if (message.uid == signedInUser.uid){
                        messageElement.append(
                            $("<a/>", {id:"delete",href:"#"})
                                .text("Delete")
                                .on("click", function() {
                                    deleteMessage(messageKey);
                                })
                        );
                    }

                    // Append the new message to the chatbox
                    messages.append(messageElement);
            });
        });
    });

    messageExitedAreaEvent = currentLocationQuery.on("key_exited", function(key) {
        messages.children("#"+key).remove();
    });
}

function unbindChatbox() {
    if (messageEnteredAreaEvent)
        messageEnteredAreaEvent.cancel();
    if (messageExitedAreaEvent)
        messageExitedAreaEvent.cancel();

    messages.empty();
}

function deleteMessage(key) {
    chatMessagesRef.child(key).remove().then(function(snapshot){
       messageLocationsGeoFire.remove(key);
    });
}

function startMonitoringLocation() {
    if (!browserSupportsLocation())
        return;

    locationWatchId = navigator.geolocation.watchPosition(function(location) {
        updateCurrentLocation(location);
    }, function(error) {
        console.log(error);
    });
}

function stopMonitoringLocation() {
    if (!browserSupportsLocation() || !locationWatchId)
        return;

    navigator.geolocation.clearWatch(locationWatchId);
    locationWatchId = null;
}

function getCurrentLocation(callback) {
    if (currentLocation)
        callback(currentLocation);

    if (!browserSupportsLocation())
        return;

    navigator.geolocation.getCurrentPosition(function(location) {
        updateCurrentLocation(location);
        callback(currentLocation);
    }, function(error) {
        console.log(error);
    });
}

function updateCurrentLocation(loc) {
    currentLocation = [loc.coords.latitude,loc.coords.longitude];
    updateCurrentLocationQuery();
}

function updateCurrentLocationQuery() {
    var criteria = {
        center: currentLocation,
        radius: SEARCH_RADIUS
    };

    if (currentLocationQuery) {
        currentLocationQuery.updateCriteria(criteria);
    } else {
        currentLocationQuery = messageLocationsGeoFire.query(criteria)
    }
}

// Public functions
function signInWithGoogle() {
    var googleProvider = new firebase.auth.GoogleAuthProvider();
    signInWithProvider(googleProvider).then(function(result) {
        console.log("Signed in!");
    }).catch(function(error) {
        console.log(error);
    });
}

// Private functions
function signInWithProvider(provider) {
    return firebaseAuth.signInWithPopup(provider);
}

function logout() {
    firebaseAuth.signOut();
}

function browserSupportsLocation() {
    return "geolocation" in navigator;
}<commit_msg>Delete the message location first, then the message itself<commit_after>const SEARCH_RADIUS = .5;

var firebaseAuth = firebase.auth();
var firebaseDatabase = firebase.database();

// Setup commonly used refs
var usersRef = firebaseDatabase.ref("users");
var chatMessagesRef = firebaseDatabase.ref("chat-messages");
var messageLocationsRef = firebaseDatabase.ref("message-locations");

// Create a geofire object for the message locations
var messageLocationsGeoFire = new GeoFire(messageLocationsRef);
var currentLocationQuery = null;

var loginButton = $("#login-button");
var chatbox = $("#chatbox");
var messages = $("#messages");
var messageTextBox = $("#message-textbox");
messageTextBox.keypress(function(event) {
   if (event.which==13) {
       event.preventDefault();
       send();
   }
});

var currentLocation = null;
var locationWatchId = null;

var messageEnteredAreaEvent = null;
var messageExitedAreaEvent = null;

firebaseAuth.onAuthStateChanged(function(user) {
    signedInUser = user;
    if (signedInUser) {
        createUserProfileIfNotExist();
    }

    toggleLoginAndUserList();
});

function toggleLoginAndUserList() {
    if (signedInUser) {
        loginButton.val("Logout").on("click", logout);
        chatbox.fadeIn();

        // First get the current location so that we can
        // start querying the surrounding area
        getCurrentLocation(function() {
            // Start monitoring our current location and updating
            // the search query whenever our location changes
            startMonitoringLocation();
            bindChatbox();
        });
    } else {
        loginButton.val("Sign in with Google").on("click", signInWithGoogle);
        chatbox.fadeOut();
        unbindChatbox();
        stopMonitoringLocation();
    }
}

function createUserProfileIfNotExist() {
    if (!signedInUser)
        return;

    usersRef.child(signedInUser.uid).once("value", function(snapshot) {
        // User entry already exists
        if (snapshot.exists())
            return;

        // Create the user entry for the user
        usersRef.child(signedInUser.uid).set({
            name: signedInUser.displayName
        });
    });
}

function send() {
    var message = messageTextBox.val();
    if (!message || message.length==0)
        return;

    // Post the message
    chatMessagesRef.push({uid:signedInUser.uid, text:message}).then(function(snapshot) {
        // Set the messages location (notifies clients)
        messageLocationsGeoFire.set(snapshot.key, currentLocation);

        messageTextBox.val("");
        messageTextBox.focus();
    })
    .catch(function(error) {
        console.log(error);
    });
}

function bindChatbox() {
    // Wait for new messages to enter the area
    messageEnteredAreaEvent = currentLocationQuery.on("key_entered", function(key, location, distance) {

        var distanceValueElement = $("<span/>", {id:"distanceValue"}).text(distance.toFixed(2) + "km ");
        var distanceElement =  $("<span/>", {id:"distance"}).text(" - Distance: ").append(distanceValueElement);

        // Get the message for the key
        chatMessagesRef.child(key).once("value", function(snapshot) {
            var message = snapshot.val();
            if (!message)
                return;

			var messageKey = snapshot.key;
            var messageElement = $("<div />", {id: messageKey});
            var textElement =  $("<span />", {id:"text"}).text(message.text);

            // Get the posting users name
            usersRef.child(message.uid).child("name").once("value", function(snapshot) {
                var name = snapshot.val();

                // Build the message element
                messageElement
                    .append($("<span />", {id:"name"}).text(name + ": "))
                    .append(textElement)
                    .append(distanceElement);

                    if (message.uid == signedInUser.uid){
                        messageElement.append(
                            $("<a/>", {id:"delete",href:"#"})
                                .text("Delete")
                                .on("click", function() {
                                    deleteMessage(messageKey);
                                })
                        );
                    }

                    // Append the new message to the chatbox
                    messages.append(messageElement);
            });
        });
    });

    messageExitedAreaEvent = currentLocationQuery.on("key_exited", function(key) {
        messages.children("#"+key).remove();
    });
}

function unbindChatbox() {
    if (messageEnteredAreaEvent)
        messageEnteredAreaEvent.cancel();
    if (messageExitedAreaEvent)
        messageExitedAreaEvent.cancel();

    messages.empty();
}

function deleteMessage(key) {
    messageLocationsGeoFire.remove(key).then(function(){
        chatMessagesRef.child(key).remove();
    });
}

function startMonitoringLocation() {
    if (!browserSupportsLocation())
        return;

    locationWatchId = navigator.geolocation.watchPosition(function(location) {
        updateCurrentLocation(location);
    }, function(error) {
        console.log(error);
    });
}

function stopMonitoringLocation() {
    if (!browserSupportsLocation() || !locationWatchId)
        return;

    navigator.geolocation.clearWatch(locationWatchId);
    locationWatchId = null;
}

function getCurrentLocation(callback) {
    if (currentLocation)
        callback(currentLocation);

    if (!browserSupportsLocation())
        return;

    navigator.geolocation.getCurrentPosition(function(location) {
        updateCurrentLocation(location);
        callback(currentLocation);
    }, function(error) {
        console.log(error);
    });
}

function updateCurrentLocation(loc) {
    currentLocation = [loc.coords.latitude,loc.coords.longitude];
    updateCurrentLocationQuery();
}

function updateCurrentLocationQuery() {
    var criteria = {
        center: currentLocation,
        radius: SEARCH_RADIUS
    };

    if (currentLocationQuery) {
        currentLocationQuery.updateCriteria(criteria);
    } else {
        currentLocationQuery = messageLocationsGeoFire.query(criteria)
    }
}

// Public functions
function signInWithGoogle() {
    var googleProvider = new firebase.auth.GoogleAuthProvider();
    signInWithProvider(googleProvider).then(function(result) {
        console.log("Signed in!");
    }).catch(function(error) {
        console.log(error);
    });
}

// Private functions
function signInWithProvider(provider) {
    return firebaseAuth.signInWithPopup(provider);
}

function logout() {
    firebaseAuth.signOut();
}

function browserSupportsLocation() {
    return "geolocation" in navigator;
}<|endoftext|>


<commit_before>/*
* Simulazione del problema degli n-corpi applicata ad una parte del sistema solare (sole, mercurio, venere, terra, marte)
* tramite metodo di Eulero, con un dt di 1 ora.
*/

//Costante di Gravitazione
var G = 6.67408e-11;

class Vector{
  constructor(x, y){
    this.x = x;
    this.y = y;
  }
}

class Planet {
  constructor(x, y, mass, velocity, stage, planetsList, color) {
    this.x = x;
    this.y = y;
    this.dx = 0;
    this.dy = 0;
    this.mass = mass;
    this.velocity = velocity;
    this.stage = stage;

    //Traccia dell'orbita
    this.orbitStroke = new createjs.Shape();
    this.stage.addChild(this.orbitStroke);

    this.shape = new createjs.Shape();
    this.shape.graphics.beginFill(color).drawCircle(0, 0, 10);
    this.stage.addChild(this.shape);

    this.planetsList = planetsList;

  }
  update(){
    //Per ogni pianeta che influisce nel sistema calcolo l'attrazione gravitazionale
    //si potrebbe ottimizzare questa parte
    var forzeAgenti = [];
    this.planetsList.forEach(function(planet) {
      if(planet != this){
        //Distanza tra i due pianeti
        var r = Math.sqrt(Math.pow(this.x - planet.x, 2) + Math.pow(this.y - planet.y, 2));
        //Forza di attrazione tra i due pianeti (intensità del vettore F)
        var Fg = -G * ((this.mass * planet.mass) / Math.pow(r, 2));
        //trovo l'angolo in radianti tra i due pianeti (direzione del vettore F)
        var deltaX = this.x - planet.x;
        var deltaY = this.y - planet.y;
        var angle = Math.atan2(deltaY, deltaX);
        //trovo le componenti x e y della forza
        var Fx = Fg * Math.cos(angle);
        var Fy = Fg * Math.sin(angle);
        //Aggiungo la forza nell'elenco di tutte le forze agenti
        forzeAgenti.push(new Vector(Fx, Fy));
      }
    }, this);

    //Trovo la forza risultante sommando i vettori di forza agenti sul pianeta
    var Fx = 0;
    var Fy = 0;
    forzeAgenti.forEach(function(forza) {
      Fx += forza.x;
      Fy += forza.y;
    });
    var Frisultante = new Vector(Fx, Fy);

    //Calcolo le componenti dell'accelerazione
    var Ax = Frisultante.x / this.mass;
    var Ay = Frisultante.y / this.mass;
    //dt in secondi
    var dt = 60*60*1; //1h
    this.dx = (this.velocity.x * dt) + ((1/2) * Ax * Math.pow(dt, 2));
    this.dy = (this.velocity.y * dt) + ((1/2) * Ay * Math.pow(dt, 2));

    this.velocity.x = this.velocity.x + (Ax * dt);
    this.velocity.y = this.velocity.y + (Ay * dt);
  }
  //Viene eseguito dopo che tutti i corpi hanno calcolato le loro forze, altrimenti se modificassi la posizione in istanti diversi dei vari corpi il calcolo risulta errato
  afterUpdate(){
    this.x += this.dx;
    this.y += this.dy;
    //Utilizzo un fattore di divisione pari a 1*10^9 per scalare le dimensioni della posizione, per farle rientrare su schermo
    var newshapeX = Math.round((stage.canvas.width/2) + (this.x/1e9));
    var newshapeY = Math.round((stage.canvas.height/2) + (this.y/1e9));

    //Traccio l'orbita
    if(this.shape.x != 0 && this.shape.y != 0){
      this.orbitStroke.graphics.setStrokeStyle(2);
      this.orbitStroke.graphics.beginStroke("red");
      this.orbitStroke.graphics.moveTo(this.shape.x,this.shape.y);
      this.orbitStroke.graphics.lineTo(newshapeX, newshapeY);
      this.orbitStroke.graphics.endStroke();
    }

    //Sposto il pianeta
    this.shape.x = newshapeX;
    this.shape.y = newshapeY;
    //console.log(this.shape.x + ", " + this.shape.y);
  }

}

stage = new createjs.Stage("appCanvas");
background = new createjs.Shape();
background.graphics.beginFill("black").drawRect(0, 0, stage.canvas.width, stage.canvas.height);
stage.addChild(background);

planetsList = [];

//Tutti i pianeti sono presi al Perielio con la loro velocità max, fonte dei dati Wikipedia
const sole = new Planet(0, 0, 1.98855e30 , new Vector(0,0), stage, planetsList, "#ffff36");
const mercurio = new Planet(4.6001272e10, 0, 3.302e23 , new Vector(0,-5.8980e4), stage, planetsList, "#808080");
const venere = new Planet(1.07476002e11, 0, 4.8685e24 , new Vector(0,-3.5259e4), stage, planetsList, "#b94646");
const terra = new Planet(1.47098074e11, 0, 5.9726e24 , new Vector(0,-3.02865e4), stage, planetsList, "#19a3ff");
const marte = new Planet(2.06644545e11, 0, 6.4185e23 , new Vector(0,-2.6499e4), stage, planetsList, "#b94646");

planetsList.push(sole);
planetsList.push(mercurio);
planetsList.push(venere);
planetsList.push(terra);
planetsList.push(marte);

//Contatore delle ore
var elapsedHours = 0;
//Calcolo le posizioni dei pianeti nel tempo ogni 10ms
function timeout() {
  window.setTimeout(function (){
    planetsList.forEach(function (planet){
      planet.update();
    });
    planetsList.forEach(function (planet){
      planet.afterUpdate();
    });
    elapsedHours++;
    timeout();

  }, 10); //1gg = 1sec
}
timeout();

//Mostro a schermo la posizione dei nuovi pianeti a circa 30FPS
function timeout2() {
  window.setTimeout(function (){

    stage.update();
    timeout2();

  }, 33);
}
timeout2();

//Aggiorno il testo che mostra il giorno ogni 200ms
var text = new createjs.Text("Giorno: 0", "20px Arial", "#ff7700");
text.x = 10;
text.y = 10;
stage.addChild(text);
function timeout3() {
  window.setTimeout(function (){
    text.text = "Giorno: " + Math.round(elapsedHours/24);
    timeout3();
  }, 200);
}
timeout3();
<commit_msg>aggiunti commenti al codice<commit_after>/*
* Simulazione del problema degli n-corpi applicata ad una parte del sistema solare (sole, mercurio, venere, terra, marte)
* tramite metodo di Eulero, con un dt di 1 ora.
*/

//Costante di Gravitazione
var G = 6.67408e-11;

class Vector{
  constructor(x, y){
    this.x = x;
    this.y = y;
  }
}

//la classe rappresenta un corpo nello spazio, la dicitura pianeta non è del tutto corretta
class Planet {
  constructor(x, y, mass, velocity, stage, planetsList, color) {
    //Posizione x e y del pianeta
    this.x = x;
    this.y = y;
    //Incremento tra uno step e l'altro delle componenti x e y
    this.dx = 0;
    this.dy = 0;
    //Massa del pianeta
    this.mass = mass;
    //Vettore velocità
    this.velocity = velocity;

    this.stage = stage;

    //Traccia dell'orbita
    this.orbitStroke = new createjs.Shape();
    this.stage.addChild(this.orbitStroke);

    //Rappresentazione del pianeta
    this.shape = new createjs.Shape();
    this.shape.graphics.beginFill(color).drawCircle(0, 0, 10);
    this.stage.addChild(this.shape);

    this.planetsList = planetsList;

  }
  update(){
    //Per ogni pianeta che influisce nel sistema calcolo l'attrazione gravitazionale
    //si potrebbe ottimizzare questa parte (anche perchè calcola due volte la stessa forza per 2 pianeti)

    //Elenco delle forze agenti sul pianeta
    var forzeAgenti = [];
    //Per ogni pianeta presente
    this.planetsList.forEach(function(planet) {
      if(planet != this){
        //Distanza tra i due pianeti
        var r = Math.sqrt(Math.pow(this.x - planet.x, 2) + Math.pow(this.y - planet.y, 2));
        //Forza di attrazione tra i due pianeti (intensità del vettore F)
        var Fg = -G * ((this.mass * planet.mass) / Math.pow(r, 2));
        //trovo l'angolo in radianti tra i due pianeti (direzione del vettore F)
        var deltaX = this.x - planet.x;
        var deltaY = this.y - planet.y;
        var angle = Math.atan2(deltaY, deltaX);
        //trovo le componenti x e y della forza
        var Fx = Fg * Math.cos(angle);
        var Fy = Fg * Math.sin(angle);
        //Aggiungo la forza nell'elenco di tutte le forze agenti
        forzeAgenti.push(new Vector(Fx, Fy));
      }
    }, this);

    //Trovo la forza risultante sommando i vettori di forza agenti sul pianeta
    var Fx = 0;
    var Fy = 0;
    forzeAgenti.forEach(function(forza) {
      Fx += forza.x;
      Fy += forza.y;
    });
    var Frisultante = new Vector(Fx, Fy);

    //Calcolo le componenti dell'accelerazione
    var Ax = Frisultante.x / this.mass;
    var Ay = Frisultante.y / this.mass;

    //dt in secondi, ovvero l'incremento dell'integratore di eulero
    var dt = 60*60*1; //1h
    //Calcolo la variazione di posizione usando l'equazione di un moto unif. accelerato
    this.dx = (this.velocity.x * dt) + ((1/2) * Ax * Math.pow(dt, 2));
    this.dy = (this.velocity.y * dt) + ((1/2) * Ay * Math.pow(dt, 2));

    //Calcolo la nuova velocità del pianeta
    this.velocity.x = this.velocity.x + (Ax * dt);
    this.velocity.y = this.velocity.y + (Ay * dt);
  }
  //Viene eseguito dopo che tutti i corpi hanno calcolato le loro forze, altrimenti se modificassi la posizione in istanti diversi dei vari corpi il calcolo risulta errato
  afterUpdate(){
    //Sposto il pianeta nella sua nuova posizione
    this.x += this.dx;
    this.y += this.dy;

    //Utilizzo un fattore di divisione pari a 1*10^9 per scalare le dimensioni della posizione, per farle rientrare su schermo
    var newshapeX = Math.round((stage.canvas.width/2) + (this.x/1e9));
    var newshapeY = Math.round((stage.canvas.height/2) + (this.y/1e9));

    //Traccio l'orbita
    if(this.shape.x != 0 && this.shape.y != 0){
      this.orbitStroke.graphics.setStrokeStyle(2);
      this.orbitStroke.graphics.beginStroke("red");
      this.orbitStroke.graphics.moveTo(this.shape.x,this.shape.y);
      this.orbitStroke.graphics.lineTo(newshapeX, newshapeY);
      this.orbitStroke.graphics.endStroke();
    }

    //Sposto il pianeta a livello grafico
    this.shape.x = newshapeX;
    this.shape.y = newshapeY;

    //console.log(this.shape.x + ", " + this.shape.y);
  }

}

stage = new createjs.Stage("appCanvas");
background = new createjs.Shape();
background.graphics.beginFill("black").drawRect(0, 0, stage.canvas.width, stage.canvas.height);
stage.addChild(background);

//Lista dei pianeti
planetsList = [];

//Tutti i pianeti sono presi al Perielio con la loro velocità max, fonte dei dati Wikipedia
const sole = new Planet(0, 0, 1.98855e30 , new Vector(0,0), stage, planetsList, "#ffff36");
const mercurio = new Planet(4.6001272e10, 0, 3.302e23 , new Vector(0,-5.8980e4), stage, planetsList, "#808080");
const venere = new Planet(1.07476002e11, 0, 4.8685e24 , new Vector(0,-3.5259e4), stage, planetsList, "#b94646");
const terra = new Planet(1.47098074e11, 0, 5.9726e24 , new Vector(0,-3.02865e4), stage, planetsList, "#19a3ff");
const marte = new Planet(2.06644545e11, 0, 6.4185e23 , new Vector(0,-2.6499e4), stage, planetsList, "#b94646");

planetsList.push(sole);
planetsList.push(mercurio);
planetsList.push(venere);
planetsList.push(terra);
planetsList.push(marte);

//Contatore delle ore
var elapsedHours = 0;

//I seguenti timeout possono essere migliorati inserendo all'interno un ciclo for che esegua tot step e solo poi aggiorni a schermo la posizione
//Calcolo le posizioni dei pianeti nel tempo ogni 10ms
function timeout() {
  window.setTimeout(function (){
    planetsList.forEach(function (planet){
      planet.update();
    });
    planetsList.forEach(function (planet){
      planet.afterUpdate();
    });
    elapsedHours++;
    timeout();

  }, 10); //1gg = 1sec
}
timeout();

//Mostro a schermo la posizione dei nuovi pianeti a circa 30FPS
function timeout2() {
  window.setTimeout(function (){

    stage.update();
    timeout2();

  }, 33);
}
timeout2();

//Aggiorno il testo che mostra il giorno ogni 200ms
var text = new createjs.Text("Giorno: 0", "20px Arial", "#ff7700");
text.x = 10;
text.y = 10;
stage.addChild(text);
function timeout3() {
  window.setTimeout(function (){
    text.text = "Giorno: " + Math.round(elapsedHours/24);
    timeout3();
  }, 200);
}
timeout3();
<|endoftext|>