<commit_before>var _ = require('underscore');
var Promise = require('bluebird');

var SearchSupport = require('./../../../core/search/search-support.js');
var NoWaitOperationPromise = require('./../../../base-services/queue/domain/no-wait-operation-promise.js');
var SharedLoadBalancerCriteria = require('./domain/balancer-criteria');
var Criteria = require('./../../../core/search/criteria.js');

module.exports = SharedLoadBalancers;

/**
 * Service that allow to manage shared load balancers groups in CenturyLink Cloud
 *
 * @param dataCenterService
 * @param loadBalancerClient
 * @param queueClient
 * @constructor
 */
function SharedLoadBalancers(dataCenterService, loadBalancerClient, queueClient) {
    var self = this;

    var Status = {
        ENABLED: "enabled",
        DISABLED: "disabled"
    };

    function init () {
        SearchSupport.call(self);
    }

    /**
     * Method allow to create shared load balancer
     *
     * @param {object} command
     * @param {DataCenterCriteria} command.dataCenter - search criteria that specify one single target data center
     * @param {string} command.name - target balancer name
     * @param {string} command.description - target balancer description
     *
     * @instance
     * @function create
     * @memberof SharedLoadBalancers
     */
    self.create = function(command) {
        var result = dataCenterService.findSingle(command.dataCenter)
            .then(function(dataCenter) {
                return loadBalancerClient.createLoadBalancer(dataCenter.id, _.omit(command, "dataCenter"));
            });

        return new NoWaitOperationPromise(queueClient, processedBalancerRef, "Create Shared Load Balancer")
            .from(result);
    };

    function processedBalancerRef(response) {
        return { id: response.id };
    }

    function deleteBalancer(metadata) {
        return loadBalancerClient
            .deleteLoadBalancer(metadata.id, metadata.dataCenter.id)
            .then(function () {
                return {id: metadata.id};
            });
    }

    function processedBalancerRefs(balancers) {
        return _.map(balancers, processedBalancerRef);
    }

    /**
     * Method allow to delete shared load balancers
     * @param {SharedLoadBalancerCriteria} args - criteria that specify set of balancers that will be removed
     *
     * @returns {OperationPromise}
     *
     * @instance
     * @function delete
     * @memberof SharedLoadBalancers
     */
    self.delete = function () {

        var result = self
            .find(self._searchCriteriaFrom(arguments))
            .then(function (balancers) {
                return Promise.settle(_.map(balancers, deleteBalancer));
            });

        return new NoWaitOperationPromise(queueClient, processedBalancerRefs, "Delete Shared Load Balancer")
            .fromInspections(result);
    };

    function modifySingle(modificationConfig, balancer) {
        if (modificationConfig.name === undefined) {
            modificationConfig.name = balancer.name;
        }

        if (modificationConfig.description === undefined) {
            modificationConfig.description = balancer.description;
        }

        return loadBalancerClient.modifyLoadBalancer(balancer.id, balancer.dataCenter.id, modificationConfig)
            .then(function() {
                return balancer;
            });
    }

    /**
     * Method allow to modify shared load balancer resource settings
     *
     * @param {SharedLoadBalancerCriteria} balancerCriteria -
     * criteria that specify set of balancers that will be modified
     *
     * @param {object} modificationConfig
     * @param {string} modificationConfig.name - new balancer name
     * @param {string} modificationConfig.description - new value of balancer description
     * @param {boolean} modificationConfig.enabled - the new status of balancer
     * @return {Promise<SharedLoadBalancerCriteria[]>} - promise that resolved by list of references to
     *                                            successfully processed resources.
     * @instance
     * @function modify
     * @memberof SharedLoadBalancers
     */
    self.modify = function (balancerCriteria, modificationConfig) {
        var criteria = initCriteria(balancerCriteria);

        if (modificationConfig.enabled === true) {
            modificationConfig.status = Status.ENABLED;
        } else if (modificationConfig.enabled === false) {
            modificationConfig.status = Status.DISABLED;
        }

        modificationConfig = _.omit(modificationConfig, "enabled");

        var result = self.find(criteria)
            .then(function(balancers) {
                return Promise.settle(_.map(balancers, _.partial(modifySingle, modificationConfig)));
            });

        return new NoWaitOperationPromise(queueClient, processedBalancerRefs, "Update Shared Load Balancer")
            .fromInspections(result);
    };

    /**
     * Method allows to search shared load balancers.
     *
     * @param {SharedLoadBalancerCriteria} args - criteria that specify set of balancers that will be searched
     *
     * @return {Promise<Array<SharedLoadBalancerCriteria>>} - promise that resolved by list of references to
     *                                            successfully processed resources.
     *
     * @instance
     * @function find
     * @memberof SharedLoadBalancers
     */
    self.find = function() {
        var criteria = initCriteria(arguments);

        var dataCenterCriteria = new Criteria(criteria).extractSubCriteria(function (criteria) {
            return criteria.dataCenter;
        });

        return dataCenterService.find(dataCenterCriteria)
            .then(loadBalancersByDataCenter)
            .then(setDataCenterToBalancers)
            .then(_.partial(filterBalancers, _, criteria));
    };

    function loadBalancersByDataCenter(dataCenters) {
        return Promise.all(
            _.map(dataCenters, function(dataCenter) {
                return Promise.props(
                    {
                        dataCenter: dataCenter,
                        balancers: loadBalancerClient.findLoadBalancers(dataCenter.id)
                    }
                );
            })
        );
    }

    function setDataCenterToBalancers(props) {
        return _.chain(props)
            .map(function(prop) {
                _.each(prop.balancers, function(balancer) {
                    balancer.dataCenter = prop.dataCenter;
                });

                return prop.balancers;
            })
            .flatten()
            .value();
    }

    function filterBalancers(balancers, criteria) {
        if (!balancers || balancers.length === 0) {
            return [];
        }
        return _.filter(balancers, new SharedLoadBalancerCriteria(criteria).predicate().fn);
    }

    function initCriteria() {
        return new SharedLoadBalancerCriteria(self._searchCriteriaFrom(arguments)).parseCriteria();
    }

    init();
}<commit_msg>update balancer groups functionality<commit_after>var _ = require('underscore');
var Promise = require('bluebird');

var SearchSupport = require('./../../../core/search/search-support.js');
var NoWaitOperationPromise = require('./../../../base-services/queue/domain/no-wait-operation-promise.js');
var SharedLoadBalancerCriteria = require('./domain/balancer-criteria');
var Criteria = require('./../../../core/search/criteria.js');

module.exports = SharedLoadBalancers;

/**
 * Service that allow to manage shared load balancers groups in CenturyLink Cloud
 *
 * @param dataCenterService
 * @param loadBalancerClient
 * @param queueClient
 * @constructor
 */
