<commit_before>(function(){

var ui = angular.module('axelor.ui');

/**
 * The Group widget.
 *
 */
ui.formWidget('Group', {

	css: 'form-item-group',
	cellCss: 'form-item v-align-top',

	link: function(scope, element, attrs) {

		var props = scope.field;

		scope.collapsed = false;

		scope.canCollapse = function() {
			return props.canCollapse || props.collapseIf;
		};

		scope.setCollapsed = function(collapsed) {
			scope.collapsed = collapsed;
			element.children('legend').nextAll(':not(br)')[collapsed ? 'hide' : 'show']();
			$.event.trigger('adjustSize');
		};

		scope.toggle = function() {
			scope.collapsed = !scope.collapsed;
			scope.setCollapsed(scope.collapsed);
		};

		scope.$watch("attr('collapse')", function(collapsed) {
			scope.setCollapsed(collapsed);
		});

		// if auto title, then don't show it
		if (attrs.title === attrs.field) {
			attrs.$set('title', '');
		}

		attrs.$observe('title', function(value){
			scope.title = value;
		});
	},
	transclude: true,
	transcludeSelect: function(element) {
		return element;
	},
	template:
		'<fieldset ng-class="{\'bordered-box\': title}" x-layout-after="> legend:first">'+
			'<legend ng-show="title">'+
				''+
				'</legend>'+
		'</fieldset>'
});

/**
 * The Tabs widget (notebook).
 */
ui.formWidget('Tabs', {

	cellCss: 'form-item v-align-top',

	widgets: ['Notebook'],

	controller: ['$scope', '$element', function($scope, $element) {

		var tabs = $scope.tabs = [],
			selected = 0;

		$scope.select = function(tab) {

			var current = selected;

			angular.forEach(tabs, function(tab, i){
				tab.selected = false;
			});

			tab.selected = true;
			selected = _.indexOf(tabs, tab);

			setTimeout(function() {
				if ($scope.$tabs) {
					$scope.$tabs.trigger('adjust');
				}
				$.event.trigger('adjustSize');
				if(current != selected){
					doSelect();
				}
			});
		};

		this.addTab = function(tab) {
			if (tabs.length === 0) $scope.select(tab);
			tabs.push(tab);
		};

		function inRange(index) {
			return index > -1 && index < tabs.length;
		}

		function findItem(index) {
			return $element.find('ul.nav-tabs:first > li:nth-child(' + (index+1) + ')');
		}

		function doSelect() {
			var select = tabs[selected],
			    onSelect = null;

			if(select){
			    onSelect = select.onSelect;
			}

			if(onSelect){
				onSelect.handle();
			}
		}

		$scope.showTab = function(index) {

			if (!inRange(index))
				return;

			var item = findItem(index);

			item.show();

			if (selected == -1 || selected === index)
				return $scope.select(tabs[index]);

			$.event.trigger('adjustSize');
		};

		$scope.$on('on:edit', function(event){
			doSelect();
		});

		$scope.hideTab = function(index) {

			if (!inRange(index))
				return;

			var item = findItem(index),
				tab = tabs[index];

			if (item.is(':hidden'))
				return;

			item.hide();
			item.removeClass('active');

			tab.selected = false;

			if (selected > -1 && selected !== index)
				return $.event.trigger('adjustSize');

			for(var i = 0 ; i < tabs.length ; i++) {
				item = findItem(i);
				if (item.is(':visible'))
					return $scope.select(tabs[i]);
			}
			selected = -1;
		};

		$scope.setTitle = function(value,index){
			var item = findItem(index),
				pageScope = item.first().data('$scope');

			pageScope.tab.title = value;
		};
	}],

	link: function(scope, elem, attrs) {
		var props = scope.getViewDef(elem);

		scope.$tabs = $(elem).bsTabs({
			closable: false
		});

		elem.on('click', '.dropdown-toggle', function(e){
			$.event.trigger('adjustSize');
		});

		// set height (#1011)
		if (props.height) {
			elem.children('.tab-content:first').height(props.height);
		}
	},
	transclude: true,
	transcludeSelect: function(element) {
		return element.find('.tab-content:first');
	},
	template:
		'
' +
			'
' +
				'

' +
				'

' +
				'
' +
					'
' +
						'
'+
							'' +
						'
' +
					'
' +
				'
' +
				'
'+
					'
'+
						''+
							'
'+
							    '
'+
							    	''+
							    '
' +
							'
' +
						''+
					'
'+
				'
'+
			'
' +
			'

' +
		'
'
});

/**
 * The Tab widget (notebook page).
 */
ui.formWidget('Tab', {

	require: '^uiTabs',

	widgets: ['Page'],

	link: function(scope, elem, attrs, tabs) {

		setTimeout(function(){
			scope.onSelect = scope.$events.onSelect;
		});

		tabs.addTab(scope);
		attrs.$observe('title', function(value){
			scope.title = value;
		});
	},
	cellCss: 'form-item v-align-top',
	transclude: true,
	transcludeSelect: function(element) {
		return element;
	},
	template: '

'
});

})(this);
<commit_msg>Fixed notebook widget issue.<commit_after>(function(){

var ui = angular.module('axelor.ui');

/**
 * The Group widget.
 *
 */
ui.formWidget('Group', {

	css: 'form-item-group',
	cellCss: 'form-item v-align-top',

	link: function(scope, element, attrs) {

		var props = scope.field;

		scope.collapsed = false;

		scope.canCollapse = function() {
			return props.canCollapse || props.collapseIf;
		};

		scope.setCollapsed = function(collapsed) {
			scope.collapsed = collapsed;
			element.children('legend').nextAll(':not(br)')[collapsed ? 'hide' : 'show']();
			$.event.trigger('adjustSize');
		};

		scope.toggle = function() {
			scope.collapsed = !scope.collapsed;
			scope.setCollapsed(scope.collapsed);
		};

		scope.$watch("attr('collapse')", function(collapsed) {
			scope.setCollapsed(collapsed);
		});

		// if auto title, then don't show it
		if (attrs.title === attrs.field) {
			attrs.$set('title', '');
		}

		attrs.$observe('title', function(value){
			scope.title = value;
		});
	},
	transclude: true,
	transcludeSelect: function(element) {
		return element;
	},
	template:
		'<fieldset ng-class="{\'bordered-box\': title}" x-layout-after="> legend:first">'+
			'<legend ng-show="title">'+
				''+
				'</legend>'+
		'</fieldset>'
});

/**
 * The Tabs widget (notebook).
 */
ui.formWidget('Tabs', {

	cellCss: 'form-item v-align-top',

	widgets: ['Notebook'],

	controller: ['$scope', '$element', function($scope, $element) {

		var tabs = $scope.tabs = [],
			selected = 0;

		$scope.select = function(tab) {

			var current = selected;

			angular.forEach(tabs, function(tab, i){
				tab.selected = false;
			});

			tab.selected = true;
			selected = _.indexOf(tabs, tab);

			setTimeout(function() {
				if ($scope.$tabs) {
					$scope.$tabs.trigger('adjust');
				}
				$.event.trigger('adjustSize');
				if(current != selected){
					doSelect();
				}
			});
		};

		this.addTab = function(tab) {
			if (tabs.length === 0) $scope.select(tab);
			tabs.push(tab);
		};

		function inRange(index) {
			return index > -1 && index < tabs.length;
		}

		function findItem(index) {
			return $element.find('ul.nav-tabs:first > li:nth-child(' + (index+1) + ')');
		}

		function doSelect() {
			var select = tabs[selected],
			    onSelect = null;

			if(select){
			    onSelect = select.onSelect;
			}

			if(onSelect){
				onSelect.handle();
			}
		}

		$scope.showTab = function(index) {

			if (!inRange(index))
				return;

			var item = findItem(index);

			item.show();

			if (selected == -1 || selected === index)
				return $scope.select(tabs[index]);

			$.event.trigger('adjustSize');
		};

		$scope.$on('on:edit', function(event){
			doSelect();
		});

		$scope.hideTab = function(index) {

			if (!inRange(index))
				return;

			var item = findItem(index),
				tab = tabs[index];

			if (item.is(':hidden'))
				return;

			item.hide();
			item.removeClass('active');

			tab.selected = false;

			if (selected > -1 && selected !== index)
				return $.event.trigger('adjustSize');

			for(var i = 0 ; i < tabs.length ; i++) {
				item = findItem(i);
				if (item.is(':visible'))
					return $scope.select(tabs[i]);
			}
			selected = -1;
		};

		$scope.setTitle = function(value,index){
			var item = findItem(index),
				pageScope = item.first().data('$scope');

			pageScope.tab.title = value;
		};
	}],

	link: function(scope, elem, attrs) {

		var props = scope.field;

		scope.$tabs = $(elem).bsTabs({
			closable: false
		});

		elem.on('click', '.dropdown-toggle', function(e){
			$.event.trigger('adjustSize');
		});

		// set height (#1011)
		if (props.height) {
			elem.children('.tab-content:first').height(props.height);
		}
	},
	transclude: true,
	transcludeSelect: function(element) {
		return element.find('.tab-content:first');
	},
	template:
		'
' +
			'
' +
				'

' +
				'

' +
				'
' +
					'
' +
						'
'+
							'' +
						'
' +
					'
' +
				'
' +
				'
'+
					'
'+
						''+
							'
'+
							    '
'+
							    	''+
							    '
' +
							'
' +
						''+
					'
'+
				'
'+
			'
' +
			'

' +
		'
'
});

/**
 * The Tab widget (notebook page).
 */
ui.formWidget('Tab', {

	require: '^uiTabs',

	widgets: ['Page'],

	link: function(scope, elem, attrs, tabs) {

		setTimeout(function(){
			scope.onSelect = scope.$events.onSelect;
		});

		scope.selected = false;

		tabs.addTab(scope);
		attrs.$observe('title', function(value){
			scope.title = value;
		});
	},
	cellCss: 'form-item v-align-top',
	transclude: true,
	transcludeSelect: function(element) {
		return element;
	},
	template: '

'
});

})(this);
<|endoftext|>


<commit_before>/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you 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.
*/

