<commit_before>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Iteration Tracking Board App
     * The Iteration Tracking Board can be used to visualize and manage your User Stories and Defects within an Iteration.
     */
    Ext.define('Rally.apps.iterationtrackingboard.IterationTrackingBoardApp', {
        extend: 'Rally.app.TimeboxScopedApp',
        requires: [
            'Rally.data.ModelFactory',
            'Rally.ui.gridboard.GridBoard',
            'Rally.ui.gridboard.plugin.GridBoardAddNew',
            'Rally.ui.gridboard.plugin.GridBoardOwnerFilter',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo',
            'Rally.ui.gridboard.plugin.GridBoardArtifactTypeChooser',
            'Rally.ui.cardboard.plugin.ColumnPolicy',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo'
        ],
        mixins: ['Rally.app.CardFieldSelectable'],
        componentCls: 'iterationtrackingboard',
        alias: 'widget.rallyiterationtrackingboard',

        settingsScope: 'project',
        scopeType: 'iteration',

        onScopeChange: function(scope) {
            this.remove('gridBoard');
            this._loadModels();
        },

        getSettingsFields: function () {
            var fields = this.callParent(arguments);
            this.appendCardFieldPickerSetting(fields);
            return fields;
        },

        launch: function() {
            this.showFieldPicker = this.getContext().isFeatureEnabled('SHOW_FIELD_PICKER_IN_ITERATION_BOARD_SETTINGS');
            this.callParent(arguments);
        },

        _addGridBoard: function() {
            var plugins = [
                {
                    ptype: 'rallygridboardfilterinfo',
                    isGloballyScoped: Ext.isEmpty(this.getSetting('project')) ? true : false,
                    stateId: 'iteration-tracking-owner-filter-' + this.getAppId()
                },
                'rallygridboardaddnew',
                'rallygridboardownerfilter'
            ];

            if (this.getContext().isFeatureEnabled('SHOW_ARTIFACT_CHOOSER_ON_ITERATION_BOARDS')) {
                plugins.splice(2, 0, {
                    ptype: 'rallygridboardartifacttypechooser',
                    artifactTypePreferenceKey: 'artifact-types',
                    showAgreements: true
                });
            }

            this.gridboard = this.add({
                itemId: 'gridBoard',
                xtype: 'rallygridboard',
                context: this.getContext(),
                enableToggle: this.getContext().isFeatureEnabled('ITERATION_TRACKING_BOARD_GRID_TOGGLE'),
                plugins: plugins,
                modelNames: this.modelNames,
                cardBoardConfig: {
                    columnConfig: {
                        additionalFetchFields: ['PortfolioItem'],
                        plugins: [{
                            ptype: 'rallycolumnpolicy',
                            app: this
                        }]
                    },
                    cardConfig: {
                        fields: this.getCardFieldNames(['Parent', 'Tasks', 'Defects', 'Discussion', 'PlanEstimate'])
                    },
                    listeners: {
                        filter: this._onBoardFilter,
                        filtercomplete: this._onBoardFilterComplete
                    }
                },
                listeners: {
                    load: this._onLoad,
                    toggle: this._publishContentUpdated,
                    recordupdate: this._publishContentUpdatedNoDashboardLayout,
                    recordcreate: this._publishContentUpdatedNoDashboardLayout,
                    scope: this
                }
            });
        },

        _loadModels: function() {
            Rally.data.ModelFactory.getModels({
                types: ['User Story', 'Defect', 'Defect Suite', 'Test Set'],
                context: this.getContext().getDataContext(),
                success: function(models) {
                    this.modelNames = Ext.Object.getKeys(models);
                    this._addGridBoard();
                },
                scope: this
            });
        },

        _onLoad: function() {
            this._publishContentUpdated();
            if (Rally.BrowserTest) {
                Rally.BrowserTest.publishComponentReady(this);
            }
        },

        _onBoardFilter: function() {
           this.setLoading(true);
        },

        _onBoardFilterComplete: function() {
           this.setLoading(false);
        },

        _publishContentUpdated: function() {
            this.fireEvent('contentupdated');
        },

        _publishContentUpdatedNoDashboardLayout: function() {
            this.fireEvent('contentupdated', {dashboardLayout: false});
        }
    });
})();
<commit_msg>S53269: enable new user story for EDP's from IterationTrackingBoardApp<commit_after>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Iteration Tracking Board App
     * The Iteration Tracking Board can be used to visualize and manage your User Stories and Defects within an Iteration.
     */
    Ext.define('Rally.apps.iterationtrackingboard.IterationTrackingBoardApp', {
        extend: 'Rally.app.TimeboxScopedApp',
        requires: [
            'Rally.data.ModelFactory',
            'Rally.ui.gridboard.GridBoard',
            'Rally.ui.gridboard.plugin.GridBoardAddNew',
            'Rally.ui.gridboard.plugin.GridBoardOwnerFilter',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo',
            'Rally.ui.gridboard.plugin.GridBoardArtifactTypeChooser',
            'Rally.ui.cardboard.plugin.ColumnPolicy',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo'
        ],
        mixins: ['Rally.app.CardFieldSelectable'],
        componentCls: 'iterationtrackingboard',
        alias: 'widget.rallyiterationtrackingboard',

        settingsScope: 'project',
        scopeType: 'iteration',

        onScopeChange: function(scope) {
            this.remove('gridBoard');
            this._loadModels();
        },

        getSettingsFields: function () {
            var fields = this.callParent(arguments);
            this.appendCardFieldPickerSetting(fields);
            return fields;
        },

        launch: function() {
            this.showFieldPicker = this.getContext().isFeatureEnabled('SHOW_FIELD_PICKER_IN_ITERATION_BOARD_SETTINGS');
            this.callParent(arguments);
        },

        _addGridBoard: function() {
            var plugins = [
                {
                    ptype: 'rallygridboardfilterinfo',
                    isGloballyScoped: Ext.isEmpty(this.getSetting('project')) ? true : false,
                    stateId: 'iteration-tracking-owner-filter-' + this.getAppId()
                },
                'rallygridboardaddnew',
                'rallygridboardownerfilter'
            ];

            if (this.getContext().isFeatureEnabled('SHOW_ARTIFACT_CHOOSER_ON_ITERATION_BOARDS')) {
                plugins.splice(2, 0, {
                    ptype: 'rallygridboardartifacttypechooser',
                    artifactTypePreferenceKey: 'artifact-types',
                    showAgreements: true
                });
            }

            this.gridboard = this.add({
                itemId: 'gridBoard',
                xtype: 'rallygridboard',
                context: this.getContext(),
                enableToggle: this.getContext().isFeatureEnabled('ITERATION_TRACKING_BOARD_GRID_TOGGLE'),
                plugins: plugins,
                modelNames: this.modelNames,
                cardBoardConfig: {
                    columnConfig: {
                        additionalFetchFields: ['PortfolioItem'],
                        plugins: [{
                            ptype: 'rallycolumnpolicy',
                            app: this
                        }]
                    },
                    cardConfig: {
                        fields: this.getCardFieldNames(['Parent', 'Tasks', 'Defects', 'Discussion', 'PlanEstimate'])
                    },
                    listeners: {
                        filter: this._onBoardFilter,
                        filtercomplete: this._onBoardFilterComplete
                    }
                },
                listeners: {
                    load: this._onLoad,
                    toggle: this._publishContentUpdated,
                    recordupdate: this._publishContentUpdatedNoDashboardLayout,
                    recordcreate: this._publishContentUpdatedNoDashboardLayout,
                    scope: this
                }
            });
        },

        _loadModels: function() {
            Rally.data.ModelFactory.getModels({
                types: ['User Story', 'Defect', 'Defect Suite', 'Test Set'],
                context: this.getContext().getDataContext(),
                success: function(models) {
                    this.modelNames = Ext.Object.getKeys(models);
                    this._addGridBoard();
                },
                scope: this
            });
        },

        _onLoad: function() {
            this._publishContentUpdated();
            if (Rally.BrowserTest) {
                Rally.BrowserTest.publishComponentReady(this);
            }
        },

        _onBoardFilter: function() {
           this.setLoading(true);
        },

        _onBoardFilterComplete: function() {
           this.setLoading(false);
        },

        _publishContentUpdated: function() {
            this.fireEvent('contentupdated');
        },

        _publishContentUpdatedNoDashboardLayout: function() {
            this.fireEvent('contentupdated', {dashboardLayout: false});
        },

        _getAddNewParams: function() {
            return this.gridboard.addNewPlugin._getAddNewParams();
        },

        _onAddNewBeforeCreate: function(addNew, record, params) {
            this.gridboard.addNewPlugin._onAddNewBeforeCreate(addNew, record, params);
        },

        _onAddNewBeforeEditorShow: function(addNew, params) {
            params.Iteration = this.getIterationRef() || 'u';
            params.Release = 'u';
            Ext.apply(params, this._getAddNewParams());
        },

        _onAddNewCreate: function(addNew, record) {
            this.gridboard.addNewPlugin._onAddNewBeforeCreate(addNew, record);
        }
    });
})();
<|endoftext|>


<commit_before>/**
 * Establish our gulp/node plugins for this project.
 */
var gulp			= require('gulp'),

	// Sass/Compass/related CSSy things
	sass			= require('gulp-ruby-sass'),
	autoprefixer	= require('gulp-autoprefixer'),
	minifycss		= require('gulp-minify-css'),
	sourcemaps		= require('gulp-sourcemaps'),

	// JavaScript
	jshint			= require('gulp-jshint'),
	uglify			= require('gulp-uglify'),

	// File system
	concat			= require('gulp-concat'),
	rename			= require('gulp-rename'),
	del				= require('del'),

	// Notifications and error handling
	gutil			= require('gulp-util');

/**
 * Set our source and destination variables
 */
var // Project
	project			= 'rptree',	// a short code for establishing things like
								// the resulting JavaScript file, etc.

	// Source files
	src				= __dirname + '/src',
	src_js			= src + '/js',
	src_js_vendor	= src_js + '/vendor',
	src_js_plugins	= src_js + '/plugins',
	src_sass		= src + '/sass',
	src_html		= src + '/html',

	// Destination files, WordPress
	dest			= __dirname + '/www',
	dest_js			= dest + '/js',
	dest_css		= dest + '/css';