function SharedLoadBalancers(dataCenterService, loadBalancerClient, queueClient) {
    var self = this;

    var Status = {
        ENABLED: "enabled",
        DISABLED: "disabled"
    };

    function init () {
        SearchSupport.call(self);
    }

    /**
     * Method allow to create shared load balancer
     *
     * @param {object} command
     * @param {DataCenterCriteria} command.dataCenter - search criteria that specify one single target data center
     * @param {string} command.name - target balancer name
     * @param {string} command.description - target balancer description
     *
     * @instance
     * @function create
     * @memberof SharedLoadBalancers
     */
    self.create = function(command) {
        var result = dataCenterService.findSingle(command.dataCenter)
            .then(function(dataCenter) {
                command = setBalancerStatus(command);
                return loadBalancerClient.createLoadBalancer(dataCenter.id, _.omit(command, "dataCenter"));
            });

        return new NoWaitOperationPromise(queueClient, processedBalancerRef, "Create Shared Load Balancer")
            .from(result);
    };

    function processedBalancerRef(response) {
        return { id: response.id };
    }

    function deleteBalancer(metadata) {
        return loadBalancerClient
            .deleteLoadBalancer(metadata.id, metadata.dataCenter.id)
            .then(function () {
                return {id: metadata.id};
            });
    }

    function processedBalancerRefs(balancers) {
        return _.map(balancers, processedBalancerRef);
    }

    /**
     * Method allow to delete shared load balancers
     * @param {SharedLoadBalancerCriteria} args - criteria that specify set of balancers that will be removed
     *
     * @returns {OperationPromise}
     *
     * @instance
     * @function delete
     * @memberof SharedLoadBalancers
     */
    self.delete = function () {

        var result = self
            .find(self._searchCriteriaFrom(arguments))
            .then(function (balancers) {
                return Promise.settle(_.map(balancers, deleteBalancer));
            });

        return new NoWaitOperationPromise(queueClient, processedBalancerRefs, "Delete Shared Load Balancer")
            .fromInspections(result);
    };

    function modifySingle(modificationConfig, balancer) {
        if (modificationConfig.name === undefined) {
            modificationConfig.name = balancer.name;
        }

        if (modificationConfig.description === undefined) {
            modificationConfig.description = balancer.description;
        }

        return loadBalancerClient.modifyLoadBalancer(balancer.id, balancer.dataCenter.id, modificationConfig)
            .then(function() {
                return balancer;
            });
    }

    function setBalancerStatus(config) {
        if (config.enabled === true) {
            config.status = Status.ENABLED;
        } else if (config.enabled === false) {
            config.status = Status.DISABLED;
        }

        return _.omit(config, "enabled");
    }

    /**
     * Method allow to modify shared load balancer resource settings
     *
     * @param {SharedLoadBalancerCriteria} balancerCriteria -
     * criteria that specify set of balancers that will be modified
     *
     * @param {object} modificationConfig
     * @param {string} modificationConfig.name - new balancer name
     * @param {string} modificationConfig.description - new value of balancer description
     * @param {boolean} modificationConfig.enabled - the new status of balancer
     * @return {Promise<SharedLoadBalancerCriteria[]>} - promise that resolved by list of references to
     *                                            successfully processed resources.
     * @instance
     * @function modify
     * @memberof SharedLoadBalancers
     */
    self.modify = function (balancerCriteria, modificationConfig) {
        var criteria = initCriteria(balancerCriteria);

        modificationConfig = setBalancerStatus(modificationConfig);

        var result = self.find(criteria)
            .then(function(balancers) {
                return Promise.settle(_.map(balancers, _.partial(modifySingle, modificationConfig)));
            });

        return new NoWaitOperationPromise(queueClient, processedBalancerRefs, "Update Shared Load Balancer")
            .fromInspections(result);
    };

    /**
     * Method allows to search shared load balancers.
     *
     * @param {SharedLoadBalancerCriteria} args - criteria that specify set of balancers that will be searched
     *
     * @return {Promise<Array<SharedLoadBalancerCriteria>>} - promise that resolved by list of references to
     *                                            successfully processed resources.
     *
     * @instance
     * @function find
     * @memberof SharedLoadBalancers
     */
    self.find = function() {
        var criteria = initCriteria(arguments);

        var dataCenterCriteria = new Criteria(criteria).extractSubCriteria(function (criteria) {
            return criteria.dataCenter;
        });

        return dataCenterService.find(dataCenterCriteria)
            .then(loadBalancersByDataCenter)
            .then(setDataCenterToBalancers)
            .then(_.partial(filterBalancers, _, criteria));
    };

    function loadBalancersByDataCenter(dataCenters) {
        return Promise.all(
            _.map(dataCenters, function(dataCenter) {
                return Promise.props(
                    {
                        dataCenter: dataCenter,
                        balancers: loadBalancerClient.findLoadBalancers(dataCenter.id)
                    }
                );
            })
        );
    }

    function setDataCenterToBalancers(props) {
        return _.chain(props)
            .map(function(prop) {
                _.each(prop.balancers, function(balancer) {
                    balancer.dataCenter = prop.dataCenter;
                });

                return prop.balancers;
            })
            .flatten()
            .value();
    }

    function filterBalancers(balancers, criteria) {
        if (!balancers || balancers.length === 0) {
            return [];
        }
        return _.filter(balancers, new SharedLoadBalancerCriteria(criteria).predicate().fn);
    }

    function initCriteria() {
        return new SharedLoadBalancerCriteria(self._searchCriteriaFrom(arguments)).parseCriteria();
    }

    init();
}<|endoftext|>


<commit_before>'use strict';

/**
* Notes:
*	=> sin(-x) = -sin(x)
*	=> sin(+n) = +0, where `n` is a positive integer
*	=> sin(-n) = -sin(+n) = -0, where `n` is a positive integer
*	=> cos(-x) = cos(x)
*/

// MODULES //

var isnan = require( '@stdlib/math/base/utils/is-nan' );
var isInfinite = require( '@stdlib/math/base/utils/is-infinite' );
var cos = require( '@stdlib/math/base/special/cos' );
var sin = require( '@stdlib/math/base/special/sin' );
var abs = require( '@stdlib/math/base/special/abs' );
var copysign = require( '@stdlib/math/base/special/copysign' );
var PI = require( '@stdlib/math/constants/float64-pi' );

// SINPI //

/**
* Computes the value of `sin(πx)`.
*
* @param {number} x - input value
* @throws {RangeError} must provide a finite number
* @returns {number} function value
*
* @example
* var y = sinpi( 0.0 );
* // returns 0.0
* @example
* var y = sinpi( 0.5 );
* // returns 1.0
* @example
* var y = sinpi( 0.9 );
* // returns ~0.309
* @example
* var y = sinpi( NaN );
* // returns NaN
*/
function sinpi( x ) {
	var ar;
	var r;
	if ( isnan( x ) ) {
		return NaN;
	}
	if ( isInfinite( x ) ) {
		// TODO: should we throw or return NaN?
		throw new RangeError( 'invalid input argument. Must provide a finite number. Value: `' + x + '`.' );
	}
	// Argument reduction (reduce to [0,2))...
	r = x % 2.0; // sign preserving
	ar = abs( r );

	// If `x` is an integer, the mod is an integer...
	if ( ar === 0.0 || ar === 1.0 ) {
		return copysign( 0.0, r );
	}
	if ( ar < 0.25 ) {
		return sin( PI*r );
	}
	// In each of the following, we further reduce to [-π/4,π/4)...
	if ( ar < 0.75 ) {
		ar = 0.5 - ar;
		return copysign( cos( PI*ar ), r );
	}
	if ( ar < 1.25 ) {
		r = copysign( 1.0, r ) - r;
		return sin( PI*r );
	}
	if ( ar < 1.75 ) {
		ar = ar - 1.5;
		return -copysign( cos( PI*ar ), r );
	}
	r = r - copysign( 2.0, r );
	return sin( PI*r );
} // end FUNCTION sinpi()

// EXPORTS //

module.exports = sinpi;
<commit_msg>Remove asterisk<commit_after>'use strict';

/*
* Notes:
*	=> sin(-x) = -sin(x)
*	=> sin(+n) = +0, where `n` is a positive integer
*	=> sin(-n) = -sin(+n) = -0, where `n` is a positive integer
*	=> cos(-x) = cos(x)
*/

// MODULES //

var isnan = require( '@stdlib/math/base/utils/is-nan' );
var isInfinite = require( '@stdlib/math/base/utils/is-infinite' );
var cos = require( '@stdlib/math/base/special/cos' );
var sin = require( '@stdlib/math/base/special/sin' );
var abs = require( '@stdlib/math/base/special/abs' );
var copysign = require( '@stdlib/math/base/special/copysign' );
var PI = require( '@stdlib/math/constants/float64-pi' );

// SINPI //

/**
* Computes the value of `sin(πx)`.
*
* @param {number} x - input value
* @throws {RangeError} must provide a finite number
* @returns {number} function value
*
* @example
* var y = sinpi( 0.0 );
* // returns 0.0
* @example
* var y = sinpi( 0.5 );
* // returns 1.0
* @example
* var y = sinpi( 0.9 );
* // returns ~0.309
* @example
* var y = sinpi( NaN );
* // returns NaN
*/
function sinpi( x ) {
	var ar;
	var r;
	if ( isnan( x ) ) {
		return NaN;
	}
	if ( isInfinite( x ) ) {
		// TODO: should we throw or return NaN?
		throw new RangeError( 'invalid input argument. Must provide a finite number. Value: `' + x + '`.' );
	}
	// Argument reduction (reduce to [0,2))...
	r = x % 2.0; // sign preserving
	ar = abs( r );

	// If `x` is an integer, the mod is an integer...
	if ( ar === 0.0 || ar === 1.0 ) {
		return copysign( 0.0, r );
	}
	if ( ar < 0.25 ) {
		return sin( PI*r );
	}
	// In each of the following, we further reduce to [-π/4,π/4)...
	if ( ar < 0.75 ) {
		ar = 0.5 - ar;
		return copysign( cos( PI*ar ), r );
	}
	if ( ar < 1.25 ) {
		r = copysign( 1.0, r ) - r;
		return sin( PI*r );
	}
	if ( ar < 1.75 ) {
		ar = ar - 1.5;
		return -copysign( cos( PI*ar ), r );
	}
	r = r - copysign( 2.0, r );
	return sin( PI*r );
} // end FUNCTION sinpi()

// EXPORTS //

module.exports = sinpi;
<|endoftext|>


