<commit_before>'use strict';

exports.BattleAbilities = {
    "defeatist": {
        inherit: true,
        onModifyAtk: function (atk, pokemon) {
            if (pokemon.hp <= pokemon.maxhp / 4) {
                return this.chainModify(0.5);
            }
        },
        onModifySpA: function (atk, pokemon) {
            if (pokemon.hp <= pokemon.maxhp / 4) {
                return this.chainModify(0.5);
            }
        }
    },
    "gluttony": {
        inherit: true,
        onEatItem: function (item, pokemon) {
            if (!pokemon.volatiles['gluttony']) pokemon.addVolatile('gluttony');
        },
        effect: {
          duration: 2,
          onStart: function (target) {
            this.add('-start', target, 'ability: Gluttony');
          },
          onModifySpe: function (spe, pokemon) {
    				return this.chainModify(0.33);
    			},
		onModifyAtk: function (atk, pokemon) {
			return this.chainModify(0.33);
		},
          onModifyAtkPriority: 6,
    		  onSourceModifyAtk: function (atk, attacker, defender, move) {
    			  if (move.type === 'Ice' || move.type === 'Fire') {
    				  this.debug('Gluttony weaken');
    				  return this.chainModify(0.5);
    			  }
    		  },
    		  onModifySpAPriority: 5,
    		  onSourceModifySpA: function (atk, attacker, defender, move) {
    			  if (move.type === 'Ice' || move.type === 'Fire') {
    				  this.debug('Gluttony weaken');
    				  return this.chainModify(0.5);
    			  }
    		  }
        }
    },
    "immunity": {
      inherit: true,
      shortDesc: "This Pokemon cannot be poisoned, burned or paralyzed. Gaining this Ability while poisoned, burned or paralyzed cures it.",
		  onUpdate: function (pokemon) {
			  if (pokemon.status === 'psn' || pokemon.status === 'tox' || pokemon.status === 'par' || pokemon.status === 'brn') {
			    this.add('-activate', pokemon, 'ability: Immunity');
				  pokemon.cureStatus();
			  }
		  },
		  onSetStatus: function (status, target, source, effect) {
			  if (status.id !== 'psn' && status.id !== 'tox' || status.id !== 'brn' || status.id !== 'par') return;
			    if (!effect || !effect.status) return false;
			    this.add('-immune', target, '[msg]', '[from] ability: Immunity');
			    return false;
		    },
    },
    "turboblaze": {
      inherit: true,
      onModifyAtkPriority: 5,
		  onModifyAtk: function (atk, attacker, defender, move) {
			  if (move.type === 'Fire') {
				  this.debug('TurboBlaze boost');
				  return this.chainModify(1.5);
			  }
		  },
		  onModifySpAPriority: 5,
		  onModifySpA: function (atk, attacker, defender, move) {
			  if (move.type === 'Fire') {
				  this.debug('TurboBlaze boost');
				  return this.chainModify(1.5);
			  }
		  }
    },
    "teravolt": {
      inherit: true,
      onModifyAtkPriority: 5,
		  onModifyAtk: function (atk, attacker, defender, move) {
			  if (move.type === 'Electric') {
				  this.debug('Teravolt boost');
				  return this.chainModify(1.5);
			  }
		  },
		  onModifySpAPriority: 5,
		  onModifySpA: function (atk, attacker, defender, move) {
			  if (move.type === 'Electric') {
				  this.debug('Teravolt boost');
				  return this.chainModify(1.5);
			  }
		  }
    },
    "moldbreaker": {
      inherit: true,
      onHit: function (target, source, move) {
        if(move && move.effectType === 'Move') {
          this.chainModify(1.33);
        }
      },
      onModifyMove: function (move, pokemon) {
        if(move.basePower < 120 && pokemon.types.indexOf(move.type) > -1) this.chainModify(1.25);
      }
    },
    "unburden": {
      inherit: true,
      onAfterUseItem: function (item, pokemon) {
        if (pokemon !== this.effectData.target) return;
          pokemon.addVolatile('unburden');
        },
        onTakeItem: function (item, pokemon) {
          pokemon.addVolatile('unburden');
        },
        onEnd: function (pokemon) {
          pokemon.removeVolatile('unburden');
        },
        effect: {
          onModifySpe: function (spe, pokemon) {
            if (!pokemon.item) {
              return this.chainModify(1.5);
            }
          },
        },
    },
    "intimidate": {
      inherit: true,
      onStart: function (pokemon) {
        let foeactive = pokemon.side.foe.active;
        let activated = false;
        for (let i = 0; i < foeactive.length; i++) {
          if (!foeactive[i] || !this.isAdjacent(foeactive[i], pokemon)) continue;
          if (!activated) {
            this.add('-ability', pokemon, 'Intimidate', 'boost');
            activated = true;
          }
          if (foeactive[i].volatiles['substitute'] || foeactive[i].ability === 'intimidate') {
            this.add('-immune', foeactive[i], '[msg]');
          } else {
            this.boost({atk: -1}, foeactive[i], pokemon);
            if(Math.floor(Math.random() * 99) < 20) this.boost({spe: -1}, foeactive[i], pokemon);
          }
        }
      },
    }

}
<commit_msg>Fix over-nerf of Gluttony<commit_after>'use strict';

exports.BattleAbilities = {
    "defeatist": {
        inherit: true,
        onModifyAtk: function (atk, pokemon) {
            if (pokemon.hp <= pokemon.maxhp / 4) {
                return this.chainModify(0.5);
            }
        },
        onModifySpA: function (atk, pokemon) {
            if (pokemon.hp <= pokemon.maxhp / 4) {
                return this.chainModify(0.5);
            }
        }
    },
    "gluttony": {
        inherit: true,
        onEatItem: function (item, pokemon) {
            if (!pokemon.volatiles['gluttony']) pokemon.addVolatile('gluttony');
        },
        effect: {
          duration: 2,
          onStart: function (target) {
            this.add('-start', target, 'ability: Gluttony');
          },
          onModifySpe: function (spe, pokemon) {
    				return this.chainModify(0.66);
    			},
		onModifyAtk: function (atk, pokemon) {
			return this.chainModify(0.66);
		},
          onModifyAtkPriority: 6,
    		  onSourceModifyAtk: function (atk, attacker, defender, move) {
    			  if (move.type === 'Ice' || move.type === 'Fire') {
    				  this.debug('Gluttony weaken');
    				  return this.chainModify(0.5);
    			  }
    		  },
    		  onModifySpAPriority: 5,
    		  onSourceModifySpA: function (atk, attacker, defender, move) {
    			  if (move.type === 'Ice' || move.type === 'Fire') {
    				  this.debug('Gluttony weaken');
    				  return this.chainModify(0.5);
    			  }
    		  }
        }
    },
    "immunity": {
      inherit: true,
      shortDesc: "This Pokemon cannot be poisoned, burned or paralyzed. Gaining this Ability while poisoned, burned or paralyzed cures it.",
		  onUpdate: function (pokemon) {
			  if (pokemon.status === 'psn' || pokemon.status === 'tox' || pokemon.status === 'par' || pokemon.status === 'brn') {
			    this.add('-activate', pokemon, 'ability: Immunity');
				  pokemon.cureStatus();
			  }
		  },
		  onSetStatus: function (status, target, source, effect) {
			  if (status.id !== 'psn' && status.id !== 'tox' || status.id !== 'brn' || status.id !== 'par') return;
			    if (!effect || !effect.status) return false;
			    this.add('-immune', target, '[msg]', '[from] ability: Immunity');
			    return false;
		    },
    },
    "turboblaze": {
      inherit: true,
      onModifyAtkPriority: 5,
		  onModifyAtk: function (atk, attacker, defender, move) {
			  if (move.type === 'Fire') {
				  this.debug('TurboBlaze boost');
				  return this.chainModify(1.5);
			  }
		  },
		  onModifySpAPriority: 5,
		  onModifySpA: function (atk, attacker, defender, move) {
			  if (move.type === 'Fire') {
				  this.debug('TurboBlaze boost');
				  return this.chainModify(1.5);
			  }
		  }
    },
    "teravolt": {
      inherit: true,
      onModifyAtkPriority: 5,
		  onModifyAtk: function (atk, attacker, defender, move) {
			  if (move.type === 'Electric') {
				  this.debug('Teravolt boost');
				  return this.chainModify(1.5);
			  }
		  },
		  onModifySpAPriority: 5,
		  onModifySpA: function (atk, attacker, defender, move) {
			  if (move.type === 'Electric') {
				  this.debug('Teravolt boost');
				  return this.chainModify(1.5);
			  }
		  }
    },
    "moldbreaker": {
      inherit: true,
      onHit: function (target, source, move) {
        if(move && move.effectType === 'Move') {
          this.chainModify(1.33);
        }
      },
      onModifyMove: function (move, pokemon) {
        if(move.basePower < 120 && pokemon.types.indexOf(move.type) > -1) this.chainModify(1.25);
      }
    },
    "unburden": {
      inherit: true,
      onAfterUseItem: function (item, pokemon) {
        if (pokemon !== this.effectData.target) return;
          pokemon.addVolatile('unburden');
        },
        onTakeItem: function (item, pokemon) {
          pokemon.addVolatile('unburden');
        },
        onEnd: function (pokemon) {
          pokemon.removeVolatile('unburden');
        },
        effect: {
          onModifySpe: function (spe, pokemon) {
            if (!pokemon.item) {
              return this.chainModify(1.5);
            }
          },
        },
    },
    "intimidate": {
      inherit: true,
      onStart: function (pokemon) {
        let foeactive = pokemon.side.foe.active;
        let activated = false;
        for (let i = 0; i < foeactive.length; i++) {
          if (!foeactive[i] || !this.isAdjacent(foeactive[i], pokemon)) continue;
          if (!activated) {
            this.add('-ability', pokemon, 'Intimidate', 'boost');
            activated = true;
          }
          if (foeactive[i].volatiles['substitute'] || foeactive[i].ability === 'intimidate') {
            this.add('-immune', foeactive[i], '[msg]');
          } else {
            this.boost({atk: -1}, foeactive[i], pokemon);
            if(Math.floor(Math.random() * 99) < 20) this.boost({spe: -1}, foeactive[i], pokemon);
          }
        }
      },
    }

}
<|endoftext|>


