<commit_before>"use strict";
let fetch = require('../../helpers/fetch-json');
let Promise = require('bluebird');
let _ = require("lodash");
let writeFile = Promise.promisify(require('fs').writeFile);
let levenshteinStringDistance = require("levenshtein-string-distance");
const NAME = "declarations.com.ua";
const input = require("./../../input/index");
const output = require("./../../output/index");
const inJudgeModel = require("./../../input/judge.json");
const outJudgeModel = require("./../../output/judge.json");
const homonymsBlacklistDeclarationsComUaKeys = {
    melnik_oleksandr_mihaylovich_novomoskovskiy_miskrayonniy_dnipropetrovskoyi_oblasti: ["vulyk_66_51", "vulyk_11_177"],
    melnik_oleksandr_mihaylovich_mikolayivskiy_okruzhniy_administrativniy_sud: ["vulyk_77_27", "vulyk_11_177"],
    tkachenko_oleg_mikolayovich: ["vulyk_30_158"],
    mikulyak_pavlo_pavlovich_zakarpatskiy_okruzhniy_administrativniy_sud: ["vulyk_68_5"],
    mikulyak_pavlo_pavlovich_uzhgorodskiy_miskrayonniy_sud_zakarpatskoyi_oblasti: ["vulyk_67_185"],
    shevchenko_oleksandr_volodimirovich: ["vulyk_35_200"],
    dyachuk_vasil_mikolayovich: ["vulyk_28_124"]
};
function getSearchLink(s) {
    if ("Абдукадирова Каріне Ескандерівна" === s) {
        s = "Абдукадирова Каріне Ескендерівна";
    }
    s = encodeURI(s);
    return `http://declarations.com.ua/search?q=${s}&format=json`;
}

module.exports = function searchDeclaration(judge) {

    return fetch(getSearchLink(judge[inJudgeModel.name]))
        .then(response => {
            let uniq, duplicatedYears, groupedDuplicates;

            return _.chain(_.get(response, "results.object_list"))
                .omit("ft_src")
                .filter(declaration => {
                    const given = _.lowerCase(judge[inJudgeModel.name]);
                    const fetched = _.lowerCase(_.get(declaration, "general.full_name"));
                    return levenshteinStringDistance(given, fetched) <= 1;
                })
                .tap(declarations => {
                    uniq = _.countBy(response, d => _.get(d, "intro.declaration_year"));
                    duplicatedYears = Object.keys(uniq).filter((a) => uniq[a] > 1);
                    if (_.size(duplicatedYears)) {
                        groupedDuplicates = _.groupBy(response, d => _.get(d, "intro.declaration_year"));
                    }
                    return declarations;
                })
                .filter(function (declaration, index, declarations) {
                    if (_.size(duplicatedYears) && _.includes(duplicatedYears, _.get(declaration, "intro.declaration_year"))) {
                        debugger;
                    }
                    if (_.includes(homonymsBlacklistDeclarationsComUaKeys[judge.key], declaration.id)) {
                        return false;
                    }
                    return true;
                })
                .sortBy(declaration => -parseInt(_.get(declaration, "intro.declaration_year"), 10))
                .value();
        })
        .then(declarations => {
            return Promise.map(declarations, declaration => {
                return writeFile(`../declarations/${declaration.id}.json`, JSON.stringify(declaration));
            })
                .then(() => {
                    return declarations;
                });
        })
        .then(declarations => {
            return _.map(declarations, declaration => {
                return {
                    provider: NAME,
                    document: declaration
                };
            });
        })
        .catch(function (e) {
            throw new Error(e.message);
        })
};
<commit_msg>make declarations KeysBeSorted from declarations.com.ua provider's data<commit_after>"use strict";
let fetch = require('../../helpers/fetch-json');
let Promise = require('bluebird');
let _ = require("lodash");
let writeFile = Promise.promisify(require('fs').writeFile);
let levenshteinStringDistance = require("levenshtein-string-distance");
const NAME = "declarations.com.ua";
const input = require("./../../input/index");
const output = require("./../../output/index");
const inJudgeModel = require("./../../input/judge.json");
const outJudgeModel = require("./../../output/judge.json");
const homonymsBlacklistDeclarationsComUaKeys = {
    melnik_oleksandr_mihaylovich_novomoskovskiy_miskrayonniy_dnipropetrovskoyi_oblasti: ["vulyk_66_51", "vulyk_11_177"],
    melnik_oleksandr_mihaylovich_mikolayivskiy_okruzhniy_administrativniy_sud: ["vulyk_77_27", "vulyk_11_177"],
    tkachenko_oleg_mikolayovich: ["vulyk_30_158"],
    mikulyak_pavlo_pavlovich_zakarpatskiy_okruzhniy_administrativniy_sud: ["vulyk_68_5"],
    mikulyak_pavlo_pavlovich_uzhgorodskiy_miskrayonniy_sud_zakarpatskoyi_oblasti: ["vulyk_67_185"],
    shevchenko_oleksandr_volodimirovich: ["vulyk_35_200"],
    dyachuk_vasil_mikolayovich: ["vulyk_28_124"]
};
function getSearchLink(s) {
    if ("Абдукадирова Каріне Ескандерівна" === s) {
        s = "Абдукадирова Каріне Ескендерівна";
    }
    s = encodeURI(s);
    return `http://declarations.com.ua/search?q=${s}&format=json`;
}

// This is workaround for making git happy.
// The problem is – git "highlight" changes, where they don't,
// just because declarations.com.ua time to time change object_list keys order without making any changes to data.
function makeObjectKeysBeSorted(o) {
    return Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {});
}

module.exports = function searchDeclaration(judge) {

    return fetch(getSearchLink(judge[inJudgeModel.name]))
        .then(response => {
            let uniq, duplicatedYears, groupedDuplicates;

            return _.chain(_.get(response, "results.object_list"))
                .omit("ft_src")
                .tap(declaration => {
                    return makeObjectKeysBeSorted(declaration);
                })
                .filter(declaration => {
                    const given = _.lowerCase(judge[inJudgeModel.name]);
                    const fetched = _.lowerCase(_.get(declaration, "general.full_name"));
                    return levenshteinStringDistance(given, fetched) <= 1;
                })
                .tap(declarations => {
                    uniq = _.countBy(response, d => _.get(d, "intro.declaration_year"));
                    duplicatedYears = Object.keys(uniq).filter((a) => uniq[a] > 1);
                    if (_.size(duplicatedYears)) {
                        groupedDuplicates = _.groupBy(response, d => _.get(d, "intro.declaration_year"));
                    }
                    return declarations;
                })
                .filter(function (declaration, index, declarations) {
                    if (_.size(duplicatedYears) && _.includes(duplicatedYears, _.get(declaration, "intro.declaration_year"))) {
                        debugger;
                    }
                    if (_.includes(homonymsBlacklistDeclarationsComUaKeys[judge.key], declaration.id)) {
                        return false;
                    }
                    return true;
                })
                .sortBy(declaration => -parseInt(_.get(declaration, "intro.declaration_year"), 10))
                .value();
        })
        .then(declarations => {
            return Promise.map(declarations, declaration => {
                return writeFile(`../declarations/${declaration.id}.json`, JSON.stringify(declaration));
            })
                .then(() => {
                    return declarations;
                });
        })
        .then(declarations => {
            return _.map(declarations, declaration => {
                return {
                    provider: NAME,
                    document: declaration
                };
            });
        })
        .catch(function (e) {
            throw new Error(e.message);
        })
};
<|endoftext|>


<commit_before>const mongoose = require('mongoose');
const logger   = require('../logger');
const Blocks   = require('./blocks');
const Txs   = require('./transactions');

mongoose.connection.on('error', (err) => {
  logger.log('error',
    `Failed to connect to Mongo Database
    ${err}`);
});

module.exports = {
  connect:    mongoose.connect,
  connection: mongoose.connection,
  blocks:     Blocks,
  txs:        Txs,
};
<commit_msg>Graceful Shutdown for mongodb<commit_after>const mongoose = require('mongoose');
const logger   = require('../logger');
const Blocks   = require('./blocks');
const Txs   = require('./transactions');

mongoose.connection.on('error', (err) => {
  logger.log('error',
    `Failed to connect to Mongo Database
    ${err}`);
});

process.on('SIGINT', gracefulExit).on('SIGTERM', gracefulExit);

function gracefulExit() {
  mongoose.connection.close(() => {
    console.log('Mongoose connection with DB disconnected through app termination');
    process.exit(0);
  });
}

module.exports = {
  connect:    mongoose.connect,
  connection: mongoose.connection,
  blocks:     Blocks,
  txs:        Txs,
};
<|endoftext|>