<commit_before>(function () {
    'use strict';

    /**
     * A component to render the pop up search field
     */
    var umbSearch = {
        templateUrl: 'views/components/application/umb-search.html',
        controllerAs: 'vm',
        controller: umbSearchController,
        bindings: {
            onClose: "&"
        }
    };

    function umbSearchController($scope, backdropService, searchService) {

        var vm = this;

        vm.$onInit = onInit;
        vm.$onDestroy = onDestroy;
        vm.search = search;
        vm.handleKeyUp = handleKeyUp;
        vm.closeSearch = closeSearch;

        function onInit() {
            vm.searchResults = [];
            vm.hasResults = false;
            backdropService.open();
        }

        function onDestroy() {
            backdropService.close();
        }

        function handleKeyUp(event) {
            // esc
            if(event.keyCode === 27) {
                closeSearch();
            }
        }

        /**
         * Used to proxy a callback
         */
        function closeSearch() {
            if(vm.onClose) {
                vm.onClose();
            }
        }

        /**
         * Used to search
         * @param {string} searchQuery
         */
        function search(searchQuery) {
            if(searchQuery.length > 0) {
                var search = {"term": searchQuery};
                searchService.searchAll(search).then(function(result){
                    //result is a dictionary of group Title and it's results
                    var filtered = {};
                    _.each(result, function (value, key) {
                        if (value.results.length > 0) {
                            filtered[key] = value;
                        }
                    });
                    // bind to view model
                    vm.searchResults = filtered;
                    // check if search has results
                    vm.hasResults = Object.keys(vm.searchResults).length > 0;
                });

            } else {
                vm.searchResults = [];
                vm.hasResults = false;
            }
        }

    }

    angular.module('umbraco.directives').component('umbSearch', umbSearch);

})();<commit_msg>close search when item is clicked<commit_after>(function () {
    'use strict';

    /**
     * A component to render the pop up search field
     */
    var umbSearch = {
        templateUrl: 'views/components/application/umb-search.html',
        controllerAs: 'vm',
        controller: umbSearchController,
        bindings: {
            onClose: "&"
        }
    };

    function umbSearchController($scope, backdropService, searchService) {

        var vm = this;

        vm.$onInit = onInit;
        vm.$onDestroy = onDestroy;
        vm.search = search;
        vm.clickItem = clickItem;
        vm.handleKeyUp = handleKeyUp;
        vm.closeSearch = closeSearch;

        function onInit() {
            vm.searchResults = [];
            vm.hasResults = false;
            backdropService.open();
        }

        function onDestroy() {
            backdropService.close();
        }

        function clickItem(item) {
            closeSearch();
        }

        function handleKeyUp(event) {
            // esc
            if(event.keyCode === 27) {
                closeSearch();
            }
        }

        /**
         * Used to proxy a callback
         */
        function closeSearch() {
            if(vm.onClose) {
                vm.onClose();
            }
        }

        /**
         * Used to search
         * @param {string} searchQuery
         */
        function search(searchQuery) {
            if(searchQuery.length > 0) {
                var search = {"term": searchQuery};
                searchService.searchAll(search).then(function(result){
                    //result is a dictionary of group Title and it's results
                    var filtered = {};
                    _.each(result, function (value, key) {
                        if (value.results.length > 0) {
                            filtered[key] = value;
                        }
                    });
                    // bind to view model
                    vm.searchResults = filtered;
                    // check if search has results
                    vm.hasResults = Object.keys(vm.searchResults).length > 0;
                });

            } else {
                vm.searchResults = [];
                vm.hasResults = false;
            }
        }

    }

    angular.module('umbraco.directives').component('umbSearch', umbSearch);

})();<|endoftext|>


<commit_before>angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.DocTypePickerController", [

    "$scope",
    "Umbraco.PropertyEditors.NestedContent.Resources",

    function ($scope, ncResources) {

        $scope.add = function () {
            $scope.model.value.push({
                // As per PR #4, all stored content type aliases must be prefixed "nc" for easier recognition.
                // For good measure we'll also prefix the tab alias "nc"
                ncAlias: "",
                ncTabAlias: "",
                nameTemplate: ""
            }
            );
        }

        $scope.remove = function (index) {
            $scope.model.value.splice(index, 1);
        }

        $scope.sortableOptions = {
            axis: 'y',
            cursor: "move",
            handle: ".icon-navigation"
        };

        $scope.docTypeTabs = {};

        ncResources.getContentTypes().then(function (docTypes) {
            $scope.model.docTypes = docTypes;

            // Populate document type tab dictionary
            docTypes.forEach(function (value) {
                $scope.docTypeTabs[value.alias] = value.tabs;
            });
        });

        $scope.selectableDocTypesFor = function (config) {
            // return all doctypes that are:
            // 1. either already selected for this config, or
            // 2. not selected in any other config
            return _.filter($scope.model.docTypes, function (docType) {
                return docType.alias === config.ncAlias || !_.find($scope.model.value, function(c) {
                    return docType.alias === c.ncAlias;
                });
            });

        }

        if (!$scope.model.value) {
            $scope.model.value = [];
            $scope.add();
        }
    }
]);

angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.PropertyEditorController", [

    "$scope",
    "$interpolate",
    "$filter",
    "$timeout",
    "contentResource",
    "localizationService",
    "iconHelper",

    function ($scope, $interpolate, $filter, $timeout, contentResource, localizationService, iconHelper) {

        //$scope.model.config.contentTypes;
        //$scope.model.config.minItems;
        //$scope.model.config.maxItems;

        var inited = false;

        _.each($scope.model.config.contentTypes, function (contentType) {
            contentType.nameExp = !!contentType.nameTemplate
                ? $interpolate(contentType.nameTemplate)
                : undefined;
        });

        $scope.nodes = [];
        $scope.currentNode = undefined;
        $scope.realCurrentNode = undefined;
        $scope.scaffolds = undefined;
        $scope.sorting = false;

        $scope.minItems = $scope.model.config.minItems || 0;
        $scope.maxItems = $scope.model.config.maxItems || 0;

        if ($scope.maxItems == 0)
            $scope.maxItems = 1000;

        $scope.singleMode = $scope.minItems == 1 && $scope.maxItems == 1;
        $scope.showIcons = $scope.model.config.showIcons;
        $scope.wideMode = $scope.model.config.hideLabel;

        $scope.labels = {};
        localizationService.localizeMany(["grid_insertControl"]).then(function(data) {
            $scope.labels.docTypePickerTitle = data[0];
        });

        // helper to force the current form into the dirty state
        $scope.setDirty = function () {
            if ($scope.propertyForm) {
                $scope.propertyForm.$setDirty();
            }
        };

        $scope.addNode = function (alias) {
            var scaffold = $scope.getScaffold(alias);

            var newNode = initNode(scaffold, null);

            $scope.currentNode = newNode;
            $scope.setDirty();
        };

        $scope.openNodeTypePicker = function ($event) {
            if ($scope.nodes.length >= $scope.maxItems) {
                return;
            }

            $scope.overlayMenu = {
                title: $scope.labels.docTypePickerTitle,
                show: false,
                style: {},
                filter: $scope.scaffolds.length > 15 ? true : false,
                orderBy: "$index",
                view: "itempicker",
                event: $event,
                submit: function(model) {
                    if(model && model.selectedItem) {
                        $scope.addNode(model.selectedItem.alias);
                    }
                    $scope.overlayMenu.show = false;
                    $scope.overlayMenu = null;
                },
                close: function() {
                    $scope.overlayMenu.show = false;
                    $scope.overlayMenu = null;
                }
            };

            // this could be used for future limiting on node types
            $scope.overlayMenu.availableItems = [];
            _.each($scope.scaffolds, function (scaffold) {
                $scope.overlayMenu.availableItems.push({
                    alias: scaffold.contentTypeAlias,
                    name: scaffold.contentTypeName,
                    icon: iconHelper.convertFromLegacyIcon(scaffold.icon)
                });
            });

            if ($scope.overlayMenu.availableItems.length === 0) {
                return;
            }

            if ($scope.overlayMenu.availableItems.length === 1) {
                // only one scaffold type - no need to display the picker
                $scope.addNode($scope.scaffolds[0].contentTypeAlias);
                return;
            }

            $scope.overlayMenu.show = true;
        };

        $scope.editNode = function (idx) {
            if ($scope.currentNode && $scope.currentNode.key == $scope.nodes[idx].key) {
                $scope.currentNode = undefined;
            } else {
                $scope.currentNode = $scope.nodes[idx];
            }
        };

        $scope.deleteNode = function (idx) {
            if ($scope.nodes.length > $scope.model.config.minItems) {
                if ($scope.model.config.confirmDeletes && $scope.model.config.confirmDeletes == 1) {
                    localizationService.localize('content_nestedContentDeleteItem').then(function (value) {
                        if (confirm(value)) {
                            $scope.nodes.splice(idx, 1);
                            $scope.setDirty();
                            updateModel();
                        }
                    });
                } else {
                    $scope.nodes.splice(idx, 1);
                    $scope.setDirty();
                    updateModel();
                }
            }
        };

        $scope.getName = function (idx) {

            var name = "Item " + (idx + 1);

            if ($scope.model.value[idx]) {

                var contentType = $scope.getContentTypeConfig($scope.model.value[idx].ncContentTypeAlias);

                if (contentType != null && contentType.nameExp) {
                    // Run the expression against the stored dictionary value, NOT the node object
                    var item = $scope.model.value[idx];

                    // Add a temporary index property
                    item['$index'] = (idx + 1);

                    var newName = contentType.nameExp(item);
                    if (newName && (newName = $.trim(newName))) {
                        name = newName;
                    }

                    // Delete the index property as we don't want to persist it
                    delete item['$index'];
                }

            }

            // Update the nodes actual name value
            if ($scope.nodes[idx].name !== name) {
                $scope.nodes[idx].name = name;
            }

            return name;
        };

        $scope.getIcon = function (idx) {
            var scaffold = $scope.getScaffold($scope.model.value[idx].ncContentTypeAlias);
            return scaffold && scaffold.icon ? iconHelper.convertFromLegacyIcon(scaffold.icon) : "icon-folder";
        }

        $scope.sortableOptions = {
            axis: 'y',
            cursor: "move",
            handle: ".umb-nested-content__icon--move",
            start: function (ev, ui) {
                updateModel();
                // Yea, yea, we shouldn't modify the dom, sue me
                $("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () {
                    tinymce.execCommand('mceRemoveEditor', false, $(this).attr('id'));
                    $(this).css("visibility", "hidden");
                });
                $scope.$apply(function () {
                    $scope.sorting = true;
                });
            },
            update: function (ev, ui) {
                $scope.setDirty();
            },
            stop: function (ev, ui) {
                $("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () {
                    tinymce.execCommand('mceAddEditor', true, $(this).attr('id'));
                    $(this).css("visibility", "visible");
                });
                $scope.$apply(function () {
                    $scope.sorting = false;
                    updateModel();
                });
            }
        };

        $scope.getScaffold = function (alias) {
            return _.find($scope.scaffolds, function (scaffold) {
                return scaffold.contentTypeAlias == alias;
            });
        }

        $scope.getContentTypeConfig = function (alias) {
            return _.find($scope.model.config.contentTypes, function (contentType) {
                return contentType.ncAlias == alias;
            });
        }

        var notSupported = [
          "Umbraco.Tags",
          "Umbraco.UploadField",
          "Umbraco.ImageCropper"
        ];

        // Initialize
        var scaffoldsLoaded = 0;
        $scope.scaffolds = [];
        _.each($scope.model.config.contentTypes, function (contentType) {
            contentResource.getScaffold(-20, contentType.ncAlias).then(function (scaffold) {
                // make sure it's an element type before allowing the user to create new ones
                if (scaffold.isElement) {
                    // remove all tabs except the specified tab
                    var tabs = scaffold.variants[0].tabs;
                    var tab = _.find(tabs, function (tab) {
                        return tab.id != 0 && (tab.alias.toLowerCase() == contentType.ncTabAlias.toLowerCase() || contentType.ncTabAlias == "");
                    });
                    scaffold.tabs = [];
                    if (tab) {
                        scaffold.tabs.push(tab);

                        angular.forEach(tab.properties,
                            function (property) {
                                if (_.find(notSupported, function (x) { return x === property.editor; })) {
                                    property.notSupported = true;
                                    // TODO: Not supported message to be replaced with 'content_nestedContentEditorNotSupported' dictionary key. Currently not possible due to async/timing quirk.
                                    property.notSupportedMessage = "Property " + property.label + " uses editor " + property.editor + " which is not supported by Nested Content.";
                                }
                            });
                    }

                    // Store the scaffold object
                    $scope.scaffolds.push(scaffold);
                }

                scaffoldsLoaded++;
                initIfAllScaffoldsHaveLoaded();
            }, function (error) {
                scaffoldsLoaded++;
                initIfAllScaffoldsHaveLoaded();
            });
        });

        var initIfAllScaffoldsHaveLoaded = function () {
            // Initialize when all scaffolds have loaded
            if ($scope.model.config.contentTypes.length == scaffoldsLoaded) {
                // Because we're loading the scaffolds async one at a time, we need to
                // sort them explicitly according to the sort order defined by the data type.
                var contentTypeAliases = [];
                _.each($scope.model.config.contentTypes, function (contentType) {
                    contentTypeAliases.push(contentType.ncAlias);
                });
                $scope.scaffolds = $filter('orderBy')($scope.scaffolds, function (s) {
                    return contentTypeAliases.indexOf(s.contentTypeAlias);
                });

                // Convert stored nodes
                if ($scope.model.value) {
                    for (var i = 0; i < $scope.model.value.length; i++) {
                        var item = $scope.model.value[i];
                        var scaffold = $scope.getScaffold(item.ncContentTypeAlias);
                        if (scaffold == null) {
                            // No such scaffold - the content type might have been deleted. We need to skip it.
                            continue;
                        }
                        initNode(scaffold, item);
                    }
                }

                // Enforce min items
                if ($scope.nodes.length < $scope.model.config.minItems) {
                    for (var i = $scope.nodes.length; i < $scope.model.config.minItems; i++) {
                        $scope.addNode($scope.scaffolds[0].contentTypeAlias);
                    }
                }

                // If there is only one item, set it as current node
                if ($scope.singleMode || ($scope.nodes.length == 1 && $scope.maxItems == 1)) {
                    $scope.currentNode = $scope.nodes[0];
                }

                inited = true;
            }
        }

        var initNode = function (scaffold, item) {
            var node = angular.copy(scaffold);

            node.key = item && item.key ? item.key : UUID.generate();
            node.ncContentTypeAlias = scaffold.contentTypeAlias;

            for (var t = 0; t < node.tabs.length; t++) {
                var tab = node.tabs[t];
                for (var p = 0; p < tab.properties.length; p++) {
                    var prop = tab.properties[p];
                    prop.propertyAlias = prop.alias;
                    prop.alias = $scope.model.alias + "___" + prop.alias;
                    // Force validation to occur server side as this is the
                    // only way we can have consistancy between mandatory and
                    // regex validation messages. Not ideal, but it works.
                    prop.validation = {
                        mandatory: false,
                        pattern: ""
                    };
                    if (item) {
                        if (item[prop.propertyAlias]) {
                            prop.value = item[prop.propertyAlias];
                        }
                    }
                }
            }

            $scope.nodes.push(node);

            return node;
        }

        var updateModel = function () {
            if ($scope.realCurrentNode) {
                $scope.$broadcast("ncSyncVal", { key: $scope.realCurrentNode.key });
            }
            if (inited) {
                var newValues = [];
                for (var i = 0; i < $scope.nodes.length; i++) {
                    var node = $scope.nodes[i];
                    var newValue = {
                        key: node.key,
                        name: node.name,
                        ncContentTypeAlias: node.ncContentTypeAlias
                    };
                    for (var t = 0; t < node.tabs.length; t++) {
                        var tab = node.tabs[t];
                        for (var p = 0; p < tab.properties.length; p++) {
                            var prop = tab.properties[p];
                            if (typeof prop.value !== "function") {
                                newValue[prop.propertyAlias] = prop.value;
                            }
                        }
                    }
                    newValues.push(newValue);
                }
                $scope.model.value = newValues;
            }
        }

        $scope.$watch("currentNode", function (newVal) {
            updateModel();
            $scope.realCurrentNode = newVal;
        });

        var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
            updateModel();
        });

        $scope.$on('$destroy', function () {
            unsubscribe();
        });

        // TODO: Move this into a shared location?
        var UUID = (function () {
            var self = {};
            var lut = []; for (var i = 0; i < 256; i++) { lut[i] = (i < 16 ? '0' : '') + (i).toString(16); }
            self.generate = function () {
                var d0 = Math.random() * 0xffffffff | 0;
                var d1 = Math.random() * 0xffffffff | 0;
                var d2 = Math.random() * 0xffffffff | 0;
                var d3 = Math.random() * 0xffffffff | 0;
                return lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' +
                  lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' +
                  lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] +
                  lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff];
            }
            return self;
        })();
    }

]);
<commit_msg>Make sure to parse as boolean in case old models still use "1" or the string "true"<commit_after>angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.DocTypePickerController", [

    "$scope",
    "Umbraco.PropertyEditors.NestedContent.Resources",

    function ($scope, ncResources) {

        $scope.add = function () {
            $scope.model.value.push({
                // As per PR #4, all stored content type aliases must be prefixed "nc" for easier recognition.
                // For good measure we'll also prefix the tab alias "nc"
                ncAlias: "",
                ncTabAlias: "",
                nameTemplate: ""
            }
            );
        }

        $scope.remove = function (index) {
            $scope.model.value.splice(index, 1);
        }

        $scope.sortableOptions = {
            axis: 'y',
            cursor: "move",
            handle: ".icon-navigation"
        };

        $scope.docTypeTabs = {};

        ncResources.getContentTypes().then(function (docTypes) {
            $scope.model.docTypes = docTypes;

            // Populate document type tab dictionary
            docTypes.forEach(function (value) {
                $scope.docTypeTabs[value.alias] = value.tabs;
            });
        });

        $scope.selectableDocTypesFor = function (config) {
            // return all doctypes that are:
            // 1. either already selected for this config, or
            // 2. not selected in any other config
            return _.filter($scope.model.docTypes, function (docType) {
                return docType.alias === config.ncAlias || !_.find($scope.model.value, function(c) {
                    return docType.alias === c.ncAlias;
                });
            });

        }

        if (!$scope.model.value) {
            $scope.model.value = [];
            $scope.add();
        }
    }
]);

angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.PropertyEditorController", [

    "$scope",
    "$interpolate",
    "$filter",
    "$timeout",
    "contentResource",
    "localizationService",
    "iconHelper",

    function ($scope, $interpolate, $filter, $timeout, contentResource, localizationService, iconHelper) {

        //$scope.model.config.contentTypes;
        //$scope.model.config.minItems;
        //$scope.model.config.maxItems;

        var inited = false;

        _.each($scope.model.config.contentTypes, function (contentType) {
            contentType.nameExp = !!contentType.nameTemplate
                ? $interpolate(contentType.nameTemplate)
                : undefined;
        });

        $scope.nodes = [];
        $scope.currentNode = undefined;
        $scope.realCurrentNode = undefined;
        $scope.scaffolds = undefined;
        $scope.sorting = false;

        $scope.minItems = $scope.model.config.minItems || 0;
        $scope.maxItems = $scope.model.config.maxItems || 0;

        if ($scope.maxItems == 0)
            $scope.maxItems = 1000;

        $scope.singleMode = $scope.minItems == 1 && $scope.maxItems == 1;
        $scope.showIcons = Object.toBoolean($scope.model.config.showIcons);
        $scope.wideMode = Object.toBoolean($scope.model.config.hideLabel);

        $scope.labels = {};
        localizationService.localizeMany(["grid_insertControl"]).then(function(data) {
            $scope.labels.docTypePickerTitle = data[0];
        });

        // helper to force the current form into the dirty state
        $scope.setDirty = function () {
            if ($scope.propertyForm) {
                $scope.propertyForm.$setDirty();
            }
        };

        $scope.addNode = function (alias) {
            var scaffold = $scope.getScaffold(alias);

            var newNode = initNode(scaffold, null);

            $scope.currentNode = newNode;
            $scope.setDirty();
        };

        $scope.openNodeTypePicker = function ($event) {
            if ($scope.nodes.length >= $scope.maxItems) {
                return;
            }

            $scope.overlayMenu = {
                title: $scope.labels.docTypePickerTitle,
                show: false,
                style: {},
                filter: $scope.scaffolds.length > 15 ? true : false,
                orderBy: "$index",
                view: "itempicker",
                event: $event,
                submit: function(model) {
                    if(model && model.selectedItem) {
                        $scope.addNode(model.selectedItem.alias);
                    }
                    $scope.overlayMenu.show = false;
                    $scope.overlayMenu = null;
                },
                close: function() {
                    $scope.overlayMenu.show = false;
                    $scope.overlayMenu = null;
                }
            };

            // this could be used for future limiting on node types
            $scope.overlayMenu.availableItems = [];
            _.each($scope.scaffolds, function (scaffold) {
                $scope.overlayMenu.availableItems.push({
                    alias: scaffold.contentTypeAlias,
                    name: scaffold.contentTypeName,
                    icon: iconHelper.convertFromLegacyIcon(scaffold.icon)
                });
            });

            if ($scope.overlayMenu.availableItems.length === 0) {
                return;
            }

            if ($scope.overlayMenu.availableItems.length === 1) {
                // only one scaffold type - no need to display the picker
                $scope.addNode($scope.scaffolds[0].contentTypeAlias);
                return;
            }

            $scope.overlayMenu.show = true;
        };

        $scope.editNode = function (idx) {
            if ($scope.currentNode && $scope.currentNode.key == $scope.nodes[idx].key) {
                $scope.currentNode = undefined;
            } else {
                $scope.currentNode = $scope.nodes[idx];
            }
        };

        $scope.deleteNode = function (idx) {
            if ($scope.nodes.length > $scope.model.config.minItems) {
                if ($scope.model.config.confirmDeletes && $scope.model.config.confirmDeletes == 1) {
                    localizationService.localize('content_nestedContentDeleteItem').then(function (value) {
                        if (confirm(value)) {
                            $scope.nodes.splice(idx, 1);
                            $scope.setDirty();
                            updateModel();
                        }
                    });
                } else {
                    $scope.nodes.splice(idx, 1);
                    $scope.setDirty();
                    updateModel();
                }
            }
        };

        $scope.getName = function (idx) {

            var name = "Item " + (idx + 1);

            if ($scope.model.value[idx]) {

                var contentType = $scope.getContentTypeConfig($scope.model.value[idx].ncContentTypeAlias);

                if (contentType != null && contentType.nameExp) {
                    // Run the expression against the stored dictionary value, NOT the node object
                    var item = $scope.model.value[idx];

                    // Add a temporary index property
                    item['$index'] = (idx + 1);

                    var newName = contentType.nameExp(item);
                    if (newName && (newName = $.trim(newName))) {
                        name = newName;
                    }

                    // Delete the index property as we don't want to persist it
                    delete item['$index'];
                }

            }

            // Update the nodes actual name value
            if ($scope.nodes[idx].name !== name) {
                $scope.nodes[idx].name = name;
            }

            return name;
        };

        $scope.getIcon = function (idx) {
            var scaffold = $scope.getScaffold($scope.model.value[idx].ncContentTypeAlias);
            return scaffold && scaffold.icon ? iconHelper.convertFromLegacyIcon(scaffold.icon) : "icon-folder";
        }

        $scope.sortableOptions = {
            axis: 'y',
            cursor: "move",
            handle: ".umb-nested-content__icon--move",
            start: function (ev, ui) {
                updateModel();
                // Yea, yea, we shouldn't modify the dom, sue me
                $("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () {
                    tinymce.execCommand('mceRemoveEditor', false, $(this).attr('id'));
                    $(this).css("visibility", "hidden");
                });
                $scope.$apply(function () {
                    $scope.sorting = true;
                });
            },
            update: function (ev, ui) {
                $scope.setDirty();
            },
            stop: function (ev, ui) {
                $("#umb-nested-content--" + $scope.model.id + " .umb-rte textarea").each(function () {
                    tinymce.execCommand('mceAddEditor', true, $(this).attr('id'));
                    $(this).css("visibility", "visible");
                });
                $scope.$apply(function () {
                    $scope.sorting = false;
                    updateModel();
                });
            }
        };

        $scope.getScaffold = function (alias) {
            return _.find($scope.scaffolds, function (scaffold) {
                return scaffold.contentTypeAlias == alias;
            });
        }

        $scope.getContentTypeConfig = function (alias) {
            return _.find($scope.model.config.contentTypes, function (contentType) {
                return contentType.ncAlias == alias;
            });
        }

        var notSupported = [
          "Umbraco.Tags",
          "Umbraco.UploadField",
          "Umbraco.ImageCropper"
        ];

        // Initialize
        var scaffoldsLoaded = 0;
        $scope.scaffolds = [];
        _.each($scope.model.config.contentTypes, function (contentType) {
            contentResource.getScaffold(-20, contentType.ncAlias).then(function (scaffold) {
                // make sure it's an element type before allowing the user to create new ones
                if (scaffold.isElement) {
                    // remove all tabs except the specified tab
                    var tabs = scaffold.variants[0].tabs;
                    var tab = _.find(tabs, function (tab) {
                        return tab.id != 0 && (tab.alias.toLowerCase() == contentType.ncTabAlias.toLowerCase() || contentType.ncTabAlias == "");
                    });
                    scaffold.tabs = [];
                    if (tab) {
                        scaffold.tabs.push(tab);

                        angular.forEach(tab.properties,
                            function (property) {
                                if (_.find(notSupported, function (x) { return x === property.editor; })) {
                                    property.notSupported = true;
                                    // TODO: Not supported message to be replaced with 'content_nestedContentEditorNotSupported' dictionary key. Currently not possible due to async/timing quirk.
                                    property.notSupportedMessage = "Property " + property.label + " uses editor " + property.editor + " which is not supported by Nested Content.";
                                }
                            });
                    }

                    // Store the scaffold object
                    $scope.scaffolds.push(scaffold);
                }

                scaffoldsLoaded++;
                initIfAllScaffoldsHaveLoaded();
            }, function (error) {
                scaffoldsLoaded++;
                initIfAllScaffoldsHaveLoaded();
            });
        });

        var initIfAllScaffoldsHaveLoaded = function () {
            // Initialize when all scaffolds have loaded
            if ($scope.model.config.contentTypes.length == scaffoldsLoaded) {
                // Because we're loading the scaffolds async one at a time, we need to
                // sort them explicitly according to the sort order defined by the data type.
                var contentTypeAliases = [];
                _.each($scope.model.config.contentTypes, function (contentType) {
                    contentTypeAliases.push(contentType.ncAlias);
                });
                $scope.scaffolds = $filter('orderBy')($scope.scaffolds, function (s) {
                    return contentTypeAliases.indexOf(s.contentTypeAlias);
                });

                // Convert stored nodes
                if ($scope.model.value) {
                    for (var i = 0; i < $scope.model.value.length; i++) {
                        var item = $scope.model.value[i];
                        var scaffold = $scope.getScaffold(item.ncContentTypeAlias);
                        if (scaffold == null) {
                            // No such scaffold - the content type might have been deleted. We need to skip it.
                            continue;
                        }
                        initNode(scaffold, item);
                    }
                }

                // Enforce min items
                if ($scope.nodes.length < $scope.model.config.minItems) {
                    for (var i = $scope.nodes.length; i < $scope.model.config.minItems; i++) {
                        $scope.addNode($scope.scaffolds[0].contentTypeAlias);
                    }
                }

                // If there is only one item, set it as current node
                if ($scope.singleMode || ($scope.nodes.length == 1 && $scope.maxItems == 1)) {
                    $scope.currentNode = $scope.nodes[0];
                }

                inited = true;
            }
        }

        var initNode = function (scaffold, item) {
            var node = angular.copy(scaffold);

            node.key = item && item.key ? item.key : UUID.generate();
            node.ncContentTypeAlias = scaffold.contentTypeAlias;

            for (var t = 0; t < node.tabs.length; t++) {
                var tab = node.tabs[t];
                for (var p = 0; p < tab.properties.length; p++) {
                    var prop = tab.properties[p];
                    prop.propertyAlias = prop.alias;
                    prop.alias = $scope.model.alias + "___" + prop.alias;
                    // Force validation to occur server side as this is the
                    // only way we can have consistancy between mandatory and
                    // regex validation messages. Not ideal, but it works.
                    prop.validation = {
                        mandatory: false,
                        pattern: ""
                    };
                    if (item) {
                        if (item[prop.propertyAlias]) {
                            prop.value = item[prop.propertyAlias];
                        }
                    }
                }
            }

            $scope.nodes.push(node);

            return node;
        }

        var updateModel = function () {
            if ($scope.realCurrentNode) {
                $scope.$broadcast("ncSyncVal", { key: $scope.realCurrentNode.key });
            }
            if (inited) {
                var newValues = [];
                for (var i = 0; i < $scope.nodes.length; i++) {
                    var node = $scope.nodes[i];
                    var newValue = {
                        key: node.key,
                        name: node.name,
                        ncContentTypeAlias: node.ncContentTypeAlias
                    };
                    for (var t = 0; t < node.tabs.length; t++) {
                        var tab = node.tabs[t];
                        for (var p = 0; p < tab.properties.length; p++) {
                            var prop = tab.properties[p];
                            if (typeof prop.value !== "function") {
                                newValue[prop.propertyAlias] = prop.value;
                            }
                        }
                    }
                    newValues.push(newValue);
                }
                $scope.model.value = newValues;
            }
        }

        $scope.$watch("currentNode", function (newVal) {
            updateModel();
            $scope.realCurrentNode = newVal;
        });

        var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
            updateModel();
        });

        $scope.$on('$destroy', function () {
            unsubscribe();
        });

        // TODO: Move this into a shared location?
        var UUID = (function () {
            var self = {};
            var lut = []; for (var i = 0; i < 256; i++) { lut[i] = (i < 16 ? '0' : '') + (i).toString(16); }
            self.generate = function () {
                var d0 = Math.random() * 0xffffffff | 0;
                var d1 = Math.random() * 0xffffffff | 0;
                var d2 = Math.random() * 0xffffffff | 0;
                var d3 = Math.random() * 0xffffffff | 0;
                return lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' +
                  lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' +
                  lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] +
                  lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff];
            }
            return self;
        })();
    }

]);
<|endoftext|>