<commit_before>'use strict';

Object.defineProperty(exports, '__esModule', {
    value: true
});

var _interopRequireDefault = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; };

var _slicedToArray = function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } };

var _toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } };

exports['default'] = createGroup;

require('core-js/fn/object/entries');

var _createStream = require('cyclejs');

var _mapValues = require('map-values');

var _mapValues2 = _interopRequireDefault(_mapValues);

var _mergeObjects = require('merge-object');

var _mergeObjects2 = _interopRequireDefault(_mergeObjects);

var _getParametersNames = require('get-parameter-names');

var _getParametersNames2 = _interopRequireDefault(_getParametersNames);

'use strict';

function _makeInjectFn(streamWithDependencies) {
    return function inject() {
        for (var _len = arguments.length, inputObjects = Array(_len), _key = 0; _key < _len; _key++) {
            inputObjects[_key] = arguments[_key];
        }

        var combinedInputObject = inputObjects.length === 1 ? inputObjects[0] : inputObjects.reduce(_mergeObjects2['default'], {});

        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
            for (var _iterator = Object.entries(streamWithDependencies)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                var _step$value = _slicedToArray(_step.value, 2);

                var _step$value$1 = _step$value[1];
                var dependencies = _step$value$1.dependencies;
                var stream = _step$value$1.stream;

                var streamDependencies = dependencies.map(function (dependencyName) {
                    if (!combinedInputObject.hasOwnProperty(dependencyName)) {
                        throw new Error('Dependency "' + dependencyName + '" is not available!');
                    }

                    return combinedInputObject[dependencyName];
                });

                stream.inject.apply(stream, _toConsumableArray(streamDependencies));
            }
        } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
        } finally {
            try {
                if (!_iteratorNormalCompletion && _iterator['return']) {
                    _iterator['return']();
                }
            } finally {
                if (_didIteratorError) {
                    throw _iteratorError;
                }
            }
        }

        if (inputObjects.length === 1) {
            return inputObjects[0];
        } else if (inputObjects.length > 1) {
            return inputObjects;
        } else {
            return null;
        }
    };
}

function _makeDisposeFn(group) {
    return function dispose() {
        var _iteratorNormalCompletion2 = true;
        var _didIteratorError2 = false;
        var _iteratorError2 = undefined;

        try {
            for (var _iterator2 = Object.entries(group)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                var _step2$value = _slicedToArray(_step2.value, 2);

                var stream = _step2$value[1];

                stream.dispose();
            }
        } catch (err) {
            _didIteratorError2 = true;
            _iteratorError2 = err;
        } finally {
            try {
                if (!_iteratorNormalCompletion2 && _iterator2['return']) {
                    _iterator2['return']();
                }
            } finally {
                if (_didIteratorError2) {
                    throw _iteratorError2;
                }
            }
        }
    };
}

function createGroup(definition) {
    var streamsDefs = 'function' === typeof definition ? definition() : definition;

    if ('object' !== typeof streamsDefs || streamsDefs === null || Array.isArray(streamsDefs)) {
        throw new TypeError('Cycle Streams Group must be an object.');
    }

    if (this instanceof createStreamsGroup) {
        // jshint ignore:line
        throw new Error('Cannot use `new` operator on `createStreamsGroup()`, it is not a constructor.');
    }

    var streamsWithDeps = _mapValues2['default'](streamsDefs, function (streamFn) {
        return {
            dependencies: _getParametersNames2['default'](streamFn),
            stream: _createStream.createStream(streamFn)
        };
    });

    var group = _mapValues2['default'](streamsWithDeps, function (_ref) {
        var stream = _ref.stream;
        return stream;
    });

    // add `inject` and `dispose` as not enumerable properties to make them
    // not visible for `each` function
    Object.defineProperty(group, 'inject', {
        enumerable: false,
        value: _makeInjectFn(streamsWithDeps)
    });

    Object.defineProperty(group, 'dispose', {
        enumerable: false,
        value: _makeDisposeFn(group)
    });

    Object.freeze(group);

    return group;
}

module.exports = exports['default'];<commit_msg>Build dist/<commit_after>'use strict';

Object.defineProperty(exports, '__esModule', {
    value: true
});

var _interopRequireDefault = function (obj) { return obj && obj.__esModule ? obj : { 'default': obj }; };

var _slicedToArray = function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } };

var _toConsumableArray = function (arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } };

exports['default'] = createGroup;

require('core-js/fn/object/entries');

var _createStream = require('cyclejs');

var _mapValues = require('map-values');

var _mapValues2 = _interopRequireDefault(_mapValues);

var _mergeObjects = require('merge-object');

var _mergeObjects2 = _interopRequireDefault(_mergeObjects);

var _getParametersNames = require('get-parameter-names');

var _getParametersNames2 = _interopRequireDefault(_getParametersNames);

'use strict';

function _makeInjectFn(streamWithDependencies) {
    return function inject() {
        for (var _len = arguments.length, inputObjects = Array(_len), _key = 0; _key < _len; _key++) {
            inputObjects[_key] = arguments[_key];
        }

        var combinedInputObject = inputObjects.length === 1 ? inputObjects[0] : inputObjects.reduce(_mergeObjects2['default'], {});

        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
            for (var _iterator = Object.entries(streamWithDependencies)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                var _step$value = _slicedToArray(_step.value, 2);

                var _step$value$1 = _step$value[1];
                var dependencies = _step$value$1.dependencies;
                var stream = _step$value$1.stream;

                var streamDependencies = dependencies.map(function (dependencyName) {
                    if (!combinedInputObject.hasOwnProperty(dependencyName)) {
                        throw new Error('Dependency "' + dependencyName + '" is not available!');
                    }

                    return combinedInputObject[dependencyName];
                });

                stream.inject.apply(stream, _toConsumableArray(streamDependencies));
            }
        } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
        } finally {
            try {
                if (!_iteratorNormalCompletion && _iterator['return']) {
                    _iterator['return']();
                }
            } finally {
                if (_didIteratorError) {
                    throw _iteratorError;
                }
            }
        }

        if (inputObjects.length === 1) {
            return inputObjects[0];
        } else if (inputObjects.length > 1) {
            return inputObjects;
        } else {
            return null;
        }
    };
}

function _makeDisposeFn(group) {
    return function dispose() {
        var _iteratorNormalCompletion2 = true;
        var _didIteratorError2 = false;
        var _iteratorError2 = undefined;

        try {
            for (var _iterator2 = Object.entries(group)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                var _step2$value = _slicedToArray(_step2.value, 2);

                var stream = _step2$value[1];

                stream.dispose();
            }
        } catch (err) {
            _didIteratorError2 = true;
            _iteratorError2 = err;
        } finally {
            try {
                if (!_iteratorNormalCompletion2 && _iterator2['return']) {
                    _iterator2['return']();
                }
            } finally {
                if (_didIteratorError2) {
                    throw _iteratorError2;
                }
            }
        }
    };
}

function createGroup(definition) {
    var streamsDefs = 'function' === typeof definition ? definition() : definition;

    if ('object' !== typeof streamsDefs || streamsDefs === null || Array.isArray(streamsDefs)) {
        throw new TypeError('Cycle Streams Group must be an object.');
    }

    if (this instanceof createGroup) {
        // jshint ignore:line
        throw new Error('Cannot use `new` operator on `createStreamsGroup()`, it is not a constructor.');
    }

    var streamsWithDeps = _mapValues2['default'](streamsDefs, function (streamFn) {
        return {
            dependencies: _getParametersNames2['default'](streamFn),
            stream: _createStream.createStream(streamFn)
        };
    });

    var group = _mapValues2['default'](streamsWithDeps, function (_ref) {
        var stream = _ref.stream;
        return stream;
    });

    // add `inject` and `dispose` as not enumerable properties to make them
    // not visible for `each` function
    Object.defineProperty(group, 'inject', {
        enumerable: false,
        value: _makeInjectFn(streamsWithDeps)
    });

    Object.defineProperty(group, 'dispose', {
        enumerable: false,
        value: _makeDisposeFn(group)
    });

    Object.freeze(group);

    return group;
}