<commit_before>angular.module('eappApp').controller('ShopController', ["$scope", "$q", "$http", "$mdDialog", "$rootScope", "eapp", function ($scope, $q, $http, $mdDialog, $rootScope, eapp)
{
    $rootScope.query =
    {
        filter: '',
        limit: '20',
        order: 'name',
        page: 1
    };

    $rootScope.searchText = "";

    $scope.ready = false;

    $scope.isLoading = false;

    $scope.isInitialized = false;

    $scope.root = $rootScope;

    var ctrl = this;

    /**
     * This variable is true when a store is selected.
     */
    $scope.isStoreSelected = false;

    $scope.viewConfig = { viewAll : true };

    $scope.productsReady = false;

    angular.element(document).ready(function()
    {
        if(!$scope.ready)
        {
            $scope.Init();
            $scope.ready = true;
        }
    });
    var bookmark;

    $scope.Init = function()
    {
        $scope.assets_dir = $scope.base_url.concat("/eapp/assets/");

        //$rootScope.hideSearchArea = true;

        if(window.sessionStorage.getItem("searchText"))
        {
            $rootScope.searchText = window.sessionStorage.getItem("searchText");
            window.sessionStorage.removeItem("searchText");
            $rootScope.query.filter = $rootScope.searchText;
        }

        // Get the products for the store
        if($scope.controller === 'shop')
        {
            // We selected a specific store flyer
            if(window.sessionStorage.getItem("store_id"))
            {
                $scope.store_id = parseInt(window.sessionStorage.getItem("store_id"));
                $scope.store_name = window.sessionStorage.getItem("store_name");
                $scope.isStoreSelected = true;
            }

            // We selected a specific category
            if(window.sessionStorage.getItem("category_id"))
            {
                $scope.category_id = parseInt(window.sessionStorage.getItem("category_id"));
                $scope.category_name = window.sessionStorage.getItem("category_name");
            }

            $rootScope.isSearch = true;

            $scope.isInitialized = true;

        }

        if(window.sessionStorage.getItem("gridView"))
        {
            var gv = window.sessionStorage.getItem("gridView").toString();

            if(!angular.isNullOrUndefined(gv))
            {
                $scope.gridView = JSON.parse(gv);
            }
            else
            {
                $scope.gridView = false;

            }
        }
        else
        {
            $scope.gridView = false;
        }

        $scope.distance = $rootScope.getOptimizationDistance();

    };

    $rootScope.add_product_to_cart = function(product_id, store_product_id = -1, product_quantity = 1)
    {
        if(typeof store_product_id === 'undefined')
        {
            store_product_id = -1;
        }

        var addToCartPromise = eapp.addToCart(
                product_id,
                store_product_id,
                $rootScope.isUserLogged ? $rootScope.loggedUser.profile.longitude : $rootScope.longitude,
                $rootScope.isUserLogged ? $rootScope.loggedUser.profile.latitude : $rootScope.latitude,
                product_quantity);

        addToCartPromise.then(function(response)
        {
            if(Boolean(response.data.success))
            {
                var cart_item =
                {
                    rowid : response.data.rowid,
                    store_product : response.data.store_product,
                    top_five_store_products : [],
                    quantity : product_quantity,
                    store_product_id : store_product_id
                };

                if($rootScope.cart === null || typeof $rootScope.cart === 'undefined')
                {
                    $rootScope.cart = [];
                }

                $rootScope.cart.push(cart_item);
            }
        });
    };

    $scope.remove_from_cart = function(product_id)
    {
        $scope.removeItemFromCart(product_id);
    };

    $scope.selected = [];

    $scope.filter =
    {
        options:
        {
            debounce: 500
        }
    };

    $scope.getProducts = function ()
    {
        $scope.productsReady = false;
        $scope.isStoreSelected = false;
        $scope.isLoading = true;

        if(!$scope.ready || !$scope.isInitialized)
        {
            return;
        }

        if(window.sessionStorage.getItem("filterSettings"))
        {
            var settings = window.sessionStorage.getItem("filterSettings");

            if(!angular.isNullOrUndefined(settings))
            {
                $scope.filterSettings = JSON.parse(settings.toString());

                // Get the filter from the current settings and checks if a store is selected
                $scope.createResultsFilter();

                $scope.productsReady = true;
            }
            else
            {
                window.sessionStorage.removeItem("filterSettings");
            }
        }

	if(window.sessionStorage.getItem("viewConfig"))
        {
            var config = window.sessionStorage.getItem("viewConfig");

            if(!angular.isNullOrUndefined(config))
            {
                $scope.viewConfig = JSON.parse(config.toString());

                if($scope.viewConfig.viewAll)
                {
                    $scope.isStoreSelected = true;
                }
            }
            else
            {
                window.sessionStorage.removeItem("viewConfig");
            }
        }

        var q = $q.defer();

        $scope.isStoreSelected = $scope.IsStoreSelected();

        if(!angular.isNullOrUndefined($scope.store_id))
        {
            $scope.promise = eapp.getFlyerProducts($scope.store_id, $scope.query, $scope.resultFilter, $scope.viewConfig);
        }
        else if(!angular.isNullOrUndefined($scope.category_id))
        {
            $scope.promise = eapp.getCategoryProducts($scope.category_id, $scope.query, $scope.resultFilter, $scope.viewConfig);
        }
        else
        {
            $scope.promise = eapp.getStoreProducts($scope.query, $scope.resultFilter, $scope.viewConfig);
        }

        $scope.promise.then(function(response)
        {
            var array = $.map(response.data.products, function(value, index) {
                return [value];
            });

            $scope.count = response.data.count;

            $scope.maxPageItem = Math.min(parseInt(($scope.query.page * $scope.query.limit)), parseInt($scope.count));

            $scope.products = array;

            $scope.filterSettings = response.data.settings;

            window.sessionStorage.setItem("filterSettings", JSON.stringify($scope.filterSettings));

            $scope.hasResults = array.length > 0;

            q.resolve( array );

            $scope.productsReady = true;

            $scope.isLoading = false;

        });

        return q.promise;
  };

    $scope.IsStoreSelected = function()
    {
        if(!angular.isNullOrUndefined($scope.store_id))
        {
            return true;
        }

        if(!angular.isNullOrUndefined($scope.filterSettings))
        {
            for(var x in $scope.filterSettings.stores.values)
            {
                var store = $scope.filterSettings.stores.values[x];

                if(store.selected)
                {
                    return true;
                }
            }
        }

        if($scope.viewConfig.viewAll)
        {
            return true;
        }

        return false;
    };

    ctrl.oldValue = null;

    $scope.search = function()
    {
        if(!ctrl.oldValue)
        {
            bookmark = $scope.query.page;
        }

        if($scope.query.filter !== ctrl.oldValue)
        {
            $scope.query.page = 1;
        }

        if(!ctrl.oldValue)
        {
            $scope.query.page = bookmark;
        }

        $scope.getProducts();
    };

    $scope.refresh = function(viewConfig)
    {
        $scope.viewConfig = viewConfig;

        if($scope.viewConfig.viewAll)
        {
            $scope.isStoreSelected = true;
        }
        else
        {
            $scope.isStoreSelected = $scope.IsStoreSelected();
        }

	// Save the new configuration for the current session
	window.sessionStorage.setItem("viewConfig", JSON.stringify($scope.viewConfig));

        $scope.getProducts();
    };

    $scope.searchProducts = function(searchText)
    {
        $scope.clearSessionItems();
        window.sessionStorage.setItem("searchText", searchText);
        window.location.href =  $scope.site_url.concat("/shop");
    };

    $rootScope.select_category = function($event, category)
    {
        $scope.clearSessionItems();
        var category_id = parseInt(category.id);
        eapp.recordHit("eapp_product_category ",category_id);
        window.sessionStorage.setItem("category_id", category_id);
        window.sessionStorage.setItem("category_name", category.name);
        window.location =  $scope.site_url.concat("/shop");
    };

    $scope.viewProduct = function(product_id, ev)
    {
        eapp.viewProduct($scope, product_id, ev);
    };

    $scope.settingsChanged = function(item)
    {
        $scope.updateItemChanged(item);

        window.sessionStorage.setItem("filterSettings", JSON.stringify($scope.filterSettings));

        // Get store filter
        $scope.createResultsFilter();

        $scope.getProducts();

    };

    $scope.updateItemChanged = function(item)
    {
        var index = $scope.filterSettings[item.type].values.map(function(e){ return e.name; }).indexOf(item.name);

        if(index > -1)
        {
            $scope.filterSettings[item.type].values[index] = item;
        }
    };

    $scope.createResultsFilter = function()
    {
        if(angular.isNullOrUndefined($scope.filterSettings))
        {
            return;
        }

        $scope.resultFilter = {};

        for(var x in $scope.filterSettings)
        {
            var values = $scope.filterSettings[x].values;
            var setting = $scope.filterSettings[x].setting;
            var filter = "";
            for(var y in values)
            {
                if(values[y].selected)
                {
                    var value = values[y].id.toString();

                    if(value === "Autre")
                    {
                        value = "";
                    }

                    if(filter === "")
                    {
                        if(value === "")
                        {
                            filter = filter.concat(",", value);
                        }
                        else
                        {
                            filter = filter.concat("", value);
                        }
                    }
                    else
                    {
                        filter = filter.concat(",", value);
                    }

                }
            }

            $scope.resultFilter[setting.name] = filter;
        }

    };

    $scope.changeDistance = function(newDistance)
    {
        if($scope.isUserLogged)
        {
            var changePromise = eapp.changeDistance('optimization_distance', newDistance);

            changePromise.then(function(response)
            {
                if(response.data)
                {
                    // Update Logged User
                    $rootScope.loggedUser = response.data;
                    $scope.getProducts();
                }
            });
        }
        else
        {
            // Change in the session
            window.localStorage.setItem('optimization_distance', newDistance);
            $scope.getProducts();
        }

        $mdDialog.cancel();
    };

    $scope.$watch("query.page", function(newValue, oldValue)
    {
        window.scrollTo(0, 0);
    });

    $scope.$watch("gridView", function(newValue, oldValue)
    {
        if(!angular.isNullOrUndefined($scope.gridView))
        {
            window.sessionStorage.setItem("gridView", JSON.stringify($scope.gridView));
        }

    });

}]);
<commit_msg>Improve feedback when distance in changed in the shop. <commit_after>angular.module('eappApp').controller('ShopController', ["$scope", "$q", "$http", "$mdDialog", "$rootScope", "eapp", function ($scope, $q, $http, $mdDialog, $rootScope, eapp)
{
    $rootScope.query =
    {
        filter: '',
        limit: '20',
        order: 'name',
        page: 1
    };

    $rootScope.searchText = "";

    $scope.ready = false;

    $scope.isLoading = false;

    $scope.isInitialized = false;

    $scope.root = $rootScope;

    var ctrl = this;

    /**
     * This variable is true when a store is selected.
     */
    $scope.isStoreSelected = false;

    $scope.viewConfig = { viewAll : true };

    $scope.productsReady = false;

    angular.element(document).ready(function()
    {
        if(!$scope.ready)
        {
            $scope.Init();
            $scope.ready = true;
        }
    });
    var bookmark;

    $scope.Init = function()
    {
        $scope.assets_dir = $scope.base_url.concat("/eapp/assets/");

        //$rootScope.hideSearchArea = true;

        if(window.sessionStorage.getItem("searchText"))
        {
            $rootScope.searchText = window.sessionStorage.getItem("searchText");
            window.sessionStorage.removeItem("searchText");
            $rootScope.query.filter = $rootScope.searchText;
        }

        // Get the products for the store
        if($scope.controller === 'shop')
        {
            // We selected a specific store flyer
            if(window.sessionStorage.getItem("store_id"))
            {
                $scope.store_id = parseInt(window.sessionStorage.getItem("store_id"));
                $scope.store_name = window.sessionStorage.getItem("store_name");
                $scope.isStoreSelected = true;
            }

            // We selected a specific category
            if(window.sessionStorage.getItem("category_id"))
            {
                $scope.category_id = parseInt(window.sessionStorage.getItem("category_id"));
                $scope.category_name = window.sessionStorage.getItem("category_name");
            }

            $rootScope.isSearch = true;

            $scope.isInitialized = true;

        }

        if(window.sessionStorage.getItem("gridView"))
        {
            var gv = window.sessionStorage.getItem("gridView").toString();

            if(!angular.isNullOrUndefined(gv))
            {
                $scope.gridView = JSON.parse(gv);
            }
            else
            {
                $scope.gridView = false;

            }
        }
        else
        {
            $scope.gridView = false;
        }

        $scope.distance = $rootScope.getOptimizationDistance();

    };

    $rootScope.add_product_to_cart = function(product_id, store_product_id = -1, product_quantity = 1)
    {
        if(typeof store_product_id === 'undefined')
        {
            store_product_id = -1;
        }

        var addToCartPromise = eapp.addToCart(
                product_id,
                store_product_id,
                $rootScope.isUserLogged ? $rootScope.loggedUser.profile.longitude : $rootScope.longitude,
                $rootScope.isUserLogged ? $rootScope.loggedUser.profile.latitude : $rootScope.latitude,
                product_quantity);

        addToCartPromise.then(function(response)
        {
            if(Boolean(response.data.success))
            {
                var cart_item =
                {
                    rowid : response.data.rowid,
                    store_product : response.data.store_product,
                    top_five_store_products : [],
                    quantity : product_quantity,
                    store_product_id : store_product_id
                };

                if($rootScope.cart === null || typeof $rootScope.cart === 'undefined')
                {
                    $rootScope.cart = [];
                }

                $rootScope.cart.push(cart_item);
            }
        });
    };

    $scope.remove_from_cart = function(product_id)
    {
        $scope.removeItemFromCart(product_id);
    };

    $scope.selected = [];

    $scope.filter =
    {
        options:
        {
            debounce: 500
        }
    };

    $scope.getProducts = function ()
    {
        $scope.productsReady = false;
        $scope.isStoreSelected = false;
        $scope.isLoading = true;

        if(!$scope.ready || !$scope.isInitialized)
        {
            return;
        }

        if(window.sessionStorage.getItem("filterSettings"))
        {
            var settings = window.sessionStorage.getItem("filterSettings");

            if(!angular.isNullOrUndefined(settings))
            {
                $scope.filterSettings = JSON.parse(settings.toString());

                // Get the filter from the current settings and checks if a store is selected
                $scope.createResultsFilter();

                $scope.productsReady = true;
            }
            else
            {
                window.sessionStorage.removeItem("filterSettings");
            }
        }

	if(window.sessionStorage.getItem("viewConfig"))
        {
            var config = window.sessionStorage.getItem("viewConfig");

            if(!angular.isNullOrUndefined(config))
            {
                $scope.viewConfig = JSON.parse(config.toString());

                if($scope.viewConfig.viewAll)
                {
                    $scope.isStoreSelected = true;
                }
            }
            else
            {
                window.sessionStorage.removeItem("viewConfig");
            }
        }

        var q = $q.defer();

        $scope.isStoreSelected = $scope.IsStoreSelected();

        if(!angular.isNullOrUndefined($scope.store_id))
        {
            $scope.promise = eapp.getFlyerProducts($scope.store_id, $scope.query, $scope.resultFilter, $scope.viewConfig);
        }
        else if(!angular.isNullOrUndefined($scope.category_id))
        {
            $scope.promise = eapp.getCategoryProducts($scope.category_id, $scope.query, $scope.resultFilter, $scope.viewConfig);
        }
        else
        {
            $scope.promise = eapp.getStoreProducts($scope.query, $scope.resultFilter, $scope.viewConfig);
        }

        $scope.promise.then(function(response)
        {
            var array = $.map(response.data.products, function(value, index) {
                return [value];
            });

            $scope.count = response.data.count;

            $scope.maxPageItem = Math.min(parseInt(($scope.query.page * $scope.query.limit)), parseInt($scope.count));

            $scope.products = array;

            $scope.filterSettings = response.data.settings;

            window.sessionStorage.setItem("filterSettings", JSON.stringify($scope.filterSettings));

            $scope.hasResults = array.length > 0;

            q.resolve( array );

            $scope.productsReady = true;

            $scope.isLoading = false;

        });

        return q.promise;
  };

    $scope.IsStoreSelected = function()
    {
        if(!angular.isNullOrUndefined($scope.store_id))
        {
            return true;
        }

        if(!angular.isNullOrUndefined($scope.filterSettings))
        {
            for(var x in $scope.filterSettings.stores.values)
            {
                var store = $scope.filterSettings.stores.values[x];

                if(store.selected)
                {
                    return true;
                }
            }
        }

        if($scope.viewConfig.viewAll)
        {
            return true;
        }

        return false;
    };

    ctrl.oldValue = null;

    $scope.search = function()
    {
        if(!ctrl.oldValue)
        {
            bookmark = $scope.query.page;
        }

        if($scope.query.filter !== ctrl.oldValue)
        {
            $scope.query.page = 1;
        }

        if(!ctrl.oldValue)
        {
            $scope.query.page = bookmark;
        }

        $scope.getProducts();
    };

    $scope.refresh = function(viewConfig)
    {
        $scope.viewConfig = viewConfig;

        if($scope.viewConfig.viewAll)
        {
            $scope.isStoreSelected = true;
        }
        else
        {
            $scope.isStoreSelected = $scope.IsStoreSelected();
        }

	// Save the new configuration for the current session
	window.sessionStorage.setItem("viewConfig", JSON.stringify($scope.viewConfig));

        $scope.getProducts();
    };

    $scope.searchProducts = function(searchText)
    {
        $scope.clearSessionItems();
        window.sessionStorage.setItem("searchText", searchText);
        window.location.href =  $scope.site_url.concat("/shop");
    };

    $rootScope.select_category = function($event, category)
    {
        $scope.clearSessionItems();
        var category_id = parseInt(category.id);
        eapp.recordHit("eapp_product_category ",category_id);
        window.sessionStorage.setItem("category_id", category_id);
        window.sessionStorage.setItem("category_name", category.name);
        window.location =  $scope.site_url.concat("/shop");
    };

    $scope.viewProduct = function(product_id, ev)
    {
        eapp.viewProduct($scope, product_id, ev);
    };

    $scope.settingsChanged = function(item)
    {
        $scope.updateItemChanged(item);

        window.sessionStorage.setItem("filterSettings", JSON.stringify($scope.filterSettings));

        // Get store filter
        $scope.createResultsFilter();

        $scope.getProducts();

    };

    $scope.updateItemChanged = function(item)
    {
        var index = $scope.filterSettings[item.type].values.map(function(e){ return e.name; }).indexOf(item.name);

        if(index > -1)
        {
            $scope.filterSettings[item.type].values[index] = item;
        }
    };

    $scope.createResultsFilter = function()
    {
        if(angular.isNullOrUndefined($scope.filterSettings))
        {
            return;
        }

        $scope.resultFilter = {};

        for(var x in $scope.filterSettings)
        {
            var values = $scope.filterSettings[x].values;
            var setting = $scope.filterSettings[x].setting;
            var filter = "";
            for(var y in values)
            {
                if(values[y].selected)
                {
                    var value = values[y].id.toString();

                    if(value === "Autre")
                    {
                        value = "";
                    }

                    if(filter === "")
                    {
                        if(value === "")
                        {
                            filter = filter.concat(",", value);
                        }
                        else
                        {
                            filter = filter.concat("", value);
                        }
                    }
                    else
                    {
                        filter = filter.concat(",", value);
                    }

                }
            }

            $scope.resultFilter[setting.name] = filter;
        }

    };

    $scope.changeDistance = function(newDistance)
    {
        if($scope.isUserLogged)
        {
            // Start Loading
            $scope.isLoading = true;

            var changePromise = eapp.changeDistance('optimization_distance', newDistance);

            changePromise.then(function onFulfilled(response)
            {
                if(response.data)
                {
                    // Update Logged User
                    $rootScope.loggedUser = response.data;
                    $scope.getProducts();
                }
            }).catch (function(err)
            {
                console.log(err);
            });

        }
        else
        {
            // Change in the session
            window.localStorage.setItem('optimization_distance', newDistance);
            $scope.getProducts();
        }

        $mdDialog.cancel();
    };

    $scope.$watch("query.page", function(newValue, oldValue)
    {
        window.scrollTo(0, 0);
    });

    $scope.$watch("gridView", function(newValue, oldValue)
    {
        if(!angular.isNullOrUndefined($scope.gridView))
        {
            window.sessionStorage.setItem("gridView", JSON.stringify($scope.gridView));
        }

    });

}]);
<|endoftext|>