var fs = require('fs-extra');
var path = require('path');
const execa = require('execa');
const glob = require('fast-glob');
var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
var PackageType = require('../PackageType');
const { compareByAll } = require('../utils');
const { createEditor } = require('properties-parser');

const MARKER = 'YOUR CHANGES WILL BE ERASED!';
const SIGNING_PROPERTIES = '-signing.properties';
const TEMPLATE =
    '# This file is automatically generated.\n' +
    '# Do not modify this file -- ' + MARKER + '\n';

const isPathArchSpecific = p => /-x86|-arm/.test(path.basename(p));

const outputFileComparator = compareByAll([
    // Sort arch specific builds after generic ones
    isPathArchSpecific,

    // Sort unsigned builds after signed ones
    filePath => /-unsigned/.test(path.basename(filePath)),

    // Sort by file modification time, latest first
    filePath => -fs.statSync(filePath).mtime.getTime(),

    // Sort by file name length, ascending
    filePath => filePath.length
]);

/**
 * @param {'apk' | 'aab'} bundleType
 * @param {'debug' | 'release'} buildType
 * @param {{arch?: string}} options
 */
function findOutputFiles (bundleType, buildType, { arch }) {
    let files = glob.sync(`**/*.${bundleType}`, {
        absolute: true,
        cwd: path.resolve(this[`${bundleType}Dir`], buildType)
    }).map(path.normalize);

    if (files.length === 0) return files;

    // Assume arch-specific build if newest apk has -x86 or -arm.
    const archSpecific = isPathArchSpecific(files[0]);

    // And show only arch-specific ones (or non-arch-specific)
    files = files.filter(p => isPathArchSpecific(p) === archSpecific);

    if (archSpecific && files.length > 1 && arch) {
        files = files.filter(p => path.basename(p).includes('-' + arch));
    }

    return files.sort(outputFileComparator);
}

class ProjectBuilder {
    constructor (rootDirectory) {
        this.root = rootDirectory || path.resolve(__dirname, '../../..');
        this.apkDir = path.join(this.root, 'app', 'build', 'outputs', 'apk');
        this.aabDir = path.join(this.root, 'app', 'build', 'outputs', 'bundle');
    }

    getArgs (cmd, opts) {
        let args;
        let buildCmd = cmd;
        if (opts.packageType === PackageType.BUNDLE) {
            if (cmd === 'release') {
                buildCmd = ':app:bundleRelease';
            } else if (cmd === 'debug') {
                buildCmd = ':app:bundleDebug';
            }

            args = [buildCmd, '-b', path.join(this.root, 'build.gradle')];
        } else {
            if (cmd === 'release') {
                buildCmd = 'cdvBuildRelease';
            } else if (cmd === 'debug') {
                buildCmd = 'cdvBuildDebug';
            }

            args = [buildCmd, '-b', path.join(this.root, 'build.gradle')];

            if (opts.arch) {
                args.push('-PcdvBuildArch=' + opts.arch);
            }
        }

        args.push.apply(args, opts.extraArgs);

        return args;
    }

    /*
    * This returns a promise
    */
    runGradleWrapper (gradle_cmd) {
        var gradlePath = path.join(this.root, 'gradlew');
        var wrapperGradle = path.join(this.root, 'wrapper.gradle');
        if (fs.existsSync(gradlePath)) {
            // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
        } else {
            return execa(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], { stdio: 'inherit' });
        }
    }

    readProjectProperties () {
        function findAllUniq (data, r) {
            var s = {};
            var m;
            while ((m = r.exec(data))) {
                s[m[1]] = 1;
            }
            return Object.keys(s);
        }

        var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
        return {
            libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
            gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
            systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
        };
    }

    extractRealProjectNameFromManifest () {
        var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml');
        var manifestData = fs.readFileSync(manifestPath, 'utf8');
        var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
        if (!m) {
            throw new CordovaError('Could not find package name in ' + manifestPath);
        }

        var packageName = m[1];
        var lastDotIndex = packageName.lastIndexOf('.');
        return packageName.substring(lastDotIndex + 1);
    }

    // Makes the project buildable, minus the gradle wrapper.
    prepBuildFiles () {
        // Update the version of build.gradle in each dependent library.
        var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
        var propertiesObj = this.readProjectProperties();
        var subProjects = propertiesObj.libs;

        // Check and copy the gradle file into the subproject
        // Called by the loop before this function def

        var checkAndCopy = function (subProject, root) {
            var subProjectGradle = path.join(root, subProject, 'build.gradle');
            // This is the future-proof way of checking if a file exists
            // This must be synchronous to satisfy a Travis test
            try {
                fs.accessSync(subProjectGradle, fs.F_OK);
            } catch (e) {
                fs.copySync(pluginBuildGradle, subProjectGradle);
            }
        };

        for (var i = 0; i < subProjects.length; ++i) {
            if (subProjects[i] !== 'CordovaLib') {
                checkAndCopy(subProjects[i], this.root);
            }
        }
        var name = this.extractRealProjectNameFromManifest();
        // Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
        var settingsGradlePaths = subProjects.map(function (p) {
            var realDir = p.replace(/[/\\]/g, ':');
            var libName = realDir.replace(name + '-', '');
            var str = 'include ":' + libName + '"\n';
            if (realDir.indexOf(name + '-') !== -1) {
                str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n';
            }
            return str;
        });

        fs.writeFileSync(path.join(this.root, 'settings.gradle'),
            '// GENERATED FILE - DO NOT EDIT\n' +
            'include ":"\n' + settingsGradlePaths.join(''));

        // Update dependencies within build.gradle.
        var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8');
        var depsList = '';
        var root = this.root;
        var insertExclude = function (p) {
            var gradlePath = path.join(root, p, 'build.gradle');
            var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
            if (projectGradleFile.indexOf('CordovaLib') !== -1) {
                depsList += '{\n        exclude module:("CordovaLib")\n    }\n';
            } else {
                depsList += '\n';
            }
        };
        subProjects.forEach(function (p) {
            events.emit('log', 'Subproject Path: ' + p);
            var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
            if (libName !== 'app') {
                depsList += '    implementation(project(path: ":' + libName + '"))';
                insertExclude(p);
            }
        });
        // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
        var SYSTEM_LIBRARY_MAPPINGS = [
            [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
            [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
        ];

        propertiesObj.systemLibs.forEach(function (p) {
            var mavenRef;
            // It's already in gradle form if it has two ':'s
            if (/:.*:/.exec(p)) {
                mavenRef = p;
            } else {
                for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
                    var pair = SYSTEM_LIBRARY_MAPPINGS[i];
                    if (pair[0].exec(p)) {
                        mavenRef = p.replace(pair[0], pair[1]);
                        break;
                    }
                }
                if (!mavenRef) {
                    throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
                }
            }
            depsList += '    implementation "' + mavenRef + '"\n';
        });

        buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + '    $2');
        var includeList = '';

        propertiesObj.gradleIncludes.forEach(function (includePath) {
            includeList += 'apply from: "../' + includePath + '"\n';
        });
        buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
        // This needs to be stored in the app gradle, not the root grade
        fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle);
    }

    prepEnv (opts) {
        var self = this;
        return check_reqs.check_gradle()
            .then(function (gradlePath) {
                return self.runGradleWrapper(gradlePath);
            }).then(function () {
                return self.prepBuildFiles();
            }).then(() => {
                // update/set the distributionUrl in the gradle-wrapper.properties
                const gradleWrapperPropertiesPath = path.join(self.root, 'gradle/wrapper/gradle-wrapper.properties');
                const gradleWrapperProperties = createEditor(gradleWrapperPropertiesPath);
                const distributionUrl = process.env.CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL || 'https://services.gradle.org/distributions/gradle-6.6.1-all.zip';
                gradleWrapperProperties.set('distributionUrl', distributionUrl);
                gradleWrapperProperties.save();

                events.emit('verbose', `Gradle Distribution URL: ${distributionUrl}`);
            })
            .then(() => {
                const signingPropertiesPath = path.join(self.root, `${opts.buildType}${SIGNING_PROPERTIES}`);

                if (fs.existsSync(signingPropertiesPath)) fs.removeSync(signingPropertiesPath);
                if (opts.packageInfo) {
                    fs.ensureFileSync(signingPropertiesPath);
                    const signingProperties = createEditor(signingPropertiesPath);
                    signingProperties.addHeadComment(TEMPLATE);
                    opts.packageInfo.appendToProperties(signingProperties);
                }
            });
    }

    /*
    * Builds the project with gradle.
    * Returns a promise.
    */
    build (opts) {
        var wrapper = path.join(this.root, 'gradlew');
        var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);

        return execa(wrapper, args, { stdio: 'inherit', cwd: path.resolve(this.root) })
            .catch(function (error) {
                if (error.toString().indexOf('failed to find target with hash string') >= 0) {
                    return check_reqs.check_android_target(error).then(function () {
                        // If due to some odd reason - check_android_target succeeds
                        // we should still fail here.
                        throw error;
                    });
                }
                throw error;
            });
    }

    clean (opts) {
        const wrapper = path.join(this.root, 'gradlew');
        const args = this.getArgs('clean', opts);
        return execa(wrapper, args, { stdio: 'inherit', cwd: path.resolve(this.root) })
            .then(() => {
                fs.removeSync(path.join(this.root, 'out'));

                ['debug', 'release'].map(config => path.join(this.root, `${config}${SIGNING_PROPERTIES}`))
                    .forEach(file => {
                        const hasFile = fs.existsSync(file);
                        const hasMarker = hasFile && fs.readFileSync(file, 'utf8')
                            .includes(MARKER);

                        if (hasFile && hasMarker) fs.removeSync(file);
                    });
            });
    }

    findOutputApks (build_type, arch) {
        return findOutputFiles.call(this, 'apk', build_type, { arch });
    }

    findOutputBundles (build_type) {
        return findOutputFiles.call(this, 'aab', build_type);
    }

    fetchBuildResults (build_type, arch) {
        return {
            apkPaths: this.findOutputApks(build_type, arch),
            buildType: build_type
        };
    }
}