module.exports = exports['default'];<|endoftext|>


<commit_before>var common = require('../casper_lib/common.js');

common.start_and_log_in();

casper.then(function () {
    var menu_selector = '#settings-dropdown';
    casper.waitUntilVisible(menu_selector, function () {
        casper.click(menu_selector);
        casper.click('a[href^="#organization"]');
    });
});

casper.then(function () {
    casper.waitUntilVisible('#settings_overlay_container.show', function () {
        casper.click("li[data-section='user-list-admin']");
    });
});

// Test user deactivation and reactivation
casper.then(function () {
    casper.waitUntilVisible('.user_row[data-email="cordelia@zulip.com"]', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="cordelia@zulip.com"]', 'Deactivate');
        casper.click('.user_row[data-email="cordelia@zulip.com"] .deactivate');
        casper.test.assertTextExists('Deactivate cordelia@zulip.com', 'Deactivate modal has right user');
        casper.test.assertTextExists('Deactivate now', 'Deactivate now button available');
        casper.click('#deactivation_user_modal .do_deactivate_button');
    });
});

casper.then(function () {
    casper.waitUntilVisible('.user_row[data-email="cordelia@zulip.com"].deactivated_user', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="cordelia@zulip.com"]', 'Reactivate');
        casper.click('.user_row[data-email="cordelia@zulip.com"] .reactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible('.user_row[data-email="cordelia@zulip.com"]:not(.deactivated_user)', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="cordelia@zulip.com"]', 'Deactivate');
    });
});

casper.then(function () {
    // Test Deactivated users section of admin page
    casper.waitUntilVisible('.user_row[data-email="cordelia@zulip.com"]', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="cordelia@zulip.com"]', 'Deactivate');
        casper.click('.user_row[data-email="cordelia@zulip.com"] .deactivate');
        casper.test.assertTextExists('Deactivate cordelia@zulip.com', 'Deactivate modal has right user');
        casper.test.assertTextExists('Deactivate now', 'Deactivate now button available');
        casper.click('#deactivation_user_modal .do_deactivate_button');
    });
});

casper.then(function () {
    // Leave the page and return
    casper.reload();

    casper.test.assertSelectorHasText("li[data-section='deactivated-users-admin']", "Deactivated users");
    casper.click("li[data-section='deactivated-users-admin']");

    casper.waitUntilVisible('#admin_deactivated_users_table .user_row[data-email="cordelia@zulip.com"] .reactivate', function () {
        casper.test.assertSelectorHasText('#admin_deactivated_users_table .user_row[data-email="cordelia@zulip.com"]', 'Reactivate');
        casper.click('#admin_deactivated_users_table .user_row[data-email="cordelia@zulip.com"] .reactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible('#admin_deactivated_users_table .user_row[data-email="cordelia@zulip.com"] button:not(.reactivate)', function () {
        casper.test.assertSelectorHasText('#admin_deactivated_users_table .user_row[data-email="cordelia@zulip.com"]', 'Deactivate');
    });
});

// Test bot deactivation and reactivation
casper.then(function () {
    casper.test.assertSelectorHasText("li[data-section='organization-settings']", "Organization settings");
    casper.click("li[data-section='bot-list-admin']");
});

casper.then(function () {
    casper.waitUntilVisible('.user_row[data-email="default-bot@zulip.com"]', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="default-bot@zulip.com"]', 'Deactivate');
        casper.click('.user_row[data-email="default-bot@zulip.com"] .deactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible('.user_row[data-email="default-bot@zulip.com"].deactivated_user', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="default-bot@zulip.com"]', 'Reactivate');
        casper.click('.user_row[data-email="default-bot@zulip.com"] .reactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible('.user_row[data-email="default-bot@zulip.com"]:not(.deactivated_user)', function () {
        casper.test.assertSelectorHasText('.user_row[data-email="default-bot@zulip.com"]', 'Deactivate');
    });
});

// NOTE: Any additional test code adding to the bottom of this test
// suite has risk of being weirdly flaky; we don't know why, but we
// recommend just adding a new suite if needed, since there isn't much
// overhead.

common.then_log_out();

casper.run(function () {
    casper.test.done();
});
<commit_msg>casper: Extract user_row() helper.<commit_after>var common = require('../casper_lib/common.js');

function user_row(name) {
    var email = name + '@zulip.com';
    return '.user_row[data-email="' + email + '"]';
}

common.start_and_log_in();

casper.then(function () {
    var menu_selector = '#settings-dropdown';
    casper.waitUntilVisible(menu_selector, function () {
        casper.click(menu_selector);
        casper.click('a[href^="#organization"]');
    });
});

casper.then(function () {
    casper.waitUntilVisible('#settings_overlay_container.show', function () {
        casper.click("li[data-section='user-list-admin']");
    });
});

// Test user deactivation and reactivation
casper.then(function () {
    casper.waitUntilVisible(user_row('cordelia'), function () {
        casper.test.assertSelectorHasText(user_row('cordelia'), 'Deactivate');
        casper.click(user_row('cordelia') + ' .deactivate');
        casper.test.assertTextExists('Deactivate cordelia@zulip.com', 'Deactivate modal has right user');
        casper.test.assertTextExists('Deactivate now', 'Deactivate now button available');
        casper.click('#deactivation_user_modal .do_deactivate_button');
    });
});