<commit_before>'use strict';

var Winston = require('winston'),
    consoleLoggingConfiguration = {
        level: 'debug',
        handleExceptions: true,
        json: false,
        colorize: true
    },
    logger = new Winston.Logger({
        transports: [
            new Winston.transports.Console(consoleLoggingConfiguration)
        ]
    });

function removeEndingNewLineCharacter(message) {
    var lastCharacter;

    if (message.length > 0) {
        lastCharacter = message[message.length-1];

        while(lastCharacter === '\n') {
            message = message.slice(0, -1);

            if(message.length > 0) {
                lastCharacter = message[message.length-1];
            }
        }
    }

    return message;
}

module.exports = logger;
module.exports.infoStream = {
    write: function (message) {
        logger.info(removeEndingNewLineCharacter(message));
    }
};
<commit_msg>Fix eslint errors (space-infix-ops).<commit_after>'use strict';

var Winston = require('winston'),
    consoleLoggingConfiguration = {
        level: 'debug',
        handleExceptions: true,
        json: false,
        colorize: true
    },
    logger = new Winston.Logger({
        transports: [
            new Winston.transports.Console(consoleLoggingConfiguration)
        ]
    });

function removeEndingNewLineCharacter(message) {
    var lastCharacter;

    if (message.length > 0) {
        lastCharacter = message[message.length - 1];

        while(lastCharacter === '\n') {
            message = message.slice(0, -1);

            if(message.length > 0) {
                lastCharacter = message[message.length - 1];
            }
        }
    }

    return message;
}

module.exports = logger;
module.exports.infoStream = {
    write: function (message) {
        logger.info(removeEndingNewLineCharacter(message));
    }
};
<|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react'
import moment from 'moment'

import style from './../../../styles/organisms/ThermostatForm.scss'

class ThermostatForm extends Component {

  getLastRemoteCheckin() {
    return moment().diff(this.props.lastCheckin, 'minutes')
  }

  render() {

    const minutesSinceLastCheckin = this.getLastRemoteCheckin.call(this)

    return (
      <form className={style.form} method="post" action={`/thermostat/${this.props.id}`}>

        <fieldset className={style.temperature}>
          <legend>Target Temperature</legend>
          <input type="hidden" name="_method" value="put" />
          <input name="temperature" type="number" required value={this.props.temperature} max="99" min="68" />
          °
        </fieldset>

        <input className={style.name} type="text" name="name" value={this.props.name} required />

        <button className="pure-button pure-button-primary">Update</button>

        {
          minutesSinceLastCheckin > 15 &&

            {"The remote hasn\'t checked in recently."}

        }

      </form>
    )

  }

}

ThermostatForm.propTypes = {
  id: PropTypes.number,
  temperature: PropTypes.string,
  name: PropTypes.string,
  lastCheckin: PropTypes.string
}

export default ThermostatForm
<commit_msg>Add a tool tip to the form.<commit_after>import React, { PropTypes, Component } from 'react'
import moment from 'moment'

import style from './../../../styles/organisms/ThermostatForm.scss'

class ThermostatForm extends Component {