module.exports = ProjectBuilder;
<commit_msg>fix: optional arch parameter (#1153)<commit_after>/*
       Licensed to the Apache Software Foundation (ASF) under one
       or more contributor license agreements.  See the NOTICE file
       distributed with this work for additional information
       regarding copyright ownership.  The ASF licenses this file
       to you 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.
*/

var fs = require('fs-extra');
var path = require('path');
const execa = require('execa');
const glob = require('fast-glob');
var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
var PackageType = require('../PackageType');
const { compareByAll } = require('../utils');
const { createEditor } = require('properties-parser');

const MARKER = 'YOUR CHANGES WILL BE ERASED!';
const SIGNING_PROPERTIES = '-signing.properties';
const TEMPLATE =
    '# This file is automatically generated.\n' +
    '# Do not modify this file -- ' + MARKER + '\n';

const isPathArchSpecific = p => /-x86|-arm/.test(path.basename(p));

const outputFileComparator = compareByAll([
    // Sort arch specific builds after generic ones
    isPathArchSpecific,

    // Sort unsigned builds after signed ones
    filePath => /-unsigned/.test(path.basename(filePath)),

    // Sort by file modification time, latest first
    filePath => -fs.statSync(filePath).mtime.getTime(),

    // Sort by file name length, ascending
    filePath => filePath.length
]);

/**
 * @param {'apk' | 'aab'} bundleType
 * @param {'debug' | 'release'} buildType
 * @param {{arch?: string}} options
 */
function findOutputFiles (bundleType, buildType, { arch } = {}) {
    let files = glob.sync(`**/*.${bundleType}`, {
        absolute: true,
        cwd: path.resolve(this[`${bundleType}Dir`], buildType)
    }).map(path.normalize);

    if (files.length === 0) return files;

    // Assume arch-specific build if newest apk has -x86 or -arm.
    const archSpecific = isPathArchSpecific(files[0]);

    // And show only arch-specific ones (or non-arch-specific)
    files = files.filter(p => isPathArchSpecific(p) === archSpecific);

    if (archSpecific && files.length > 1 && arch) {
        files = files.filter(p => path.basename(p).includes('-' + arch));
    }

    return files.sort(outputFileComparator);
}

class ProjectBuilder {
    constructor (rootDirectory) {
        this.root = rootDirectory || path.resolve(__dirname, '../../..');
        this.apkDir = path.join(this.root, 'app', 'build', 'outputs', 'apk');
        this.aabDir = path.join(this.root, 'app', 'build', 'outputs', 'bundle');
    }

    getArgs (cmd, opts) {
        let args;
        let buildCmd = cmd;
        if (opts.packageType === PackageType.BUNDLE) {
            if (cmd === 'release') {
                buildCmd = ':app:bundleRelease';
            } else if (cmd === 'debug') {
                buildCmd = ':app:bundleDebug';
            }

            args = [buildCmd, '-b', path.join(this.root, 'build.gradle')];
        } else {
            if (cmd === 'release') {
                buildCmd = 'cdvBuildRelease';
            } else if (cmd === 'debug') {
                buildCmd = 'cdvBuildDebug';
            }

            args = [buildCmd, '-b', path.join(this.root, 'build.gradle')];

            if (opts.arch) {
                args.push('-PcdvBuildArch=' + opts.arch);
            }
        }

        args.push.apply(args, opts.extraArgs);

        return args;
    }

    /*
    * This returns a promise
    */
    runGradleWrapper (gradle_cmd) {
        var gradlePath = path.join(this.root, 'gradlew');
        var wrapperGradle = path.join(this.root, 'wrapper.gradle');
        if (fs.existsSync(gradlePath)) {
            // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
        } else {
            return execa(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], { stdio: 'inherit' });
        }
    }

    readProjectProperties () {
        function findAllUniq (data, r) {
            var s = {};
            var m;
            while ((m = r.exec(data))) {
                s[m[1]] = 1;
            }
            return Object.keys(s);
        }

        var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
        return {
            libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
            gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
            systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
        };
    }

    extractRealProjectNameFromManifest () {
        var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml');
        var manifestData = fs.readFileSync(manifestPath, 'utf8');
        var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
        if (!m) {
            throw new CordovaError('Could not find package name in ' + manifestPath);
        }

        var packageName = m[1];
        var lastDotIndex = packageName.lastIndexOf('.');
        return packageName.substring(lastDotIndex + 1);
    }

    // Makes the project buildable, minus the gradle wrapper.
    prepBuildFiles () {
        // Update the version of build.gradle in each dependent library.
        var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
        var propertiesObj = this.readProjectProperties();
        var subProjects = propertiesObj.libs;

        // Check and copy the gradle file into the subproject
        // Called by the loop before this function def

        var checkAndCopy = function (subProject, root) {
            var subProjectGradle = path.join(root, subProject, 'build.gradle');
            // This is the future-proof way of checking if a file exists
            // This must be synchronous to satisfy a Travis test
            try {
                fs.accessSync(subProjectGradle, fs.F_OK);
            } catch (e) {
                fs.copySync(pluginBuildGradle, subProjectGradle);
            }
        };

        for (var i = 0; i < subProjects.length; ++i) {
            if (subProjects[i] !== 'CordovaLib') {
                checkAndCopy(subProjects[i], this.root);
            }
        }
        var name = this.extractRealProjectNameFromManifest();
        // Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
        var settingsGradlePaths = subProjects.map(function (p) {
            var realDir = p.replace(/[/\\]/g, ':');
            var libName = realDir.replace(name + '-', '');
            var str = 'include ":' + libName + '"\n';
            if (realDir.indexOf(name + '-') !== -1) {
                str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n';
            }
            return str;
        });

        fs.writeFileSync(path.join(this.root, 'settings.gradle'),
            '// GENERATED FILE - DO NOT EDIT\n' +
            'include ":"\n' + settingsGradlePaths.join(''));

        // Update dependencies within build.gradle.
        var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8');
        var depsList = '';
        var root = this.root;
        var insertExclude = function (p) {
            var gradlePath = path.join(root, p, 'build.gradle');
            var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
            if (projectGradleFile.indexOf('CordovaLib') !== -1) {
                depsList += '{\n        exclude module:("CordovaLib")\n    }\n';
            } else {
                depsList += '\n';
            }
        };
        subProjects.forEach(function (p) {
            events.emit('log', 'Subproject Path: ' + p);
            var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
            if (libName !== 'app') {
                depsList += '    implementation(project(path: ":' + libName + '"))';
                insertExclude(p);
            }
        });
        // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
        var SYSTEM_LIBRARY_MAPPINGS = [
            [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
            [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
        ];

        propertiesObj.systemLibs.forEach(function (p) {
            var mavenRef;
            // It's already in gradle form if it has two ':'s
            if (/:.*:/.exec(p)) {
                mavenRef = p;
            } else {
                for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
                    var pair = SYSTEM_LIBRARY_MAPPINGS[i];
                    if (pair[0].exec(p)) {
                        mavenRef = p.replace(pair[0], pair[1]);
                        break;
                    }
                }
                if (!mavenRef) {
                    throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
                }
            }
            depsList += '    implementation "' + mavenRef + '"\n';
        });

        buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + '    $2');
        var includeList = '';

        propertiesObj.gradleIncludes.forEach(function (includePath) {
            includeList += 'apply from: "../' + includePath + '"\n';
        });
        buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
        // This needs to be stored in the app gradle, not the root grade
        fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle);
    }

    prepEnv (opts) {
        var self = this;
        return check_reqs.check_gradle()
            .then(function (gradlePath) {
                return self.runGradleWrapper(gradlePath);
            }).then(function () {
                return self.prepBuildFiles();
            }).then(() => {
                // update/set the distributionUrl in the gradle-wrapper.properties
                const gradleWrapperPropertiesPath = path.join(self.root, 'gradle/wrapper/gradle-wrapper.properties');
                const gradleWrapperProperties = createEditor(gradleWrapperPropertiesPath);
                const distributionUrl = process.env.CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL || 'https://services.gradle.org/distributions/gradle-6.6.1-all.zip';
                gradleWrapperProperties.set('distributionUrl', distributionUrl);
                gradleWrapperProperties.save();

                events.emit('verbose', `Gradle Distribution URL: ${distributionUrl}`);
            })
            .then(() => {
                const signingPropertiesPath = path.join(self.root, `${opts.buildType}${SIGNING_PROPERTIES}`);

                if (fs.existsSync(signingPropertiesPath)) fs.removeSync(signingPropertiesPath);
                if (opts.packageInfo) {
                    fs.ensureFileSync(signingPropertiesPath);
                    const signingProperties = createEditor(signingPropertiesPath);
                    signingProperties.addHeadComment(TEMPLATE);
                    opts.packageInfo.appendToProperties(signingProperties);
                }
            });
    }

    /*
    * Builds the project with gradle.
    * Returns a promise.
    */
    build (opts) {
        var wrapper = path.join(this.root, 'gradlew');
        var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);

        return execa(wrapper, args, { stdio: 'inherit', cwd: path.resolve(this.root) })
            .catch(function (error) {
                if (error.toString().indexOf('failed to find target with hash string') >= 0) {
                    return check_reqs.check_android_target(error).then(function () {
                        // If due to some odd reason - check_android_target succeeds
                        // we should still fail here.
                        throw error;
                    });
                }
                throw error;
            });
    }

    clean (opts) {
        const wrapper = path.join(this.root, 'gradlew');
        const args = this.getArgs('clean', opts);
        return execa(wrapper, args, { stdio: 'inherit', cwd: path.resolve(this.root) })
            .then(() => {
                fs.removeSync(path.join(this.root, 'out'));

                ['debug', 'release'].map(config => path.join(this.root, `${config}${SIGNING_PROPERTIES}`))
                    .forEach(file => {
                        const hasFile = fs.existsSync(file);
                        const hasMarker = hasFile && fs.readFileSync(file, 'utf8')
                            .includes(MARKER);

                        if (hasFile && hasMarker) fs.removeSync(file);
                    });
            });
    }

    findOutputApks (build_type, arch) {
        return findOutputFiles.call(this, 'apk', build_type, { arch });
    }

    findOutputBundles (build_type) {
        return findOutputFiles.call(this, 'aab', build_type);
    }

    fetchBuildResults (build_type, arch) {
        return {
            apkPaths: this.findOutputApks(build_type, arch),
            buildType: build_type
        };
    }
}