casper.then(function () {
    casper.waitUntilVisible(user_row('cordelia') + '.deactivated_user', function () {
        casper.test.assertSelectorHasText(user_row('cordelia'), 'Reactivate');
        casper.click(user_row('cordelia') + ' .reactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible(user_row('cordelia') + ':not(.deactivated_user)', function () {
        casper.test.assertSelectorHasText(user_row('cordelia'), 'Deactivate');
    });
});

casper.then(function () {
    // Test Deactivated users section of admin page
    casper.waitUntilVisible(user_row('cordelia'), function () {
        casper.test.assertSelectorHasText(user_row('cordelia'), 'Deactivate');
        casper.click(user_row('cordelia') + ' .deactivate');
        casper.test.assertTextExists('Deactivate cordelia@zulip.com', 'Deactivate modal has right user');
        casper.test.assertTextExists('Deactivate now', 'Deactivate now button available');
        casper.click('#deactivation_user_modal .do_deactivate_button');
    });
});

casper.then(function () {
    // Leave the page and return
    casper.reload();

    casper.test.assertSelectorHasText("li[data-section='deactivated-users-admin']", "Deactivated users");
    casper.click("li[data-section='deactivated-users-admin']");

    casper.waitUntilVisible('#admin_deactivated_users_table ' + user_row('cordelia') + ' .reactivate', function () {
        casper.test.assertSelectorHasText('#admin_deactivated_users_table ' + user_row('cordelia') + '', 'Reactivate');
        casper.click('#admin_deactivated_users_table ' + user_row('cordelia') + ' .reactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible('#admin_deactivated_users_table ' + user_row('cordelia') + ' button:not(.reactivate)', function () {
        casper.test.assertSelectorHasText('#admin_deactivated_users_table ' + user_row('cordelia') + '', 'Deactivate');
    });
});

// Test bot deactivation and reactivation
casper.then(function () {
    casper.test.assertSelectorHasText("li[data-section='organization-settings']", "Organization settings");
    casper.click("li[data-section='bot-list-admin']");
});

casper.then(function () {
    casper.waitUntilVisible(user_row('default-bot'), function () {
        casper.test.assertSelectorHasText(user_row('default-bot'), 'Deactivate');
        casper.click(user_row('default-bot') + ' .deactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible(user_row('default-bot') + '.deactivated_user', function () {
        casper.test.assertSelectorHasText(user_row('default-bot'), 'Reactivate');
        casper.click(user_row('default-bot') + ' .reactivate');
    });
});

casper.then(function () {
    casper.waitUntilVisible(user_row('default-bot') + ':not(.deactivated_user)', function () {
        casper.test.assertSelectorHasText(user_row('default-bot'), 'Deactivate');
    });
});

// NOTE: Any additional test code adding to the bottom of this test
// suite has risk of being weirdly flaky; we don't know why, but we
// recommend just adding a new suite if needed, since there isn't much
// overhead.

common.then_log_out();

casper.run(function () {
    casper.test.done();
});
<|endoftext|>


<commit_before>var kue = require('kue')
  , cfg = require('./config')
  , logger = require('./utils/logger')
  , Job = kue.Job
  , jobs = kue.createQueue({
      redis: {
        port: cfg.redis.PORT || 6379,
        host: cfg.redis.HOST || '127.0.0.1',
        auth: cfg.redis.AUTH || null
      }
    });

var workers = {
  ESLint: require('./workers/eslint')
};

// Process eslint jobs
jobs.process('eslint', function(job, done) {
  var worker = new workers.ESLint(job);

  worker.process(done);
});

// Reports queued jobs
jobs.on('job enqueue', function(id) {
  logger.info('Job #%s got queued', id);
});

// Removes completed jobs
jobs.on('job complete', function(id) {
  Job.get(id, function(err, job) {
    if (err) return;

    job.remove(function (err) {
      if (err) throw err;

      logger.info('Removed completed job #%d', job.id);
    });
  });
});

module.exports = jobs;
<commit_msg>Minor<commit_after>var kue = require('kue')
  , cfg = require('./config')
  , logger = require('./utils/logger')
  , Job = kue.Job
  , jobs = kue.createQueue({
      redis: {
        port: cfg.redis.PORT,
        host: cfg.redis.HOST,
        auth: cfg.redis.AUTH
      }
    });

var workers = {
  ESLint: require('./workers/eslint')
};

// Process eslint jobs
jobs.process('eslint', function(job, done) {
  var worker = new workers.ESLint(job);

  worker.process(done);
});

// Reports queued jobs
jobs.on('job enqueue', function(id) {
  logger.info('Job #%s got queued', id);
});

// Removes completed jobs
jobs.on('job complete', function(id) {
  Job.get(id, function(err, job) {
    if (err) return;

    job.remove(function (err) {
      if (err) throw err;

      logger.info('Removed completed job #%d', job.id);
    });
  });
});

module.exports = jobs;
<|endoftext|>


<commit_before>(function() {

'use strict';

function AuthoringWidgetsProvider() {

    var widgets = [];

    this.widget = function(id, config) {
        widgets.push(angular.extend({ // make a new instance for every widget
        }, config, {_id: id}));
    };

    this.$get = function() {
        return widgets;
    };
}

WidgetsManagerCtrl.$inject = ['$scope', '$routeParams', 'authoringWidgets', 'archiveService', 'keyboardManager'];
function WidgetsManagerCtrl($scope, $routeParams, authoringWidgets, archiveService, keyboardManager) {
    $scope.active = null;

    $scope.$watch('item', function(item) {
        if (!item) {
            $scope.widgets = null;
            return;
        }

        var display;

        if (archiveService.isLegal(item)) {
            display = 'legalArchive';
        } else {
            display = item.type === 'composite' ? 'packages' : item.state === 'killed' ? 'killedItem' : 'authoring';
        }

        $scope.widgets = authoringWidgets.filter(function(widget) {
            return !!widget.display[display];
        });

        /*
         * Navigate throw right tab widgets with keyboard combination
         * Combination: Ctrl + {{widget number}}
         */
        angular.forEach(_.sortBy($scope.widgets, 'order'), function (widget, index) {
            keyboardManager.bind('ctrl+' + (index + 1), function () {
                $scope.activate(widget);
            }, {inputDisabled: false});
        });
    });

    $scope.isLocked = function(widget) {
        return (widget.needUnlock && $scope.item._locked) ||
        (widget.needEditable && !$scope.item._editable);
    };

    $scope.activate = function(widget) {
        if (!$scope.isLocked(widget)) {
            $scope.active = $scope.active === widget ? null : widget;
        }
    };

    this.activate = function(widget) {
        $scope.activate(widget);
    };

    $scope.closeWidget = function(widget) {
        $scope.active = null;
    };

    // activate widget based on query string
    angular.forEach($scope.widgets, function(widget) {
        if ($routeParams[widget._id]) {
            $scope.activate(widget);
        }
    });

    $scope.$watch('item._locked', function() {
        if ($scope.active) {
            var widget = $scope.active;
            $scope.closeWidget(widget);
            $scope.activate(widget);
        }
    });
}
AuthoringWidgetsDir.$inject = ['desks'];
function AuthoringWidgetsDir(desks) {
    return {
        controller: WidgetsManagerCtrl,
        templateUrl: 'scripts/superdesk-authoring/widgets/views/authoring-widgets.html',
        transclude: true,
        link: function (scope, elem) {
            scope.userLookup = desks.userLookup;
            var editor = elem.find('.page-content-container'),
                stickyHeader = elem.find('.authoring-sticky');

            editor.on('scroll', function () {
                if (editor.scrollTop() > 5) {
                    stickyHeader.addClass('authoring-sticky--fixed');
                } else {
                    stickyHeader.removeClass('authoring-sticky--fixed');
                }
            });
        }
    };
}

angular.module('superdesk.authoring.widgets', [])
    .provider('authoringWidgets', AuthoringWidgetsProvider)
    .directive('sdAuthoringWidgets', AuthoringWidgetsDir);

})();
<commit_msg>fix(client: superdesk-authoring: widgets): show widgets if they're in<commit_after>(function() {

'use strict';

function AuthoringWidgetsProvider() {

    var widgets = [];

    this.widget = function(id, config) {
        widgets.push(angular.extend({ // make a new instance for every widget
        }, config, {_id: id}));
    };

    this.$get = function() {
        return widgets;
    };
}

WidgetsManagerCtrl.$inject = ['$scope', '$routeParams', 'authoringWidgets', 'archiveService', 'keyboardManager', '$location'];
function WidgetsManagerCtrl($scope, $routeParams, authoringWidgets, archiveService, keyboardManager, $location) {
    $scope.active = null;

    $scope.$watch('item', function(item) {
        if (!item) {
            $scope.widgets = null;
            return;
        }

        var display;

        if (archiveService.isLegal(item)) {
            display = 'legalArchive';
        } else {
            display = item.type === 'composite' ? 'packages' : item.state === 'killed' ? 'killedItem' : 'authoring';
        }

        $scope.widgets = authoringWidgets.filter(function(widget) {
            return !!widget.display[display];
        });

        /*
         * Navigate throw right tab widgets with keyboard combination
         * Combination: Ctrl + {{widget number}}
         */
        angular.forEach(_.sortBy($scope.widgets, 'order'), function (widget, index) {
            keyboardManager.bind('ctrl+' + (index + 1), function () {
                $scope.activate(widget);
            }, {inputDisabled: false});
            if ($location.search()[widget._id]) {
                $scope.activate(widget);
            }
        });
    });

    $scope.isLocked = function(widget) {
        return (widget.needUnlock && $scope.item._locked) ||
        (widget.needEditable && !$scope.item._editable);
    };

    $scope.activate = function(widget) {
        if (!$scope.isLocked(widget)) {
            $scope.active = $scope.active === widget ? null : widget;
        }
    };

    this.activate = function(widget) {
        $scope.activate(widget);
    };

    $scope.closeWidget = function(widget) {
        $scope.active = null;
    };

    // activate widget based on query string
    angular.forEach($scope.widgets, function(widget) {
        if ($routeParams[widget._id]) {
            $scope.activate(widget);
        }
    });

    $scope.$watch('item._locked', function() {
        if ($scope.active) {
            var widget = $scope.active;
            $scope.closeWidget(widget);
            $scope.activate(widget);
        }
    });
}
AuthoringWidgetsDir.$inject = ['desks'];
function AuthoringWidgetsDir(desks) {
    return {
        controller: WidgetsManagerCtrl,
        templateUrl: 'scripts/superdesk-authoring/widgets/views/authoring-widgets.html',
        transclude: true,
        link: function (scope, elem) {
            scope.userLookup = desks.userLookup;
            var editor = elem.find('.page-content-container'),
                stickyHeader = elem.find('.authoring-sticky');

            editor.on('scroll', function () {
                if (editor.scrollTop() > 5) {
                    stickyHeader.addClass('authoring-sticky--fixed');
                } else {
                    stickyHeader.removeClass('authoring-sticky--fixed');
                }
            });
        }
    };
}

angular.module('superdesk.authoring.widgets', [])
    .provider('authoringWidgets', AuthoringWidgetsProvider)
    .directive('sdAuthoringWidgets', AuthoringWidgetsDir);

})();
<|endoftext|>


<commit_before># Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
<commit_msg>add correct commenting character in users js files<commit_after>// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
// You can use CoffeeScript in this file: http://coffeescript.org/
<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { find, settled, triggerEvent } from '@ember/test-helpers';
import setupAuthentication from '../helpers/setup-authentication';
import page from '../pages/learner-group';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';

module('Acceptance | learner group bulk assign', function(hooks) {
  setupApplicationTest(hooks);
  setupMirage(hooks);

  hooks.beforeEach(async function() {
    const school = this.server.create('school');
    await setupAuthentication( { id: 1, school} );

    const program = this.server.create('program', {
      title: 'program 0',
      school,
    });
    const programYear = this.server.create('program-year', {
      program,
    });
    const cohort =server.create('cohort', {
      title: 'class of this year',
      programYear,
    });
    const group1 = this.server.create('learner-group', {
      title: 'group 1',
      cohort,
    });
    this.server.create('learnerGroup', {
      title: 'group 1 child 0',
      cohort,
      parent: group1,
    });
    this.server.create('learnerGroup', {
      title: 'group 1 child 1',
      cohort,
      parent: group1,
    });
  });

  let createFile = function(users){
    let file;
    let lines = users.map(arr => {
      return arr.join("\t");
    });

    let contents = lines.join("\n");
    file = new Blob([contents], { type: 'text/plain' });

    file.mime = 'text/plain';
    file.name = 'test.txt';
    return file;
  };

  let triggerUpload = async function(users, selector){
    let file = createFile(users);
    await triggerEvent(
      selector,
      'change',
      [file]
    );
    await settled();
  };

  test('upload users', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jasper', 'johnson', '1234567890', '123Test'],
      ['jackson', 'johnson', '12345'],
    ];
    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    assert.equal(page.bulkAssign.validUploadedUsers(0).firstName, 'jasper');
    assert.equal(page.bulkAssign.validUploadedUsers(0).lastName, 'johnson');
    assert.equal(page.bulkAssign.validUploadedUsers(0).campusId, '1234567890');
    assert.equal(page.bulkAssign.validUploadedUsers(0).smallGroupName, '123Test');
    assert.equal(page.bulkAssign.validUploadedUsers(1).firstName, 'jackson');
    assert.equal(page.bulkAssign.validUploadedUsers(1).lastName, 'johnson');
    assert.equal(page.bulkAssign.validUploadedUsers(1).campusId, '12345');
    assert.equal(page.bulkAssign.validUploadedUsers(1).smallGroupName, '');

    assert.ok(page.bulkAssign.showConfirmUploadButton);
  });

  test('upload user errors', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'mrs',
      lastName: 'maisel',
      campusId: '123456',
    });
    let users = [
      ['j', 'johnson', '1234567890', '123Test'],
      ['jackson', 'j', '12345'],
      ['', 'johnson', '12345', '123Test'],
      ['Magick', '', '12345'],
      ['Missing', 'Person', 'abcd'],
      ['mrs', 'maisel', '123456'],
    ];
    await triggerUpload(users, '[data-test-user-upload]');

    assert.equal(page.bulkAssign.invalidUploadedUsers().count, 6);
    assert.equal(page.bulkAssign.invalidUploadedUsers(0).errors, 'First Name does not match user record: jasper');
    assert.equal(page.bulkAssign.invalidUploadedUsers(1).errors, 'Last Name does not match user record: johnson');
    assert.equal(page.bulkAssign.invalidUploadedUsers(2).errors, 'First Name is required');
    assert.equal(page.bulkAssign.invalidUploadedUsers(3).errors, 'Last Name is required');
    assert.equal(page.bulkAssign.invalidUploadedUsers(4).errors, 'Could not find a user with the campusId abcd');
    assert.equal(page.bulkAssign.invalidUploadedUsers(5).errors, "User is not in this group's cohort: class of this year");
    assert.notOk(page.bulkAssign.showConfirmUploadButton);
  });

  test('choose small group match', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jasper', 'johnson', '1234567890', '123Test'],
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    await page.bulkAssign.groupsToMatch(0).chooseGroup('2');
  });

  test('finalize and save', async function (assert) {
    assert.expect(16);
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jasper', 'johnson', '1234567890'],
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();

    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    await page.bulkAssign.groupsToMatch(0).chooseGroup('3');

    assert.equal(page.bulkAssign.finalData().count, 2);
    assert.equal(page.bulkAssign.finalData(0).name, 'jasper M. johnson');
    assert.equal(page.bulkAssign.finalData(0).campusId, '1234567890');
    assert.equal(page.bulkAssign.finalData(0).groupName, 'group 1');
    assert.equal(page.bulkAssign.finalData(1).name, 'jackson M. johnson');
    assert.equal(page.bulkAssign.finalData(1).campusId, '12345');
    assert.equal(page.bulkAssign.finalData(1).groupName, 'group 1 child 1');
    assert.ok(page.bulkAssign.canSubmitFinalData);
    assert.equal( this.server.db.learnerGroups[0].userIds, null);
    assert.equal( this.server.db.learnerGroups[1].userIds, null);
    assert.equal( this.server.db.learnerGroups[2].userIds, null);

    await page.bulkAssign.submitFinalData();
    assert.deepEqual( this.server.db.learnerGroups[0].userIds, ['2', '3']);
    assert.deepEqual( this.server.db.learnerGroups[1].userIds, null);
    assert.deepEqual( this.server.db.learnerGroups[2].userIds, ['3']);
  });

  test('catch user already in group and do not save', async function (assert) {
    assert.expect(11);
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
      learnerGroupIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
      learnerGroupIds: [3],
    });
    let users = [
      ['jasper', 'johnson', '1234567890'],
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();

    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    await page.bulkAssign.groupsToMatch(0).chooseGroup('2');

    assert.equal(page.bulkAssign.finalData().count, 0);

    assert.equal(page.bulkAssign.finalErrorData().count, 2);
    assert.equal(page.bulkAssign.finalErrorData(0).name, 'jasper M. johnson');
    assert.equal(page.bulkAssign.finalErrorData(0).campusId, '1234567890');
    assert.equal(page.bulkAssign.finalErrorData(0).error, 'Already in the group 1 group. Please remove them and try again.');
    assert.equal(page.bulkAssign.finalErrorData(1).name, 'jackson M. johnson');
    assert.equal(page.bulkAssign.finalErrorData(1).campusId, '12345');
    assert.equal(page.bulkAssign.finalErrorData(1).error, 'Already in the group 1 group. Please remove them and try again.');

    assert.notOk(page.bulkAssign.canSubmitFinalData);

  });

  test('create a new group when requested', async function (assert) {
    assert.expect(14);
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();

    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 1);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    assert.equal( this.server.db.learnerGroups.length, 3);
    assert.equal(server.db.learnerGroups[0].userIds, null);
    await page.bulkAssign.groupsToMatch(0).createNewGroup();
    assert.equal( this.server.db.learnerGroups.length, 4);
    assert.equal( this.server.db.learnerGroups[3].userIds, null);

    assert.equal(page.bulkAssign.finalData().count, 1);
    assert.equal(page.bulkAssign.finalData(0).groupName, '123Test');
    assert.ok(page.bulkAssign.canSubmitFinalData);

    await page.bulkAssign.submitFinalData();
    assert.deepEqual( this.server.db.learnerGroups[0].userIds, ['2']);
    assert.equal( this.server.db.learnerGroups[1].userIds, null);
    assert.equal( this.server.db.learnerGroups[2].userIds, null);
    assert.equal( this.server.db.learnerGroups[3].title, '123Test');
    assert.deepEqual( this.server.db.learnerGroups[3].userIds, ['2']);
  });

  test('small group matches are trimmed', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    const users = this.server.createList('user', 4, {
      cohortIds: [1],
    });
    const data = users.map(obj => {
      return [
        obj.firstName,
        obj.lastName,
        obj.campusId
      ];
    });
    data[0].pushObject('group 1 child 0');
    data[1].pushObject('group 1 child 1');
    data[2].pushObject('group 1 child 1 ');
    data[3].pushObject(' group 1 child 1');
    await triggerUpload(data, '[data-test-user-upload]');
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 2);
  });
});
<commit_msg>Remove unused import<commit_after>import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { settled, triggerEvent } from '@ember/test-helpers';
import setupAuthentication from '../helpers/setup-authentication';
import page from '../pages/learner-group';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';