<commit_before>/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

export type FeatureFlags = {|
  /**
   * Function used to enable / disabled Layout Animations in React Native.
   * Default value = true.
   */
  isLayoutAnimationEnabled: () => boolean,
  /**
   * Function used to enable / disable W3C pointer event emitting in React Native.
   * If enabled you must also flip the equivalent native flags on each platform:
   * iOS -> RCTSetDispatchW3CPointerEvents
   * Android -> ReactFeatureFlags.dispatchPointerEvents
   */
  shouldEmitW3CPointerEvents: () => boolean,
  /**
   * Function used to enable / disable Pressibility from using W3C Pointer Events
   * for its hover callbacks
   */
  shouldPressibilityUseW3CPointerEventsForHover: () => boolean,
  /**
   * Enables an experimental flush-queue debouncing in Animated.js.
   */
  animatedShouldDebounceQueueFlush: () => boolean,
  /**
   * Enables an experimental mega-operation for Animated.js that replaces
   * many calls to native with a single call into native, to reduce JSI/JNI
   * traffic.
   */
  animatedShouldUseSingleOp: () => boolean,
|};

const ReactNativeFeatureFlags: FeatureFlags = {
  isLayoutAnimationEnabled: () => true,
  shouldEmitW3CPointerEvents: () => false,
  shouldPressibilityUseW3CPointerEventsForHover: () => false,
  animatedShouldDebounceQueueFlush: () => false,
  animatedShouldUseSingleOp: () => false,
};

module.exports = ReactNativeFeatureFlags;
<commit_msg>Create Feature Flag to Enable/Disable C++ Render System in JS<commit_after>/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

export type FeatureFlags = {|
  /**
   * Function used to enable / disabled Layout Animations in React Native.
   * Default value = true.
   */
  isLayoutAnimationEnabled: () => boolean,
  /**
   * Function used to enable / disable W3C pointer event emitting in React Native.
   * If enabled you must also flip the equivalent native flags on each platform:
   * iOS -> RCTSetDispatchW3CPointerEvents
   * Android -> ReactFeatureFlags.dispatchPointerEvents
   */
  shouldEmitW3CPointerEvents: () => boolean,
  /**
   * Function used to enable / disable Pressibility from using W3C Pointer Events
   * for its hover callbacks
   */
  shouldPressibilityUseW3CPointerEventsForHover: () => boolean,
  /**
   * Enables an experimental flush-queue debouncing in Animated.js.
   */
  animatedShouldDebounceQueueFlush: () => boolean,
  /**
   * Enables an experimental mega-operation for Animated.js that replaces
   * many calls to native with a single call into native, to reduce JSI/JNI
   * traffic.
   */
  animatedShouldUseSingleOp: () => boolean,
  /**
   * Enables C++ render system.
   */
  enableCppRenderSystem: () => boolean,
|};

const ReactNativeFeatureFlags: FeatureFlags = {
  isLayoutAnimationEnabled: () => true,
  shouldEmitW3CPointerEvents: () => false,
  shouldPressibilityUseW3CPointerEventsForHover: () => false,
  animatedShouldDebounceQueueFlush: () => false,
  animatedShouldUseSingleOp: () => false,
  enableCppRenderSystem: () => false,
};

module.exports = ReactNativeFeatureFlags;
<|endoftext|>


<commit_before>"use strict";
/* jshint esnext:true, node:true*/

/**
 * Providing some helper methods to normalize how state that is going to
 * be persisted in the DB is handled.
 */
const stateDef = Symbol('stateDefinition');
function stateManagerMixin(_p, stateDefinition) {
    var isFirstMixing = !(stateDef in _p);
    if(isFirstMixing) {
        // truly new, stateDef is not in the prototype chain
         _p[stateDef] = Object.create(null);
    }
    else if(Object.getOwnPropertySymbols(_p).indexOf(stateDef) === -1) {
        // Inherited, because stateDef is in the prototype chain,
        // but not in getOwnPropertySymbols.
        // Inherit from _p[stateDef], instead of changing the
        // inherited version:
        _p[stateDef] = Object.create(_p[stateDef]);
    }

    for(let [key, definition] of Object.entries(stateDefinition))
        // should we log a `info` or `debug` when overriding?
        // NOTE: at this point log levels etc. are not available
        // since this is Class definition meta programming not
        // initialization.
        _p[stateDef][key] = definition;

    // no need to extend prototype again
    if(!isFirstMixing)
        return;

    _p._stateDefEntries = function* () {
        // this uses a for ... in loop, so we get the keys from the
        // prototype chain.
        for(let k in this[stateDef])
            yield [k, this[stateDef][k]];
    };

    _p._isExpectedState = function(key) {
        var definition;
        if(!(key in this[stateDef]))
            return false;
        definition = this[stateDef][key];
        if(!('isExpected' in definition))
            return true;
        return definition.isExpected.call(this);
    };

    /**
     * Called on a fresh initialization in the constructor, when there's
     * no state available yet.
     */
    _p._initState = function() {
        this._state = {};
        for(let [key, definition] of this._stateDefEntries()) {
            if(!this._isExpectedState(key))
                continue;
            this._state[key] = definition.init.call(this);
        }
    };

    _p.serialize = function() {
        var state = {};
        for(let [key, definition] of this._stateDefEntries()) {
            if(!this._isExpectedState(key))
                // we could iterate just over the keys of this._state
                // instead and only expected keys would appear, see
                // _initState and _loadState, but this way is working
                // as well, and maybe more explixit.
                continue;
            state[key] = definition.serialize.call(this, this._state[key]);
        }
        return state;
    };

    /**
     * Validation on construction is to figure if we received a valid state
     * to begin with.
     * After changing state, if it is still valid, we can commit the changes
     * to the database.
     *
     * FIXME: This implies state can go bad after the process was created,
     * from within. Not sure we need this and not sure how to implement...
     * A self-health test would be nice to have though.
     *
     * TODO: this is not used anywhere! do we need it?
     */
    _p.validateState = function() {
        throw new Error('Not implemented!');
    };

    _p._callAndCatch = function(func, ...args) {
        try {
            return [true, func.call(this, ...args)];
        }
        catch(error) {
            // I don't want the original error stack trace to be lost completely.
            // Make this a `this.log.debug(error);`?
            this.log.warning(error);
            return [false, error.message];
        }
    };

    /**
     * Called in the constructor on an initialization that loads existing
     * state from the database i.e. like a resurrection of the object from
     * persistence.
     */
    _p._loadState = function(state) {
        this._state = {};
        var errorMessages = []
          , stateDefKeys = new Set()
          , indent = str=>str.split('\n').map(line=>'    '+line).join('\n')
          ;
        for(let [key, definition] of this._stateDefEntries()) {
            stateDefKeys.add(key);
            // some simple validation
            if(!this._isExpectedState(key)) {
                // if there's a state now for this key it's not compatible
                if(key in state)
                    errorMessages.push('* ' + key + ' (key): '
                                           + 'State is incompatible, key "'
                                           + key +'" is NOT EXPECTED but present.');
                // else: all good: not expected and not in state
                continue;
            }
            else if(!(key in state)) {
                errorMessages.push('* ' + key + ' (key): '
                                       +'State is incompatible, key "'
                                       + key +'" is expected but NOT PRESENT.');
                continue;
            }
            // expected and in state

            // In this case validate ensures the data for key can be loaded,
            // but not, that the result is valid. So maybe we need a single
            // point of failure which is where the state is actually used?
            // Thus `validate` is optional and also `load` can just raise an
            // error. `validate` is useful for simple data types, such as dates
            // or booleans, but more complex types like steps would fail when
            // loading bad state instead, doing internal validation.
            // If we never use `validate` remove it again!
            if('validate' in definition) {
                let [result, message] = definition.validate.call(this, state[key]);
                if(!result) {
                    errorMessages.push('* ' + key + ' (validate): ' + message);
                    continue;
                }
            }
            // try/catch and collect these as well, as in valiation.
            // because e.g. in load of a 'tasks' key of Step this validation
            // will happen as well, but in this case,
            let [result, valueOrMessage] = this._callAndCatch(definition.load, state[key]);
            if(!result) {
                errorMessages.push('* ' + key + ' (load): ' + valueOrMessage);
                continue;
            }
            else
                this._state[key] = valueOrMessage;
        }

        let notDefKeys = [];
        for(let key in state)
            if(!(stateDefKeys.has(key)))
                notDefKeys.push(key);
        if(notDefKeys.length)
            errorMessages.push('* State defines unspecified keys: '
                                                + notDefKeys.join(', '));

        if(errorMessages.length)
            throw new Error('State to load had the following issues:\n'
                            + '===============\n'
                            + errorMessages.map(indent).join('\n')
                            + '\n==============='
                            );
    };
}