module.exports = ProjectBuilder;
<|endoftext|>


<commit_before>var BetterContent = {};

BetterContent.config = {
    host: location.origin.replace(/^http/, 'ws'),
    nativeAppSize : null
}
BetterContent.App = function(){};

BetterContent.App.prototype.onMessage = function(event){
    console.log("Received Message");
    console.log(event);

    var nativeContent = JSON.parse(event.data);
    BetterContent.config.nativeAppSize = {"width": 320, "height":480}
    var elementsDiv = document.querySelector('#nativeContent')
    elementsDiv.innerHTML = '';
    for (var i = 0; i < nativeContent.length; i++) {
        var componentClass = nativeContent[i].attributes.class;
        var componentHandler = BetterContent.Components[componentClass];
        if (typeof componentHandler !== "undefined"){
            componentHandler.draw(nativeContent[i], elementsDiv);
        }
    }
}

BetterContent.App.prototype.onOpen = function() {
    this.ws.send(JSON.stringify({'type': 'register', 'data': 'webClient'}));
    this.keepAlive();
}

BetterContent.App.prototype.onClose = function() {
    // kill keepAlive
    var that = this;
    setTimeout(function () {
        that.setupWebsocket();
    }, 1000);
}

BetterContent.App.prototype.keepAlive = function(){
    var that = this;
    setTimeout(function () {
        BetterContent.ws.send(JSON.stringify({'type': 'ping'}));
        that.keepAlive();
    }, 5000);
}

BetterContent.App.prototype.setupWebSocket = function(){
    var that = this;
    this.ws = new WebSocket(BetterContent.config.host);
    this.ws.onmessage = this.onMessage;
    this.ws.onopen = function(event){ that.onOpen.call(that, event) };
    this.ws.onclose = this.onClose;
    BetterContent.ws = this.ws;
}

BetterContent.Components = {}

BetterContent.Components.label = {
    draw: function(component, elementsDiv){
        var element = document.createElement('div');
        var frame = component.attributes.frame;
        var font = component.attributes.font;

        element.innerHTML = component.attributes.text;
        element.setAttribute('class', 'element');
        element.setAttribute('contenteditable', true);
        element.setAttribute("key", component.key);

        element.style.top = frame.Y + 'px';
        element.style.left = frame.X + 'px';
        element.style.width = frame.Width + 'px';
        element.style.height = frame.Height + 'px';
        element.style.fontSize = (font.pointSize * 0.85) + 'px';
        element.style.color = font.color;

        elementsDiv.appendChild(element);

        element.addEventListener("input", function (event) {
            console.log(event.srcElement);
            sendLabel(event.srcElement);
        }, false);

        var sendLabel = function (element) {
            var newLabelMap = [];
            var value = element.innerText;
            newLabelMap.push({'key': element.getAttribute('key'), 'attributes': {'text': value}});
            BetterContent.ws.send(JSON.stringify({'type': 'labelMap', 'data': newLabelMap}));
        };
    }
}

BetterContent.Components.image = {
    draw: function (component, elementsDiv) {
        if (component.attributes.hidden || component.attributes.image === ""){
            return;
        }
        var element = new Image();
        element.src = 'data:image/png;base64,' + component.attributes.image;
        var frame = component.attributes.frame;

        element.setAttribute('class', 'element image');
        element.setAttribute("key", component.key);

        element.style.top = frame.Y + 'px';
        element.style.left = frame.X + 'px';
        element.style.width = frame.Width + 'px';
        element.style.height = frame.Height + 'px';
        elementsDiv.appendChild(element);
    }
}

var app = new BetterContent.App();
app.setupWebSocket();

<commit_msg>Label - don't display if hidden<commit_after>var BetterContent = {};

BetterContent.config = {
    host: location.origin.replace(/^http/, 'ws'),
    nativeAppSize : null
}
BetterContent.App = function(){};

BetterContent.App.prototype.onMessage = function(event){
    console.log("Received Message");
    console.log(event);

    var nativeContent = JSON.parse(event.data);
    BetterContent.config.nativeAppSize = {"width": 320, "height":480}
    var elementsDiv = document.querySelector('#nativeContent')
    elementsDiv.innerHTML = '';
    for (var i = 0; i < nativeContent.length; i++) {
        var componentClass = nativeContent[i].attributes.class;
        var componentHandler = BetterContent.Components[componentClass];
        if (typeof componentHandler !== "undefined"){
            componentHandler.draw(nativeContent[i], elementsDiv);
        }
    }
}

BetterContent.App.prototype.onOpen = function() {
    this.ws.send(JSON.stringify({'type': 'register', 'data': 'webClient'}));
    this.keepAlive();
}

BetterContent.App.prototype.onClose = function() {
    // kill keepAlive
    var that = this;
    setTimeout(function () {
        that.setupWebsocket();
    }, 1000);
}

BetterContent.App.prototype.keepAlive = function(){
    var that = this;
    setTimeout(function () {
        BetterContent.ws.send(JSON.stringify({'type': 'ping'}));
        that.keepAlive();
    }, 5000);
}

BetterContent.App.prototype.setupWebSocket = function(){
    var that = this;
    this.ws = new WebSocket(BetterContent.config.host);
    this.ws.onmessage = this.onMessage;
    this.ws.onopen = function(event){ that.onOpen.call(that, event) };
    this.ws.onclose = this.onClose;
    BetterContent.ws = this.ws;
}

BetterContent.Components = {}

BetterContent.Components.label = {
    draw: function(component, elementsDiv){
        if (component.attributes.hidden){
            return;
        }
        var element = document.createElement('div');
        var frame = component.attributes.frame;
        var font = component.attributes.font;

        element.innerHTML = component.attributes.text;
        element.setAttribute('class', 'element');
        element.setAttribute('contenteditable', true);
        element.setAttribute("key", component.key);

        element.style.top = frame.Y + 'px';
        element.style.left = frame.X + 'px';
        element.style.width = frame.Width + 'px';
        element.style.height = frame.Height + 'px';
        element.style.fontSize = (font.pointSize * 0.85) + 'px';
        element.style.color = font.color;

        elementsDiv.appendChild(element);

        element.addEventListener("input", function (event) {
            console.log(event.srcElement);
            sendLabel(event.srcElement);
        }, false);

        var sendLabel = function (element) {
            var newLabelMap = [];
            var value = element.innerText;
            newLabelMap.push({'key': element.getAttribute('key'), 'attributes': {'text': value}});
            BetterContent.ws.send(JSON.stringify({'type': 'labelMap', 'data': newLabelMap}));
        };
    }
}

BetterContent.Components.image = {
    draw: function (component, elementsDiv) {
        if (component.attributes.hidden || component.attributes.image === ""){
            return;
        }
        var element = new Image();
        element.src = 'data:image/png;base64,' + component.attributes.image;
        var frame = component.attributes.frame;

        element.setAttribute('class', 'element image');
        element.setAttribute("key", component.key);

        element.style.top = frame.Y + 'px';
        element.style.left = frame.X + 'px';
        element.style.width = frame.Width + 'px';
        element.style.height = frame.Height + 'px';
        elementsDiv.appendChild(element);
    }
}

var app = new BetterContent.App();
app.setupWebSocket();

<|endoftext|>