module('Acceptance | learner group bulk assign', function(hooks) {
  setupApplicationTest(hooks);
  setupMirage(hooks);

  hooks.beforeEach(async function() {
    const school = this.server.create('school');
    await setupAuthentication( { id: 1, school} );

    const program = this.server.create('program', {
      title: 'program 0',
      school,
    });
    const programYear = this.server.create('program-year', {
      program,
    });
    const cohort =server.create('cohort', {
      title: 'class of this year',
      programYear,
    });
    const group1 = this.server.create('learner-group', {
      title: 'group 1',
      cohort,
    });
    this.server.create('learnerGroup', {
      title: 'group 1 child 0',
      cohort,
      parent: group1,
    });
    this.server.create('learnerGroup', {
      title: 'group 1 child 1',
      cohort,
      parent: group1,
    });
  });

  let createFile = function(users){
    let file;
    let lines = users.map(arr => {
      return arr.join("\t");
    });

    let contents = lines.join("\n");
    file = new Blob([contents], { type: 'text/plain' });

    file.mime = 'text/plain';
    file.name = 'test.txt';
    return file;
  };

  let triggerUpload = async function(users, selector){
    let file = createFile(users);
    await triggerEvent(
      selector,
      'change',
      [file]
    );
    await settled();
  };

  test('upload users', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jasper', 'johnson', '1234567890', '123Test'],
      ['jackson', 'johnson', '12345'],
    ];
    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    assert.equal(page.bulkAssign.validUploadedUsers(0).firstName, 'jasper');
    assert.equal(page.bulkAssign.validUploadedUsers(0).lastName, 'johnson');
    assert.equal(page.bulkAssign.validUploadedUsers(0).campusId, '1234567890');
    assert.equal(page.bulkAssign.validUploadedUsers(0).smallGroupName, '123Test');
    assert.equal(page.bulkAssign.validUploadedUsers(1).firstName, 'jackson');
    assert.equal(page.bulkAssign.validUploadedUsers(1).lastName, 'johnson');
    assert.equal(page.bulkAssign.validUploadedUsers(1).campusId, '12345');
    assert.equal(page.bulkAssign.validUploadedUsers(1).smallGroupName, '');

    assert.ok(page.bulkAssign.showConfirmUploadButton);
  });

  test('upload user errors', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'mrs',
      lastName: 'maisel',
      campusId: '123456',
    });
    let users = [
      ['j', 'johnson', '1234567890', '123Test'],
      ['jackson', 'j', '12345'],
      ['', 'johnson', '12345', '123Test'],
      ['Magick', '', '12345'],
      ['Missing', 'Person', 'abcd'],
      ['mrs', 'maisel', '123456'],
    ];
    await triggerUpload(users, '[data-test-user-upload]');

    assert.equal(page.bulkAssign.invalidUploadedUsers().count, 6);
    assert.equal(page.bulkAssign.invalidUploadedUsers(0).errors, 'First Name does not match user record: jasper');
    assert.equal(page.bulkAssign.invalidUploadedUsers(1).errors, 'Last Name does not match user record: johnson');
    assert.equal(page.bulkAssign.invalidUploadedUsers(2).errors, 'First Name is required');
    assert.equal(page.bulkAssign.invalidUploadedUsers(3).errors, 'Last Name is required');
    assert.equal(page.bulkAssign.invalidUploadedUsers(4).errors, 'Could not find a user with the campusId abcd');
    assert.equal(page.bulkAssign.invalidUploadedUsers(5).errors, "User is not in this group's cohort: class of this year");
    assert.notOk(page.bulkAssign.showConfirmUploadButton);
  });

  test('choose small group match', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jasper', 'johnson', '1234567890', '123Test'],
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    await page.bulkAssign.groupsToMatch(0).chooseGroup('2');
  });

  test('finalize and save', async function (assert) {
    assert.expect(16);
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jasper', 'johnson', '1234567890'],
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();

    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    await page.bulkAssign.groupsToMatch(0).chooseGroup('3');

    assert.equal(page.bulkAssign.finalData().count, 2);
    assert.equal(page.bulkAssign.finalData(0).name, 'jasper M. johnson');
    assert.equal(page.bulkAssign.finalData(0).campusId, '1234567890');
    assert.equal(page.bulkAssign.finalData(0).groupName, 'group 1');
    assert.equal(page.bulkAssign.finalData(1).name, 'jackson M. johnson');
    assert.equal(page.bulkAssign.finalData(1).campusId, '12345');
    assert.equal(page.bulkAssign.finalData(1).groupName, 'group 1 child 1');
    assert.ok(page.bulkAssign.canSubmitFinalData);
    assert.equal( this.server.db.learnerGroups[0].userIds, null);
    assert.equal( this.server.db.learnerGroups[1].userIds, null);
    assert.equal( this.server.db.learnerGroups[2].userIds, null);

    await page.bulkAssign.submitFinalData();
    assert.deepEqual( this.server.db.learnerGroups[0].userIds, ['2', '3']);
    assert.deepEqual( this.server.db.learnerGroups[1].userIds, null);
    assert.deepEqual( this.server.db.learnerGroups[2].userIds, ['3']);
  });

  test('catch user already in group and do not save', async function (assert) {
    assert.expect(11);
    this.server.create('user', {
      firstName: 'jasper',
      lastName: 'johnson',
      campusId: '1234567890',
      cohortIds: [1],
      learnerGroupIds: [1],
    });
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
      learnerGroupIds: [3],
    });
    let users = [
      ['jasper', 'johnson', '1234567890'],
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();

    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 2);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    await page.bulkAssign.groupsToMatch(0).chooseGroup('2');

    assert.equal(page.bulkAssign.finalData().count, 0);

    assert.equal(page.bulkAssign.finalErrorData().count, 2);
    assert.equal(page.bulkAssign.finalErrorData(0).name, 'jasper M. johnson');
    assert.equal(page.bulkAssign.finalErrorData(0).campusId, '1234567890');
    assert.equal(page.bulkAssign.finalErrorData(0).error, 'Already in the group 1 group. Please remove them and try again.');
    assert.equal(page.bulkAssign.finalErrorData(1).name, 'jackson M. johnson');
    assert.equal(page.bulkAssign.finalErrorData(1).campusId, '12345');
    assert.equal(page.bulkAssign.finalErrorData(1).error, 'Already in the group 1 group. Please remove them and try again.');

    assert.notOk(page.bulkAssign.canSubmitFinalData);

  });

  test('create a new group when requested', async function (assert) {
    assert.expect(14);
    this.server.create('user', {
      firstName: 'jackson',
      lastName: 'johnson',
      campusId: '12345',
      cohortIds: [1],
    });
    let users = [
      ['jackson', 'johnson', '12345', '123Test'],
    ];
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();

    await triggerUpload(users, '[data-test-user-upload]');
    assert.equal(page.bulkAssign.validUploadedUsers().count, 1);
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 1);
    assert.equal( this.server.db.learnerGroups.length, 3);
    assert.equal(server.db.learnerGroups[0].userIds, null);
    await page.bulkAssign.groupsToMatch(0).createNewGroup();
    assert.equal( this.server.db.learnerGroups.length, 4);
    assert.equal( this.server.db.learnerGroups[3].userIds, null);

    assert.equal(page.bulkAssign.finalData().count, 1);
    assert.equal(page.bulkAssign.finalData(0).groupName, '123Test');
    assert.ok(page.bulkAssign.canSubmitFinalData);

    await page.bulkAssign.submitFinalData();
    assert.deepEqual( this.server.db.learnerGroups[0].userIds, ['2']);
    assert.equal( this.server.db.learnerGroups[1].userIds, null);
    assert.equal( this.server.db.learnerGroups[2].userIds, null);
    assert.equal( this.server.db.learnerGroups[3].title, '123Test');
    assert.deepEqual( this.server.db.learnerGroups[3].userIds, ['2']);
  });

  test('small group matches are trimmed', async function (assert) {
    await page.visit({ learnerGroupId: 1 });
    await page.activateBulkAssign();
    const users = this.server.createList('user', 4, {
      cohortIds: [1],
    });
    const data = users.map(obj => {
      return [
        obj.firstName,
        obj.lastName,
        obj.campusId
      ];
    });
    data[0].pushObject('group 1 child 0');
    data[1].pushObject('group 1 child 1');
    data[2].pushObject('group 1 child 1 ');
    data[3].pushObject(' group 1 child 1');
    await triggerUpload(data, '[data-test-user-upload]');
    await page.bulkAssign.confirmUploadedUsers();
    assert.equal(page.bulkAssign.groupsToMatch().count, 2);
  });
});
<|endoftext|>