exports.mixin = stateManagerMixin;

<commit_msg>[PRDispatcher] WIP stateManagerMixin: minor add a warning log message.<commit_after>"use strict";
/* jshint esnext:true, node:true*/

/**
 * Providing some helper methods to normalize how state that is going to
 * be persisted in the DB is handled.
 */
const stateDef = Symbol('stateDefinition');
function stateManagerMixin(_p, stateDefinition) {
    var isFirstMixing = !(stateDef in _p);
    if(isFirstMixing) {
        // truly new, stateDef is not in the prototype chain
         _p[stateDef] = Object.create(null);
    }
    else if(Object.getOwnPropertySymbols(_p).indexOf(stateDef) === -1) {
        // Inherited, because stateDef is in the prototype chain,
        // but not in getOwnPropertySymbols.
        // Inherit from _p[stateDef], instead of changing the
        // inherited version:
        _p[stateDef] = Object.create(_p[stateDef]);
    }

    for(let [key, definition] of Object.entries(stateDefinition))
        // should we log a `info` or `debug` when overriding?
        // NOTE: at this point log levels etc. are not available
        // since this is Class definition meta programming not
        // initialization.
        _p[stateDef][key] = definition;

    // no need to extend prototype again
    if(!isFirstMixing)
        return;

    _p._stateDefEntries = function* () {
        // this uses a for ... in loop, so we get the keys from the
        // prototype chain.
        for(let k in this[stateDef])
            yield [k, this[stateDef][k]];
    };

    _p._isExpectedState = function(key) {
        var definition;
        if(!(key in this[stateDef]))
            return false;
        definition = this[stateDef][key];
        if(!('isExpected' in definition))
            return true;
        return definition.isExpected.call(this);
    };

    /**
     * Called on a fresh initialization in the constructor, when there's
     * no state available yet.
     */
    _p._initState = function() {
        this._state = {};
        for(let [key, definition] of this._stateDefEntries()) {
            if(!this._isExpectedState(key))
                continue;
            this._state[key] = definition.init.call(this);
        }
    };

    _p.serialize = function() {
        var state = {};
        for(let [key, definition] of this._stateDefEntries()) {
            if(!this._isExpectedState(key))
                // we could iterate just over the keys of this._state
                // instead and only expected keys would appear, see
                // _initState and _loadState, but this way is working
                // as well, and maybe more explixit.
                continue;
            state[key] = definition.serialize.call(this, this._state[key]);
        }
        return state;
    };

    /**
     * Validation on construction is to figure if we received a valid state
     * to begin with.
     * After changing state, if it is still valid, we can commit the changes
     * to the database.
     *
     * FIXME: This implies state can go bad after the process was created,
     * from within. Not sure we need this and not sure how to implement...
     * A self-health test would be nice to have though.
     *
     * TODO: this is not used anywhere! do we need it?
     */
    _p.validateState = function() {
        throw new Error('Not implemented!');
    };

    _p._callAndCatch = function(func, ...args) {
        try {
            return [true, func.call(this, ...args)];
        }
        catch(error) {
            // I don't want the original error stack trace to be lost completely.
            // Make this a `this.log.debug(error);`?
            this.log.warning(error);
            return [false, error.message];
        }
    };

    /**
     * Called in the constructor on an initialization that loads existing
     * state from the database i.e. like a resurrection of the object from
     * persistence.
     */
    _p._loadState = function(state) {
        this._state = {};
        var errorMessages = []
          , stateDefKeys = new Set()
          , indent = str=>str.split('\n').map(line=>'    '+line).join('\n')
          ;
        for(let [key, definition] of this._stateDefEntries()) {
            stateDefKeys.add(key);
            // some simple validation
            if(!this._isExpectedState(key)) {
                // if there's a state now for this key it's not compatible
                if(key in state)
                    errorMessages.push('* ' + key + ' (key): '
                                           + 'State is incompatible, key "'
                                           + key +'" is NOT EXPECTED but present.');
                // else: all good: not expected and not in state
                continue;
            }
            else if(!(key in state)) {
                errorMessages.push('* ' + key + ' (key): '
                                       +'State is incompatible, key "'
                                       + key +'" is expected but NOT PRESENT.');
                continue;
            }
            // expected and in state

            // In this case validate ensures the data for key can be loaded,
            // but not, that the result is valid. So maybe we need a single
            // point of failure which is where the state is actually used?
            // Thus `validate` is optional and also `load` can just raise an
            // error. `validate` is useful for simple data types, such as dates
            // or booleans, but more complex types like steps would fail when
            // loading bad state instead, doing internal validation.
            // If we never use `validate` remove it again!
            if('validate' in definition && !definition.validate)
                // this is likely a programming error
                this.log.warning('"validate" is falsy in', key, 'of', this.constructor.name);
            if(definition.validate) {
                let [result, message] = definition.validate.call(this, state[key]);
                if(!result) {
                    errorMessages.push('* ' + key + ' (validate): ' + message);
                    continue;
                }
            }
            // try/catch and collect these as well, as in valiation.
            // because e.g. in load of a 'tasks' key of Step this validation
            // will happen as well, but in this case,
            let [result, valueOrMessage] = this._callAndCatch(definition.load, state[key]);
            if(!result) {
                errorMessages.push('* ' + key + ' (load): ' + valueOrMessage);
                continue;
            }
            else
                this._state[key] = valueOrMessage;
        }

        let notDefKeys = [];
        for(let key in state)
            if(!(stateDefKeys.has(key)))
                notDefKeys.push(key);
        if(notDefKeys.length)
            errorMessages.push('* State defines unspecified keys: '
                                                + notDefKeys.join(', '));

        if(errorMessages.length)
            throw new Error('State to load had the following issues:\n'
                            + '===============\n'
                            + errorMessages.map(indent).join('\n')
                            + '\n==============='
                            );
    };
}

exports.mixin = stateManagerMixin;

<|endoftext|>


<commit_before>(function () {
	'use strict';

	angular
		.module('core')
		.controller('RankingsController', RankingsController);

	RankingsController.$inject = ['$scope', '$state', '$http'];

	var RatingTresholds = {R1 : 0, R2 : 100, R3 : 200};

	function RankingsController($scope, $state, $http) {
		var vm = this;
		vm.error = null;
		vm.users = [];
		GetUsers(vm, $http);
	}

	function GetUsers(vm, $http){

		$http.get('/api/users',{username: user.username, score: user.score})
		.then(successCallback, errorCallback)

			function successCallback(res) {

				res.data.sort(function (a, b) {
					return a.score == b.score ? (a.username.toLowerCase()) > (b.username.toLowerCase()) : a.score < b.score;
				});

				for (var i = 0; i < res.data.length; ++i)
				{
					res.data[i].RatingStyle = GetStyle(res.data[i].score);
					res.data[i].index = i + 1;
				}

				vm.users = res.data;
			}

			function errorCallback(res) {
				vm.users = [];
			}
	}

	function GetStyle(score)
	{
		var color = "grey";

		if(score >= RatingTresholds.R3) color = "red"; else
		if(score >= RatingTresholds.R2) color = "deepskyblue";

		return "{\'float\': \'left\', \'color\' : \'" + color + "\'}"
	}

}());<commit_msg>Fixes ranking color bug<commit_after>(function () {
	'use strict';

	angular
		.module('core')
		.controller('RankingsController', RankingsController);

	RankingsController.$inject = ['$scope', '$state', '$http'];

	var RatingTresholds = {R1 : 0, R2 : 100, R3 : 200};

	function RankingsController($scope, $state, $http) {
		var vm = this;
		vm.error = null;
		vm.users = [];
		GetUsers(vm, $http);
	}

	function GetUsers(vm, $http){

		$http.get('/api/users',{username: user.username, score: user.score})
		.then(successCallback, errorCallback)

			function successCallback(res) {

				res.data.sort(function (a, b) {
					return a.score == b.score ? (a.username.toLowerCase()) > (b.username.toLowerCase()) : a.score < b.score;
				});

				for (var i = 0; i < res.data.length; ++i)
				{
					res.data[i].RatingStyle = GetStyle(res.data[i].score);
					res.data[i].index = i + 1;
				}

				vm.users = res.data;
			}

			function errorCallback(res) {
				vm.users = [];
			}
	}

	function GetStyle(score)
	{
		var color = "grey";

		if(score >= RatingTresholds.R3) color = 'red'; else
		if(score >= RatingTresholds.R2) color = 'deepskyblue'; else
		if(score >= RatingTresholds.R1) color = 'green';

		return "{\'float\': \'left\', \'color\' : \'" + color + "\'}"
	}

}());<|endoftext|>


<commit_before>import { _millisDateRepresentation } from '/resources/reflection/tg-date-utils.js';
import { TgReflector } from '/app/tg-reflector.js';
import { TgAppConfig } from '/app/tg-app-config.js';