<commit_before>this.DeviceEditor = (function(){
  'use strict';

  var DeviceEditor = function DeviceEditor() {

    this.service = (new SW.Card()).services("inventory");

    // modified from https://datatables.net/reference/option/dom
    var editorLayout =
      "<'row'<'editor-search col-sm-6'fi><'editor-actions col-sm-6'B>>" +
      "<'row'<'col-sm-12'rt>>" +
      "<'row'<'editor-paging col-sm-12'p>>" ;

    this.defaultEditorOptions = {idSrc: "id", formOptions: {main: {submit: "changed", drawType: "full-hold", title: "Edit Device(s)"}}};
    this.defaultTableOptions = {pageLength: 15, search: {caseInsensitive: true, regex: false}, searchDelay: 500, select: true, dom: editorLayout};
    this.editorOptions = undefined;
    this.tableOptions = undefined;
    this.editor = undefined;

    this.adminDefinedColumns = undefined;
    this.standardColumns = [
      {name: "name", label: "Name", type: "text", orderable: true, searchable: true},
      {name: "ip_address", label: "IP Address", type: "text", orderable: true, searchable: false},
      {name: "serial_number", label: "Serial Number", type: "text", orderable: false, searchable: false},
      {name: "mac_address", label: "MAC Address", type: "text", orderable: false, searchable: false},
      {name: "asset_tag", label: "Asset Tag", type: "text", orderable: false, searchable: false},
      {name: "device_type", label: "Device Type", type: "text", orderable: true, searchable: false},
      {name: "description", label: "Description", type: "text", orderable: false, searchable: false},
      {name: "manufacturer", label: "Manufacturer", type: "text", orderable: true, searchable: true},
      {name: "model", label: "Model", type: "text", orderable: true, searchable: true},
      {name: "location", label: "Location", type: "text", orderable: false, searchable: false},
      {name: "site", label: "Site", type: "text", orderable: false, searchable: false}, // must be translated to/from site.name
      {name: "owner", label: "Owner", type: "enum", orderable: false, searchable: false}, // must be translated to/from user objects
      {name: "purchase_date", label: "Purchase Date", type: "date", orderable: false, searchable: false},
      {name: "purchase_price", label: "Purchase Price", type: "text", orderable: false, searchable: false},
    ];

    this.users = undefined;
    this.loadAllUsers = function(prevMeta) {
      // prevMeta is undefined on the first call
      prevMeta = _.extend({current_page: 0, page_count: 1}, prevMeta);
      var page = prevMeta.current_page + 1;
      if (page > prevMeta.page_count) {
        return;
      }
      console.log("API load users page=" + page);
      var that = this;
      return (new SW.Card()).services("people")
        .request("people", {page: page, per_page: 5})
        .then(function(response){
          // create "hash" of {"First Last": id}
          var users = _.inject(response.people, function(hash, person) {
            hash[person.first_name.concat(" ", person.last_name)] = person.id;
            return hash;
          }, {});
          // merge with existing
          that.users = _.extend({}, that.users, users);
          return response.meta;
        })
        .then(this.loadAllUsers.bind(this));
    };

    this.initialResponse = undefined;
    this.loadDeviceMeta = function() {
      var that = this;
      return this.service
        .request("devices", {sort: [{name: "asc"}]})
        .then(function(response){
          that.initialResponse = response;
          that.adminDefinedColumns = response.meta.admin_defined_attrs || [];
        });
    };

    this.errorResponseToString = function errorResponseToString(error) {
      if (_.isArray(error)) {
        return _.collect(error, errorResponseToString).join(", ");
      }
      if (_.isObject(error) && error.errors) {
        return errorResponseToString(error.errors);
      }
      var result = "";
      if (error.title) {
        result = result.concat(error.title, ": ");
      }
      if (error.details) {
        result = result.concat(error.details);
      }
      else if (typeof(error) === "string") {
        result = result.concat(error);
      }
      else {
        result = result.concat(JSON.stringify(error));
      }
      return result;
    };

    this.editorAjaxAdapter = function(method, url, data, callback, xhrErrorCallback) {
      if (data.action !== "edit") {
        xhrErrorCallback(null, "error", "invalid");
        return;
      }
      var that = this;
      var requests = _.collect(data.data, function(updates, id) {
        var d = $.Deferred();
        console.log("API updates for device " + id + ": " + JSON.stringify(updates));
        that.service
          .request("device:update", parseInt(id, 10), updates)
          .then(
            function(response){
              d.resolve(response);
            },
            function(response){
              console.warn("API device " + id + " update error: ", that.errorResponseToString(response));
              d.reject(response);
            }
          );
        return d.promise();
      });
      $.when.apply($, requests).then(
        function(args) {
          var devices = _.toArray(arguments);
          callback({data: devices});
        },
        function(args) {
          var errors = _.collect(_.toArray(arguments), that.errorResponseToString).join(", ");
          callback({error: errors});
        }
      );
    };

    this.getEditorField = function(columnConfig, accessor) {
      var type;
      switch(columnConfig.type) {
        case "enum":
          type = "select";
          break;
        case "date":
          type = "date";
          break;
        default:
          type = "text";
      }
      var options = null;
      if (columnConfig.name === "owner") {
        options = this.users;
      }
      var field = _.pick(columnConfig, "name", "label");
      _.extend(field, {type: type, data: accessor, options: options});
      return field;
    };

    this.standardAttributeEditorAccessor = function(columnConfig, data, type, value) {
      if (type !== "set") {
        return this.standardAttributeTableRenderer(columnConfig, data);
      }
    };

    this.customAttributeEditorAccessor = function(columnConfig, data, type, value) {
      if (type !== "set") {
        return this.customAttributeTableRenderer(columnConfig, data);
      }
    };

    this.getEditorFields = function() {
      var that = this;
      var fields = [];
      _.each(this.standardColumns, function(columnConfig) {
        fields.push(that.getEditorField(columnConfig, that.standardAttributeEditorAccessor.bind(that, columnConfig)));
      });
      _.each(this.adminDefinedColumns, function(columnConfig) {
        fields.push(that.getEditorField(columnConfig, that.customAttributeEditorAccessor.bind(that, columnConfig)));
      });
      return fields;
    };

    this.configureEditor = function(selector, editorOptions) {
      this.editorOptions = _.extend(this.defaultEditorOptions,
        {table: selector, fields: this.getEditorFields()},
        editorOptions,
        {ajax: this.editorAjaxAdapter.bind(this)});
      return this.editorOptions;
    };

    this.createEditor = function(editorOptions) {
      this.editor = new $.fn.dataTable.Editor(editorOptions);
    };

    this.standardAttributeTableRenderer = function(columnConfig, data, requestType, row, meta) {
      var value = data[columnConfig.name] || "";
      if (columnConfig.name === "site") {
        if (data["site"] && data["site"].name) {
          value = data["site"].name;
        }
      }
      else if (columnConfig.name === "owner") {
        if (data["owner"] && data["owner"].id) {
          value = data["owner"].first_name + " " + data["owner"].last_name;
        }
        else if (data["primary_owner_name"]) {
          value = data["primary_owner_name"];
        }
      }
      return value;
    };

    this.customAttributeTableRenderer = function(columnConfig, data, requestType, row, meta) {
      return data.admin_defined_attrs[columnConfig.name] || "";
    };

    this.getTableColumn = function(columnConfig, renderer) {
      var type;
      switch(columnConfig.type) {
        case "date":
          type = "date";
          break;
        default:
          type = "string";
      }
      var column = _.pick(columnConfig, "name", "visible", "orderable", "searchable");
      _.extend(column, {title: columnConfig.label, type: type, data: null, render: renderer});
      _.defaults(column, {orderable: false, searchable: false});
      return column;
    };

    this.getTableColumns = function() {
      var that = this;
      var columns = [];
      _.each(this.standardColumns, function(columnConfig) {
        columns.push(that.getTableColumn(columnConfig, that.standardAttributeTableRenderer.bind(that, columnConfig)));
      });
      _.each(this.adminDefinedColumns, function(columnConfig) {
        columns.push(that.getTableColumn(columnConfig, that.customAttributeTableRenderer.bind(that, columnConfig)));
      });
      return columns;
    }

    this.tableAjaxAdapter = function(data, callback, settings) {
      var that = this;
      var page = 1 + data.start / this.tableOptions.pageLength;
      var requestOptions = {sort: [{name: "asc"}], page: page, per_page: data.length};
      if (data.order && data.order[0]) {
        var sortName = this.tableOptions.columns[data.order[0].column].name;
        var sortDir = data.order[0].dir;
        var sortSpec = {};
        sortSpec[sortName] = sortDir;
        requestOptions.sort[0] = sortSpec;
      }
      if (data.search && data.search.value) {
        requestOptions.search = {query: {terms: data.search.value}, fields: {names: ["name", "manufacturer", "model"]}};
      }
      console.log("API load devices:" + JSON.stringify(requestOptions));
      this.service
        .request("devices", requestOptions)
        .then(
          function(response){
            callback({draw: data.draw,
              data: response.devices,
              recordsTotal: that.initialResponse.meta.total_entries,
              recordsFiltered: response.meta.total_entries
            });
          },
          function(response){
            var error = that.errorResponseToString(response);
            console.warn("API devices fetch error: ", error);
            callback({draw: data.draw, error: error});
          }
        );
    };

    this.configureTable = function(tableOptions) {
      this.tableOptions = _.extend(this.defaultTableOptions,
        tableOptions,
        { columns: this.getTableColumns(),
          serverSide: true, ajax: this.tableAjaxAdapter.bind(this),
          data: this.initialResponse.devices,
          deferLoading: [this.initialResponse.meta.total_entries, this.initialResponse.meta.total_entries],
          buttons: [{extend: "edit", editor: this.editor}]
        }
      );
      return this.tableOptions;
    };

    this.createTable = function(selector, tableOptions) {
      $(selector).DataTable(tableOptions);
    };

    this.load = function(selector, editorOptions, tableOptions) {
      var that = this;
      return this.loadAllUsers.call(this)
        .then(this.loadDeviceMeta.bind(this))
        .then(this.configureEditor.bind(this, selector, editorOptions))
        .then(this.createEditor.bind(this))
        .then(this.configureTable.bind(this, tableOptions))
        .then(this.createTable.bind(this, selector));
    }
  };

  return DeviceEditor;

})();