<commit_before><commit_msg>Build :fire:<commit_after><|endoftext|>


<commit_before>const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const Config = require("./config");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const fs = require("fs-extra");
const path = require("path");
const postCssReporter = require("postcss-reporter");
const postCssScssSyntax = require("postcss-scss");
const program = require("commander");
const stylelint = require("stylelint");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpack = require("webpack");

/**
 * Main Kaba class
 */
class Kaba
{
    /**
     *
     */
    constructor ()
    {
        /**
         * @private
         * @type {string}
         */
        this.cwd = process.cwd();

        /**
         * @private
         * @†ype {string}
         */
        this.libRoot = path.dirname(__dirname);

        /**
         * @private
         * @type {Config}
         */
        this.config = new Config(program);

        /**
         * @private
         * @type {Object<string,string>}
         */
        this.entries = {};

        /**
         * @private
         * @type {string}
         */
        this.outputPath = "";

        /**
         * @private
         * @type {string}
         */
        this.publicPath = "";

        /**
         * @private
         * @type {Object<string,string>}
         */
        this.externals = {};

        /**
         * @private
         * @type {string[]}
         */
        this.browserList = [];

        /**
         * @private
         * @type {boolean}
         * @deprecated
         */
        this.moduleConcatenationEnabled = true;

        /**
         * @private
         * @type {string[]}
         */
        this.removeOutputSubDirectories = [];

        /**
         * @private
         * @type {string[]}
         */
        this.sassIncludePaths = [];

        /**
         * @private
         * @type {?{names: string[], minChunks: number}}
         */
        this.sharedEntryConfig = null;

        /**
         * The webpack plugins
         *
         * @private
         * @type {Array}
         */
        this.plugins = [
            new webpack.DefinePlugin({
                "process.env.NODE_ENV": this.config.isDebug() ? '"development"' : '"production"',
            }),
            new ExtractTextPlugin({
                filename: "[name].css",
            }),
            new FriendlyErrorsWebpackPlugin({
                clearConsole: this.config.isWatch(),
            }),
        ];

        // set defaults
        this
            .setOutputPath("build")
            .setPublicPath("/assets/")
            .cleanOutputDir(["css", "js"])
            .setBrowserList(["last 2 versions", "IE 11"])
        ;
    }

    /**
     * Adds an entry
     *
     * @param {Object<string,string>} mapping
     * @return {Kaba}
     */
    addEntries (mapping)
    {
        for (const name in mapping)
        {
            if (!mapping.hasOwnProperty(name))
            {
                continue;
            }

            if (this.entries[name] !== undefined)
            {
                throw new Error(`Can't add entry named ${name}: an entry with this name already exists.`);
            }

            if (null !== this.sharedEntryConfig && -1 !== this.sharedEntryConfig.names.indexOf(name))
            {
                throw new Error(`Can't add entry named ${name}: it is named like the extracted shared entries.`);
            }

            this.entries[name] = mapping[name];
        }

        return this;
    }

    /**
     * Sets the output path
     *
     * @param {string} outputPath
     * @return {Kaba}
     */
    setOutputPath (outputPath)
    {
        this.outputPath = path.join(this.cwd, outputPath);
        return this;
    }