  getLastRemoteCheckin() {
    return moment().diff(this.props.lastCheckin, 'minutes')
  }

  render() {

    const minutesSinceLastCheckin = this.getLastRemoteCheckin.call(this)

    return (
      <form
        title={`The remote last checked in ${minutesSinceLastCheckin} minutes ago.`}
        className={style.form}
        method="post"
        action={`/thermostat/${this.props.id}`}>

        <fieldset className={style.temperature}>
          <legend>Target Temperature</legend>
          <input type="hidden" name="_method" value="put" />
          <input name="temperature" type="number" required value={this.props.temperature} max="99" min="68" />
          °
        </fieldset>

        <input
          className={style.name}
          type="text" name="name"
          value={this.props.name} required />

        <button className="pure-button pure-button-primary">Update</button>

        {
          minutesSinceLastCheckin > 15 &&

            {"The remote hasn\'t checked in recently."}

        }

      </form>
    )

  }

}

ThermostatForm.propTypes = {
  id: PropTypes.number,
  temperature: PropTypes.string,
  name: PropTypes.string,
  lastCheckin: PropTypes.string
}

export default ThermostatForm
<|endoftext|>


<commit_before>(function () {
	'use strict';
	/**
	** DEPENDENCIES
	**  - moment
	**/
	var formatMoment = function (_moment, _format) { //expects a moment
		if (!_moment) {
			return "";
		}
		var m = moment(_moment);
		return m.isValid() ? m.format(_format) : _moment;
	};

	angular.module('lui')
	.filter('luifFriendlyRange', function () {
		var translations = {
			'en': {
				startOnly: 'date(dddd, LL) onwards',
				startOnlyThisYear: 'date(dddd, MMMM Do) onwards',
				endOnly: 'until date(dddd, LL)',
				endOnlyThisYear: 'until date(dddd, MMMM Do)',
				sameDay: 'start(dddd, LL)',
				sameDayThisYear: 'start(dddd, MMMM Do)',
				sameMonth: 'start(MMMM Do) - end(Do\, YYYY)',
				sameMonthThisYear: 'start(MMMM Do) - end(Do)',
				sameYear: 'start(MMMM Do) - end(LL)',
				sameYearThisYear: 'start(MMMM Do) - end(MMMM Do)',
				other: 'start(LL) - end(LL)'
			},
			'fr': {
				startOnly: 'à partir du date(dddd LL)',
				startOnlyThisYear: 'à partir du date(dddd Do MMMM)',
				endOnly: 'jusqu\'au date(dddd LL)',
				endOnlyThisYear: 'jusqu\'au date(dddd Do MMMM)',
				sameDay: 'le start(dddd LL)',
				sameDayThisYear: 'le start(dddd Do MMMM)',
				sameMonth: 'du start(Do) au end(LL)',
				sameMonthThisYear: 'du start(Do) au end(Do MMMM)',
				sameYear: 'du start(Do MMMM) au end(LL)',
				sameYearThisYear: 'du start(Do MMMM) au end(Do MMMM)',
				other: 'du start(LL) au end(LL)'
			},
			'de': {

				// startOnly: 'start(dddd, LL) onwards',
				// startOnlyThisYear: 'start(dddd, MMMM Do) onwards',
				// endOnly: 'until end(dddd, LL)',
				// endOnlyThisYear: 'until end(dddd, MMMM Do)',

				sameDay: 'der start(dddd LL)',
				sameDayThisYear: 'der start(dddd Do MMMM)',
				sameMonth: 'von start(Do) bis end(LL)',
				sameMonthThisYear: 'von start(Do) bis end(Do MMMM)',
				sameYear: 'von start(Do MMMM) bis end(LL)',
				sameYearThisYear: 'von start(Do MMMM) bis end(Do MMMM)',
				other: 'von start(LL) bis end(LL)'
			}
		};
		return function (_block, _excludeEnd, _ampm, _translations) {
			if(!_block){ return; }
			var start = _block.start || _block.startsAt || _block.startsOn || _block.startDate;
			var end = _block.end || _block.endsAt || _block.endsOn || _block.endDate;
			if (!start && !end) {
				return "";
			}
			start = !!start ? moment(start) : undefined;
			end = !!end ? moment(end) : undefined;
			if(_excludeEnd){
				end.add(-1,'minutes');
			}
			var trads = translations[moment.locale()] || translations.en;
			var format;
			var regex;
			if (!!start && !!end) {
				format = start.year() === end.year() ? start.month() === end.month() ? start.date() === end.date() ? 'sameDay' : 'sameMonth' : 'sameYear' : 'other';
				if(moment().year() === start.year() && moment().year() === end.year()){
					format += "ThisYear";
				}
				regex = /(start\((.*?)\))(.*(end\((.*?)\))){0,1}/gi.exec(trads[format]);
				return trads[format].replace(regex[1], start.format(regex[2])).replace(regex[4], end.format(regex[5]));
			}
			format = !!start ? "startOnly" : "endOnly";
			var date = start || end;
			if(moment().year() === date.year()){
				format += "ThisYear";
			}
			regex = /(date\((.*?)\))/gi.exec(trads[format]);
			return trads[format].replace(regex[1], date.format(regex[2]));
		};
	})
	.filter('luifMoment', function () {
		return function (_moment, _format) {
			if (!_format) { _format = 'LLL'; } // default format
			return formatMoment(_moment, _format);
		};
	})
	.filter('luifCalendar', function () {
		return function (_moment, _refDate) {
			var m = moment(_moment);
			var refDate = (_refDate && moment(_refDate).isValid()) ? moment(_refDate) : moment();

			return m.isValid() ? m.calendar(_refDate) : _moment;
		};
	})
	.filter('luifDuration', ['$filter', function ($filter) {
		//expects a duration, returns the duration in the given unit with the given precision
		return function (_duration, _sign, _unit, _precision) {
			function getConfigIndex(expectedUnit){
				switch(expectedUnit){
					case 'd':
					case 'day':
					case 'days': return 0;
					case undefined:
					case '':
					case 'h':
					case 'hour':
					case 'hours': return 1;// default
					case 'm':
					case 'min':
					case 'mins':
					case 'minute':
					case 'minutes': return 2;
					case 's':
					case 'sec':
					case 'second':
					case 'seconds': return 3;
					case 'ms':
					case 'millisec':
					case 'millisecond':
					case 'milliseconds': return 4;
				}
			}

			function getNextNotNull(array, startIndex){
				return startIndex === 4 ? 4 : array[startIndex] !== 0 ? startIndex : getNextNotNull(array, startIndex + 1);
			}

			function getPrevNotNull(array, startIndex){
				return startIndex === 0 ? 0 : array[startIndex] !== 0 ? startIndex : getPrevNotNull(array, startIndex - 1);
			}

			function getDecimalNumber(days){
				switch(true){
					case (Math.floor((days * 10) % 10) === 0 && Math.floor((days * 100) % 10) === 0):	return 0;
					case (Math.floor((days * 100) % 10) === 0):											return 1;
					default: 																			return 2;
				}
			}

			function formatValue (value, u, expectedUnit){
				switch(u){
					case expectedUnit :	return value;
					case 2 :
					case 3 : 			return (value < 10 ? '0' + value : value);
					case 4 : 			return (value < 10 ? '00' + value : value < 100 ? '0' + value : value);
					default : 			return value;
				}
			}

			function getPrefix(sign, duration){
				if (sign) {
					if (duration.asMilliseconds() > 0) { return '+'; }
					else if (duration.asMilliseconds() < 0) { return '-'; }
				}
				return '';
			}

			// some localisation shenanigans
			function getUnitSymbols(unit, precision){
				var result = ['d ', 'h', 'm', 's', 'ms'];
				switch(moment.locale()){
					case "fr": result[0] = 'j '; break;
				}

				// if precision = ms and unit bigger than s we want to display 12.525s and not 12s525ms
				if(unit <= 3 && precision === 4) { result[3] = '.'; result[4] = 's'; }
				if(unit <= 1 && precision === 2) { result[2] = ''; }
				if(unit === 2 && precision === 3) { result[3] = ''; }

				return result;
			}

			var unitConfigs = [
				{
					index: 0,
					unit: 'd',
					dateConversion : 'asDays',
					expectedPrecision : 'h'
				},
				{
					index: 1,
					unit: 'h',
					dateConversion : 'asHours',
					expectedPrecision :'m'
				},
				{
					index: 2,
					unit: 'm',
					dateConversion : 'asMinutes',
					expectedPrecision : 's'
				},
				{
					index: 3,
					unit: 's',
					dateConversion : 'asSeconds',
					expectedPrecision : 's'
				},
				{
					index: 4,
					unit: 'ms',
					dateConversion : 'asMilliseconds',
					expectedPrecision : 'ms'
				},
			];

			var d = moment.duration(_duration);

			if (d.asMilliseconds() === 0) { return ''; }

			var values = [Math.abs(d.days()), Math.abs(d.hours()), Math.abs(d.minutes()), Math.abs(d.seconds()), Math.abs(d.milliseconds())];
			var config = unitConfigs[getConfigIndex(_unit)];
			var minimumUnit = Math.max(config.index, getNextNotNull(values, 0));
			values[config.index] = Math.abs(d[config.dateConversion]() >= 0 ? Math.floor(d[config.dateConversion]()) : Math.ceil(d[config.dateConversion]()));

			if (config.index === 0 && getConfigIndex(_precision) === 0 && d.asDays() > 0){
				var myDays = d.asDays();
				var decimalNumber = getDecimalNumber(myDays);
				minimumUnit = 0;
				values[0] = $filter("number")(myDays, decimalNumber);
			}

			var precision = getPrevNotNull(values, getConfigIndex(_precision || config.expectedPrecision));
			var units = getUnitSymbols(minimumUnit, precision);

			var result = '';
			for(var i = minimumUnit; i <= precision; i++){
				result += formatValue(values[i], i, minimumUnit) + units[i];
			}

			var prefix = !!result ? getPrefix(_sign, d) : '';
			return prefix + result;
		};
	}])
	.filter('luifHumanize', function () {
		return function (_duration, suffix) {
			suffix = !!suffix;
			var d = moment.duration(_duration);
			return d.humanize(suffix);
		};
	});
})();
<commit_msg>Lucca ui MOD: add date value in translations for EN, FR and DE languages. Implement method getTrad which returns date format according to locale, trads, key and fallbackkey params.<commit_after>(function () {
	'use strict';
	/**
	** DEPENDENCIES
	**  - moment
	**/
	var formatMoment = function (_moment, _format) { //expects a moment
		if (!_moment) {
			return "";
		}
		var m = moment(_moment);
		return m.isValid() ? m.format(_format) : _moment;
	};

	angular.module('lui')
	.filter('luifFriendlyRange', function () {
		var translations = {
			'en': {
				startOnly: 'date(dddd, LL) onwards',
				startOnlyThisYear: 'date(dddd, MMMM Do) onwards',
				endOnly: 'until date(dddd, LL)',
				endOnlyThisYear: 'until date(dddd, MMMM Do)',
				date: 'date(LL)',
				sameDay: 'start(dddd, LL)',
				sameDayThisYear: 'start(dddd, MMMM Do)',
				sameMonth: 'start(MMMM Do) - end(Do\, YYYY)',
				sameMonthThisYear: 'start(MMMM Do) - end(Do)',
				sameYear: 'start(MMMM Do) - end(LL)',
				sameYearThisYear: 'start(MMMM Do) - end(MMMM Do)',
				other: 'start(LL) - end(LL)'
			},
			'fr': {
				startOnly: 'à partir du date(dddd LL)',
				startOnlyThisYear: 'à partir du date(dddd Do MMMM)',
				endOnly: 'jusqu\'au date(dddd LL)',
				endOnlyThisYear: 'jusqu\'au date(dddd Do MMMM)',
				date: 'date(LL)',
				sameDay: 'le start(dddd LL)',
				sameDayThisYear: 'le start(dddd Do MMMM)',
				sameMonth: 'du start(Do) au end(LL)',
				sameMonthThisYear: 'du start(Do) au end(Do MMMM)',
				sameYear: 'du start(Do MMMM) au end(LL)',
				sameYearThisYear: 'du start(Do MMMM) au end(Do MMMM)',
				other: 'du start(LL) au end(LL)'
			},
			'de': {

				startOnly: 'von date(Do MMMM)',
				startOnlyThisYear: 'von date(LL)',
				endOnly: 'bis date(Do MMMM)',
				endOnlyThisYear: 'bis date(LL)',
				date: 'date(LL)',
				sameDay: 'der start(dddd LL)',
				sameDayThisYear: 'der start(dddd Do MMMM)',
				sameMonth: 'von start(Do) bis end(LL)',
				sameMonthThisYear: 'von start(Do) bis end(Do MMMM)',
				sameYear: 'von start(Do MMMM) bis end(LL)',
				sameYearThisYear: 'von start(Do MMMM) bis end(Do MMMM)',
				other: 'von start(LL) bis end(LL)'
			}
		};
		function getTrad(trads, locale, key, fallbackKey) {
			if (!!trads && !!trads[locale] && !!trads[locale][key]) {
				return trads[locale][key];
			}
			if (!!trads && !!trads[locale] && !!trads[locale][fallbackKey]) {
				return trads[locale][fallbackKey];
			}
			// fallback opn english in providsed translations
			var fallbackLocale = "en";
			if (!!trads && !!trads[fallbackLocale] && !!trads[fallbackLocale][key]) {
				return trads[fallbackLocale][key];
			}
			if (!!trads && !!trads[fallbackLocale] && !!trads[fallbackLocale][fallbackKey]) {
				return trads[fallbackLocale][fallbackKey];
			}
			// using range format property when start date and end date are valid
			if (!!trads && fallbackKey === "other") {
				return trads;
			}

			// fallback on standard translmations if i couldnt find zhat i need in provided trads
			var fallbackTrads = translations;
			if (!!fallbackTrads && !!fallbackTrads[locale] && !!fallbackTrads[locale][key]) {
				return fallbackTrads[locale][key];
			}
			if (!!fallbackTrads && !!fallbackTrads[locale] && !!fallbackTrads[locale][fallbackKey]) {
				return fallbackTrads[locale][fallbackKey];
			}
			// fallback opn english in providsed translations
			if (!!fallbackTrads && !!fallbackTrads[fallbackLocale] && !!fallbackTrads[fallbackLocale][key]) {
				return fallbackTrads[fallbackLocale][key];
			}
			if (!!fallbackTrads && !!fallbackTrads[fallbackLocale] && !!fallbackTrads[fallbackLocale][fallbackKey]) {
				return fallbackTrads[fallbackLocale][fallbackKey];
			}
		}
		return function (_block, _excludeEnd, _translations) {
			if(!_block){ return; }
			var start = _block.start || _block.startsAt || _block.startsOn || _block.startDate;
			var end = _block.end || _block.endsAt || _block.endsOn || _block.endDate;
			if (!start && !end) {
				return "";
			}
			start = !!start ? moment(start) : undefined;
			end = !!end ? moment(end) : undefined;
			if(_excludeEnd){
				end.add(-1,'minutes');
			}
			var trad;
			var format;
			var regex;
			if (!!start && !!end) {
				format = start.year() === end.year() ? start.month() === end.month() ? start.date() === end.date() ? 'sameDay' : 'sameMonth' : 'sameYear' : 'other';
				if(moment().year() === start.year() && moment().year() === end.year()){
					format += "ThisYear";
				}
				trad = getTrad(_translations, moment.locale(), format, "other");
				regex = /(start\((.*?)\))(.*(end\((.*?)\))){0,1}/gi.exec(trad);
				return trad.replace(regex[1], start.format(regex[2])).replace(regex[4], end.format(regex[5]));
			}
			format = !!start ? "startOnly" : "endOnly";
			var date = start || end;
			if(moment().year() === date.year()){
				format += "ThisYear";
			}
			trad = getTrad(_translations, moment.locale(), format, "date");
			regex = /(date\((.*?)\))/gi.exec(trad);
			return trad.replace(regex[1], date.format(regex[2]));
		};
	})
	.filter('luifMoment', function () {
		return function (_moment, _format) {
			if (!_format) { _format = 'LLL'; } // default format
			return formatMoment(_moment, _format);
		};
	})
	.filter('luifCalendar', function () {
		return function (_moment, _refDate) {
			var m = moment(_moment);
			var refDate = (_refDate && moment(_refDate).isValid()) ? moment(_refDate) : moment();

			return m.isValid() ? m.calendar(_refDate) : _moment;
		};
	})
	.filter('luifDuration', ['$filter', function ($filter) {
		//expects a duration, returns the duration in the given unit with the given precision
		return function (_duration, _sign, _unit, _precision) {
			function getConfigIndex(expectedUnit){
				switch(expectedUnit){
					case 'd':
					case 'day':
					case 'days': return 0;
					case undefined:
					case '':
					case 'h':
					case 'hour':
					case 'hours': return 1;// default
					case 'm':
					case 'min':
					case 'mins':
					case 'minute':
					case 'minutes': return 2;
					case 's':
					case 'sec':
					case 'second':
					case 'seconds': return 3;
					case 'ms':
					case 'millisec':
					case 'millisecond':
					case 'milliseconds': return 4;
				}
			}

			function getNextNotNull(array, startIndex){
				return startIndex === 4 ? 4 : array[startIndex] !== 0 ? startIndex : getNextNotNull(array, startIndex + 1);
			}

			function getPrevNotNull(array, startIndex){
				return startIndex === 0 ? 0 : array[startIndex] !== 0 ? startIndex : getPrevNotNull(array, startIndex - 1);
			}

			function getDecimalNumber(days){
				switch(true){
					case (Math.floor((days * 10) % 10) === 0 && Math.floor((days * 100) % 10) === 0):	return 0;
					case (Math.floor((days * 100) % 10) === 0):											return 1;
					default: 																			return 2;
				}
			}

			function formatValue (value, u, expectedUnit){
				switch(u){
					case expectedUnit :	return value;
					case 2 :
					case 3 : 			return (value < 10 ? '0' + value : value);
					case 4 : 			return (value < 10 ? '00' + value : value < 100 ? '0' + value : value);
					default : 			return value;
				}
			}

			function getPrefix(sign, duration){
				if (sign) {
					if (duration.asMilliseconds() > 0) { return '+'; }
					else if (duration.asMilliseconds() < 0) { return '-'; }
				}
				return '';
			}

			// some localisation shenanigans
			function getUnitSymbols(unit, precision){
				var result = ['d ', 'h', 'm', 's', 'ms'];
				switch(moment.locale()){
					case "fr": result[0] = 'j '; break;
				}

				// if precision = ms and unit bigger than s we want to display 12.525s and not 12s525ms
				if(unit <= 3 && precision === 4) { result[3] = '.'; result[4] = 's'; }
				if(unit <= 1 && precision === 2) { result[2] = ''; }
				if(unit === 2 && precision === 3) { result[3] = ''; }

				return result;
			}

			var unitConfigs = [
				{
					index: 0,
					unit: 'd',
					dateConversion : 'asDays',
					expectedPrecision : 'h'
				},
				{
					index: 1,
					unit: 'h',
					dateConversion : 'asHours',
					expectedPrecision :'m'
				},
				{
					index: 2,
					unit: 'm',
					dateConversion : 'asMinutes',
					expectedPrecision : 's'
				},
				{
					index: 3,
					unit: 's',
					dateConversion : 'asSeconds',
					expectedPrecision : 's'
				},
				{
					index: 4,
					unit: 'ms',
					dateConversion : 'asMilliseconds',
					expectedPrecision : 'ms'
				},
			];

			var d = moment.duration(_duration);

			if (d.asMilliseconds() === 0) { return ''; }

			var values = [Math.abs(d.days()), Math.abs(d.hours()), Math.abs(d.minutes()), Math.abs(d.seconds()), Math.abs(d.milliseconds())];
			var config = unitConfigs[getConfigIndex(_unit)];
			var minimumUnit = Math.max(config.index, getNextNotNull(values, 0));
			values[config.index] = Math.abs(d[config.dateConversion]() >= 0 ? Math.floor(d[config.dateConversion]()) : Math.ceil(d[config.dateConversion]()));

			if (config.index === 0 && getConfigIndex(_precision) === 0 && d.asDays() > 0){
				var myDays = d.asDays();
				var decimalNumber = getDecimalNumber(myDays);
				minimumUnit = 0;
				values[0] = $filter("number")(myDays, decimalNumber);
			}

			var precision = getPrevNotNull(values, getConfigIndex(_precision || config.expectedPrecision));
			var units = getUnitSymbols(minimumUnit, precision);

			var result = '';
			for(var i = minimumUnit; i <= precision; i++){
				result += formatValue(values[i], i, minimumUnit) + units[i];
			}

			var prefix = !!result ? getPrefix(_sign, d) : '';
			return prefix + result;
		};
	}])
	.filter('luifHumanize', function () {
		return function (_duration, suffix) {
			suffix = !!suffix;
			var d = moment.duration(_duration);
			return d.humanize(suffix);
		};
	});
})();
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
import Sequelize from 'sequelize';
import configure from '../config/config.json';