<commit_msg>don't show all columns initially<commit_after>this.DeviceEditor = (function(){
  'use strict';

  var DeviceEditor = function DeviceEditor() {

    this.service = (new SW.Card()).services("inventory");

    // modified from https://datatables.net/reference/option/dom
    var editorLayout =
      "<'row'<'editor-search col-sm-6'fi><'editor-actions col-sm-6'B>>" +
      "<'row'<'col-sm-12'rt>>" +
      "<'row'<'editor-paging col-sm-12'p>>" ;

    this.defaultEditorOptions = {idSrc: "id", formOptions: {main: {submit: "changed", drawType: "full-hold", title: "Edit Device(s)"}}};
    this.defaultTableOptions = {pageLength: 15, search: {caseInsensitive: true, regex: false}, searchDelay: 500, select: true, dom: editorLayout};
    this.editorOptions = undefined;
    this.tableOptions = undefined;
    this.editor = undefined;

    this.adminDefinedColumns = undefined;
    this.standardColumns = [
      {name: "name", label: "Name", type: "text", orderable: true, searchable: true, visible: true},
      {name: "ip_address", label: "IP Address", type: "text", orderable: true, searchable: false, visible: true},
      {name: "serial_number", label: "Serial Number", type: "text", orderable: false, searchable: false, visible: false},
      {name: "mac_address", label: "MAC Address", type: "text", orderable: false, searchable: false, visible: false},
      {name: "asset_tag", label: "Asset Tag", type: "text", orderable: false, searchable: false, visible: false},
      {name: "device_type", label: "Device Type", type: "text", orderable: true, searchable: false, visible: false},
      {name: "description", label: "Description", type: "text", orderable: false, searchable: false, visible: false},
      {name: "manufacturer", label: "Manufacturer", type: "text", orderable: true, searchable: true, visible: true},
      {name: "model", label: "Model", type: "text", orderable: true, searchable: true, visible: true},
      {name: "location", label: "Location", type: "text", orderable: false, searchable: false, visible: false},
      {name: "site", label: "Site", type: "text", orderable: false, searchable: false, visible: false}, // must be translated to/from site.name
      {name: "owner", label: "Owner", type: "enum", orderable: false, searchable: false, visible: true}, // must be translated to/from user objects
      {name: "purchase_date", label: "Purchase Date", type: "date", orderable: false, searchable: false, visible: false},
      {name: "purchase_price", label: "Purchase Price", type: "text", orderable: false, searchable: false, visible: false},
    ];

    this.users = undefined;
    this.loadAllUsers = function(prevMeta) {
      // prevMeta is undefined on the first call
      prevMeta = _.extend({current_page: 0, page_count: 1}, prevMeta);
      var page = prevMeta.current_page + 1;
      if (page > prevMeta.page_count) {
        return;
      }
      console.log("API load users page=" + page);
      var that = this;
      return (new SW.Card()).services("people")
        .request("people", {page: page, per_page: 5})
        .then(function(response){
          // create "hash" of {"First Last": id}
          var users = _.inject(response.people, function(hash, person) {
            hash[person.first_name.concat(" ", person.last_name)] = person.id;
            return hash;
          }, {});
          // merge with existing
          that.users = _.extend({}, that.users, users);
          return response.meta;
        })
        .then(this.loadAllUsers.bind(this));
    };

    this.initialResponse = undefined;
    this.loadDeviceMeta = function() {
      var that = this;
      return this.service
        .request("devices", {sort: [{name: "asc"}]})
        .then(function(response){
          that.initialResponse = response;
          that.adminDefinedColumns = response.meta.admin_defined_attrs || [];
        });
    };

    this.errorResponseToString = function errorResponseToString(error) {
      if (_.isArray(error)) {
        return _.collect(error, errorResponseToString).join(", ");
      }
      if (_.isObject(error) && error.errors) {
        return errorResponseToString(error.errors);
      }
      var result = "";
      if (error.title) {
        result = result.concat(error.title, ": ");
      }
      if (error.details) {
        result = result.concat(error.details);
      }
      else if (typeof(error) === "string") {
        result = result.concat(error);
      }
      else {
        result = result.concat(JSON.stringify(error));
      }
      return result;
    };

    this.editorAjaxAdapter = function(method, url, data, callback, xhrErrorCallback) {
      if (data.action !== "edit") {
        xhrErrorCallback(null, "error", "invalid");
        return;
      }
      var that = this;
      var requests = _.collect(data.data, function(updates, id) {
        var d = $.Deferred();
        console.log("API updates for device " + id + ": " + JSON.stringify(updates));
        that.service
          .request("device:update", parseInt(id, 10), updates)
          .then(
            function(response){
              d.resolve(response);
            },
            function(response){
              console.warn("API device " + id + " update error: ", that.errorResponseToString(response));
              d.reject(response);
            }
          );
        return d.promise();
      });
      $.when.apply($, requests).then(
        function(args) {
          var devices = _.toArray(arguments);
          callback({data: devices});
        },
        function(args) {
          var errors = _.collect(_.toArray(arguments), that.errorResponseToString).join(", ");
          callback({error: errors});
        }
      );
    };

    this.getEditorField = function(columnConfig, accessor) {
      var type;
      switch(columnConfig.type) {
        case "enum":
          type = "select";
          break;
        case "date":
          type = "date";
          break;
        default:
          type = "text";
      }
      var options = null;
      if (columnConfig.name === "owner") {
        options = this.users;
      }
      var field = _.pick(columnConfig, "name", "label");
      _.extend(field, {type: type, data: accessor, options: options});
      return field;
    };

    this.standardAttributeEditorAccessor = function(columnConfig, data, type, value) {
      if (type !== "set") {
        return this.standardAttributeTableRenderer(columnConfig, data);
      }
    };

    this.customAttributeEditorAccessor = function(columnConfig, data, type, value) {
      if (type !== "set") {
        return this.customAttributeTableRenderer(columnConfig, data);
      }
    };

    this.getEditorFields = function() {
      var that = this;
      var fields = [];
      _.each(this.standardColumns, function(columnConfig) {
        fields.push(that.getEditorField(columnConfig, that.standardAttributeEditorAccessor.bind(that, columnConfig)));
      });
      _.each(this.adminDefinedColumns, function(columnConfig) {
        fields.push(that.getEditorField(columnConfig, that.customAttributeEditorAccessor.bind(that, columnConfig)));
      });
      return fields;
    };

    this.configureEditor = function(selector, editorOptions) {
      this.editorOptions = _.extend(this.defaultEditorOptions,
        {table: selector, fields: this.getEditorFields()},
        editorOptions,
        {ajax: this.editorAjaxAdapter.bind(this)});
      return this.editorOptions;
    };

    this.createEditor = function(editorOptions) {
      this.editor = new $.fn.dataTable.Editor(editorOptions);
    };

    this.standardAttributeTableRenderer = function(columnConfig, data, requestType, row, meta) {
      var value = data[columnConfig.name] || "";
      if (columnConfig.name === "site") {
        if (data["site"] && data["site"].name) {
          value = data["site"].name;
        }
      }
      else if (columnConfig.name === "owner") {
        if (data["owner"] && data["owner"].id) {
          value = data["owner"].first_name + " " + data["owner"].last_name;
        }
        else if (data["primary_owner_name"]) {
          value = data["primary_owner_name"];
        }
      }
      return value;
    };

    this.customAttributeTableRenderer = function(columnConfig, data, requestType, row, meta) {
      return data.admin_defined_attrs[columnConfig.name] || "";
    };

    this.getTableColumn = function(columnConfig, renderer) {
      var type;
      switch(columnConfig.type) {
        case "date":
          type = "date";
          break;
        default:
          type = "string";
      }
      var column = _.pick(columnConfig, "name", "visible", "orderable", "searchable");
      _.extend(column, {title: columnConfig.label, type: type, data: null, render: renderer});
      _.defaults(column, {orderable: false, searchable: false, visible: false});
      return column;
    };

    this.getTableColumns = function() {
      var that = this;
      var columns = [];
      _.each(this.standardColumns, function(columnConfig) {
        columns.push(that.getTableColumn(columnConfig, that.standardAttributeTableRenderer.bind(that, columnConfig)));
      });
      _.each(this.adminDefinedColumns, function(columnConfig) {
        columns.push(that.getTableColumn(columnConfig, that.customAttributeTableRenderer.bind(that, columnConfig)));
      });
      return columns;
    }

    this.tableAjaxAdapter = function(data, callback, settings) {
      var that = this;
      var page = 1 + data.start / this.tableOptions.pageLength;
      var requestOptions = {sort: [{name: "asc"}], page: page, per_page: data.length};
      if (data.order && data.order[0]) {
        var sortName = this.tableOptions.columns[data.order[0].column].name;
        var sortDir = data.order[0].dir;
        var sortSpec = {};
        sortSpec[sortName] = sortDir;
        requestOptions.sort[0] = sortSpec;
      }
      if (data.search && data.search.value) {
        requestOptions.search = {query: {terms: data.search.value}, fields: {names: ["name", "manufacturer", "model"]}};
      }
      console.log("API load devices:" + JSON.stringify(requestOptions));
      this.service
        .request("devices", requestOptions)
        .then(
          function(response){
            callback({draw: data.draw,
              data: response.devices,
              recordsTotal: that.initialResponse.meta.total_entries,
              recordsFiltered: response.meta.total_entries
            });
          },
          function(response){
            var error = that.errorResponseToString(response);
            console.warn("API devices fetch error: ", error);
            callback({draw: data.draw, error: error});
          }
        );
    };

    this.configureTable = function(tableOptions) {
      this.tableOptions = _.extend(this.defaultTableOptions,
        tableOptions,
        { columns: this.getTableColumns(),
          serverSide: true, ajax: this.tableAjaxAdapter.bind(this),
          data: this.initialResponse.devices,
          deferLoading: [this.initialResponse.meta.total_entries, this.initialResponse.meta.total_entries],
          buttons: [{extend: "edit", editor: this.editor}]
        }
      );
      return this.tableOptions;
    };

    this.createTable = function(selector, tableOptions) {
      $(selector).DataTable(tableOptions);
    };

    this.load = function(selector, editorOptions, tableOptions) {
      var that = this;
      return this.loadAllUsers.call(this)
        .then(this.loadDeviceMeta.bind(this))
        .then(this.configureEditor.bind(this, selector, editorOptions))
        .then(this.createEditor.bind(this))
        .then(this.configureTable.bind(this, tableOptions))
        .then(this.createTable.bind(this, selector));
    }
  };

  return DeviceEditor;

})();

<|endoftext|>


<commit_before>// @flow
import os from 'os';
import { uniq, get, includes } from 'lodash';
import { version } from '../../package.json';
import type { Environment } from '../common/types/environment.types';
import {
  DEVELOPMENT,
  OS_NAMES,
  MAINNET,
  MAINNET_FLIGHT,
  SHELLEY_TESTNET,
  SHELLEY_TESTNET_V6,
} from '../common/types/environment.types';
import {
  evaluateNetwork,
  checkIsDev,
  checkIsTest,
  checkIsProduction,
  checkIsMainnet,
  checkIsStaging,
  checkIsTestnet,
  checkIsSelfnode,
  checkIsDevelopment,
  checkIsIncentivizedTestnet,
  checkIsIncentivizedTestnetQA,
  checkIsIncentivizedTestnetNightly,
  checkIsIncentivizedTestnetSelfnode,
  checkIsMacOS,
  checkIsWindows,
  checkIsLinux,
} from '../common/utils/environmentCheckers';

/* ==================================================================
=                           Evaluations                             =
================================================================== */

// environment variables
const CURRENT_NODE_ENV = process.env.NODE_ENV || DEVELOPMENT;
let RAW_NETWORK =
  process.env.NETWORK === MAINNET_FLIGHT ? MAINNET : process.env.NETWORK || '';