    /**
     * Sets the relative public path (for automatic imports)
     *
     * @param {string} publicPath relative to the cwd
     * @return {Kaba}
     */
    setPublicPath (publicPath)
    {
        this.publicPath = publicPath;
        return this;
    }

    /**
     *
     * @param {Object<string,string>} externals
     * @return {Kaba}
     */
    setExternals (externals)
    {
        this.externals = externals;
        return this;
    }

    /**
     * Sets the browser list
     *
     * @param {string[]} list
     * @return {Kaba}
     */
    setBrowserList (list)
    {
        this.browserList = list;
        return this;
    }

    /**
     * Disabled module concatenation
     *
     * @deprecated will be removed, as soon as webpack is updated to v4
     * @return {Kaba}
     */
    disableModuleConcatenation ()
    {
        this.moduleConcatenationEnabled = false;
        return this;
    }

    /**
     * Creates a shared vendor entry name
     *
     * @param {string[]} vendorFiles
     * @param {string} vendorName
     * @param {string|null} runtimeName
     * @return {Kaba}
     */
    extractSharedEntry (vendorFiles = [], vendorName = "vendor", runtimeName = "runtime")
    {
        if (null === vendorName)
        {
            throw new Error("extractSharedLibraries() failed: vendorName can not be null.");
        }

        if (this.sharedEntryConfig !== null)
        {
            throw new Error("extractSharedLibraries() can only be called once: only one vendor entry can be created.");
        }

        if (this.entries[vendorName] !== undefined)
        {
            throw new Error("Cannot extract shared entry: there already is a regular entry with the same name as the vendor name.");
        }

        if (runtimeName !== null && this.entries[runtimeName] !== undefined)
        {
            throw new Error("Cannot extract shared entry: there already is a regular entry with the same name as the runtime name.");
        }

        const names = [vendorName];

        if (null !== runtimeName)
        {
            names.push(runtimeName);
        }

        // first add entry, as it checks the name for conflicts with the shared entry config name
        if (vendorFiles.length > 0)
        {
            this.addEntries({
                [vendorName]: vendorFiles,
            });
        }

        this.sharedEntryConfig = {
            names: names,
            minChunks: 3,
        };

        this.plugins.push(
            new webpack.optimize.CommonsChunkPlugin(this.sharedEntryConfig),
        );

        return this;
    }

    /**
     * Enables cleaning the output dir before the build
     *
     * @param {string[]} subDirectories
     * @return {Kaba}
     */
    cleanOutputDir (subDirectories)
    {
        this.removeOutputSubDirectories = subDirectories;
        return this;
    }

    /**
     * Adds `node_modules` to the include dir of sass.
     *
     * @return {Kaba}
     */
    enableSassNodeModulesIncludePaths ()
    {
        this.sassIncludePaths = [
            path.join(this.cwd, "node_modules"),
        ];
        return this;
    }

    /**
     * Returns the built webpack config
     *
     * @return {Object}
     */
    getWebpackConfig ()
    {
        // clean output sub directories
        this.removeOutputSubDirectories.map(
            (dir) => fs.removeSync(path.join(this.outputPath, dir))
        );

        const stylelintLoader = [];

        if (this.config.isLint())
        {
            stylelintLoader.push({
                loader: "postcss-loader",
                options: {
                    syntax: postCssScssSyntax,
                    plugins: [
                        stylelint({
                            configFile: path.join(this.libRoot, ".stylelintrc.yml"),
                        }),
                        postCssReporter({
                            clearMessages: true,
                        }),
                    ],
                },
            });
        }

        /** @type {webpack.options} config */
        const config = {
            // entry
            entry: this.entries,

            // output
            output: {
                path: this.outputPath,
                filename: '[name].js',
                chunkFilename: 'chunk.[name].js',
                publicPath: this.publicPath,
                pathinfo: !this.config.isDebug(),
            },

            // module
            module: {
                rules: [
                    // Babel
                    {
                        test: /\.jsx?$/,
                        loader: "babel-loader?cacheDirectory",
                        options: {
                            babelrc: false,
                            presets: [
                                require("kaba-babel-preset"),
                            ],
                        },
                    },
                    // TypeScript
                    {
                        test: /\.tsx?$/,
                        use: [
                            // run TypeScript through Babel, so that ES5 compatibility is ensured
                            {
                                loader: "babel-loader?cacheDirectory",
                                options: {
                                    babelrc: false,
                                    presets: [
                                        require("kaba-babel-preset"),
                                    ],
                                },
                            },
                            {
                                loader: "awesome-typescript-loader",
                                query: {
                                    configFileName: path.join(this.libRoot, "tsconfig.json"),
                                },
                            },
                        ],
                    },
                    // SCSS
                    {
                        test: /\.scss$/,
                        use: ExtractTextPlugin.extract({
                            use: [
                                {
                                    loader: "css-loader",
                                    options: {
                                        url: false,
                                        import: false,
                                        modules: false,
                                        minimize: !this.config.isDebug(),
                                        sourceMap: this.config.includeSourceMaps(),
                                    },
                                },
                                {
                                    loader: "postcss-loader",
                                    options: {
                                        plugins: [
                                            require("autoprefixer")({
                                                browsers: this.browserList,
                                            }),
                                        ],
                                        sourceMap: this.config.includeSourceMaps(),
                                    },
                                },
                                {
                                    loader: "sass-loader",
                                    options: {
                                        outputStyle: "compact",
                                        sourceMapEmbed: this.config.includeSourceMaps(),
                                        includePaths: this.sassIncludePaths,
                                    },
                                },
                            ].concat(stylelintLoader),
                        }),
                    },
                ],
            },

            // resolve
            resolve: {
                extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
                modules: [
                    path.join(this.cwd, "node_modules"),
                    path.join(this.libRoot, "node_modules"),
                ],
            },

            // performance

            // context
            context: this.cwd,

            // target
            target: "web",

            // externals
            externals: this.externals,

            // stats
            stats: {
                // hide children information (like from the ExtractTextPlugin)
                children: false,
                // errors are shown through the FriendlyErrorsWebpackPlugin instead
                errors: false,
            },

            // devServer

            // plugins
            plugins: this.plugins,

            // watch
            watch: this.config.isWatch(),

            // node
            // don't automatically polyfill certain node libraries
            // as we don't care about these implementations and they just add weight
            node: false,
        };

        // @deprecated
        // in webpack 4 this will always be enabled
        if (this.moduleConcatenationEnabled)
        {
            config.plugins.push(
                new webpack.optimize.ModuleConcatenationPlugin(),
            );
        }

        if (this.config.isDebug() || this.config.includeSourceMaps())
        {
            config.devtool = this.config.isDebug()
                ? "inline-source-map"
                : "hidden-source-map";
        }
        else
        {
            config.plugins.push(
                new UglifyJsPlugin({
                    uglifyOptions: {
                        warnings: false,
                        //eslint-disable-next-line camelcase
                        drop_console: false,
                    },
                    parallel: true,
                    extractComments: true,
                    sourceMap: this.config.isDebug(),
                }),
            );
        }

        if (this.config.isLint())
        {
            config.module.rules.push({
                enforce: "pre",
                test: /\.jsx?$/,
                exclude: /node_modules|vendor/,
                loader: "eslint-loader",
                options: {
                    cache: true,
                    configFile: path.join(this.libRoot, ".eslintrc.yml"),
                    parser: "babel-eslint",
                },
            });
        }

        if (this.config.isBundleAnalyzerEnabled())
        {
            config.plugins.push(new BundleAnalyzerPlugin());
        }

        return config;
    }
}

module.exports = Kaba;
<commit_msg>Simplify conditionals about source maps<commit_after>const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const Config = require("./config");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const fs = require("fs-extra");
const path = require("path");
const postCssReporter = require("postcss-reporter");
const postCssScssSyntax = require("postcss-scss");
const program = require("commander");
const stylelint = require("stylelint");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpack = require("webpack");

/**
 * Main Kaba class
 */
class Kaba
{
    /**
     *
     */
    constructor ()
    {
        /**
         * @private
         * @type {string}
         */
        this.cwd = process.cwd();

        /**
         * @private
         * @†ype {string}
         */
        this.libRoot = path.dirname(__dirname);

        /**
         * @private
         * @type {Config}
         */
        this.config = new Config(program);

        /**
         * @private
         * @type {Object<string,string>}
         */
        this.entries = {};

        /**
         * @private
         * @type {string}
         */
        this.outputPath = "";

        /**
         * @private
         * @type {string}
         */
        this.publicPath = "";

        /**
         * @private
         * @type {Object<string,string>}
         */
        this.externals = {};

        /**
         * @private
         * @type {string[]}
         */
        this.browserList = [];

        /**
         * @private
         * @type {boolean}
         * @deprecated
         */
        this.moduleConcatenationEnabled = true;

        /**
         * @private
         * @type {string[]}
         */
        this.removeOutputSubDirectories = [];

        /**
         * @private
         * @type {string[]}
         */
        this.sassIncludePaths = [];

        /**
         * @private
         * @type {?{names: string[], minChunks: number}}
         */
        this.sharedEntryConfig = null;

        /**
         * The webpack plugins
         *
         * @private
         * @type {Array}
         */
        this.plugins = [
            new webpack.DefinePlugin({
                "process.env.NODE_ENV": this.config.isDebug() ? '"development"' : '"production"',
            }),
            new ExtractTextPlugin({
                filename: "[name].css",
            }),
            new FriendlyErrorsWebpackPlugin({
                clearConsole: this.config.isWatch(),
            }),
        ];

        // set defaults
        this
            .setOutputPath("build")
            .setPublicPath("/assets/")
            .cleanOutputDir(["css", "js"])
            .setBrowserList(["last 2 versions", "IE 11"])
        ;
    }