/**
 * Now, let's do things.
 */

// Styles
gulp.task('styles', function() {
	console.log(src_sass + '/*.scss');
	return gulp.src(src_sass + '/*.scss')
		.pipe(sass({
			bundleExec: true,
			require: ['breakpoint']
		}))
		.on( 'error', gutil.log )
		.pipe(sourcemaps.init())
		.pipe(autoprefixer({
			browsers: ['last 2 versions', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4']
		}))
		.pipe(sourcemaps.write())
		.pipe(gulp.dest(dest_css))
		.pipe(rename({
			suffix: '.min'
		}))
		.pipe(minifycss())
		.pipe(gulp.dest(dest_css));
});

// Scripts task: JSHint & minify custom js
gulp.task('scripts-custom', function() {
	return gulp.src(src_js + '/*.js')
		.pipe(jshint(__dirname + '/.jshintrc'))
		.pipe(jshint.reporter('default'))
		.pipe(concat(project + '.js'))
		.pipe(rename({suffix: '.min'}))
		.pipe(uglify())
		.on('error', gutil.log)
		.pipe(gulp.dest(dest_js));
});

// Scripts task: Plugins
gulp.task('scripts-plugins', function() {
	return gulp.src(src_js_plugins + '/*.js')
		.pipe(concat(project + '-plugins.js'))
		.pipe(rename({suffix: '.min'}))
		.pipe(uglify())
		.on('error', gutil.log)
		.pipe(gulp.dest(dest_js));
});

// Scripts task: Vendor
gulp.task('scripts-vendor', function() {
	return gulp.src(src_js_vendor + '/*.js')
		.pipe(concat(project + '-vendor.js'))
		.pipe(rename({suffix: '.min'}))
		.pipe(uglify())
		.on('error', gutil.log)
		.pipe(gulp.dest(dest_js));
});

// Scripts task: run the three other scripts tasks
gulp.task('scripts', function() {
	gulp.start('scripts-custom');
	gulp.start('scripts-plugins');
	gulp.start('scripts-vendor');
});

// Clean
gulp.task('clean', function() {
	del( [dest + '/*'], function( err ) {
		console.log( 'Web directory contents deleted.' );
	});
});

// build-www: build web (html) files to the www directory
gulp.task('build-www', function() {
	var filesToMove = [
		src_html + '/**/*.*',
		src_html + '/**/.htaccess'
	];

	return gulp.src(filesToMove, { base: src_html })
		.pipe(gulp.dest(dest));
});

// build: run the build-www, CSS & JS processing tasks
gulp.task('build', ['styles', 'scripts'], function() {
	gulp.start('build-www');
});

// Dist: much like build, except clean our destination first.
gulp.task('dist', ['clean'], function() {
	gulp.start('build');
});

// Default: right now, just running build
gulp.task('default', function() {
	gulp.start('build');
});

// Watch: watch our files and do things when they change
gulp.task('watch', function() {
	gulp.start('default');

	// Watch .scss files
	gulp.watch( src_sass + '/**/*.scss', ['styles'] );

	// Watch custom JavaScript files
	gulp.watch( src_js + '/*.js', ['scripts-custom'] );

	// Watch theme template files
	gulp.watch( src_html + '/**/*.*', ['build-www'] );
});
<commit_msg>added an images task [#RPTREE-17]<commit_after>/**
 * Establish our gulp/node plugins for this project.
 */
var gulp			= require('gulp'),

	// Sass/Compass/related CSSy things
	sass			= require('gulp-ruby-sass'),
	autoprefixer	= require('gulp-autoprefixer'),
	minifycss		= require('gulp-minify-css'),
	sourcemaps		= require('gulp-sourcemaps'),

	// JavaScript
	jshint			= require('gulp-jshint'),
	uglify			= require('gulp-uglify'),

	// File system
	concat			= require('gulp-concat'),
	rename			= require('gulp-rename'),
	del				= require('del'),

	// Notifications and error handling
	gutil			= require('gulp-util');

/**
 * Set our source and destination variables
 */
var // Project
	project			= 'rptree',	// a short code for establishing things like
								// the resulting JavaScript file, etc.

	// Source files
	src				= __dirname + '/src',
	src_js			= src + '/js',
	src_js_vendor	= src_js + '/vendor',
	src_js_plugins	= src_js + '/plugins',
	src_sass		= src + '/sass',
	src_html		= src + '/html',
	src_images		= src + '/images',

	// Destination files, WordPress
	dest			= __dirname + '/www',
	dest_js			= dest + '/js',
	dest_css		= dest + '/css',
	dest_images		= dest + '/images';

/**
 * Now, let's do things.
 */

// Styles
gulp.task('styles', function() {
	console.log(src_sass + '/*.scss');
	return gulp.src(src_sass + '/*.scss')
		.pipe(sass({
			bundleExec: true,
			require: ['breakpoint']
		}))
		.on( 'error', gutil.log )
		.pipe(sourcemaps.init())
		.pipe(autoprefixer({
			browsers: ['last 2 versions', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4']
		}))
		.pipe(sourcemaps.write())
		.pipe(gulp.dest(dest_css))
		.pipe(rename({
			suffix: '.min'
		}))
		.pipe(minifycss())
		.pipe(gulp.dest(dest_css));
});

// Scripts task: JSHint & minify custom js
gulp.task('scripts-custom', function() {
	return gulp.src(src_js + '/*.js')
		.pipe(jshint(__dirname + '/.jshintrc'))
		.pipe(jshint.reporter('default'))
		.pipe(concat(project + '.js'))
		.pipe(rename({suffix: '.min'}))
		.pipe(uglify())
		.on('error', gutil.log)
		.pipe(gulp.dest(dest_js));
});

// Scripts task: Plugins
gulp.task('scripts-plugins', function() {
	return gulp.src(src_js_plugins + '/*.js')
		.pipe(concat(project + '-plugins.js'))
		.pipe(rename({suffix: '.min'}))
		.pipe(uglify())
		.on('error', gutil.log)
		.pipe(gulp.dest(dest_js));
});

// Scripts task: Vendor
gulp.task('scripts-vendor', function() {
	return gulp.src(src_js_vendor + '/*.js')
		.pipe(concat(project + '-vendor.js'))
		.pipe(rename({suffix: '.min'}))
		.pipe(uglify())
		.on('error', gutil.log)
		.pipe(gulp.dest(dest_js));
});

// Scripts task: run the three other scripts tasks
gulp.task('scripts', function() {
	gulp.start('scripts-custom');
	gulp.start('scripts-plugins');
	gulp.start('scripts-vendor');
});

// Images: for now, just move them into /www/, but we really should be imageminning them
gulp.task('images', function() {
	var filesToMove = [ src_images + '/**/*.*' ];

	return gulp.src(filesToMove)
		.pipe(gulp.dest(dest_images));
})

// Clean
gulp.task('clean', function() {
	del( [dest + '/*'], function( err ) {
		console.log( 'Web directory contents deleted.' );
	});
});

// build-www: build web (html) files to the www directory
gulp.task('build-www', function() {
	var filesToMove = [
		src_html + '/**/*.*',
		src_html + '/**/.htaccess'
	];

	return gulp.src(filesToMove, { base: src_html })
		.pipe(gulp.dest(dest));
});

// build: run the build-www, CSS & JS processing tasks
gulp.task('build', ['styles', 'scripts', 'images'], function() {
	gulp.start('build-www');
});

// Dist: much like build, except clean our destination first.
gulp.task('dist', ['clean'], function() {
	gulp.start('build');
});

// Default: right now, just running build
gulp.task('default', function() {
	gulp.start('build');
});

// Watch: watch our files and do things when they change
gulp.task('watch', function() {
	gulp.start('default');

	// Watch .scss files
	gulp.watch( src_sass + '/**/*.scss', ['styles'] );

	// Watch custom JavaScript files
	gulp.watch( src_js + '/*.js', ['scripts-custom'] );

	// Watch HTML files
	gulp.watch( src_html + '/**/*.*', ['build-www'] );

	// Watch image files
	gulp.watch( src_images + '/**/*.*', ['images'] );
});
<|endoftext|>


<commit_before>module.exports = {
    "my_variable_name": {
        "prompt": "please enter a variable for the app name",
        "defaultValue": "123"
    },
    "application_name": {
        "prompt": "what's the name of the application?"
    }
};
<commit_msg>schema changes<commit_after>module.exports = {
    "my_variable_name": {
        "description": "please enter a variable for the app name",
        "default": "123"
    },
    "application_name": {
        "description": "what's the name of the application?"
    }
};
<|endoftext|>


<commit_before>'use strict';
/*eslint no-restricted-modules: [0]*/

const fs = require('fs');
const path = require('path');
const request = require('request');

const AVATAR_PATH = path.join(__dirname, '../config/avatars/');

function download_image(image_url, name, extension) {
	request
		.get(image_url)
		.on('error', function (err) {
			console.error(err);
		})
		.on('response', function (response) {
			if (response.statusCode !== 200) return;
			const type = response.headers['content-type'].split('/');
			if (type[0] !== 'image') return;

			response.pipe(fs.createWriteStream(AVATAR_PATH + name + extension));
		});
}

function load_custom_avatars() {
	fs.readdir(AVATAR_PATH, function (err, files) {
		if (!files) files = [];
		files
			.filter(function (file) {
				return ['.jpg', '.png', '.gif'].indexOf(path.extname(file)) >= 0;
			})
			.forEach(function (file) {
				const name = path.basename(file, path.extname(file));
				Config.customavatars[name] = file;
			});
	});
}

load_custom_avatars();

exports.commands = {
	customavatar: {
		set: function (target, room, user) {
			if (!this.can('forcewin')) return false;

			const parts = target.split(',');

			if (parts.length < 2) return this.parse('/help customavatar');

			const name = toId(parts[0]);
			let image_url = parts[1];
			if (image_url.match(/^https?:\/\//i)) image_url = 'http://' + image_url;
			const ext = path.extname(image_url);

			if (!name || !image_url) return this.parse('/help customavatar');
			if (['.jpg', '.png', '.gif'].indexOf(ext) < 0) {
				return this.errorReply("Image url must have .jpg, .png, or .gif extension.");
			}

			Config.customavatars[name] = name + ext;

			download_image(image_url, name, ext);
			this.sendReply(parts[0] + "'s avatar has been set.");
		},

		delete: function (target, room, user) {
			if (!this.can('forcewin')) return false;

			const userid = toId(target);
			const image = Config.customavatars[userid];

			if (!image) {
				return this.errorReply("This user does not have a custom avatar");
			}

			delete Config.customavatars[userid];

			fs.unlink(AVATAR_PATH + image, function (err) {
				if (err && err.code === 'ENOENT') {
					this.errorReply("This user's avatar does not exist.");
				} else if (err) {
					console.error(err);
				}
				this.sendReply("This user's avatar has been successfully removed.");
			}.bind(this));
		},

		'': 'help',
		help: function (target, room, user) {
			this.parse('/help customavatar');
		},
	},
	customavatarhelp: ["Commands for /customavatar are:",
	"/customavatar set [username], [image link] - Set a user's avatar.",
	"/customavatar delete [username] - Delete a user's avatar."],
};
<commit_msg>ad refresh<commit_after>'use strict';
/*eslint no-restricted-modules: [0]*/

const fs = require('fs');
const path = require('path');
const request = require('request');

const AVATAR_PATH = path.join(__dirname, '../config/avatars/');

function download_image(image_url, name, extension) {
	request
		.get(image_url)
		.on('error', function (err) {
			console.error(err);
		})
		.on('response', function (response) {
			if (response.statusCode !== 200) return;
			const type = response.headers['content-type'].split('/');
			if (type[0] !== 'image') return;

			response.pipe(fs.createWriteStream(AVATAR_PATH + name + extension));
		});
}

function load_custom_avatars() {
	fs.readdir(AVATAR_PATH, function (err, files) {
		if (!files) files = [];
		files
			.filter(function (file) {
				return ['.jpg', '.png', '.gif'].indexOf(path.extname(file)) >= 0;
			})
			.forEach(function (file) {
				const name = path.basename(file, path.extname(file));
				Config.customavatars[name] = file;
			});
	});
}

load_custom_avatars();

exports.commands = {
	customavatar: {
		set: function (target, room, user) {
			if (!this.can('forcewin')) return false;

			const parts = target.split(',');

			if (parts.length < 2) return this.parse('/help customavatar');

			const name = toId(parts[0]);
			let image_url = parts[1];
			if (image_url.match(/^https?:\/\//i)) image_url = 'http://' + image_url;
			const ext = path.extname(image_url);

			if (!name || !image_url) return this.parse('/help customavatar');
			if (['.jpg', '.png', '.gif'].indexOf(ext) < 0) {
				return this.errorReply("Image url must have .jpg, .png, or .gif extension.");
			}

			Config.customavatars[name] = name + ext;

			download_image(image_url, name, ext);
			this.sendReply(parts[0] + "'s avatar has been set.");
			 Users.get(target.split(',').send('|refresh|')
		},

		delete: function (target, room, user) {
			if (!this.can('forcewin')) return false;

			const userid = toId(target);
			const image = Config.customavatars[userid];

			if (!image) {
				return this.errorReply("This user does not have a custom avatar");
			}

			delete Config.customavatars[userid];

			fs.unlink(AVATAR_PATH + image, function (err) {
				if (err && err.code === 'ENOENT') {
					this.errorReply("This user's avatar does not exist.");
				} else if (err) {
					console.error(err);
				}
				this.sendReply("This user's avatar has been successfully removed.");
			}.bind(this));
		},

		'': 'help',
		help: function (target, room, user) {
			this.parse('/help customavatar');
		},
	},
	customavatarhelp: ["Commands for /customavatar are:",
	"/customavatar set [username], [image link] - Set a user's avatar.",
	"/customavatar delete [username] - Delete a user's avatar."],
};
<|endoftext|>


<commit_before>/**
 * Phase
 *
 * @module      ::  Model
 * @description ::  This model represents project phases in taskboard. Note that all phases are
 *                  connected to specified project.
 */
module.exports = {
    attributes: {
        projectId: {
            type:       'integer',
            required:   true
        },
        title: {
            type:       'string',
            required:   true
        },
        description: {
            type:       'text'
        },
        order: {
            type:       'integer',
            required:   true,
            defaultsTo: 0
        },
        tasks: {
            type:       'integer',
            required:   true,
            defaultsTo: 0
        }
    }
};
<commit_msg>Added split bit to model attributes.<commit_after>/**
 * Phase
 *
 * @module      ::  Model
 * @description ::  This model represents project phases in taskboard. Note that all phases are
 *                  connected to specified project.
 */
module.exports = {
    attributes: {
        projectId: {
            type:       'integer',
            required:   true
        },
        title: {
            type:       'string',
            required:   true
        },
        description: {
            type:       'text'
        },
        order: {
            type:       'integer',
            required:   true,
            defaultsTo: 0
        },
        tasks: {
            type:       'integer',
            required:   true,
            defaultsTo: 0
        },
        split: {
            type:       'boolean',
            required:   true,
            defaultsTo: 0
        }
    }
};
<|endoftext|>


<commit_before>'use strict'
var Base = require('vigour-js/lib/base')
var Observable = require('vigour-js/lib/observable')
var Element = require('../')
var Prop = require('../../property')

function $map (map, path, nolog) {
  if (this.storedmap) {
    return this.storedmap // not allways correct but good in 99% of the cases
  }
  // this can be optmized a lot!
  var maker
  if (!map) {
    path = []
    maker = true
    map = this.storedmap = {}
    if (this.$) {
      map.$ = this.$
      if (this.$collection) {
        map.$collection = this.ChildConstructor.prototype.$map(void 0, void 0, true)
      }
    } else {
      map.$context = true
    }
  }
  function each (prop, key) {
    var isProp = prop instanceof Prop
    if (prop.$) {
      var p = path.concat([key])
      var mymap = map
      if (!isProp && mymap.$context) {
        delete mymap.$context
      }
      for (var i = 0, len = p.length; i < len; i++) {
        if (mymap[p[i]]) {
          mymap = mymap[p[i]]
          if (!isProp && mymap.$context) {
            delete mymap.$context
          }
        } else {
          mymap = mymap[p[i]] = {}
          if (isProp) {
            mymap.$context = true
          }
        }
        if (i === p.length - 1) {
          mymap.$ = prop.$
          if (prop.$collection) {
            mymap.$collection = prop.ChildConstructor.prototype.$map(void 0, void 0, true)
          }
        }
      }
    }
    prop.$map(map, path.concat([key]))
  }
  this.each(each, (p) => p instanceof Element || p instanceof Prop)
  if (maker && !nolog) {
    // console.log(JSON.stringify(map, false, 2))
  }
  return map
}

function defBind () {
  return (this._contextLevel === 1 ? this._context : this._parent).parseValue()
}

// function walkcntx (parent§) {

// }

function getit (field) {
  // save ram by storing in a map !
  return function fieldbind () {
    var self

    var parent = this._contextLevel === 1 ? this._context : this._parent
    while (parent) {
      self = parent._input
      if (self) {
        let a = self.retrieve && self.retrieve(field)
        return a ? a.parseValue() : 'smurky:' + field
      }
      parent = parent._contextLevel === 1 ? parent._context : parent._parent // context if context else stop
    }
    return ''
  }
}

Prop.prototype.set({
  properties: {
    $storedmap: true,
    $ (val) {
      this.$ = val
      if (val === true) {
        this.set(defBind)
      } else {
        this.set(getit(val))
      }
    }
  },
  define: {
    $map: $map,
    origin: {
      get () {
        // without context polution!
        var field = this.$
        var reference = this
        if (field) {
          let self
          let parent = this._contextLevel === 1 ? (this._context || this._parent) : this._parent
          while (parent) {
            self = parent._input
            if (self) {
              let a = self.retrieve && self.retrieve(field)
              if (a) {
                return a
              }
            }
            parent = parent._contextLevel === 1 ? (parent._context || parent._parent) : parent._parent
          }
        } else {
          while (reference._input instanceof Base) {
            reference = reference._input
          }
        }
        return reference
      }
    }
  }
})

exports.define = {
  $map: $map,
  $subscribeProperty (p, target, event) {
    var element = this
    if (p.$) {
      let cntxt = element._context
      let level = element._contextLevel
      let pCntxt
      let store
      if (element._context) {
        cntxt
        store = element.storeContext()
      }
      if (p._context) {
        pCntxt = true
      }

      let subscontext = cntxt ? store[store.length - 1] : element
      target.subscribe(p.$, 'data', [ function (data, event) {
        // Element
        if (cntxt) {
          element.applyContext(store)
          p._context = cntxt
          p._contextLevel = level ? level + 1 : 1
          // element._context = cntxt
          // element._contextLevel = level
        } else if (pCntxt) {
          p._context = element
          p._contextLevel = 1
        }

        let node = element.getNode()

        if (node) {
          p.render(node, event, element)
        }
      }, subscontext ], subscontext.uid + '.' + this.uid + element._path.join('.'))
    }
  },
  renderData (target, oldVal, event, old$, map) {
    console.log('wtf wtf wtf', this.path, event)
    var element = this
    if (!map) {
      map = this.$map()
    }
    walk(map, element, target, void 0, event)
    function walk (obj, element, target, rerenderinherit, event) {
      if (!target) {
        // trarget is null unsubscribe --- target is different -- unsubscribe nested
        return
      }
      if (obj.$context) {
        // if (rerenderinherit) {
        //   console.warn('CONTEXT prop have to do or something', element.path, 'X', element._context._path)
        // }
        for (let i in obj) {
          if (element[i] && element[i] instanceof Prop) {
                console.log(' 2 wtf wtf wtf', element.path, event)

            element.$subscribeProperty(element[i], target)
            if (rerenderinherit) {
              let nodex = element.getNode()
              if (nodex) {
                element[i].render(nodex, event, element)
              }
            }
          } else {
            if (element[i]) {
              walk(obj[i], element[i], target, rerenderinherit, event)
            }
          }
        }
      } else {
        if (element._context) {
          element = element.resolveContext(void 0, event, element._context) // moet nog met false
        }

        if (element.listensOnAttach && element._input !== target) {
          element.listensOnAttach.each(function (p, i) {
            // this can become 1000x faster (also dont do for nested)
            var keep
            for (var j in p.attach) {
              if (p.attach[j] && p.attach[j][1] === element) {
                // if (p.attach[j][0] === thisone) {
                //   keep = true
                // }
              }
            }
            // have to handle collection as well!
            if (!keep) {
              element.listensOnAttach[i].remove()
            }
          })
        }

        if (obj.$) {
          if (obj.$collection) {
            target.subscribe(obj.$, 'property', [
              function (data, event) {
                // xxx
                // console.error('--------', this._path, element._path, obj.$)
                var origin = this.origin
                if (origin._input === null) {
                  element.each(function (p) {
                    p instanceof Element && p.remove(event)
                  })
                } else {
                  if (element._input !== origin) {
                    element.each(function (p) {
                      p instanceof Element && p.remove(event)
                    })
                  } else if (data && data.removed) {
                    for (let n in data.removed) {
                      if (element[data.removed[n]]) {
                        element[data.removed[n]].remove(event)
                      }
                    }
                  }
                  element._input = origin
                  origin.each(function (property, key) {
                    if (!property) {
                      return
                    }
                    var elem = element[key]
                    var origin = property.origin
                    if (origin && ((!elem || elem._input !== origin) && origin._input !== null)) {
                      element.set({ [key]: origin }, event)
                      if (!element[key].$) {
                        element[key].renderData(origin, oldVal, event)
                      }
                    }
                  })
                }
              }, element
            ], element.uid, true, event)
          } else {
            // console.log('subscribe bitch')
            // first --- different
            let stamp = event.stamp
            target.subscribe(obj.$, 'data', [
              function thisone (data, event) {
                var origin = this.origin
                // console.log('yo yo yo!', origin)
                var rerender
                // this check is not enough!
                if (element._input && this.origin !== element._input || (stamp === event.stamp && oldVal)) {
                  if (element.listensOnAttach) {
                    element.listensOnAttach.each(function (p, i) {
                      // this can become 1000x faster (also dont do for nested)
                      var keep
                      for (var j in p.attach) {
                        if (p.attach[j] && p.attach[j][1] === element) {
                          if (p.attach[j][0] === thisone) {
                            keep = true
                          }
                        }
                      }
                      // have to handle collection as well!
                      if (!keep) {
                        element.listensOnAttach[i].remove()
                      }
                    })
                  }
                  // console.log('SWITCH')
                  if (origin && origin._input !== null) {
                    rerender = element.getNode()
                  }
                }
                element._input = origin //eslint-disable-line
                if (!rerenderinherit && element.getNode()) {
                  rerender = element.getNode()
                }
                for (let i in obj) {
                  if (element[i] && element[i] instanceof Prop) {
                    element.$subscribeProperty(element[i], origin)
                    if (rerender || rerenderinherit) {
                      element[i].render(rerender || element.getNode(), event, element)
                    }
                  } else if (i !== '$') {
                    // this is super annoying
                    walk(obj[i], element[i], origin, rerender || rerenderinherit, event)
                  }
                }
                if (rerender && !rerenderinherit) {
                  // this is only render props
                  // console.error('!!!rerender!!!', element) // only do for top!
                  // render(element, rerender.parentNode, Element, event, element.engine)
                }
              }, element
            ], element.uid, true, event)
          }
        } else {
          for (let i in obj) {
            if (i !== '$' && i !== '$collection') {
              if (element[i] && element[i] instanceof Prop) {
                element.$subscribeProperty(element[i], target)
                // element[i].
                if (rerenderinherit) {
                  element[i].render(element.getNode(), event, element)
                }
              } else {
                walk(obj[i], element[i], target, rerenderinherit, event)
              }
            }
          }
        }
      }
    }
    // return
  },
  handleReference (val, event, oldVal) {
    var valIsObservable = val instanceof Observable
    if (valIsObservable) {
      this._input = val
      if (this.$) {
        this.renderData(val, oldVal, event)
      }
    } else if (oldVal instanceof Observable) {
      if (this.$) {
        this.renderData(val, oldVal, event)
      }
    }
  }
}

exports.properties = {
  $storedmap: true,
  $collection (val, event) {
    this.$collection = val
    this.properties.$.call(this, val, event)
  },
  $ (val, event) {
    this.$ = val
  }
}
<commit_msg>removed logs<commit_after>'use strict'
var Base = require('vigour-js/lib/base')
var Observable = require('vigour-js/lib/observable')
var Element = require('../')
var Prop = require('../../property')

function $map (map, path, nolog) {
  if (this.storedmap) {
    return this.storedmap // not allways correct but good in 99% of the cases
  }
  // this can be optmized a lot!
  var maker
  if (!map) {
    path = []
    maker = true
    map = this.storedmap = {}
    if (this.$) {
      map.$ = this.$
      if (this.$collection) {
        map.$collection = this.ChildConstructor.prototype.$map(void 0, void 0, true)
      }
    } else {
      map.$context = true
    }
  }
  function each (prop, key) {
    var isProp = prop instanceof Prop
    if (prop.$) {
      var p = path.concat([key])
      var mymap = map
      if (!isProp && mymap.$context) {
        delete mymap.$context
      }
      for (var i = 0, len = p.length; i < len; i++) {
        if (mymap[p[i]]) {
          mymap = mymap[p[i]]
          if (!isProp && mymap.$context) {
            delete mymap.$context
          }
        } else {
          mymap = mymap[p[i]] = {}
          if (isProp) {
            mymap.$context = true
          }
        }
        if (i === p.length - 1) {
          mymap.$ = prop.$
          if (prop.$collection) {
            mymap.$collection = prop.ChildConstructor.prototype.$map(void 0, void 0, true)
          }
        }
      }
    }
    prop.$map(map, path.concat([key]))
  }
  this.each(each, (p) => p instanceof Element || p instanceof Prop)
  if (maker && !nolog) {
    // console.log(JSON.stringify(map, false, 2))
  }
  return map
}

function defBind () {
  return (this._contextLevel === 1 ? this._context : this._parent).parseValue()
}

// function walkcntx (parent§) {

// }

function getit (field) {
  // save ram by storing in a map !
  return function fieldbind () {
    var self

    var parent = this._contextLevel === 1 ? this._context : this._parent
    while (parent) {
      self = parent._input
      if (self) {
        let a = self.retrieve && self.retrieve(field)
        return a ? a.parseValue() : 'smurky:' + field
      }
      parent = parent._contextLevel === 1 ? parent._context : parent._parent // context if context else stop
    }
    return ''
  }
}

Prop.prototype.set({
  properties: {
    $storedmap: true,
    $ (val) {
      this.$ = val
      if (val === true) {
        this.set(defBind)
      } else {
        this.set(getit(val))
      }
    }
  },
  define: {
    $map: $map,
    origin: {
      get () {
        // without context polution!
        var field = this.$
        var reference = this
        if (field) {
          let self
          let parent = this._contextLevel === 1 ? (this._context || this._parent) : this._parent
          while (parent) {
            self = parent._input
            if (self) {
              let a = self.retrieve && self.retrieve(field)
              if (a) {
                return a
              }
            }
            parent = parent._contextLevel === 1 ? (parent._context || parent._parent) : parent._parent
          }
        } else {
          while (reference._input instanceof Base) {
            reference = reference._input
          }
        }
        return reference
      }
    }
  }
})

exports.define = {
  $map: $map,
  $subscribeProperty (p, target, event) {
    var element = this
    if (p.$) {
      let cntxt = element._context
      let level = element._contextLevel
      let pCntxt
      let store
      if (element._context) {
        cntxt
        store = element.storeContext()
      }
      if (p._context) {
        pCntxt = true
      }

      let subscontext = cntxt ? store[store.length - 1] : element
      target.subscribe(p.$, 'data', [ function (data, event) {
        // Element
        if (cntxt) {
          element.applyContext(store)
          p._context = cntxt
          p._contextLevel = level ? level + 1 : 1
          // element._context = cntxt
          // element._contextLevel = level
        } else if (pCntxt) {
          p._context = element
          p._contextLevel = 1
        }

        let node = element.getNode()

        if (node) {
          p.render(node, event, element)
        }
      }, subscontext ], subscontext.uid + '.' + this.uid + element._path.join('.'))
    }
  },
  renderData (target, oldVal, event, old$, map) {
    var element = this
    if (!map) {
      map = this.$map()
    }
    walk(map, element, target, void 0, event)
    function walk (obj, element, target, rerenderinherit, event) {
      if (!target) {
        // trarget is null unsubscribe --- target is different -- unsubscribe nested
        return
      }
      if (obj.$context) {
        // if (rerenderinherit) {
        //   console.warn('CONTEXT prop have to do or something', element.path, 'X', element._context._path)
        // }
        for (let i in obj) {
          if (element[i] && element[i] instanceof Prop) {

            element.$subscribeProperty(element[i], target)
            if (rerenderinherit) {
              let nodex = element.getNode()
              if (nodex) {
                element[i].render(nodex, event, element)
              }
            }
          } else {
            if (element[i]) {
              walk(obj[i], element[i], target, rerenderinherit, event)
            }
          }
        }
      } else {
        if (element._context) {
          element = element.resolveContext(void 0, event, element._context) // moet nog met false
        }

        if (element.listensOnAttach && element._input !== target) {
          element.listensOnAttach.each(function (p, i) {
            // this can become 1000x faster (also dont do for nested)
            var keep
            for (var j in p.attach) {
              if (p.attach[j] && p.attach[j][1] === element) {
                // if (p.attach[j][0] === thisone) {
                //   keep = true
                // }
              }
            }
            // have to handle collection as well!
            if (!keep) {
              element.listensOnAttach[i].remove()
            }
          })
        }

        if (obj.$) {
          if (obj.$collection) {
            target.subscribe(obj.$, 'property', [
              function (data, event) {
                // xxx
                // console.error('--------', this._path, element._path, obj.$)
                var origin = this.origin
                if (origin._input === null) {
                  element.each(function (p) {
                    p instanceof Element && p.remove(event)
                  })
                } else {
                  if (element._input !== origin) {
                    element.each(function (p) {
                      p instanceof Element && p.remove(event)
                    })
                  } else if (data && data.removed) {
                    for (let n in data.removed) {
                      if (element[data.removed[n]]) {
                        element[data.removed[n]].remove(event)
                      }
                    }
                  }
                  element._input = origin
                  origin.each(function (property, key) {
                    if (!property) {
                      return
                    }
                    var elem = element[key]
                    var origin = property.origin
                    if (origin && ((!elem || elem._input !== origin) && origin._input !== null)) {
                      element.set({ [key]: origin }, event)
                      if (!element[key].$) {
                        element[key].renderData(origin, oldVal, event)
                      }
                    }
                  })
                }
              }, element
            ], element.uid, true, event)
          } else {
            // console.log('subscribe bitch')
            // first --- different
            let stamp = event.stamp
            target.subscribe(obj.$, 'data', [
              function thisone (data, event) {
                var origin = this.origin
                // console.log('yo yo yo!', origin)
                var rerender
                // this check is not enough!
                if (element._input && this.origin !== element._input || (stamp === event.stamp && oldVal)) {
                  if (element.listensOnAttach) {
                    element.listensOnAttach.each(function (p, i) {
                      // this can become 1000x faster (also dont do for nested)
                      var keep
                      for (var j in p.attach) {
                        if (p.attach[j] && p.attach[j][1] === element) {
                          if (p.attach[j][0] === thisone) {
                            keep = true
                          }
                        }
                      }
                      // have to handle collection as well!
                      if (!keep) {
                        element.listensOnAttach[i].remove()
                      }
                    })
                  }
                  // console.log('SWITCH')
                  if (origin && origin._input !== null) {
                    rerender = element.getNode()
                  }
                }
                element._input = origin //eslint-disable-line
                if (!rerenderinherit && element.getNode()) {
                  rerender = element.getNode()
                }
                for (let i in obj) {
                  if (element[i] && element[i] instanceof Prop) {
                    element.$subscribeProperty(element[i], origin)
                    if (rerender || rerenderinherit) {
                      element[i].render(rerender || element.getNode(), event, element)
                    }
                  } else if (i !== '$') {
                    // this is super annoying
                    walk(obj[i], element[i], origin, rerender || rerenderinherit, event)
                  }
                }
                if (rerender && !rerenderinherit) {
                  // this is only render props
                  // console.error('!!!rerender!!!', element) // only do for top!
                  // render(element, rerender.parentNode, Element, event, element.engine)
                }
              }, element
            ], element.uid, true, event)
          }
        } else {
          for (let i in obj) {
            if (i !== '$' && i !== '$collection') {
              if (element[i] && element[i] instanceof Prop) {
                element.$subscribeProperty(element[i], target)
                // element[i].
                if (rerenderinherit) {
                  element[i].render(element.getNode(), event, element)
                }
              } else {
                walk(obj[i], element[i], target, rerenderinherit, event)
              }
            }
          }
        }
      }
    }
    // return
  },
  handleReference (val, event, oldVal) {
    var valIsObservable = val instanceof Observable
    if (valIsObservable) {
      this._input = val
      if (this.$) {
        this.renderData(val, oldVal, event)
      }
    } else if (oldVal instanceof Observable) {
      if (this.$) {
        this.renderData(val, oldVal, event)
      }
    }
  }
}

exports.properties = {
  $storedmap: true,
  $collection (val, event) {
    this.$collection = val
    this.properties.$.call(this, val, event)
  },
  $ (val, event) {
    this.$ = val
  }
}
<|endoftext|>


<commit_before>const webdriver = require('selenium-webdriver');
const bindAll = require('lodash.bindall');
require('chromedriver');

const headless = process.env.SMOKE_HEADLESS || false;
const remote = process.env.SMOKE_REMOTE || false;
const ci = process.env.CI || false;
const buildID = process.env.TRAVIS_BUILD_NUMBER;
const {SAUCE_USERNAME, SAUCE_ACCESS_KEY} = process.env;
const {By, Key, until} = webdriver;

const DEFAULT_TIMEOUT_MILLISECONDS = 20 * 1000;

class SeleniumHelper {
    constructor () {
        bindAll(this, [
            'buildDriver',
            'clickButton',
            'clickCss',
            'clickText',
            'clickXpath',
            'dragFromXpathToXpath',
            'findByCss',
            'findByXpath',
            'findText',
            'getKey',
            'getDriver',
            'getLogs',
            'getSauceDriver',
            'urlMatches',
            'waitUntilGone'
        ]);
    }
    buildDriver (name) {
        if (remote === 'true'){
            let nameToUse;
            if (ci === 'true'){
                nameToUse = 'travis ' + buildID + ' : ' + name;
            } else {
                nameToUse = name;
            }
            this.driver = this.getSauceDriver(SAUCE_USERNAME, SAUCE_ACCESS_KEY, nameToUse);
        } else {
            this.driver = this.getDriver();
        }
        return this.driver;
    }

    getDriver () {
        const chromeCapabilities = webdriver.Capabilities.chrome();
        let args = [];
        if (headless) {
            args.push('--headless');
            args.push('window-size=1024,1680');
            args.push('--no-sandbox');
        }
        chromeCapabilities.set('chromeOptions', {args});
        let driver = new webdriver.Builder()
            .forBrowser('chrome')
            .withCapabilities(chromeCapabilities)
            .build();
        return driver;
    }

    getSauceDriver (username, accessKey, name) {
        // Driver configs can be generated with the Sauce Platform Configurator
        // https://wiki.saucelabs.com/display/DOCS/Platform+Configurator
        let driverConfig = {
            browserName: 'chrome',
            platform: 'macOS 10.14',
            version: '76.0'
        };
        var driver = new webdriver.Builder()
            .withCapabilities({
                browserName: driverConfig.browserName,
                platform: driverConfig.platform,
                version: driverConfig.version,
                username: username,
                accessKey: accessKey,
                name: name
            })
            .usingServer(`http://${username}:${accessKey
            }@ondemand.saucelabs.com:80/wd/hub`)
            .build();
        return driver;
    }

    getKey (keyName) {
        return Key[keyName];
    }

    findByXpath (xpath, timeoutMessage = `findByXpath timed out for path: ${xpath}`) {
        return this.driver.wait(until.elementLocated(By.xpath(xpath)), DEFAULT_TIMEOUT_MILLISECONDS, timeoutMessage)
            .then(el => (
                this.driver.wait(el.isDisplayed(), DEFAULT_TIMEOUT_MILLISECONDS, `${xpath} is not visible`)
                    .then(() => el)
            ));
    }

    waitUntilGone (element) {
        return this.driver.wait(until.stalenessOf(element));
    }

    clickXpath (xpath) {
        return this.findByXpath(xpath).then(el => el.click());
    }

    clickText (text) {
        return this.clickXpath(`//*[contains(text(), '${text}')]`);
    }

    findText (text) {
        return this.driver.wait(until.elementLocated(By.xpath(`//*[contains(text(), '${text}')]`), 5 * 1000));
    }

    clickButton (text) {
        return this.clickXpath(`//button[contains(text(), '${text}')]`);
    }

    findByCss (css) {
        return this.driver.wait(until.elementLocated(By.css(css), 1000 * 5));
    }

    clickCss (css) {
        return this.findByCss(css).then(el => el.click());
    }

    dragFromXpathToXpath (startXpath, endXpath) {
        return this.findByXpath(startXpath).then(startEl => {
            return this.findByXpath(endXpath).then(endEl => {
                return this.driver.actions()
                    .dragAndDrop(startEl, endEl)
                    .perform();
            });
        });
    }

    urlMatches (regex) {
        return this.driver.wait(until.urlMatches(regex), 1000 * 5);
    }

    getLogs (whitelist) {
        return this.driver.manage()
            .logs()
            .get('browser')
            .then((entries) => {
                return entries.filter((entry) => {
                    const message = entry.message;
                    for (let i = 0; i < whitelist.length; i++) {
                        if (message.indexOf(whitelist[i]) !== -1) {
                            // eslint-disable-next-line no-console
                            // console.warn('Ignoring whitelisted error: ' + whitelist[i]);
                            return false;
                        } else if (entry.level !== 'SEVERE') {
                            // eslint-disable-next-line no-console
                            // console.warn('Ignoring non-SEVERE entry: ' + message);
                            return false;
                        }
                        return true;
                    }
                    return true;
                });
            });
    }

}

module.exports = SeleniumHelper;
<commit_msg>Update Chrome version used by sauselabs in tests<commit_after>const webdriver = require('selenium-webdriver');
const bindAll = require('lodash.bindall');
require('chromedriver');

const headless = process.env.SMOKE_HEADLESS || false;
const remote = process.env.SMOKE_REMOTE || false;
const ci = process.env.CI || false;
const buildID = process.env.TRAVIS_BUILD_NUMBER;
const {SAUCE_USERNAME, SAUCE_ACCESS_KEY} = process.env;
const {By, Key, until} = webdriver;

const DEFAULT_TIMEOUT_MILLISECONDS = 20 * 1000;

class SeleniumHelper {
    constructor () {
        bindAll(this, [
            'buildDriver',
            'clickButton',
            'clickCss',
            'clickText',
            'clickXpath',
            'dragFromXpathToXpath',
            'findByCss',
            'findByXpath',
            'findText',
            'getKey',
            'getDriver',
            'getLogs',
            'getSauceDriver',
            'urlMatches',
            'waitUntilGone'
        ]);
    }
    buildDriver (name) {
        if (remote === 'true'){
            let nameToUse;
            if (ci === 'true'){
                nameToUse = 'travis ' + buildID + ' : ' + name;
            } else {
                nameToUse = name;
            }
            this.driver = this.getSauceDriver(SAUCE_USERNAME, SAUCE_ACCESS_KEY, nameToUse);
        } else {
            this.driver = this.getDriver();
        }
        return this.driver;
    }

    getDriver () {
        const chromeCapabilities = webdriver.Capabilities.chrome();
        let args = [];
        if (headless) {
            args.push('--headless');
            args.push('window-size=1024,1680');
            args.push('--no-sandbox');
        }
        chromeCapabilities.set('chromeOptions', {args});
        let driver = new webdriver.Builder()
            .forBrowser('chrome')
            .withCapabilities(chromeCapabilities)
            .build();
        return driver;
    }

    getSauceDriver (username, accessKey, name) {
        // Driver configs can be generated with the Sauce Platform Configurator
        // https://wiki.saucelabs.com/display/DOCS/Platform+Configurator
        let driverConfig = {
            browserName: 'chrome',
            platform: 'macOS 10.14',
            version: '84.0'
        };
        var driver = new webdriver.Builder()
            .withCapabilities({
                browserName: driverConfig.browserName,
                platform: driverConfig.platform,
                version: driverConfig.version,
                username: username,
                accessKey: accessKey,
                name: name
            })
            .usingServer(`http://${username}:${accessKey
            }@ondemand.saucelabs.com:80/wd/hub`)
            .build();
        return driver;
    }

    getKey (keyName) {
        return Key[keyName];
    }

    findByXpath (xpath, timeoutMessage = `findByXpath timed out for path: ${xpath}`) {
        return this.driver.wait(until.elementLocated(By.xpath(xpath)), DEFAULT_TIMEOUT_MILLISECONDS, timeoutMessage)
            .then(el => (
                this.driver.wait(el.isDisplayed(), DEFAULT_TIMEOUT_MILLISECONDS, `${xpath} is not visible`)
                    .then(() => el)
            ));
    }

    waitUntilGone (element) {
        return this.driver.wait(until.stalenessOf(element));
    }

    clickXpath (xpath) {
        return this.findByXpath(xpath).then(el => el.click());
    }

    clickText (text) {
        return this.clickXpath(`//*[contains(text(), '${text}')]`);
    }

    findText (text) {
        return this.driver.wait(until.elementLocated(By.xpath(`//*[contains(text(), '${text}')]`), 5 * 1000));
    }

    clickButton (text) {
        return this.clickXpath(`//button[contains(text(), '${text}')]`);
    }

    findByCss (css) {
        return this.driver.wait(until.elementLocated(By.css(css), 1000 * 5));
    }

    clickCss (css) {
        return this.findByCss(css).then(el => el.click());
    }

    dragFromXpathToXpath (startXpath, endXpath) {
        return this.findByXpath(startXpath).then(startEl => {
            return this.findByXpath(endXpath).then(endEl => {
                return this.driver.actions()
                    .dragAndDrop(startEl, endEl)
                    .perform();
            });
        });
    }

    urlMatches (regex) {
        return this.driver.wait(until.urlMatches(regex), 1000 * 5);
    }

    getLogs (whitelist) {
        return this.driver.manage()
            .logs()
            .get('browser')
            .then((entries) => {
                return entries.filter((entry) => {
                    const message = entry.message;
                    for (let i = 0; i < whitelist.length; i++) {
                        if (message.indexOf(whitelist[i]) !== -1) {
                            // eslint-disable-next-line no-console
                            // console.warn('Ignoring whitelisted error: ' + whitelist[i]);
                            return false;
                        } else if (entry.level !== 'SEVERE') {
                            // eslint-disable-next-line no-console
                            // console.warn('Ignoring non-SEVERE entry: ' + message);
                            return false;
                        }
                        return true;
                    }
                    return true;
                });
            });
    }

}

module.exports = SeleniumHelper;
<|endoftext|>


<commit_before>;(function(runloop) {
	////-----------------------------------------------------------------------------------------
	// Active jobs-array
	runloop.jobs = [];
	////-----------------------------------------------------------------------------------------
	// How many miliseconds should triggering the jobs
	runloop.interval = 10;
	////-----------------------------------------------------------------------------------------
	// What tick we are currently in
	runloop.tick = 0;
	////-----------------------------------------------------------------------------------------
	// Calls runloop jobs
	// @TODO call not every controller on each tick but depending on there interval
	// @TODO remove job when not needed
	runloop.loop = function(){
		for( var i = 0; i < this.jobs.length; i++ ){
			this.jobs[ i ].callback(this.tick);
		}

		this.tick++;
		if( !this.stopped ){
			setTimeout( this.loop.bind( this ), this.interval );
		}
	};
	////-----------------------------------------------------------------------------------------
	// add a job to the list
	// @TODO validation
	runloop.addJob = function( job ){
		// @FIXME dont take just the callbacks, but the scope
		return this.jobs.push( job );
	};
	////-----------------------------------------------------------------------------------------
	// Stops the runloop
	runloop.stop = function() {
		this.stopped = true;
	};
	////-----------------------------------------------------------------------------------------
	// Starts the loop
	runloop.start = function() {
		this.stopped = false;
		this.loop();
	};
	runloop.start();
}(typeof module == 'object' ? module.exports : window.runloop = {}));
<commit_msg>[tick] fixed interval<commit_after>;(function(runloop) {
	////-----------------------------------------------------------------------------------------
	// Active jobs-array
	runloop.jobs = [];
	////-----------------------------------------------------------------------------------------
	// How many miliseconds should triggering the jobs
	runloop.interval = 100;
	////-----------------------------------------------------------------------------------------
	// What tick we are currently in
	runloop.tick = 0;
	////-----------------------------------------------------------------------------------------
	// Calls runloop jobs
	// @TODO call not every controller on each tick but depending on there interval
	// @TODO remove job when not needed
	runloop.loop = function(){
		for( var i = 0; i < this.jobs.length; i++ ){
			this.jobs[ i ].callback(this.tick);
		}

		this.tick++;
		if( !this.stopped ){
			setTimeout( this.loop.bind( this ), this.interval );
		}
	};
	////-----------------------------------------------------------------------------------------
	// add a job to the list
	// @TODO validation
	runloop.addJob = function( job ){
		// @FIXME dont take just the callbacks, but the scope
		return this.jobs.push( job );
	};
	////-----------------------------------------------------------------------------------------
	// Stops the runloop
	runloop.stop = function() {
		this.stopped = true;
	};
	////-----------------------------------------------------------------------------------------
	// Starts the loop
	runloop.start = function() {
		this.stopped = false;
		this.loop();
	};
	runloop.start();
}(typeof module == 'object' ? module.exports : window.runloop = {}));
<|endoftext|>


<commit_before>'use strict';

const https = require('https');
const {parseString} = require('xml2js');
const icecatProduct = require('./product');

/**
 *
 * @param instance
 */
const openCatalog = function (instance) {
    this.icecat = instance || {};
};

/**
 * getProduct
 * @param lang
 * @param GTIN
 * @returns {Promise}
 */
openCatalog.prototype.getProduct = function (lang, GTIN) {
    const httpRequestUrl = this._getBaseUrl(lang) + ';ean_upc=' + GTIN;

    return this._requestProduct(httpRequestUrl);
};

/**
 * getProductById
 *
 * @param {string} lang
 * @param {integer} productId
 */
openCatalog.prototype.getProductById = function (lang, productId) {
    const httpRequestUrl = this._getBaseUrl(lang) + ';product_id=' + productId;

    return this._requestProduct(httpRequestUrl);
};

/**
 * Create base url.
 *
 * @param {string} lang
 */
openCatalog.prototype._getBaseUrl = function (lang) {
    return this.icecat.scheme +
        this.icecat.httpAuth + '@' +
        this.icecat.httpUrl + '?' +
        'lang=' + lang +
        ';output=productxml';
};

/**
 * Fetch the product by the http request url.
 *
 * @param httpRequestUrl
 * @returns {Promise}
 */
openCatalog.prototype._requestProduct = function (httpRequestUrl) {
    return new Promise(
        function (resolve, reject) {
            let request = https.get(httpRequestUrl, function (response) {
                let body = '';

                response.on('data', function (chunk) {
                    body += chunk;
                });

                response.on('end', function () {
                    parseString(body, function (err, jsonData) {
                        if (err) {
                            reject(err);
                        }

                        resolve(new icecatProduct(jsonData, body, httpRequestUrl));
                    });
                });
            });

            request.on('error', function (err) {
                reject(err);
            });

        });
};

module.exports = openCatalog;<commit_msg>code review<commit_after>'use strict';

const https = require('https');
const {parseString} = require('xml2js');
const icecatProduct = require('./product');

/**
 *
 * @param instance
 */
const openCatalog = function (instance) {
    this.icecat = instance || {};
};

/**
 * getProduct
 * @param lang
 * @param GTIN
 * @returns {Promise}
 */
openCatalog.prototype.getProduct = function (lang, GTIN) {
    const httpRequestUrl = this._getBaseUrl(lang) + ';ean_upc=' + GTIN;

    return this._requestProduct(httpRequestUrl);
};

/**
 * getProductById
 *
 * @param {string} lang
 * @param {integer} productId
 */
openCatalog.prototype.getProductById = function (lang, productId) {
    const httpRequestUrl = this._getBaseUrl(lang) + ';product_id=' + productId;

    return this._requestProduct(httpRequestUrl);
};

/**
 * Create base url.
 *
 * @param {string} lang
 */
openCatalog.prototype._getBaseUrl = function (lang) {
    const {scheme, httpAuth, httpUrl} = this.icecat;
    return `${scheme}${httpAuth}@${httpUrl}?lang=${lang};output=productxml`;
};

/**
 * Fetch the product by the http request url.
 *
 * @param httpRequestUrl
 * @returns {Promise}
 */
openCatalog.prototype._requestProduct = function (httpRequestUrl) {
    return new Promise(
        function (resolve, reject) {
            let request = https.get(httpRequestUrl, function (response) {
                let body = '';

                response.on('data', function (chunk) {
                    body += chunk;
                });

                response.on('end', function () {
                    parseString(body, function (err, jsonData) {
                        if (err) {
                            reject(err);
                        }

                        resolve(new icecatProduct(jsonData, body, httpRequestUrl));
                    });
                });
            });

            request.on('error', function (err) {
                reject(err);
            });

        });
};

module.exports = openCatalog;<|endoftext|>


<commit_before>import chunk from 'lodash/fp/chunk'

import db from 'src/pouchdb'
import encodeUrl from 'src/util/encode-url-for-id'
import { pageKeyPrefix, generatePageDocId } from 'src/page-storage'
import { checkWithBlacklist } from 'src/blacklist'
import { isLoggable } from 'src/activity-logger'
import {
    IMPORT_TYPE,
    OLD_EXT_KEYS,
    DEF_ALLOW,
} from 'src/options/imports/constants'

// Binds old ext bookmark urls to a function that transforms old ext data to an import item
const transformOldExtDataToImportItem = bookmarkUrls => (data, index) => ({
    type: IMPORT_TYPE.OLD,
    url: data.url,
    timestamp: data.time,
    hasBookmark: bookmarkUrls.has(data.url),
    index,
})

// Binds an import type to a function that transforms a history/bookmark doc to an import item.
const transformBrowserItemToImportItem = type => item => ({
    browserId: item.id,
    url: item.url,
    // HistoryItems contain lastVisitTime while BookmarkTreeNodes contain dateAdded
    timestamp: item.lastVisitTime || item.dateAdded,
    type,
})

/**
 * @returns {({ url: string }) => boolean} A function affording checking of a URL against the
 *  URLs of existing page docs.
 */
async function checkWithExistingDocs() {
    const { rows: existingPageDocs } = await db.allDocs({
        startkey: pageKeyPrefix,
        endkey: `${pageKeyPrefix}\uffff`,
    })

    const existingIds = new Set(existingPageDocs.map(row => row.id))
    return item => {
        try {
            return !existingIds.has(generatePageDocId(item))
        } catch (err) {
            return false // Malformed URI
        }
    }
}

const transformToImportItemMap = items =>
    items.reduce(
        (acc, currItem) => acc.set(encodeUrl(currItem.url), currItem),
        new Map(),
    )

/**
 * Handles performing blacklist and pending import filtering logic on any type
 * of items containing a `url` field.
 *
 * @param {Array<any>} browserItems Some Iterable of items of any shape, as long as they contain `url` field.
 * @returns {Array<any>} Filtered version of the items arg.
 */
async function initFilterItemsByUrl() {
    const isNotBlacklisted = await checkWithBlacklist()
    const doesNotExist = await checkWithExistingDocs()

    const isWorthRemembering = item =>
        isLoggable(item) && isNotBlacklisted(item) && doesNotExist(item)

    return browserItems => browserItems.filter(isWorthRemembering)
}

/**
 * @param {number} [maxResults=9999999] The max amount of items to grab from browser.
 * @param {number} [startTime=0] The time to start search from for browser history.
 * @returns {Array<browser.history.HistoryItem>} All history items in browser filtered by URL.
 */
const getHistoryItems = (maxResults = 9999999, startTime = 0) =>
    browser.history.search({
        text: '',
        maxResults,
        startTime,
    })

/**
 * @param {number} [maxResults=100000] The max amount of items to grab from browser.
 * @returns {Array<browser.bookmarks.BookmarkTreeNode>} All bookmark items in browser filtered by URL.
 */
const getBookmarkItems = (maxResults = 100000) =>
    browser.bookmarks.getRecent(maxResults)

export async function getOldExtItems() {
    let bookmarkUrls = new Set()
    const {
        [OLD_EXT_KEYS.INDEX]: index,
        [OLD_EXT_KEYS.BOOKMARKS]: bookmarks,
    } = await browser.storage.local.get({
        [OLD_EXT_KEYS.INDEX]: { index: [] },
        [OLD_EXT_KEYS.BOOKMARKS]: '[]',
    })

    if (typeof bookmarks === 'string') {
        try {
            bookmarkUrls = new Set(JSON.parse(bookmarks).map(bm => bm.url))
        } catch (error) {}
    }

    const transform = transformOldExtDataToImportItem(bookmarkUrls)
    const importItems = []

    // Only attempt page data conversion if index + bookmark storage values are correct types
    if (index && index.index instanceof Array) {
        // NOTE: There is a bug with old ext index sometimes repeating the index keys
        //  (eg.I indexed 400 pages, index contained 43)
        const indexSet = new Set(index.index)

        for (const keyChunk of chunk(200)([...indexSet])) {
            const storageChunk = await browser.storage.local.get(keyChunk)

            keyChunk.forEach((key, i) => {
                if (storageChunk[key] == null) {
                    return
                }

                importItems.push(transform(storageChunk[key], i))
            })
        }
    }

    return importItems
}

export default async function createImportItems(allowTypes = DEF_ALLOW) {
    const filterItemsByUrl = await initFilterItemsByUrl()

    console.time('hist')
    const historyItems = allowTypes[IMPORT_TYPE.HISTORY]
        ? await getHistoryItems()
        : []
    console.timeEnd('hist')
    console.time('bm')
    const bookmarkItems = allowTypes[IMPORT_TYPE.BOOKMARK]
        ? await getBookmarkItems()
        : []
    console.timeEnd('bm')
    console.time('old')
    const oldExtItems = allowTypes[IMPORT_TYPE.OLD]
        ? await getOldExtItems()
        : []
    console.timeEnd('old')

    return {
        historyItemsMap: transformToImportItemMap(
            filterItemsByUrl(historyItems).map(
                transformBrowserItemToImportItem(IMPORT_TYPE.HISTORY),
            ),
        ),
        bookmarkItemsMap: transformToImportItemMap(
            filterItemsByUrl(bookmarkItems).map(
                transformBrowserItemToImportItem(IMPORT_TYPE.BOOKMARK),
            ),
        ),
        oldExtItemsMap: transformToImportItemMap(filterItemsByUrl(oldExtItems)),
    }
}
<commit_msg>Improve import item creation filtering<commit_after>import chunk from 'lodash/fp/chunk'

import db from 'src/pouchdb'
import encodeUrl from 'src/util/encode-url-for-id'
import { pageKeyPrefix } from 'src/page-storage'
import { checkWithBlacklist } from 'src/blacklist'
import { isLoggable } from 'src/activity-logger'
import {
    IMPORT_TYPE,
    OLD_EXT_KEYS,
    DEF_ALLOW,
} from 'src/options/imports/constants'

// Binds old ext bookmark urls to a function that transforms old ext data to an import item
const transformOldExtDataToImportItem = bookmarkUrls => (item, index) => ({
    type: IMPORT_TYPE.OLD,
    url: item.url,
    timestamp: item.time,
    hasBookmark: bookmarkUrls.has(item.url),
    index,
})

// Binds an import type to a function that transforms a history/bookmark doc to an import item.
const transformBrowserItemToImportItem = type => item => ({
    browserId: item.id,
    url: item.url,
    encodedUrl: item.encodedUrl,
    // HistoryItems contain lastVisitTime while BookmarkTreeNodes contain dateAdded
    timestamp: item.lastVisitTime || item.dateAdded,
    type,
})

/**
 * @returns {({ url: string }) => boolean} A function affording checking of a URL against the
 *  URLs of existing page docs.
 */
async function checkWithExistingDocs() {
    const { rows: existingPageDocs } = await db.allDocs({
        startkey: pageKeyPrefix,
        endkey: `${pageKeyPrefix}\uffff`,
    })

    const existingIds = new Set(existingPageDocs.map(row => row.id))
    return item => existingIds.has(`${pageKeyPrefix}${item.encodedUrl}`)
}

/**
 * @param {Array<any>} items Items with `encodedUrl` prop
 * @returns {Map<string, any>} Map of `encodedUrl` to the remaining import item data.
 */
const transformToImportItemMap = items =>
    items.reduce(
        (acc, { encodedUrl, ...currItem }) => acc.set(encodedUrl, currItem),
        new Map(),
    )

async function initFilterItemsByUrl() {
    const isNotBlacklisted = await checkWithBlacklist()
    const alreadyExists = await checkWithExistingDocs()

    /**
     * @param {Array<any>} items Array of items with `url` to filter on.
     * @return {Array<any>} Filtered version of `items` array, also augmented with `encodedUrl`.
     */
    return items =>
        items.reduce((accItems, currItem) => {
            if (!isLoggable(currItem) || !isNotBlacklisted(currItem)) {
                return accItems
            }

            try {
                // Augment the item with encoded URL for DB check and item map
                const encodedUrl = encodeUrl(currItem.url)
                const augItem = { ...currItem, encodedUrl }

                // Filter out items already existing in DB
                return alreadyExists(augItem)
                    ? accItems
                    : [...accItems, augItem]
            } catch (error) {
                // URI malformed; don't add to list
                return accItems
            }
        }, [])
}

/**
 * @param {number} [maxResults=9999999] The max amount of items to grab from browser.
 * @param {number} [startTime=0] The time to start search from for browser history.
 * @returns {Array<browser.history.HistoryItem>} All history items in browser filtered by URL.
 */
const getHistoryItems = (maxResults = 9999999, startTime = 0) =>
    browser.history.search({
        text: '',
        maxResults,
        startTime,
    })

/**
 * @param {number} [maxResults=100000] The max amount of items to grab from browser.
 * @returns {Array<browser.bookmarks.BookmarkTreeNode>} All bookmark items in browser filtered by URL.
 */
const getBookmarkItems = (maxResults = 100000) =>
    browser.bookmarks.getRecent(maxResults)

export async function getOldExtItems() {
    let bookmarkUrls = new Set()
    const {
        [OLD_EXT_KEYS.INDEX]: index,
        [OLD_EXT_KEYS.BOOKMARKS]: bookmarks,
    } = await browser.storage.local.get({
        [OLD_EXT_KEYS.INDEX]: { index: [] },
        [OLD_EXT_KEYS.BOOKMARKS]: '[]',
    })

    if (typeof bookmarks === 'string') {
        try {
            bookmarkUrls = new Set(JSON.parse(bookmarks).map(bm => bm.url))
        } catch (error) {}
    }

    const transform = transformOldExtDataToImportItem(bookmarkUrls)
    const importItems = []

    // Only attempt page data conversion if index + bookmark storage values are correct types
    if (index && index.index instanceof Array) {
        // NOTE: There is a bug with old ext index sometimes repeating the index keys
        //  (eg.I indexed 400 pages, index contained 43)
        const indexSet = new Set(index.index)

        for (const keyChunk of chunk(200)([...indexSet])) {
            const storageChunk = await browser.storage.local.get(keyChunk)

            keyChunk.forEach((key, i) => {
                if (storageChunk[key] == null) {
                    return
                }

                importItems.push(transform(storageChunk[key], i))
            })
        }
    }

    return importItems
}

/**
 * @param {any} allowTypes
 * @returns {any} Object containing three Maps of encoded URL keys to import item values.
 *   Used to create the imports list and estimate counts.
 */
export default async function createImportItems(allowTypes = DEF_ALLOW) {
    const filterItemsByUrl = await initFilterItemsByUrl()

    const historyItems = filterItemsByUrl(
        allowTypes[IMPORT_TYPE.HISTORY] ? await getHistoryItems() : [],
    )
    const bookmarkItems = filterItemsByUrl(
        allowTypes[IMPORT_TYPE.BOOKMARK] ? await getBookmarkItems() : [],
    )
    const oldExtItems = filterItemsByUrl(
        allowTypes[IMPORT_TYPE.OLD] ? await getOldExtItems() : [],
    )

    return {
        historyItemsMap: transformToImportItemMap(
            historyItems.map(
                transformBrowserItemToImportItem(IMPORT_TYPE.HISTORY),
            ),
        ),
        bookmarkItemsMap: transformToImportItemMap(
            bookmarkItems.map(
                transformBrowserItemToImportItem(IMPORT_TYPE.BOOKMARK),
            ),
        ),
        oldExtItemsMap: transformToImportItemMap(oldExtItems),
    }
}
<|endoftext|>


<commit_before>/**
 * Preset of Class Extensions: 'events'
 */
;(function(K){

// @param {this} self
// @return {Array.<function()>}
function getStorage(host, type){
	var ATTR_EVENTS = '__ev',
		storage;

	storage = host[ATTR_EVENTS] || (host[ATTR_EVENTS] = {});

	return storage[type] || (storage[type] = []);
};

// @return {this}
function addOrRemoveEvent(host, type, fn, toAdd){
	var storage = getStorage(host, type),
		i = 0,
		len = storage.lenth;

	if(toAdd){
		// add an event
		if(K.isFunction(fn)){
			storage.push(fn);
		}

	}else{
		// remove an event
		if(K.isFunction(fn)){
			for(; i < len; i ++){
				if(storage[i] === fn){
					storage.splice(i, 1);
				}
			}

		// remove all events
		}else if(!fn){
			storage.length = 0;
		}
	}

	return host;
};

K.Class.EXTS.events = {
	on: K._overloadSetter(function(type, fn){
		return addOrRemoveEvent(this, type, fn, true);
	}),

	off: function(type, fn){
		return addOrRemoveEvent(this, type, fn);
	},

	fire: function(type, args){
		var self = this;

		args = K.makeArray(args);

		getStorage(self, type).forEach(function(fn){
			fn.apply(self, args);
		});

		return self;
	}
};

})(KM);

/**
 change log

 2011-02-24  Kael:
 TODO:
 A. add .after and .before

 */<commit_msg>oop/events: fix a syntax bug of .off<commit_after>/**
 * Preset of Class Extensions: 'events'
 */
;(function(K){

// @param {this} self
// @return {Array.<function()>}
function getStorage(host, type){
	var ATTR_EVENTS = '__ev',
		storage;

	storage = host[ATTR_EVENTS] || (host[ATTR_EVENTS] = {});

	return storage[type] || (storage[type] = []);
};

// @return {this}
function addOrRemoveEvent(host, type, fn, toAdd){
	var storage = getStorage(host, type),
		i = 0,
		len = storage.length;

	if(toAdd){
		// add an event
		if(K.isFunction(fn)){
			storage.push(fn);
		}

	}else{
		// remove an event
		if(K.isFunction(fn)){
			for(; i < len; i ++){
				if(storage[i] === fn){
					storage.splice(i, 1);
				}
			}

		// remove all events
		}else if(!fn){
			storage.length = 0;
		}
	}

	return host;
};

K.Class.EXTS.events = {
	on: K._overloadSetter(function(type, fn){
		return addOrRemoveEvent(this, type, fn, true);
	}),

	off: function(type, fn){
		return addOrRemoveEvent(this, type, fn);
	},

	fire: function(type, args){
		var self = this;

		args = K.makeArray(args);

		getStorage(self, type).forEach(function(fn){
			fn.apply(self, args);
		});

		return self;
	}
};

})(KM);

/**
 change log

 2011-02-24  Kael:
 TODO:
 A. add .after and .before

 */<|endoftext|>


<commit_before>const path = require('path');
const _ = require('lodash');
const async = require('async');
const dictionary = require('include-all');

/**
 * Async module loader to create a
 * dictionary of the user APIs.
 */
module.exports = (restapi) => {
  return {
    /**
     * Initialize the hook
     */
    initialize: (callback) => {
      async.auto({
        // Load API controllers from `./api/controllers/*.js`
        'controllers/*': (cb) => {
          dictionary.optional({
            dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.controllers),
            filter: /(.+)\.(js)$/,
            identity: false,
            depth: 1,
          }, cb);
        },

        // Load API models from `./api/models/*.js`
        'models/*': (cb) => {
          async.parallel({
            settings: (cb) => {
              dictionary.optional({
                dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.models),
                excludeDirs: /(index|base|associations)$/,
                filter: /^((?!base).+)\.(js|json)$/,
                identity: false,
                depth: 1,
              }, cb);
            },
            relations: (cb) => {
              dictionary.optional({
                dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.models, 'associations'),
                filter: /(.+)\.js$/,
                identity: false,
                depth: 1,
              }, cb);
            },
          }, cb);
        },

        // Load API helpers from `./api/helpers/*.js`.
        'helpers/*': (cb) => {
          dictionary.optional({
            dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.helpers),
            filter: /(.+)\.(js)$/,
            identity: false,
            depth: 1,
          }, cb);
        },

        // Load API services from `./api/services/*.js`.
        'services/*': (cb) => {
          dictionary.optional({
            dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.services),
            filter: /(.+)\.(js)$/,
            depth: 1,
          }, cb);
        },

        // Load API routrs from `./api/routes.js`.
        'routes/*': (cb) => {
          const routePath = path.resolve(restapi.config.rootPath, restapi.config.paths.routes);
          cb(null, require(routePath));
        },
      },

      // Callback.
      (err, api) => {
        // Just in case there is an error.
        if (err) {
          return callback(err);
        }

        // Merge API controllers with the main ones.
        restapi.controllers = _.merge({}, restapi.controllers, api['controllers/*']);

        // Merge API models with the main ones.
        restapi._models = api['models/*'];

        // Merge API helpers with the main ones.
        restapi.helpers = _.merge({}, restapi.helpers, api['helpers/*']);

        // Merge API services with the main ones.
        restapi.services = _.merge({}, restapi.services, api['services/*']);

        // Merge API routes with the main ones.
        restapi.routes = api['routes/*'];

        return callback();
      });
    },
  };
};
<commit_msg>Change services directory and helpers directory load order<commit_after>const path = require('path');
const _ = require('lodash');
const async = require('async');
const dictionary = require('include-all');

/**
 * Async module loader to create a
 * dictionary of the user APIs.
 */
module.exports = (restapi) => {
  return {
    /**
     * Initialize the hook
     */
    initialize: (callback) => {
      async.auto({
        // Load API controllers from `./api/controllers/*.js`
        'controllers/*': (cb) => {
          dictionary.optional({
            dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.controllers),
            filter: /(.+)\.(js)$/,
            identity: false,
            depth: 1,
          }, cb);
        },

        // Load API models from `./api/models/*.js`
        'models/*': (cb) => {
          async.parallel({
            settings: (cb) => {
              dictionary.optional({
                dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.models),
                excludeDirs: /(index|base|associations)$/,
                filter: /^((?!base).+)\.(js|json)$/,
                identity: false,
                depth: 1,
              }, cb);
            },
            relations: (cb) => {
              dictionary.optional({
                dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.models, 'associations'),
                filter: /(.+)\.js$/,
                identity: false,
                depth: 1,
              }, cb);
            },
          }, cb);
        },

        // Load API services from `./api/services/*.js`.
        'services/*': (cb) => {
          dictionary.optional({
            dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.services),
            filter: /(.+)\.(js)$/,
            depth: 1,
          }, cb);
        },

        // Load API helpers from `./api/helpers/*.js`.
        'helpers/*': (cb) => {
          dictionary.optional({
            dirname: path.resolve(restapi.config.rootPath, restapi.config.paths.helpers),
            filter: /(.+)\.(js)$/,
            identity: false,
            depth: 1,
          }, cb);
        },

        // Load API routrs from `./api/routes.js`.
        'routes/*': (cb) => {
          const routePath = path.resolve(restapi.config.rootPath, restapi.config.paths.routes);
          cb(null, require(routePath));
        },
      },

      // Callback.
      (err, api) => {
        // Just in case there is an error.
        if (err) {
          return callback(err);
        }

        // Merge API controllers with the main ones.
        restapi.controllers = _.merge({}, restapi.controllers, api['controllers/*']);

        // Merge API models with the main ones.
        restapi._models = api['models/*'];

        // Merge API services with the main ones.
        restapi.services = _.merge({}, restapi.services, api['services/*']);

        // Merge API helpers with the main ones.
        restapi.helpers = _.merge({}, restapi.helpers, api['helpers/*']);

        // Merge API routes with the main ones.
        restapi.routes = api['routes/*'];

        return callback();
      });
    },
  };
};
<|endoftext|>