if (process.env.NETWORK === SHELLEY_TESTNET_V6) {
  RAW_NETWORK = SHELLEY_TESTNET;
}
const NETWORK = evaluateNetwork(process.env.NETWORK);
const isDev = checkIsDev(CURRENT_NODE_ENV);
const isTest = checkIsTest(CURRENT_NODE_ENV);
const isProduction = checkIsProduction(CURRENT_NODE_ENV);
const isMainnet = checkIsMainnet(NETWORK);
const isStaging = checkIsStaging(NETWORK);
const isTestnet = checkIsTestnet(NETWORK);
const isSelfnode = checkIsSelfnode(NETWORK);
const isIncentivizedTestnet = checkIsIncentivizedTestnet(NETWORK);
const isIncentivizedTestnetQA = checkIsIncentivizedTestnetQA(RAW_NETWORK);
const isIncentivizedTestnetNightly = checkIsIncentivizedTestnetNightly(
  RAW_NETWORK
);
const isIncentivizedTestnetSelfnode = checkIsIncentivizedTestnetSelfnode(
  RAW_NETWORK
);
const isDevelopment = checkIsDevelopment(NETWORK);
const isWatchMode = process.env.IS_WATCH_MODE;
const API_VERSION = process.env.API_VERSION || 'dev';
const NODE_VERSION = '1.18.0'; // TODO: pick up this value from process.env
const mainProcessID = get(process, 'ppid', '-');
const rendererProcessID = process.pid;
const PLATFORM = os.platform();
const PLATFORM_VERSION = os.release();
const OS = OS_NAMES[PLATFORM] || PLATFORM;
const cpu = os.cpus();
const ram = os.totalmem();
const isBlankScreenFixActive = includes(process.argv.slice(1), '--safe-mode');
const BUILD = process.env.BUILD_NUMBER || 'dev';
const BUILD_NUMBER = uniq([API_VERSION, BUILD]).join('.');
const INSTALLER_VERSION = uniq([API_VERSION, BUILD]).join('.');
const MOBX_DEV_TOOLS = process.env.MOBX_DEV_TOOLS || false;
const isMacOS = checkIsMacOS(PLATFORM);
const isWindows = checkIsWindows(PLATFORM);
const isLinux = checkIsLinux(PLATFORM);

/* ==================================================================
=                       Compose environment                         =
================================================================== */

export const environment: Environment = Object.assign(
  {},
  {
    network: NETWORK,
    rawNetwork: RAW_NETWORK,
    apiVersion: API_VERSION,
    nodeVersion: NODE_VERSION,
    mobxDevTools: MOBX_DEV_TOOLS,
    current: CURRENT_NODE_ENV,
    isDev,
    isTest,
    isProduction,
    isMainnet,
    isStaging,
    isTestnet,
    isSelfnode,
    isIncentivizedTestnet,
    isIncentivizedTestnetQA,
    isIncentivizedTestnetNightly,
    isIncentivizedTestnetSelfnode,
    isDevelopment,
    isWatchMode,
    build: BUILD,
    buildNumber: BUILD_NUMBER,
    platform: PLATFORM,
    platformVersion: PLATFORM_VERSION,
    mainProcessID,
    rendererProcessID,
    os: OS,
    cpu,
    ram,
    installerVersion: INSTALLER_VERSION,
    version,
    isWindows,
    isMacOS,
    isLinux,
    isBlankScreenFixActive,
  },
  process.env
);
<commit_msg>update hard-coded node version<commit_after>// @flow
import os from 'os';
import { uniq, get, includes } from 'lodash';
import { version } from '../../package.json';
import type { Environment } from '../common/types/environment.types';
import {
  DEVELOPMENT,
  OS_NAMES,
  MAINNET,
  MAINNET_FLIGHT,
  SHELLEY_TESTNET,
  SHELLEY_TESTNET_V6,
} from '../common/types/environment.types';
import {
  evaluateNetwork,
  checkIsDev,
  checkIsTest,
  checkIsProduction,
  checkIsMainnet,
  checkIsStaging,
  checkIsTestnet,
  checkIsSelfnode,
  checkIsDevelopment,
  checkIsIncentivizedTestnet,
  checkIsIncentivizedTestnetQA,
  checkIsIncentivizedTestnetNightly,
  checkIsIncentivizedTestnetSelfnode,
  checkIsMacOS,
  checkIsWindows,
  checkIsLinux,
} from '../common/utils/environmentCheckers';

/* ==================================================================
=                           Evaluations                             =
================================================================== */

// environment variables
const CURRENT_NODE_ENV = process.env.NODE_ENV || DEVELOPMENT;
let RAW_NETWORK =
  process.env.NETWORK === MAINNET_FLIGHT ? MAINNET : process.env.NETWORK || '';
if (process.env.NETWORK === SHELLEY_TESTNET_V6) {
  RAW_NETWORK = SHELLEY_TESTNET;
}
const NETWORK = evaluateNetwork(process.env.NETWORK);
const isDev = checkIsDev(CURRENT_NODE_ENV);
const isTest = checkIsTest(CURRENT_NODE_ENV);
const isProduction = checkIsProduction(CURRENT_NODE_ENV);
const isMainnet = checkIsMainnet(NETWORK);
const isStaging = checkIsStaging(NETWORK);
const isTestnet = checkIsTestnet(NETWORK);
const isSelfnode = checkIsSelfnode(NETWORK);
const isIncentivizedTestnet = checkIsIncentivizedTestnet(NETWORK);
const isIncentivizedTestnetQA = checkIsIncentivizedTestnetQA(RAW_NETWORK);
const isIncentivizedTestnetNightly = checkIsIncentivizedTestnetNightly(
  RAW_NETWORK
);
const isIncentivizedTestnetSelfnode = checkIsIncentivizedTestnetSelfnode(
  RAW_NETWORK
);
const isDevelopment = checkIsDevelopment(NETWORK);
const isWatchMode = process.env.IS_WATCH_MODE;
const API_VERSION = process.env.API_VERSION || 'dev';
const NODE_VERSION = '1.19.0'; // TODO: pick up this value from process.env
const mainProcessID = get(process, 'ppid', '-');
const rendererProcessID = process.pid;
const PLATFORM = os.platform();
const PLATFORM_VERSION = os.release();
const OS = OS_NAMES[PLATFORM] || PLATFORM;
const cpu = os.cpus();
const ram = os.totalmem();
const isBlankScreenFixActive = includes(process.argv.slice(1), '--safe-mode');
const BUILD = process.env.BUILD_NUMBER || 'dev';
const BUILD_NUMBER = uniq([API_VERSION, BUILD]).join('.');
const INSTALLER_VERSION = uniq([API_VERSION, BUILD]).join('.');
const MOBX_DEV_TOOLS = process.env.MOBX_DEV_TOOLS || false;
const isMacOS = checkIsMacOS(PLATFORM);
const isWindows = checkIsWindows(PLATFORM);
const isLinux = checkIsLinux(PLATFORM);

/* ==================================================================
=                       Compose environment                         =
================================================================== */

export const environment: Environment = Object.assign(
  {},
  {
    network: NETWORK,
    rawNetwork: RAW_NETWORK,
    apiVersion: API_VERSION,
    nodeVersion: NODE_VERSION,
    mobxDevTools: MOBX_DEV_TOOLS,
    current: CURRENT_NODE_ENV,
    isDev,
    isTest,
    isProduction,
    isMainnet,
    isStaging,
    isTestnet,
    isSelfnode,
    isIncentivizedTestnet,
    isIncentivizedTestnetQA,
    isIncentivizedTestnetNightly,
    isIncentivizedTestnetSelfnode,
    isDevelopment,
    isWatchMode,
    build: BUILD,
    buildNumber: BUILD_NUMBER,
    platform: PLATFORM,
    platformVersion: PLATFORM_VERSION,
    mainProcessID,
    rendererProcessID,
    os: OS,
    cpu,
    ram,
    installerVersion: INSTALLER_VERSION,
    version,
    isWindows,
    isMacOS,
    isLinux,
    isBlankScreenFixActive,
  },
  process.env
);
<|endoftext|>


<commit_before>/*Sets the testing environnement*/
process.env.NODE_ENV = 'test'

var should = require('should');
var assert = require('assert');
var request = require('supertest');
var mongoose = require('mongoose');
var winston = require('winston');
var app = require("../app");
var config = require('../config');

describe('Routing', function() {

	/*Url of the server*/
  	var url = 'http://localhost:8101';

  	/*Clears all the collections to have an empty DB*/
  	before(function(done) {
  		for (var i in mongoose.connection.collections) {
	    	mongoose.connection.collections[i].remove(function() {});
	   	}
  		done();
 	});

  	//Tests ingredients
  	require('./API/tests-ingredient');

	/*Disconnects mongoose from the DB*/
	after(function(done) {
		mongoose.disconnect();
		done();
	})

});
<commit_msg>changed describe to API<commit_after>/*Sets the testing environnement*/
process.env.NODE_ENV = 'test'

var should = require('should');
var assert = require('assert');
var request = require('supertest');
var mongoose = require('mongoose');
var winston = require('winston');
var app = require("../app");
var config = require('../config');

describe('API', function() {

	/*Url of the server*/
  	var url = 'http://localhost:8101';

  	/*Clears all the collections to have an empty DB*/
  	before(function(done) {
  		for (var i in mongoose.connection.collections) {
	    	mongoose.connection.collections[i].remove(function() {});
	   	}
  		done();
 	});

  	//Tests ingredients
  	require('./API/tests-ingredient');

	/*Disconnects mongoose from the DB*/
	after(function(done) {
		mongoose.disconnect();
		done();
	})

});
<|endoftext|>


<commit_before>exports.SystemOperatorOverRide = function () {

    var SystemOperators = ['creaturephil', 'blakjack'];

    Users.User.prototype.hasSysopAccess = function () {
        if (SystemOperators.indexOf(this.userid) > -1 && this.authenticated) {
        	return true;
        } else {
        	return false;
        }
    };

};
<commit_msg>Update system-operators.js<commit_after>exports.SystemOperatorOverRide = function () {

    var SystemOperators = ['blakjack'];

    Users.User.prototype.hasSysopAccess = function () {
        if (SystemOperators.indexOf(this.userid) > -1 && this.authenticated) {
        	return true;
        } else {
        	return false;
        }
    };

};
<|endoftext|>


<commit_before>import cx from 'classnames'
import * as React from 'react'
import * as M from '@material-ui/core'

import img2x from 'utils/img2x'
import scrollIntoView from 'utils/scrollIntoView'

import Bar from 'website/components/Bar'
import Backlight from 'website/components/Backgrounds/Backlight4'