    /**
     * Adds an entry
     *
     * @param {Object<string,string>} mapping
     * @return {Kaba}
     */
    addEntries (mapping)
    {
        for (const name in mapping)
        {
            if (!mapping.hasOwnProperty(name))
            {
                continue;
            }

            if (this.entries[name] !== undefined)
            {
                throw new Error(`Can't add entry named ${name}: an entry with this name already exists.`);
            }

            if (null !== this.sharedEntryConfig && -1 !== this.sharedEntryConfig.names.indexOf(name))
            {
                throw new Error(`Can't add entry named ${name}: it is named like the extracted shared entries.`);
            }

            this.entries[name] = mapping[name];
        }

        return this;
    }

    /**
     * Sets the output path
     *
     * @param {string} outputPath
     * @return {Kaba}
     */
    setOutputPath (outputPath)
    {
        this.outputPath = path.join(this.cwd, outputPath);
        return this;
    }

    /**
     * Sets the relative public path (for automatic imports)
     *
     * @param {string} publicPath relative to the cwd
     * @return {Kaba}
     */
    setPublicPath (publicPath)
    {
        this.publicPath = publicPath;
        return this;
    }

    /**
     *
     * @param {Object<string,string>} externals
     * @return {Kaba}
     */
    setExternals (externals)
    {
        this.externals = externals;
        return this;
    }

    /**
     * Sets the browser list
     *
     * @param {string[]} list
     * @return {Kaba}
     */
    setBrowserList (list)
    {
        this.browserList = list;
        return this;
    }

    /**
     * Disabled module concatenation
     *
     * @deprecated will be removed, as soon as webpack is updated to v4
     * @return {Kaba}
     */
    disableModuleConcatenation ()
    {
        this.moduleConcatenationEnabled = false;
        return this;
    }

    /**
     * Creates a shared vendor entry name
     *
     * @param {string[]} vendorFiles
     * @param {string} vendorName
     * @param {string|null} runtimeName
     * @return {Kaba}
     */
    extractSharedEntry (vendorFiles = [], vendorName = "vendor", runtimeName = "runtime")
    {
        if (null === vendorName)
        {
            throw new Error("extractSharedLibraries() failed: vendorName can not be null.");
        }

        if (this.sharedEntryConfig !== null)
        {
            throw new Error("extractSharedLibraries() can only be called once: only one vendor entry can be created.");
        }

        if (this.entries[vendorName] !== undefined)
        {
            throw new Error("Cannot extract shared entry: there already is a regular entry with the same name as the vendor name.");
        }

        if (runtimeName !== null && this.entries[runtimeName] !== undefined)
        {
            throw new Error("Cannot extract shared entry: there already is a regular entry with the same name as the runtime name.");
        }

        const names = [vendorName];

        if (null !== runtimeName)
        {
            names.push(runtimeName);
        }

        // first add entry, as it checks the name for conflicts with the shared entry config name
        if (vendorFiles.length > 0)
        {
            this.addEntries({
                [vendorName]: vendorFiles,
            });
        }

        this.sharedEntryConfig = {
            names: names,
            minChunks: 3,
        };

        this.plugins.push(
            new webpack.optimize.CommonsChunkPlugin(this.sharedEntryConfig),
        );

        return this;
    }

    /**
     * Enables cleaning the output dir before the build
     *
     * @param {string[]} subDirectories
     * @return {Kaba}
     */
    cleanOutputDir (subDirectories)
    {
        this.removeOutputSubDirectories = subDirectories;
        return this;
    }

    /**
     * Adds `node_modules` to the include dir of sass.
     *
     * @return {Kaba}
     */
    enableSassNodeModulesIncludePaths ()
    {
        this.sassIncludePaths = [
            path.join(this.cwd, "node_modules"),
        ];
        return this;
    }

    /**
     * Returns the built webpack config
     *
     * @return {Object}
     */
    getWebpackConfig ()
    {
        // clean output sub directories
        this.removeOutputSubDirectories.map(
            (dir) => fs.removeSync(path.join(this.outputPath, dir))
        );

        const stylelintLoader = [];

        if (this.config.isLint())
        {
            stylelintLoader.push({
                loader: "postcss-loader",
                options: {
                    syntax: postCssScssSyntax,
                    plugins: [
                        stylelint({
                            configFile: path.join(this.libRoot, ".stylelintrc.yml"),
                        }),
                        postCssReporter({
                            clearMessages: true,
                        }),
                    ],
                },
            });
        }

        /** @type {webpack.options} config */
        const config = {
            // entry
            entry: this.entries,

            // output
            output: {
                path: this.outputPath,
                filename: '[name].js',
                chunkFilename: 'chunk.[name].js',
                publicPath: this.publicPath,
                pathinfo: !this.config.isDebug(),
            },

            // module
            module: {
                rules: [
                    // Babel
                    {
                        test: /\.jsx?$/,
                        loader: "babel-loader?cacheDirectory",
                        options: {
                            babelrc: false,
                            presets: [
                                require("kaba-babel-preset"),
                            ],
                        },
                    },
                    // TypeScript
                    {
                        test: /\.tsx?$/,
                        use: [
                            // run TypeScript through Babel, so that ES5 compatibility is ensured
                            {
                                loader: "babel-loader?cacheDirectory",
                                options: {
                                    babelrc: false,
                                    presets: [
                                        require("kaba-babel-preset"),
                                    ],
                                },
                            },
                            {
                                loader: "awesome-typescript-loader",
                                query: {
                                    configFileName: path.join(this.libRoot, "tsconfig.json"),
                                },
                            },
                        ],
                    },
                    // SCSS
                    {
                        test: /\.scss$/,
                        use: ExtractTextPlugin.extract({
                            use: [
                                {
                                    loader: "css-loader",
                                    options: {
                                        url: false,
                                        import: false,
                                        modules: false,
                                        minimize: !this.config.isDebug(),
                                        sourceMap: this.config.includeSourceMaps(),
                                    },
                                },
                                {
                                    loader: "postcss-loader",
                                    options: {
                                        plugins: [
                                            require("autoprefixer")({
                                                browsers: this.browserList,
                                            }),
                                        ],
                                        sourceMap: this.config.includeSourceMaps(),
                                    },
                                },
                                {
                                    loader: "sass-loader",
                                    options: {
                                        outputStyle: "compact",
                                        sourceMapEmbed: this.config.includeSourceMaps(),
                                        includePaths: this.sassIncludePaths,
                                    },
                                },
                            ].concat(stylelintLoader),
                        }),
                    },
                ],
            },

            // resolve
            resolve: {
                extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
                modules: [
                    path.join(this.cwd, "node_modules"),
                    path.join(this.libRoot, "node_modules"),
                ],
            },

            // performance

            // context
            context: this.cwd,

            // target
            target: "web",

            // externals
            externals: this.externals,

            // stats
            stats: {
                // hide children information (like from the ExtractTextPlugin)
                children: false,
                // errors are shown through the FriendlyErrorsWebpackPlugin instead
                errors: false,
            },

            // devServer

            // plugins
            plugins: this.plugins,

            // watch
            watch: this.config.isWatch(),

            // node
            // don't automatically polyfill certain node libraries
            // as we don't care about these implementations and they just add weight
            node: false,
        };

        // @deprecated
        // in webpack 4 this will always be enabled
        if (this.moduleConcatenationEnabled)
        {
            config.plugins.push(
                new webpack.optimize.ModuleConcatenationPlugin(),
            );
        }

        if (this.config.includeSourceMaps())
        {
            config.devtool = this.config.isDebug()
                ? "inline-source-map"
                : "hidden-source-map";
        }
        else
        {
            config.plugins.push(
                new UglifyJsPlugin({
                    uglifyOptions: {
                        warnings: false,
                        //eslint-disable-next-line camelcase
                        drop_console: false,
                    },
                    parallel: true,
                    extractComments: true,
                    sourceMap: true,
                }),
            );
        }

        if (this.config.isLint())
        {
            config.module.rules.push({
                enforce: "pre",
                test: /\.jsx?$/,
                exclude: /node_modules|vendor/,
                loader: "eslint-loader",
                options: {
                    cache: true,
                    configFile: path.join(this.libRoot, ".eslintrc.yml"),
                    parser: "babel-eslint",
                },
            });
        }

        if (this.config.isBundleAnalyzerEnabled())
        {
            config.plugins.push(new BundleAnalyzerPlugin());
        }

        return config;
    }
}

module.exports = Kaba;
<|endoftext|>