dotenv.config();
const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
const config = configure[env];
const db = {};

let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(file =>
    (file.indexOf('.') !== 0) &&
    (file !== basename) &&
    (file.slice(-3) === '.js'))
  .forEach((file) => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;
<commit_msg>fix production database setting<commit_after>import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
import Sequelize from 'sequelize';
import configure from '../config/config.json';

dotenv.config();
const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
const config = configure[env];
const db = {};

let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env.DATABASE_URL);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter(file =>
    (file.indexOf('.') !== 0) &&
    (file !== basename) &&
    (file.slice(-3) === '.js'))
  .forEach((file) => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

export default db;
<|endoftext|>


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

CLASS({
  name: "BuildApp",
  package: 'foam.build',
  imports: [
    'log',
    'error'
  ],
  requires: [
    'foam.dao.NodeFileDAO as FileDAO',
    'foam.dao.File'
  ],
  properties: [
    {
      name: 'controller',
      help: 'Name of the main controller/model to create',
      required: true
    },
    {
      name: 'defaultView',
      help: "Default view of the controller to use.  If not set, the controller will be used as view (if it is one), or DetailView will be used"
    },
    {
      name: 'targetPath',
      help: "Directory to write output files to.  Will be created if it doesn't exist.",
      required: true
    },
    {
      model_: 'BooleanProperty',
      name: 'precompileTemplates',
      defaultValue: false
    },
    {
      name: 'formatter',
      factory: function() {
        return {
          __proto__: JSONUtil.compact,
          outputObject_: function(out, obj, opt_defaultModel) {
            var first = true;

            out('{');
            if ( obj.model_.id !== opt_defaultModel ) {
              this.outputModel_(out, obj);
              first = false;
            }

            if ( Template.isInstance(obj) ) var isTemplate = true;

            for ( var key in obj.model_.properties_ ) {
              var prop = obj.model_.properties_[key];

              if ( ! this.p(prop) && ( ! isTemplate || prop.name !== 'code' ) ) continue;

              if ( prop.name in obj.instance_ ) {
                var val = obj[prop.name];
                if ( Array.isArray(val) && ! val.length ) continue;
                if ( ! first ) out(',');
                out(this.keyify(prop.name), ': ');
                this.output(out, val);
                first = false;
              }
            }

            out('}');
          }
        };
      }
    },
    {
      name: 'path',
      factory: function() { return require('path'); }
    },
    {
      name: 'fileDAO',
      factory: function() { return this.FileDAO.create(); }
    }
  ],
  methods: {
    execute: function() {
      if ( ! this.targetPath ) {
        this.error("targetPath is required");
        process.exit(1);
      }
      if ( ! this.controller ) {
        this.error("controller is required");
        process.exit(1);
      }
      var view = this.defaultView ? arequire(this.defaultView) : anop;
      aseq(
        view,
        arequire(this.controller))(this.execute_.bind(this));
    },
    buildCoreJS_: function(ret) {
      var i = 0;
      var self = this;
      var corejs = '';
      var file;
      awhile(
        function() { return i < files.length; },
        aif(
          function() {
            file = files[i++];
            if ( Array.isArray(file) ) {
              if ( file[1] != IN_BROWSER ) return false;
              file = file[0];
            }
            return true;
          },
          aseq(
            function(ret) {
              var path = FOAM_BOOT_DIR + this.path.sep + file + '.js';
              this.fileDAO.find(path, {
                put: ret,
                error: function() {
                  self.error.apply(["Error reading file: ", path].concat(arguments));
                }
              });
            }.bind(this),
            function(ret, file) {
              corejs += '\n';
              corejs += file.contents;
              ret();
            })))(function() { ret(corejs); });
    },
    buildAppJS_: function(ret) {
      var models = {};
      var visited = {};
      var error = this.error;

      function add(require) {
        if ( visited[require] ) return;
        visited[require] = true;

        var model = FOAM.lookup(require, X);
        if ( ! model ) {
          error("Could not load model: ", require);
        }
        if ( model.package ) models[model.id] = model;

        model.getAllRequires().forEach(add);
      };
      add(this.controller);
      if ( this.defaultView ) add(this.defaultView);

      var contents = '';

      var ids = Object.keys(models);
      this.fileDAO.put(this.File.create({
        path: this.targetPath + this.path.sep + 'MANIFEST',
        contents: ids.join('\n')
      }));
      for ( var i = 0; i < ids.length; i++ ) {
        var model = models[ids[i]];
        if ( this.precompileTemplates ) {
          for ( var j = 0 ; j < model.templates.length ; j++ ) {
            model.templates[j].code = TemplateUtil.compile(model.templates[j]);
            model.templates[j].clearProperty('template');
          }
        }
        contents += 'CLASS(';
        if ( this.precompileTemplates )
          contents += this.formatter.where(NOT_TRANSIENT).stringify(models[ids[i]]);
        else
          contents += JSONUtil.compact.where(NOT_TRANSIENT).stringify(models[ids[i]]);
        contents += ')\n';
      }

      ret(contents);
    },
    execute_: function(model) {
      if ( ! model ) {
        this.error("Could not find model: ", this.controller);
      }
      this.log("Building   ", model.id);
      this.log("Target is: ", this.targetPath);
      this.log(this.precompileTemplates ? '' : 'NOT ', 'pre-compiling templates.');

      var self = this;
      aseq(
        function(ret) {
          var file = this.File.create({
            path: this.targetPath + this.path.sep + 'main.html',
            contents: this.HTML()
          });

          console.log("Writing: ", file.path);
          this.fileDAO.put(file, {
            put: ret,
            error: function() {
              self.error('ERROR writing file: ', file.path);
              process.exit(1);
            }
          });
        }.bind(this),
        apar(
          function(ret) { this.buildCoreJS_(ret); }.bind(this),
          function(ret) { this.buildAppJS_(ret); }.bind(this)),
        function(ret, corejs, appjs) {
          var file = this.File.create({
            path: this.targetPath + this.path.sep + 'foam.js',
            contents: corejs + appjs
          });
          console.log("Writing: ", file.path);
          this.fileDAO.put(file, {
            put: ret,
            error: function() {
              self.error("ERROR writing file: ", file.path);
              process.exit(1);
            }
          });
        }.bind(this)
      )(
        function(){
          process.exit(0);
        });
    }
  },
  templates: [
    function HTML() {/*<foam model="<%= this.controller %>"<% if ( this.defaultView ) { %> view="<%= this.defaultView %>"<% } %>></foam>*/}
  ]
});
<commit_msg>Add charset=UTF-8 to BuildApp output. Add coreFiles parameter to BuildApp allowing the user to specify which files from core/ to includes verbatim.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  name: "BuildApp",
  package: 'foam.build',
  imports: [
    'log',
    'error'
  ],
  requires: [
    'foam.dao.NodeFileDAO as FileDAO',
    'foam.dao.File'
  ],
  properties: [
    {
      name: 'controller',
      help: 'Name of the main controller/model to create',
      required: true
    },
    {
      model_: 'StringArrayProperty',
      name: 'coreFiles',
      adapt: function(_, s) { if ( typeof s === 'string' ) return s.split(','); return s; }
    },
    {
      name: 'defaultView',
      help: "Default view of the controller to use.  If not set, the controller will be used as view (if it is one), or DetailView will be used"
    },
    {
      name: 'targetPath',
      help: "Directory to write output files to.  Will be created if it doesn't exist.",
      required: true
    },
    {
      model_: 'BooleanProperty',
      name: 'precompileTemplates',
      defaultValue: false
    },
    {
      name: 'formatter',
      factory: function() {
        return {
          __proto__: JSONUtil.compact,
          outputObject_: function(out, obj, opt_defaultModel) {
            var first = true;

            out('{');
            if ( obj.model_.id !== opt_defaultModel ) {
              this.outputModel_(out, obj);
              first = false;
            }

            if ( Template.isInstance(obj) ) var isTemplate = true;

            for ( var key in obj.model_.properties_ ) {
              var prop = obj.model_.properties_[key];

              if ( ! this.p(prop) && ( ! isTemplate || prop.name !== 'code' ) ) continue;

              if ( prop.name in obj.instance_ ) {
                var val = obj[prop.name];
                if ( Array.isArray(val) && ! val.length ) continue;
                if ( ! first ) out(',');
                out(this.keyify(prop.name), ': ');
                this.output(out, val);
                first = false;
              }
            }

            out('}');
          }
        };
      }
    },
    {
      name: 'path',
      factory: function() { return require('path'); }
    },
    {
      name: 'fileDAO',
      factory: function() { return this.FileDAO.create(); }
    }
  ],
  methods: {
    execute: function() {
      if ( ! this.targetPath ) {
        this.error("targetPath is required");
        process.exit(1);
      }
      if ( ! this.controller ) {
        this.error("controller is required");
        process.exit(1);
      }
      var view = this.defaultView ? arequire(this.defaultView) : anop;
      aseq(
        view,
        arequire(this.controller))(this.execute_.bind(this));
    },
    buildCoreJS_: function(ret) {
      var i = 0;
      var self = this;
      var corejs = '';
      var file;
      if ( this.coreFiles ) var myfiles = this.coreFiles;
      else myfiles = files;
      awhile(
        function() { return i < myfiles.length; },
        aif(
          function() {
            file = myfiles[i++];
            if ( Array.isArray(file) ) {
              if ( file[1] != IN_BROWSER ) return false;
              file = file[0];
            }
            return true;
          },
          aseq(
            function(ret) {
              var path = FOAM_BOOT_DIR + this.path.sep + file + '.js';
              this.fileDAO.find(path, {
                put: ret,
                error: function() {
                  self.error.apply(["Error reading file: ", path].concat(arguments));
                }
              });
            }.bind(this),
            function(ret, file) {
              corejs += '\n';
              corejs += file.contents;
              ret();
            })))(function() { ret(corejs); });
    },
    buildAppJS_: function(ret) {
      var models = {};
      var visited = {};
      var error = this.error;

      function add(require) {
        if ( visited[require] ) return;
        visited[require] = true;

        var model = FOAM.lookup(require, X);
        if ( ! model ) {
          error("Could not load model: ", require);
        }
        if ( model.package ) models[model.id] = model;

        model.getAllRequires().forEach(add);
      };
      add(this.controller);
      if ( this.defaultView ) add(this.defaultView);

      var contents = '';

      var ids = Object.keys(models);
      this.fileDAO.put(this.File.create({
        path: this.targetPath + this.path.sep + 'MANIFEST',
        contents: ids.join('\n')
      }));
      for ( var i = 0; i < ids.length; i++ ) {
        var model = models[ids[i]];
        if ( this.precompileTemplates ) {
          for ( var j = 0 ; j < model.templates.length ; j++ ) {
            model.templates[j].code = TemplateUtil.compile(model.templates[j]);
            model.templates[j].clearProperty('template');
          }
        }
        contents += 'CLASS(';
        if ( this.precompileTemplates )
          contents += this.formatter.where(NOT_TRANSIENT).stringify(models[ids[i]]);
        else
          contents += JSONUtil.compact.where(NOT_TRANSIENT).stringify(models[ids[i]]);
        contents += ')\n';
      }

      ret(contents);
    },
    execute_: function(model) {
      if ( ! model ) {
        this.error("Could not find model: ", this.controller);
      }
      this.log("Building   ", model.id);
      this.log("Target is: ", this.targetPath);
      this.log(this.precompileTemplates ? '' : 'NOT ', 'pre-compiling templates.');

      var self = this;
      aseq(
        function(ret) {
          var file = this.File.create({
            path: this.targetPath + this.path.sep + 'main.html',
            contents: this.HTML()
          });

          console.log("Writing: ", file.path);
          this.fileDAO.put(file, {
            put: ret,
            error: function() {
              self.error('ERROR writing file: ', file.path);
              process.exit(1);
            }
          });
        }.bind(this),
        apar(
          function(ret) { this.buildCoreJS_(ret); }.bind(this),
          function(ret) { this.buildAppJS_(ret); }.bind(this)),
        function(ret, corejs, appjs) {
          var file = this.File.create({
            path: this.targetPath + this.path.sep + 'foam.js',
            contents: corejs + appjs
          });
          console.log("Writing: ", file.path);
          this.fileDAO.put(file, {
            put: ret,
            error: function() {
              self.error("ERROR writing file: ", file.path);
              process.exit(1);
            }
          });
        }.bind(this)
      )(
        function(){
          process.exit(0);
        });
    }
  },
  templates: [
    function HTML() {/*<meta charset="utf-8"><foam model="<%= this.controller %>"<% if ( this.defaultView ) { %> view="<%= this.defaultView %>"<% } %>></foam>*/}
  ]
});
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import configs from '../config/config';