import bgPri from './bg-primary.png'
import bgPri2x from './bg-primary@2x.png'
import bgSec from './bg-secondary.png'
import bgSec2x from './bg-secondary@2x.png'
import bgTer from './bg-tertiary.png'
import bgTer2x from './bg-tertiary@2x.png'

const PLANS = [
  {
    name: 'open.quiltdata.com',
    price: 0,
    features: ['Unlimited public packages'],
    cta: 'Explore',
    href: 'https://open.quiltdata.com',
    variant: 'tertiary',
  },
  {
    name: 'AWS Marketplace',
    price: 600,
    features: ['Unlimited data', 'Unlimited users', 'One S3 bucket'],
    cta: 'Buy Now',
    href: 'https://aws.amazon.com/marketplace/pp/B07QF1VXFQ?qid=1568410363536',
    variant: 'primary',
    featured: true,
  },
  {
    name: 'Enterprise',
    price: 999,
    features: [
      'Unlimited data',
      'Unlimited users',
      'Up to five S3 buckets',
      'Priority support',
      'Custom features',
      'Education and instruction',
    ],
    cta: 'Contact',
    href: 'mailto:sales@quiltdata.io?subject=Quilt Enterprise',
    variant: 'secondary',
  },
]

const useStyles = M.makeStyles((t) => ({
  root: {},
  plans: {
    alignItems: 'stretch',
    display: 'flex',
    justifyContent: 'center',
    marginTop: t.spacing(13),
    paddingBottom: t.spacing(10),
    position: 'relative',
    [t.breakpoints.down('sm')]: {
      alignItems: 'center',
      flexDirection: 'column',
      marginTop: t.spacing(1),
    },
  },
  plan: {
    alignItems: 'center',
    backgroundPosition: 'top center',
    backgroundSize: 'cover',
    borderRadius: 19,
    boxShadow: '0px 24px 12px 0 rgba(26, 28, 67, 0.8)',
    display: 'flex',
    flexDirection: 'column',
    maxWidth: 400,
    width: '40%',
    zIndex: 0,
    [t.breakpoints.down('sm')]: {
      marginTop: t.spacing(6),
      width: '100%',
    },
  },
  featured: {
    [t.breakpoints.up('md')]: {
      marginBottom: 52,
      marginLeft: -32,
      marginRight: -32,
      marginTop: -52,
      maxWidth: 428,
      position: 'relative',
      zIndex: 1,
    },
    [t.breakpoints.up('lg')]: {
      marginLeft: -44,
      marginRight: -44,
    },
  },
  primary: {
    backgroundImage: `url(${img2x(bgPri, bgPri2x)})`,
  },
  secondary: {
    backgroundImage: `url(${img2x(bgSec, bgSec2x)})`,
  },
  tertiary: {
    backgroundImage: `url(${img2x(bgTer, bgTer2x)})`,
  },
  name: {
    ...t.typography.h3,
    color: t.palette.text.primary,
    lineHeight: '3rem',
    marginTop: t.spacing(5),
  },
  price: {
    ...t.typography.h1,
    color: t.palette.text.primary,
    fontWeight: t.typography.fontWeightMedium,
    lineHeight: 1.5,
  },
  perMonth: {
    ...t.typography.caption,
    color: t.palette.text.secondary,
    fontStyle: 'italic',
  },
  featureBox: {
    alignItems: 'center',
    display: 'flex',
    flexDirection: 'column',
    height: 160,
    justifyContent: 'center',
    marginTop: t.spacing(10),
  },
  feature: {
    ...t.typography.caption,
    color: t.palette.text.secondary,
    fontStyle: 'italic',
    lineHeight: 2,
  },
  btn: {
    marginBottom: t.spacing(4),
    marginTop: t.spacing(2),
    width: 160,
    '$tertiary &': {
      color: t.palette.tertiary.contrastText,
      backgroundImage: [
        'linear-gradient(225deg, #bde7d6, #4088da)',
        'linear-gradient(to top, #000000, rgba(255, 255, 255, 0.7))',
      ],
    },
  },
}))

export default function Pricing() {
  const classes = useStyles()
  return (
    <M.Box position="relative">
      <Backlight top={-320} />
      <M.Container maxWidth="lg">
        <M.Box
          display="flex"
          flexDirection="column"
          alignItems="center"
          pt={10}
          position="relative"
        >
          <Bar color="secondary" />
          <M.Box mt={5}>
            <M.Typography
              variant="h1"
              color="textPrimary"
              id="pricing"
              ref={scrollIntoView()}
            >
              Pricing
            </M.Typography>
          </M.Box>
        </M.Box>

          {PLANS.map((p) => (

{p.name}

{p.price}

$ per month

                {p.features.map((f) => (

                    {f}

                ))}

              <M.Button
                variant="contained"
                className={classes.btn}
                color={p.variant !== 'tertiary' ? p.variant : undefined}
                href={p.href}
              >
                {p.cta}
              </M.Button>

          ))}

      </M.Container>
    </M.Box>
  )
}
<commit_msg>Point to docs instead of directly to Marketplace<commit_after>import cx from 'classnames'
import * as React from 'react'
import * as M from '@material-ui/core'

import img2x from 'utils/img2x'
import scrollIntoView from 'utils/scrollIntoView'

import Bar from 'website/components/Bar'
import Backlight from 'website/components/Backgrounds/Backlight4'

import bgPri from './bg-primary.png'
import bgPri2x from './bg-primary@2x.png'
import bgSec from './bg-secondary.png'
import bgSec2x from './bg-secondary@2x.png'
import bgTer from './bg-tertiary.png'
import bgTer2x from './bg-tertiary@2x.png'

const PLANS = [
  {
    name: 'open.quiltdata.com',
    price: 0,
    features: ['Unlimited public packages'],
    cta: 'Explore',
    href: 'https://open.quiltdata.com',
    variant: 'tertiary',
  },
  {
    name: 'AWS Marketplace',
    price: 600,
    features: ['Unlimited data', 'Unlimited users', 'One S3 bucket'],
    cta: 'Try Now',
    href:
      'https://docs.quiltdata.com/references/technical-reference#installation-instructions',
    variant: 'primary',
    featured: true,
  },
  {
    name: 'Enterprise',
    price: 999,
    features: [
      'Unlimited data',
      'Unlimited users',
      'Up to five S3 buckets',
      'Priority support',
      'Custom features',
      'Education and instruction',
    ],
    cta: 'Contact',
    href: 'mailto:sales@quiltdata.io?subject=Quilt Enterprise',
    variant: 'secondary',
  },
]

const useStyles = M.makeStyles((t) => ({
  root: {},
  plans: {
    alignItems: 'stretch',
    display: 'flex',
    justifyContent: 'center',
    marginTop: t.spacing(13),
    paddingBottom: t.spacing(10),
    position: 'relative',
    [t.breakpoints.down('sm')]: {
      alignItems: 'center',
      flexDirection: 'column',
      marginTop: t.spacing(1),
    },
  },
  plan: {
    alignItems: 'center',
    backgroundPosition: 'top center',
    backgroundSize: 'cover',
    borderRadius: 19,
    boxShadow: '0px 24px 12px 0 rgba(26, 28, 67, 0.8)',
    display: 'flex',
    flexDirection: 'column',
    maxWidth: 400,
    width: '40%',
    zIndex: 0,
    [t.breakpoints.down('sm')]: {
      marginTop: t.spacing(6),
      width: '100%',
    },
  },
  featured: {
    [t.breakpoints.up('md')]: {
      marginBottom: 52,
      marginLeft: -32,
      marginRight: -32,
      marginTop: -52,
      maxWidth: 428,
      position: 'relative',
      zIndex: 1,
    },
    [t.breakpoints.up('lg')]: {
      marginLeft: -44,
      marginRight: -44,
    },
  },
  primary: {
    backgroundImage: `url(${img2x(bgPri, bgPri2x)})`,
  },
  secondary: {
    backgroundImage: `url(${img2x(bgSec, bgSec2x)})`,
  },
  tertiary: {
    backgroundImage: `url(${img2x(bgTer, bgTer2x)})`,
  },
  name: {
    ...t.typography.h3,
    color: t.palette.text.primary,
    lineHeight: '3rem',
    marginTop: t.spacing(5),
  },
  price: {
    ...t.typography.h1,
    color: t.palette.text.primary,
    fontWeight: t.typography.fontWeightMedium,
    lineHeight: 1.5,
  },
  perMonth: {
    ...t.typography.caption,
    color: t.palette.text.secondary,
    fontStyle: 'italic',
  },
  featureBox: {
    alignItems: 'center',
    display: 'flex',
    flexDirection: 'column',
    height: 160,
    justifyContent: 'center',
    marginTop: t.spacing(10),
  },
  feature: {
    ...t.typography.caption,
    color: t.palette.text.secondary,
    fontStyle: 'italic',
    lineHeight: 2,
  },
  btn: {
    marginBottom: t.spacing(4),
    marginTop: t.spacing(2),
    width: 160,
    '$tertiary &': {
      color: t.palette.tertiary.contrastText,
      backgroundImage: [
        'linear-gradient(225deg, #bde7d6, #4088da)',
        'linear-gradient(to top, #000000, rgba(255, 255, 255, 0.7))',
      ],
    },
  },
}))

export default function Pricing() {
  const classes = useStyles()
  return (
    <M.Box position="relative">
      <Backlight top={-320} />
      <M.Container maxWidth="lg">
        <M.Box
          display="flex"
          flexDirection="column"
          alignItems="center"
          pt={10}
          position="relative"
        >
          <Bar color="secondary" />
          <M.Box mt={5}>
            <M.Typography
              variant="h1"
              color="textPrimary"
              id="pricing"
              ref={scrollIntoView()}
            >
              Pricing
            </M.Typography>
          </M.Box>
        </M.Box>

          {PLANS.map((p) => (

{p.name}

{p.price}

$ per month

                {p.features.map((f) => (

                    {f}

                ))}

              <M.Button
                variant="contained"
                className={classes.btn}
                color={p.variant !== 'tertiary' ? p.variant : undefined}
                href={p.href}
              >
                {p.cta}
              </M.Button>

          ))}

      </M.Container>
    </M.Box>
  )
}
<|endoftext|>