export const TgEgiDataRetrievalBehavior = {

    created: function () {
        this._reflector = new TgReflector();
        this._appConfig = new TgAppConfig();
    },

    isHyperlinkProp: function (entity, column) {
        return column.type === 'Hyperlink' && this.getValueFromEntity(entity, column) !== null
    },

    isBooleanProp: function (entity, column) {
        return column.type === 'Boolean' && this.getValueFromEntity(entity, column) !== null
    },

    isNotBooleanOrHyperlinkProp: function (entity, column) {
        return !(this.isBooleanProp(entity, column) || this.isHyperlinkProp(entity, column));
    },

    getAttachmentIfPossible: function (entity, column) {
        const valueFromEntity = this.getValueFromEntity(entity, column);
        if (entity.type && entity.constructor.prototype.type.call(entity).notEnhancedFullClassName() === "ua.com.fielden.platform.attachment.Attachment") {
            return entity;
        } else if (valueFromEntity && valueFromEntity.type &&
            valueFromEntity.type().notEnhancedFullClassName() === "ua.com.fielden.platform.attachment.Attachment") {
            return valueFromEntity;
        } else if (this._reflector.entityPropOwner(this.getRealEntity(entity, column), this.getRealProperty(column))) {
            const owner = this._reflector.entityPropOwner(this.getRealEntity(entity, column), this.getRealProperty(column));
            if (owner.type().notEnhancedFullClassName() === "ua.com.fielden.platform.attachment.Attachment") {
                return owner;
            }
            return null;
        } else {
            return null;
        }
    },

    getRealEntity: function (entity, column) {
        return entity && column.collectionalProperty ? this.getCollectionalItem(entity, column) : entity;
    },

    getRealProperty: function (column) {
        return column.collectionalProperty ? column.valueProperty : column.property;
    },

    getCollectionalItem: function (entity, column) {
        if (column.collectionalProperty) {
            const collection = entity.get(column.collectionalProperty);
            const item = collection.find(cItem => column.property === cItem[column.keyProperty]);
            return item || null;
        }
    },

    getValueFromEntity: function (entity, column) {
        const realEntity = this.getRealEntity(entity, column);
        const realProperty = this.getRealProperty(column);
        return realEntity && realEntity.get(realProperty);
    },

    getBindedValue: function (entity, column) {
        return this.getValue(this.getRealEntity(entity, column), this.getRealProperty(column), column.type);
    },

    getValue: function (entity, property, type) {
        if (entity === null || property === null || type === null) {
            return '';
        } else {
            const value = entity.get(property);
            if (value === null) {
                return "";
            } else if (this._reflector.findTypeByName(type)) {
                return this._reflector.tg_toString(this._reflector.tg_convert(value), entity.type(), property);
            } else if (type.lastIndexOf('Date', 0) === 0) { // check whether type startsWith 'Date'. Type can be like 'Date', 'Date:UTC:' or 'Date:Europe/London:'
                return this._reflector.tg_toString(this._reflector.tg_convert(value), entity.type(), property);
            } else if (typeof value === 'number') {
                if (type === 'BigDecimal') {
                    return this._reflector.tg_toStringForDisplay(this._reflector.tg_convert(value), entity.type(), property, this._appConfig.locale);
                } else {
                    return this._reflector.tg_toStringForDisplay(this._reflector.tg_convert(value), entity.type(), property, this._appConfig.locale);
                }
            } else if (type === 'Money') {
                return this._reflector.tg_toStringForDisplay(this._reflector.tg_convert(value), entity.type(), property, this._appConfig.locale);
            } else if (type === 'Colour') {
                return this._reflector.tg_toStringForDisplay(this._reflector.tg_convert(value), entity.type(), property);
            } else if (type === 'Hyperlink') {
                return this._reflector.tg_toString(this._reflector.tg_convert(value), entity.type(), property);
            } else { // the following case represents string; booleans are treated separately, see tg-egi-cell._propertyChangeHandler for more details
                return this._reflector.tg_toString(this._reflector.tg_convert(value), entity.type(), property);
            }
        }
    }

};<commit_msg>#1044 6. Used single generic tg_toStringForDisplay invocation for all types of columns in EGI.<commit_after>import { _millisDateRepresentation } from '/resources/reflection/tg-date-utils.js';
import { TgReflector } from '/app/tg-reflector.js';
import { TgAppConfig } from '/app/tg-app-config.js';

export const TgEgiDataRetrievalBehavior = {

    created: function () {
        this._reflector = new TgReflector();
        this._appConfig = new TgAppConfig();
    },

    isHyperlinkProp: function (entity, column) {
        return column.type === 'Hyperlink' && this.getValueFromEntity(entity, column) !== null
    },

    isBooleanProp: function (entity, column) {
        return column.type === 'Boolean' && this.getValueFromEntity(entity, column) !== null
    },

    isNotBooleanOrHyperlinkProp: function (entity, column) {
        return !(this.isBooleanProp(entity, column) || this.isHyperlinkProp(entity, column));
    },

    getAttachmentIfPossible: function (entity, column) {
        const valueFromEntity = this.getValueFromEntity(entity, column);
        if (entity.type && entity.constructor.prototype.type.call(entity).notEnhancedFullClassName() === "ua.com.fielden.platform.attachment.Attachment") {
            return entity;
        } else if (valueFromEntity && valueFromEntity.type &&
            valueFromEntity.type().notEnhancedFullClassName() === "ua.com.fielden.platform.attachment.Attachment") {
            return valueFromEntity;
        } else if (this._reflector.entityPropOwner(this.getRealEntity(entity, column), this.getRealProperty(column))) {
            const owner = this._reflector.entityPropOwner(this.getRealEntity(entity, column), this.getRealProperty(column));
            if (owner.type().notEnhancedFullClassName() === "ua.com.fielden.platform.attachment.Attachment") {
                return owner;
            }
            return null;
        } else {
            return null;
        }
    },

    getRealEntity: function (entity, column) {
        return entity && column.collectionalProperty ? this.getCollectionalItem(entity, column) : entity;
    },

    getRealProperty: function (column) {
        return column.collectionalProperty ? column.valueProperty : column.property;
    },

    getCollectionalItem: function (entity, column) {
        if (column.collectionalProperty) {
            const collection = entity.get(column.collectionalProperty);
            const item = collection.find(cItem => column.property === cItem[column.keyProperty]);
            return item || null;
        }
    },

    getValueFromEntity: function (entity, column) {
        const realEntity = this.getRealEntity(entity, column);
        const realProperty = this.getRealProperty(column);
        return realEntity && realEntity.get(realProperty);
    },

    getBindedValue: function (entity, column) {
        return this.getValue(this.getRealEntity(entity, column), this.getRealProperty(column), column.type);
    },

    getValue: function (entity, property, type) {
        if (entity === null || property === null || type === null) {
            return '';
        } else {
            return this._reflector.tg_toStringForDisplay(this._reflector.tg_convert(entity.get(property)), entity.type(), property, this._appConfig.locale);
        }
    }

};<|endoftext|>


<commit_before>const config = {
    uri: 'mongodb://localhost:3001/meteor',
    expressPORT: 3010
};

// const config = {
//     uri: 'mongodb://mongo_instance:27017/sociallyapp',
//     expressPORT: 3010
// };

module.exports = config;
<commit_msg>hoarcoded config<commit_after>// const config = {
//     uri: 'mongodb://localhost:3001/meteor',
//     expressPORT: 3010
// };

const config = {
    uri: 'mongodb://mongo_instance:27017/sociallyapp',
    expressPORT: 3010
};

module.exports = config;
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const { StatsWriterPlugin } = require("webpack-stats-plugin")

module.exports = {
  modifyPaths(opts) {
    const paths = opts.paths;
    paths.appServerJs = path.join(paths.appPath, 'src/cli.server');
    paths.appServerIndexJs = path.join(paths.appPath, 'src/index.server');
    paths.appClientIndexJs = path.join(paths.appPath, 'src/index.client');
    return paths;
  },
  modifyWebpackOptions(opts) {
    const options = opts.options.webpackOptions;

    // Enable HtmlWebpackPlugin in iso app
    if (opts.env.target === 'web') {
      options.enableHtmlWebpackPlugin = true;
    }

    return options;
  },
  modifyWebpackConfig(opts) {
    const config = opts.webpackConfig;

    // Enable StatsWriterPlugin
    if (opts.env.target === 'web') {
      config.plugins = config.plugins.concat([
        // Write out stats file to build directory.
        new StatsWriterPlugin({
          filename: "../stats.json" // Default
        })
      ]);
    }

    return config;
  },
}
<commit_msg>fix(examples): write to disk in dev in with-flight<commit_after>'use strict';

const path = require('path');
const { StatsWriterPlugin } = require("webpack-stats-plugin")

module.exports = {
  modifyPaths(opts) {
    const paths = opts.paths;
    paths.appServerJs = path.join(paths.appPath, 'src/cli.server');
    paths.appServerIndexJs = path.join(paths.appPath, 'src/index.server');
    paths.appClientIndexJs = path.join(paths.appPath, 'src/index.client');
    return paths;
  },
  modifyWebpackOptions(opts) {
    const options = opts.options.webpackOptions;

    // Enable HtmlWebpackPlugin in iso app
    if (opts.env.target === 'web') {
      options.enableHtmlWebpackPlugin = true;
    }

    return options;
  },
  modifyWebpackConfig(opts) {
    const config = opts.webpackConfig;

    // Enable StatsWriterPlugin
    if (opts.env.target === 'web') {
      config.plugins = config.plugins.concat([
        // Write out stats file to build directory.
        new StatsWriterPlugin({
          filename: "../stats.json" // Default
        })
      ]);
    }

    if (opts.env.target === 'web' && opts.env.dev) {
      config.devServer.writeToDisk = true;
    }

    return config;
  },
}
<|endoftext|>