const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
const config = configs[env];

const db = {};
let sequelize;

if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
  sequelize = new Sequelize(config.database, config.username,
    config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter((file) => {
    const fileName = (file.indexOf('.') !== 0) &&
                      (file !== basename) &&
                      (file.slice(-3) === '.js');
    return fileName;
  })
  .forEach((file) => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;

module.exports = db;
<commit_msg>Fix bug on travis CI<commit_after>import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import configs from '../config/config';

const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'test';
const config = configs[env];

const db = {};
let sequelize;

if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable]);
} else {
  sequelize = new Sequelize(config.database, config.username,
    config.password, config);
}

fs
  .readdirSync(__dirname)
  .filter((file) => {
    const fileName = (file.indexOf('.') !== 0) &&
                      (file !== basename) &&
                      (file.slice(-3) === '.js');
    return fileName;
  })
  .forEach((file) => {
    const model = sequelize.import(path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;

module.exports = db;
<|endoftext|>


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

CLASS({
  package: 'foam.graphics',
  name:  'CView',
  label: 'CView',

  requires: [
    'foam.graphics.PositionedCViewView',
    'foam.graphics.CViewView',
    'foam.graphics.webgl.CViewGLView'

  ],

  traits: [ 'foam.patterns.ChildTreeTrait' ],

  documentation: function() {/*
      The base class for a canvas item. A $$DOC{ref:'.'} can be directly inserted
      into the DOM with $$DOC{ref:'.write'}, and will generate a $$DOC{ref:'CViewView'}
      wrapper.

$$DOC{ref:'.'} submodels directly nest inside each other, with a single
      root $$DOC{ref:'.'} attached to the canvas. Use $$DOC{ref:'.addChild'} to attach a new
      $$DOC{ref:'.'} to the scene graph:

            var rootNode = this.X.CView.create({width:300, height:200});

            rootNode.write(document); // a CViewView wrapper is created for us

            rootNode.addChild(this.X.Circle.create({x:30, y:50, radius: 30, color: 'blue'});

            rootNode.addChild(this.X.Label.create({x: 50, y: 30, text: "Hello", color: 'black'});

When modeling your own $$DOC{ref:'foam.graphics.CView'} submodel, override $$DOC{ref:'.paintSelf'}
      to render your content. Children will automatically be painted for you. For more direct
      control over child rendering, override $$DOC{ref:'.paint'}.
    */},

  properties: [
    {
      name:  'view',
      type:  'Canvas2',
      postSet: function(_, view) {
        for ( var key in this.children ) {
          var child = this.children[key];
          child.view = view;
          if ( view ) child.addListener(view.paint);
        }
      },
      transient: true,
      hidden: true,
      documentation: function() {/* The canvas view this scene draws into */ }
    },
    {
      name:  'canvas',
      getter: function() { return this.view && this.view.canvas; },
      transient: true,
      hidden: true,
      documentation: function() {/* Safe getter for the canvas view this scene draws into */ }
    },
    {
      name:  '$',
      getter: function() { return this.view && this.view.$; },
      transient: true,
      hidden: true,
      documentation: function() {/* Safe getter for the canvas DOM element this scene draws into */ }
    },
    {
      name: 'state',
      defaultValue: 'initial',
      documentation: function() {/* Indicates if canvas setup is in progress ('initial'),
                                  or ready to paint ('active'). */}
    },
    {
      name: 'suspended',
      model_: 'BooleanProperty',
      defaultValue: false,
      documentation: function() {/*
          Suspend painting. While this property is true, this
          $$DOC{ref:'foam.graphics.CView'} will not paint itself or its
          children.
        */},
    },
    {
      name: 'className',
      help: 'CSS class name(s), space separated. Used if adapted with a CViewView.',
      defaultValue: '',
      documentation: function() {/* CSS class name(s), space separated.
          Only used if this is the root node adapted with a $$DOC{ref:'CViewView'}. */},
      postSet: function() {
        if ( ! this.$ ) return;
        this.$.className = this.className;
      }
    },
    {
      model_: 'FloatProperty',
      name: 'x',
      defaultValue: 0,
      documentation: function() {/*
          The X offset of this view relative to its parent. */}
    },
    {
      model_: 'FloatProperty',
      name: 'y',
      defaultValue: 0,
      documentation: function() {/*
          The Y offset of this view relative to its parent. */}
    },
    {
      model_: 'FloatProperty',
      name: 'a',
      label: 'Rotation',
      defaultValue: 0
    },
    {
      model_: 'FloatProperty',
      name: 'scaleX',
      defaultValue: 1
    },
    {
      model_: 'FloatProperty',
      name: 'scaleY',
      defaultValue: 1
    },
    {
      name: 'canvasX',
      getter: function() { return this.x + ( this.parent ? this.parent.canvasX : 0 ); }
    },
    {
      name: 'canvasY',
      getter: function() { return this.y + ( this.parent ? this.parent.canvasY : 0 ); }
    },
    {
      model_: 'IntProperty',
      name:  'width',
      defaultValue: 10,
      documentation: function() {/*
          The width of this view. Painting is not automatically clipped, so a view
          may render outside of its apparent rectangle. */}
    },
    {
      model_: 'IntProperty',
      name:  'height',
      defaultValue: 10,
      documentation: function() {/*
          The height of this view. Painting is not automatically clipped, so a view
          may render outside of its apparent rectangle. */}
    },
    {
      model_: 'FloatProperty',
      name:  'alpha',
      defaultValue: 1,
      documentation: function() {/*
          The desired opacity of the content, from 0:transparent to 1:opaque.
          Child views do not inherit and are not limited by this value. */}
    },
    {
      name:  'color',
      label: 'Foreground Color',
      type:  'String',
      defaultValue: 'black',
      documentation: function() {/*
          The foreground color for rendering primary content. */}
    },
    {
      name:  'background',
      label: 'Background Color',
      type:  'String',
      defaultValue: 'white',
      documentation: function() {/*
          The optional background color for opaque items that $$DOC{ref:'.erase'}
          their background. */}
    },
    {
      name: 'font',
      documentation: function() {/*
          The font to use for rendering text, in CSS string format: '24px Roboto'. */}
    },
    {
      name: 'clipped',
      model_: 'BooleanProperty',
      defaultValue: false
    }
  ],

  methods: {
    toView_: function() { /* Internal. Creates a CViewView wrapper. */
      if ( ! this.view ) {
        var params = {cview: this};
        if ( this.className )   params.className   = this.className;
        if ( this.tooltip )     params.tooltip     = this.tooltip;
        if ( this.speechLabel ) params.speechLabel = this.speechLabel;
        if ( this.tabIndex )    params.tabIndex    = this.tabIndex;
        if ( this.role )        params.role        = this.role;
        if ( this.data$ )       params.data$       = this.data$;
        this.view = this.CViewView.create(params);
      }
      return this.view;
    },
    toGLView_: function() { /* internal, creates a CViewGLView wrapper for 3d canvases */
      return this.CViewGLView.create({ sourceView: this });
    },

    toPositionedView_: function() { /* Internal. Creates a PositionedCViewView wrapper. */
      if ( ! this.view ) {
        var params = {cview: this};
        if ( this.className ) params.className = this.className;
        this.view = this.PositionedCViewView.create(params);
      }
      return this.view;
    },

    initCView: function() { /* Override in submodels for initialization. Callled
          once on first $$DOC{ref:'.paint'} when transitioning from 'initial'
          to 'active' '$$DOC{ref:'.state'}. */ },

    write: function(document) { /* Inserts this $$DOC{ref:'foam.graphics.CView'} into the DOM
                                   with an $$DOC{ref:'foam.graphics.AbstractCViewView'} wrapper. */
      this.toView_().write(document);
    },

    addChild: function(child) { /* Adds a child $$DOC{ref:'foam.graphics.CView'} to the scene
                                   under this. */
      this.SUPER(child);

      if ( this.view ) {
        child.view = this.view;
        child.addListener(this.view.paint);
      }
      return this;
    },

    removeChild: function(child) { /* Removes a child from the scene. */
      this.SUPER(child);
      child.view = undefined;
      child.removeListener(this.view.paint);
      return this;
    },

    erase: function() { /* Wipes the canvas area of this $$DOC{ref:'.'}. Primarily used
                          by the root node to clear the entire canvas, but an opaque child
                          may choose to erase its own area, if required. */
// Why do we do a clearRect()?  It causes problems when opacity isn't 1.
//      this.canvas.clearRect(0, 0, this.width, this.height);
      this.canvas.fillStyle = this.background;
      this.canvas.fillRect(0, 0, this.width, this.height);
    },

    paintChildren: function() { /* Paints each child. */
      for ( var i = 0 ; i < this.children.length ; i++ ) {
        var child = this.children[i];
        this.canvas.save();
        this.canvas.beginPath(); // reset any existing path (canvas.restore() does not affect path)
        child.paint();
        this.canvas.restore();
      }
    },

    paintSelf: function() { /* Implement this in sub-models to do your painting. */ },

    paint: function() { /* Translates the canvas to our ($$DOC{ref:'.x'}, $$DOC{ref:'.y'}),
                          does a $$DOC{ref:'.paintSelf'} then paints all the children. */
      if ( ! this.$ ) return; // no canvas element, so do nothing
      if ( ! this.width || ! this.height ) return;
      if ( this.state === 'initial' ) {
        this.state = 'active';
        this.initCView();
      }
      if ( this.suspended ) return; // we allowed initialization, but if suspended don't paint

      this.canvas.save();
      this.transform();
      if ( this.clipped ) {
        this.canvas.rect(0,0,this.width,this.height);
        this.canvas.clip();
      }
      this.paintSelf();
      this.paintChildren();
      this.canvas.restore();
    },

    transform: function() {
      this.canvas.translate(this.x, this.y);
      this.canvas.scale(this.scaleX, this.scaleY);
      this.canvas.rotate(this.a);
    },

    scale: function(s) {
      this.scaleX = this.scaleY = s;
    },

    mapToParent: function(point) { /* Maps a coordinate from this to our parents'. */
      point.x += this.x;
      point.y += this.y;
      return point;
    },

    mapToCanvas: function(point) { /* Maps a coordinate from this to the canvas.
                    Useful for sharing a point between sibling or cousin items. */
      this.mapToParent(point);
      if ( this.parent && this.parent.mapToCanvas )
        this.parent.mapToCanvas(point);
      return point;
    },

    destroy: function() {}
  }
});
<commit_msg>CView no longer rotates when angle is zero.<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'foam.graphics',
  name:  'CView',
  label: 'CView',

  requires: [
    'foam.graphics.PositionedCViewView',
    'foam.graphics.CViewView',
    'foam.graphics.webgl.CViewGLView'

  ],

  traits: [ 'foam.patterns.ChildTreeTrait' ],

  documentation: function() {/*
      The base class for a canvas item. A $$DOC{ref:'.'} can be directly inserted
      into the DOM with $$DOC{ref:'.write'}, and will generate a $$DOC{ref:'CViewView'}
      wrapper.

$$DOC{ref:'.'} submodels directly nest inside each other, with a single
      root $$DOC{ref:'.'} attached to the canvas. Use $$DOC{ref:'.addChild'} to attach a new
      $$DOC{ref:'.'} to the scene graph:

            var rootNode = this.X.CView.create({width:300, height:200});

            rootNode.write(document); // a CViewView wrapper is created for us

            rootNode.addChild(this.X.Circle.create({x:30, y:50, radius: 30, color: 'blue'});

            rootNode.addChild(this.X.Label.create({x: 50, y: 30, text: "Hello", color: 'black'});

When modeling your own $$DOC{ref:'foam.graphics.CView'} submodel, override $$DOC{ref:'.paintSelf'}
      to render your content. Children will automatically be painted for you. For more direct
      control over child rendering, override $$DOC{ref:'.paint'}.
    */},

  properties: [
    {
      name:  'view',
      type:  'Canvas2',
      postSet: function(_, view) {
        for ( var key in this.children ) {
          var child = this.children[key];
          child.view = view;
          if ( view ) child.addListener(view.paint);
        }
      },
      transient: true,
      hidden: true,
      documentation: function() {/* The canvas view this scene draws into */ }
    },
    {
      name:  'canvas',
      getter: function() { return this.view && this.view.canvas; },
      transient: true,
      hidden: true,
      documentation: function() {/* Safe getter for the canvas view this scene draws into */ }
    },
    {
      name:  '$',
      getter: function() { return this.view && this.view.$; },
      transient: true,
      hidden: true,
      documentation: function() {/* Safe getter for the canvas DOM element this scene draws into */ }
    },
    {
      name: 'state',
      defaultValue: 'initial',
      documentation: function() {/* Indicates if canvas setup is in progress ('initial'),
                                  or ready to paint ('active'). */}
    },
    {
      name: 'suspended',
      model_: 'BooleanProperty',
      defaultValue: false,
      documentation: function() {/*
          Suspend painting. While this property is true, this
          $$DOC{ref:'foam.graphics.CView'} will not paint itself or its
          children.
        */},
    },
    {
      name: 'className',
      help: 'CSS class name(s), space separated. Used if adapted with a CViewView.',
      defaultValue: '',
      documentation: function() {/* CSS class name(s), space separated.
          Only used if this is the root node adapted with a $$DOC{ref:'CViewView'}. */},
      postSet: function() {
        if ( ! this.$ ) return;
        this.$.className = this.className;
      }
    },
    {
      model_: 'FloatProperty',
      name: 'x',
      defaultValue: 0,
      documentation: function() {/*
          The X offset of this view relative to its parent. */}
    },
    {
      model_: 'FloatProperty',
      name: 'y',
      defaultValue: 0,
      documentation: function() {/*
          The Y offset of this view relative to its parent. */}
    },
    {
      model_: 'FloatProperty',
      name: 'a',
      label: 'Rotation',
      defaultValue: 0
    },
    {
      model_: 'FloatProperty',
      name: 'scaleX',
      defaultValue: 1
    },
    {
      model_: 'FloatProperty',
      name: 'scaleY',
      defaultValue: 1
    },
    {
      name: 'canvasX',
      getter: function() { return this.x + ( this.parent ? this.parent.canvasX : 0 ); }
    },
    {
      name: 'canvasY',
      getter: function() { return this.y + ( this.parent ? this.parent.canvasY : 0 ); }
    },
    {
      model_: 'IntProperty',
      name:  'width',
      defaultValue: 10,
      documentation: function() {/*
          The width of this view. Painting is not automatically clipped, so a view
          may render outside of its apparent rectangle. */}
    },
    {
      model_: 'IntProperty',
      name:  'height',
      defaultValue: 10,
      documentation: function() {/*
          The height of this view. Painting is not automatically clipped, so a view
          may render outside of its apparent rectangle. */}
    },
    {
      model_: 'FloatProperty',
      name:  'alpha',
      defaultValue: 1,
      documentation: function() {/*
          The desired opacity of the content, from 0:transparent to 1:opaque.
          Child views do not inherit and are not limited by this value. */}
    },
    {
      name:  'color',
      label: 'Foreground Color',
      type:  'String',
      defaultValue: 'black',
      documentation: function() {/*
          The foreground color for rendering primary content. */}
    },
    {
      name:  'background',
      label: 'Background Color',
      type:  'String',
      defaultValue: 'white',
      documentation: function() {/*
          The optional background color for opaque items that $$DOC{ref:'.erase'}
          their background. */}
    },
    {
      name: 'font',
      documentation: function() {/*
          The font to use for rendering text, in CSS string format: '24px Roboto'. */}
    },
    {
      name: 'clipped',
      model_: 'BooleanProperty',
      defaultValue: false
    }
  ],

  methods: {
    toView_: function() { /* Internal. Creates a CViewView wrapper. */
      if ( ! this.view ) {
        var params = {cview: this};
        if ( this.className )   params.className   = this.className;
        if ( this.tooltip )     params.tooltip     = this.tooltip;
        if ( this.speechLabel ) params.speechLabel = this.speechLabel;
        if ( this.tabIndex )    params.tabIndex    = this.tabIndex;
        if ( this.role )        params.role        = this.role;
        if ( this.data$ )       params.data$       = this.data$;
        this.view = this.CViewView.create(params);
      }
      return this.view;
    },
    toGLView_: function() { /* internal, creates a CViewGLView wrapper for 3d canvases */
      return this.CViewGLView.create({ sourceView: this });
    },

    toPositionedView_: function() { /* Internal. Creates a PositionedCViewView wrapper. */
      if ( ! this.view ) {
        var params = {cview: this};
        if ( this.className ) params.className = this.className;
        this.view = this.PositionedCViewView.create(params);
      }
      return this.view;
    },

    initCView: function() { /* Override in submodels for initialization. Callled
          once on first $$DOC{ref:'.paint'} when transitioning from 'initial'
          to 'active' '$$DOC{ref:'.state'}. */ },

    write: function(document) { /* Inserts this $$DOC{ref:'foam.graphics.CView'} into the DOM
                                   with an $$DOC{ref:'foam.graphics.AbstractCViewView'} wrapper. */
      this.toView_().write(document);
    },

    addChild: function(child) { /* Adds a child $$DOC{ref:'foam.graphics.CView'} to the scene
                                   under this. */
      this.SUPER(child);

      if ( this.view ) {
        child.view = this.view;
        child.addListener(this.view.paint);
      }
      return this;
    },

    removeChild: function(child) { /* Removes a child from the scene. */
      this.SUPER(child);
      child.view = undefined;
      child.removeListener(this.view.paint);
      return this;
    },

    erase: function() { /* Wipes the canvas area of this $$DOC{ref:'.'}. Primarily used
                          by the root node to clear the entire canvas, but an opaque child
                          may choose to erase its own area, if required. */
// Why do we do a clearRect()?  It causes problems when opacity isn't 1.
//      this.canvas.clearRect(0, 0, this.width, this.height);
      this.canvas.fillStyle = this.background;
      this.canvas.fillRect(0, 0, this.width, this.height);
    },

    paintChildren: function() { /* Paints each child. */
      for ( var i = 0 ; i < this.children.length ; i++ ) {
        var child = this.children[i];
        this.canvas.save();
        this.canvas.beginPath(); // reset any existing path (canvas.restore() does not affect path)
        child.paint();
        this.canvas.restore();
      }
    },

    paintSelf: function() { /* Implement this in sub-models to do your painting. */ },

    paint: function() { /* Translates the canvas to our ($$DOC{ref:'.x'}, $$DOC{ref:'.y'}),
                          does a $$DOC{ref:'.paintSelf'} then paints all the children. */
      if ( ! this.$ ) return; // no canvas element, so do nothing
      if ( ! this.width || ! this.height ) return;
      if ( this.state === 'initial' ) {
        this.state = 'active';
        this.initCView();
      }
      if ( this.suspended ) return; // we allowed initialization, but if suspended don't paint

      this.canvas.save();
      this.transform();
      if ( this.clipped ) {
        this.canvas.rect(0,0,this.width,this.height);
        this.canvas.clip();
      }
      this.paintSelf();
      this.paintChildren();
      this.canvas.restore();
    },

    transform: function() {
      this.canvas.translate(this.x, this.y);
      this.canvas.scale(this.scaleX, this.scaleY);
      if ( this.a ) this.canvas.rotate(this.a);
    },

    scale: function(s) {
      this.scaleX = this.scaleY = s;
    },

    mapToParent: function(point) { /* Maps a coordinate from this to our parents'. */
      point.x += this.x;
      point.y += this.y;
      return point;
    },

    mapToCanvas: function(point) { /* Maps a coordinate from this to the canvas.
                    Useful for sharing a point between sibling or cousin items. */
      this.mapToParent(point);
      if ( this.parent && this.parent.mapToCanvas )
        this.parent.mapToCanvas(point);
      return point;
    },

    destroy: function() {}
  }
});
<|endoftext|>