浏览代码

Replace lodash methods with native ones and remove lodash.fp

JC Brand 6 年之前
父节点
当前提交
6193a9dc80

+ 3 - 3
spec/converse.js

@@ -261,7 +261,7 @@
                 // You can retrieve multiple contacts by passing in an array
                 const jid2 = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
                 let list = await _converse.api.contacts.get([jid, jid2]);
-                expect(_.isArray(list)).toBeTruthy();
+                expect(Array.isArray(list)).toBeTruthy();
                 expect(list[0].get('fullname')).toBe(mock.cur_names[0]);
                 expect(list[1].get('fullname')).toBe(mock.cur_names[1]);
                 // Check that all JIDs are returned if you call without any parameters
@@ -313,7 +313,7 @@
                 test_utils.openChatBoxFor(_converse, jid2);
                 await test_utils.waitUntil(() => _converse.chatboxes.length == 2);
                 const list = _converse.api.chats.get([jid, jid2]);
-                expect(_.isArray(list)).toBeTruthy();
+                expect(Array.isArray(list)).toBeTruthy();
                 expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
                 expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
                 done();
@@ -343,7 +343,7 @@
                 expect(u.isVisible(chatboxview.el)).toBeTruthy();
                 // Test for multiple JIDs
                 const list = await _converse.api.chats.open([jid, jid2]);
-                expect(_.isArray(list)).toBeTruthy();
+                expect(Array.isArray(list)).toBeTruthy();
                 expect(list[0].get('box_id')).toBe(`box-${btoa(jid)}`);
                 expect(list[1].get('box_id')).toBe(`box-${btoa(jid2)}`);
                 done();

+ 2 - 3
spec/push.js

@@ -5,7 +5,6 @@
     const $iq = converse.env.$iq;
     const Strophe = converse.env.Strophe;
     const _ = converse.env._;
-    const f = converse.env.f;
 
     describe("XEP-0357 Push Notifications", function () {
 
@@ -30,7 +29,7 @@
                     _converse.bare_jid,
                     [{'category': 'account', 'type':'registered'}],
                     ['urn:xmpp:push:0'], [], 'info');
-            const node = await test_utils.waitUntil(() => 
+            const node = await test_utils.waitUntil(() =>
                 _.filter(IQ_stanzas, iq => iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]')).pop()
             );
             const stanza = node.nodeTree;
@@ -84,7 +83,7 @@
                 'type': 'result',
                 'id': stanza.nodeTree.getAttribute('id')
             })));
-            await test_utils.waitUntil(() => f.includes('chat.shakespeare.lit', _converse.session.get('push_enabled')));
+            await test_utils.waitUntil(() => _.includes(_converse.session.get('push_enabled'), 'chat.shakespeare.lit'));
             done();
         }));
 

+ 5 - 8
src/converse-chatview.js

@@ -28,7 +28,7 @@ import tpl_user_details_modal from "templates/user_details_modal.html";
 import u from "@converse/headless/utils/emoji";
 import xss from "xss/dist/xss";
 
-const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, dayjs } = converse.env;
+const { $msg, Backbone, Promise, Strophe, _, b64_sha1, sizzle, dayjs } = converse.env;
 
 
 converse.plugins.add('converse-chatview', {
@@ -593,10 +593,7 @@ converse.plugins.add('converse-chatview', {
             },
 
             clearSpinner () {
-                _.each(
-                    this.content.querySelectorAll('span.spinner'),
-                    (el) => el.parentNode.removeChild(el)
-                );
+                this.content.querySelectorAll('.spinner').forEach(u.removeElement);
             },
 
             /**
@@ -696,7 +693,7 @@ converse.plugins.add('converse-chatview', {
             },
 
             showHelpMessages (msgs, type, spinner) {
-                _.each(msgs, (msg) => {
+                msgs.forEach(msg => {
                     this.content.insertAdjacentHTML(
                         'beforeend',
                         tpl_help_message({
@@ -996,7 +993,7 @@ converse.plugins.add('converse-chatview', {
             },
 
             getOwnMessages () {
-                return f(this.model.messages.filter({'sender': 'me'}));
+                return this.model.messages.filter({'sender': 'me'});
             },
 
             onEscapePressed (ev) {
@@ -1065,7 +1062,7 @@ converse.plugins.add('converse-chatview', {
                         }
                     }
                 }
-                message = message || this.getOwnMessages().findLast((msg) => msg.get('message'));
+                message = message || _.findLast(this.getOwnMessages(), msg => msg.get('message'));
                 if (message) {
                     this.insertIntoTextArea(message.get('message'), true, true);
                     message.save('correcting', true);

+ 0 - 1
src/converse-controlbox.js

@@ -12,7 +12,6 @@ import "converse-rosterview";
 import _FormData from "formdata-polyfill";
 import bootstrap from "bootstrap.native";
 import converse from "@converse/headless/converse-core";
-import fp from "@converse/headless/lodash.fp";
 import tpl_brand_heading from "templates/converse_brand_heading.html";
 import tpl_controlbox from "templates/controlbox.html";
 import tpl_controlbox_toggle from "templates/controlbox_toggle.html";

+ 1 - 1
src/converse-embedded.js

@@ -26,7 +26,7 @@ converse.plugins.add('converse-embedded', {
             'hide_muc_server': true
         });
         const { _converse } = this;
-        if (!_.isArray(_converse.auto_join_rooms) && !_.isArray(_converse.auto_join_private_chats)) {
+        if (!Array.isArray(_converse.auto_join_rooms) && !_.isArray(_converse.auto_join_private_chats)) {
             throw new Error("converse-embedded: auto_join_rooms must be an Array");
         }
         if (_converse.auto_join_rooms.length > 1 && _converse.auto_join_private_chats.length > 1) {

+ 45 - 45
src/converse-muc-views.js

@@ -38,7 +38,7 @@ import tpl_spinner from "templates/spinner.html";
 import xss from "xss/dist/xss";
 
 
-const { Backbone, Promise, Strophe, dayjs, f, sizzle, _, $build, $iq, $msg, $pres } = converse.env;
+const { Backbone, Promise, Strophe, dayjs, sizzle, _, $build, $iq, $msg, $pres } = converse.env;
 const u = converse.env.utils;
 const AFFILIATION_CHANGE_COMANDS = ['admin', 'ban', 'owner', 'member', 'revoke'];
 const OWNER_COMMANDS = ['owner'];
@@ -341,9 +341,7 @@ converse.plugins.add('converse-muc-views', {
             },
 
             removeSpinner () {
-                _.each(this.el.querySelectorAll('span.spinner'),
-                    (el) => el.parentNode.removeChild(el)
-                );
+                sizzle('.spinner', this.el).forEach(u.removeElement);
             },
 
             informNoRoomsFound () {
@@ -359,12 +357,14 @@ converse.plugins.add('converse-muc-views', {
                  * all its public groupchats.
                  */
                 const available_chatrooms = this.el.querySelector('.available-chatrooms');
-                this.rooms = iq.querySelectorAll('query item');
-                if (this.rooms.length) {
+                const rooms = sizzle('query item', iq);
+                if (rooms.length) {
                     available_chatrooms.innerHTML = tpl_rooms_results({'feedback_text': __('Groupchats found:')});
                     const fragment = document.createDocumentFragment();
-                    const children = _.reject(_.map(this.rooms, this.roomStanzaItemToHTMLElement), _.isNil)
-                    _.each(children, (child) => fragment.appendChild(child));
+                    rooms.map(this.roomStanzaItemToHTMLElement)
+                         .filter(r => r)
+                         .forEach(child => fragment.appendChild(child));
+
                     available_chatrooms.appendChild(fragment);
                     this.removeSpinner();
                 } else {
@@ -890,26 +890,28 @@ converse.plugins.add('converse-muc-views', {
                 if (!occupant) {
                     occupant = this.model.occupants.findWhere({'jid': _converse.bare_jid});
                 }
-                if (!_.includes(roles, occupant.get('role'))) {
-                    if (show_error) {
-                        this.showErrorMessage(__('Forbidden: you do not have the necessary role in order to do that.'))
-                    }
-                    return false;
+                const role = occupant.get('role');
+                if (Array.isArray(roles) && roles.includes(role) || roles === role) {
+                    return true;
                 }
-                return true;
+                if (show_error) {
+                    this.showErrorMessage(__('Forbidden: you do not have the necessary role in order to do that.'))
+                }
+                return false;
             },
 
             verifyAffiliations (affiliations, occupant, show_error=true) {
                 if (!occupant) {
                     occupant = this.model.occupants.findWhere({'jid': _converse.bare_jid});
                 }
-                if (!_.includes(affiliations, occupant.get('affiliation'))) {
-                    if (show_error) {
-                        this.showErrorMessage(__('Forbidden: you do not have the necessary affiliation in order to do that.'))
-                    }
-                    return false;
+                const a = occupant.get('affiliation');
+                if (Array.isArray(affiliations) && affiliations.includes(a) || affiliations === a) {
+                    return true;
                 }
-                return true;
+                if (show_error) {
+                    this.showErrorMessage(__('Forbidden: you do not have the necessary affiliation in order to do that.'))
+                }
+                return false;
             },
 
             validateRoleChangeCommand (command, args) {
@@ -922,9 +924,9 @@ converse.plugins.add('converse-muc-views', {
                     );
                     return false;
                 }
-                if (!(_.includes(AFFILIATION_CHANGE_COMANDS, command) && u.isValidJID(args[0])) &&
+                if (!(AFFILIATION_CHANGE_COMANDS.includes(command) && u.isValidJID(args[0])) &&
                         !this.model.occupants.findWhere({'nick': args[0]}) &&
-                            !this.model.occupants.findWhere({'jid': args[0]})) {
+                        !this.model.occupants.findWhere({'jid': args[0]})) {
                     this.showErrorMessage(__('Error: couldn\'t find a groupchat participant "%1$s"', args[0]));
                     return false;
                 }
@@ -937,14 +939,13 @@ converse.plugins.add('converse-muc-views', {
             },
 
             parseMessageForCommands (text) {
-                if (_converse.muc_disable_slash_commands &&
-                        !_.isArray(_converse.muc_disable_slash_commands)) {
+                if (_converse.muc_disable_slash_commands && !Array.isArray(_converse.muc_disable_slash_commands)) {
                     return _converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments);
                 }
                 const match = text.replace(/^\s*/, "").match(/^\/(.*?)(?: (.*))?$/) || [false, '', ''],
                       args = match[2] && match[2].splitOnce(' ').filter(s => s) || [],
                       command = match[1].toLowerCase(),
-                      disabled_commands = _.isArray(_converse.muc_disable_slash_commands) ?
+                      disabled_commands = Array.isArray(_converse.muc_disable_slash_commands) ?
                         _converse.muc_disable_slash_commands : [];
                 if (_.includes(disabled_commands, command)) {
                     return false;
@@ -992,7 +993,7 @@ converse.plugins.add('converse-muc-views', {
                         break;
                     }
                     case 'destroy': {
-                        if (!this.verifyAffiliations(['owner'])) {
+                        if (!this.verifyAffiliations('owner')) {
                             break;
                         }
                         this.destroy(this.model.get('jid'), args[0])
@@ -1374,7 +1375,8 @@ converse.plugins.add('converse-muc-views', {
             showDestroyedMessage (error) {
                 u.hideElement(this.el.querySelector('.chat-area'));
                 u.hideElement(this.el.querySelector('.occupants'));
-                _.each(this.el.querySelectorAll('.spinner'), u.removeElement);
+                sizzle('.spinner', this.el).forEach(u.removeElement);
+
                 const container = this.el.querySelector('.disconnect-container');
                 const moved_jid = _.get(
                         sizzle('gone[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]', error).pop(),
@@ -1410,7 +1412,7 @@ converse.plugins.add('converse-muc-views', {
                 }
                 u.hideElement(this.el.querySelector('.chat-area'));
                 u.hideElement(this.el.querySelector('.occupants'));
-                _.each(this.el.querySelectorAll('.spinner'), u.removeElement);
+                sizzle('.spinner', this.el).forEach(u.removeElement);
                 const container = this.el.querySelector('.disconnect-container');
                 container.innerHTML = tpl_chatroom_disconnect({
                     '_': _,
@@ -1524,7 +1526,7 @@ converse.plugins.add('converse-muc-views', {
                     this.model.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
                     return;
                 }
-                _.each(notification.messages, (message) => {
+                notification.messages.forEach(message => {
                     this.content.insertAdjacentHTML(
                         'beforeend',
                         tpl_info({
@@ -1709,7 +1711,7 @@ converse.plugins.add('converse-muc-views', {
                 const is_self = stanza.querySelectorAll("status[code='110']").length;
                 const iteratee = _.partial(this.parseXUserElement.bind(this), _, stanza, is_self);
                 const notifications = _.reject(_.map(elements, iteratee), _.isEmpty);
-                _.each(notifications, this.showNotificationsforUser.bind(this));
+                notifications.forEach(n => this.showNotificationsforUser(n));
             },
 
             showErrorMessageFromPresence (presence) {
@@ -1768,7 +1770,7 @@ converse.plugins.add('converse-muc-views', {
             },
 
             showSpinner () {
-                u.removeElement(this.el.querySelector('.spinner'));
+                sizzle('.spinner', this.el).forEach(u.removeElement);
                 this.hideChatRoomContents();
                 const container_el = this.el.querySelector('.chatroom-body');
                 container_el.insertAdjacentHTML('afterbegin', tpl_spinner());
@@ -2075,7 +2077,7 @@ converse.plugins.add('converse-muc-views', {
                       picks = _.pick(features.attributes, converse.ROOM_FEATURES),
                       iteratee = (a, v) => a || v;
 
-                if (_.reduce(_.values(picks), iteratee)) {
+                if (_.reduce(Object.values(picks), iteratee)) {
                     const el = this.el.querySelector('.chatroom-features');
                     el.innerHTML = tpl_chatroom_features(Object.assign(features.toJSON(), {__}));
                     this.setOccupantsHeight();
@@ -2283,7 +2285,7 @@ converse.plugins.add('converse-muc-views', {
                  *
                  */
                 get (jids) {
-                    if (_.isArray(jids)) {
+                    if (Array.isArray(jids)) {
                         const views = _converse.api.chatviews.get(jids);
                         return views.filter(v => v.model.get('type') === _converse.CHATROOMS_TYPE)
                     } else {
@@ -2306,21 +2308,19 @@ converse.plugins.add('converse-muc-views', {
                  * @param {(String[]|String)} jids The JID or array of JIDs of the chatroom(s)
                  */
                 'close' (jids) {
+                    let views;
                     if (_.isUndefined(jids)) {
-                        _converse.chatboxviews.each(function (view) {
-                            if (view.is_chatroom && view.model) {
-                                view.close();
-                            }
-                        });
+                        views = _converse.chatboxviews;
                     } else if (_.isString(jids)) {
-                        const view = _converse.chatboxviews.get(jids);
-                        if (view) { view.close(); }
-                    } else {
-                        _.each(jids, function (jid) {
-                            const view = _converse.chatboxviews.get(jid);
-                            if (view) { view.close(); }
-                        });
+                        views = [_converse.chatboxviews.get(jids)].filter(v => v);
+                    } else if (Array.isArray(jids)) {
+                        views = jids.map(jid => _converse.chatboxviews.get(jid));
                     }
+                    views.forEach(view => {
+                        if (view.is_chatroom && view.model) {
+                            view.close();
+                        }
+                    });
                 }
             }
         });

+ 1 - 1
src/converse-notification.js

@@ -66,7 +66,7 @@ converse.plugins.add('converse-notification', {
             }
             const mentioned = (new RegExp(`\\b${room.get('nick')}\\b`)).test(body.textContent);
             notify_all = notify_all === true ||
-                (_.isArray(notify_all) && _.includes(notify_all, room_jid));
+                (Array.isArray(notify_all) && _.includes(notify_all, room_jid));
             if (sender === room.get('nick') || (!notify_all && !mentioned)) {
                 return false;
             }

+ 2 - 2
src/converse-omemo.js

@@ -9,7 +9,7 @@
 import converse from "@converse/headless/converse-core";
 import tpl_toolbar_omemo from "templates/toolbar_omemo.html";
 
-const { Backbone, Promise, Strophe, dayjs, sizzle, $build, $iq, $msg, _, f } = converse.env;
+const { Backbone, Promise, Strophe, dayjs, sizzle, $build, $iq, $msg, _ } = converse.env;
 const u = converse.env.utils;
 
 Strophe.addNamespace('OMEMO_DEVICELIST', Strophe.NS.OMEMO+".devicelist");
@@ -67,7 +67,7 @@ function parseBundle (bundle_el) {
 converse.plugins.add('converse-omemo', {
 
     enabled (_converse) {
-        return !_.isNil(window.libsignal) && !f.includes('converse-omemo', _converse.blacklisted_plugins) && _converse.config.get('trusted');
+        return !_.isNil(window.libsignal) && !_converse.blacklisted_plugins.includes('converse-omemo') && _converse.config.get('trusted');
     },
 
     dependencies: ["converse-chatview", "converse-pubsub"],

+ 11 - 19
src/converse-register.js

@@ -438,7 +438,7 @@ converse.plugins.add('converse-register', {
             },
 
             renderLegacyRegistrationForm (form) {
-                _.each(Object.keys(this.fields), (key) => {
+                Object.keys(this.fields).forEach(key => {
                     if (key === "username") {
                         form.insertAdjacentHTML(
                             'beforeend',
@@ -466,12 +466,10 @@ converse.plugins.add('converse-register', {
                     }
                 });
                 // Show urls
-                _.each(this.urls, (url) => {
-                    form.insertAdjacentHTML(
-                        'afterend',
-                        '<a target="blank" rel="noopener" href="'+url+'">'+url+'</a>'
-                    );
-                });
+                this.urls.forEach(u => form.insertAdjacentHTML(
+                    'afterend',
+                    '<a target="blank" rel="noopener" href="'+u+'">'+u+'</a>'
+                ));
             },
 
             /**
@@ -493,7 +491,7 @@ converse.plugins.add('converse-register', {
 
                 const buttons = form.querySelector('fieldset.buttons');
                 if (this.form_type === 'xform') {
-                    _.each(stanza.querySelectorAll('field'), (field) => {
+                    stanza.querySelectorAll('field').forEach(field => {
                         buttons.insertAdjacentHTML(
                             'beforebegin',
                             utils.xForm2webForm(field, stanza, {'domain': this.domain})
@@ -540,9 +538,7 @@ converse.plugins.add('converse-register', {
              */
             reportErrors (stanza) {
                 const errors = stanza.querySelectorAll('error');
-                _.each(errors, (error) => {
-                    this.showValidationError(error.textContent);
-                });
+                errors.forEach(e => this.showValidationError(e.textContent));
                 if (!errors.length) {
                     const message = __('The provider rejected your registration attempt. '+
                         'Please check the values you entered for correctness.');
@@ -596,13 +592,9 @@ converse.plugins.add('converse-register', {
 
                 if (this.form_type === 'xform') {
                     iq.c("x", {xmlns: Strophe.NS.XFORM, type: 'submit'});
-                    _.each(inputs, (input) => {
-                        iq.cnode(utils.webForm2xForm(input)).up();
-                    });
+                    inputs.forEach(input => iq.cnode(utils.webForm2xForm(input)).up());
                 } else {
-                    _.each(inputs, (input) => {
-                        iq.c(input.getAttribute('name'), {}, input.value);
-                    });
+                    inputs.forEach(input => iq.c(input.getAttribute('name'), {}, input.value));
                 }
                 _converse.connection._addSysHandler(this._onRegisterIQ.bind(this), null, "iq", null, null);
                 _converse.connection.send(iq);
@@ -625,7 +617,7 @@ converse.plugins.add('converse-register', {
             },
 
             _setFieldsFromLegacy (query) {
-                _.each(query.children, (field) => {
+                [].forEach.call(query.children, field => {
                     if (field.tagName.toLowerCase() === 'instructions') {
                         this.instructions = Strophe.getText(field);
                         return;
@@ -643,7 +635,7 @@ converse.plugins.add('converse-register', {
             _setFieldsFromXForm (xform) {
                 this.title = _.get(xform.querySelector('title'), 'textContent');
                 this.instructions = _.get(xform.querySelector('instructions'), 'textContent');
-                _.each(xform.querySelectorAll('field'), (field) => {
+                xform.querySelectorAll('field').forEach(field => {
                     const _var = field.getAttribute('var');
                     if (_var) {
                         this.fields[_var.toLowerCase()] = _.get(field.querySelector('value'), 'textContent', '');

+ 1 - 1
src/converse.js

@@ -57,7 +57,7 @@ const WHITELISTED_PLUGINS = [
 const initialize = converse.initialize;
 
 converse.initialize = function (settings, callback) {
-    if (converse.env._.isArray(settings.whitelisted_plugins)) {
+    if (Array.isArray(settings.whitelisted_plugins)) {
         settings.whitelisted_plugins = settings.whitelisted_plugins.concat(WHITELISTED_PLUGINS);
     } else {
         settings.whitelisted_plugins = WHITELISTED_PLUGINS;

+ 0 - 1041
src/headless/3rdparty/lodash.fp.js

@@ -1,1041 +0,0 @@
-/*global module, exports, _ */
-
-(function webpackUniversalModuleDefinition(root, factory) {
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = factory();
-    else if(typeof define === 'function' && define.amd)
-        define([], factory);
-    else if(typeof exports === 'object')
-        exports["fp"] = factory();
-    else
-        root["fp"] = factory();
-})(this, function() {
-return /******/ (function(modules) { // webpackBootstrap
-/******/     // The module cache
-/******/     var installedModules = {};
-
-/******/     // The require function
-/******/     function __webpack_require__(moduleId) {
-
-/******/         // Check if module is in cache
-/******/         if(installedModules[moduleId])
-/******/             return installedModules[moduleId].exports;
-
-/******/         // Create a new module (and put it into the cache)
-/******/         var module = installedModules[moduleId] = {
-/******/             exports: {},
-/******/             id: moduleId,
-/******/             loaded: false
-/******/         };
-
-/******/         // Execute the module function
-/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-
-/******/         // Flag the module as loaded
-/******/         module.loaded = true;
-
-/******/         // Return the exports of the module
-/******/         return module.exports;
-/******/     }
-
-
-/******/     // expose the modules object (__webpack_modules__)
-/******/     __webpack_require__.m = modules;
-
-/******/     // expose the module cache
-/******/     __webpack_require__.c = installedModules;
-
-/******/     // __webpack_public_path__
-/******/     __webpack_require__.p = "";
-
-/******/     // Load entry module and return exports
-/******/     return __webpack_require__(0);
-/******/ })([
-/* 0 */
-/***/ function(module, exports, __webpack_require__) {
-
-    var baseConvert = __webpack_require__(1);
-
-    /**
-     * Converts `lodash` to an immutable auto-curried iteratee-first data-last
-     * version with conversion `options` applied.
-     *
-     * @param {Function} lodash The lodash function to convert.
-     * @param {Object} [options] The options object. See `baseConvert` for more details.
-     * @returns {Function} Returns the converted `lodash`.
-     */
-    function browserConvert(lodash, options) {
-      return baseConvert(lodash, lodash, options);
-    }
-
-    if (typeof _ == 'function' && typeof _.runInContext == 'function') {
-      // XXX: Customization in order to be able to run both _ and fp in the
-      // non-AMD usecase.
-      window.fp = browserConvert(_.runInContext());
-    }
-    module.exports = browserConvert;
-
-
-/***/ },
-/* 1 */
-/***/ function(module, exports, __webpack_require__) {
-
-    var mapping = __webpack_require__(2),
-        fallbackHolder = __webpack_require__(3);
-
-    /** Built-in value reference. */
-    var push = Array.prototype.push;
-
-    /**
-     * Creates a function, with an arity of `n`, that invokes `func` with the
-     * arguments it receives.
-     *
-     * @private
-     * @param {Function} func The function to wrap.
-     * @param {number} n The arity of the new function.
-     * @returns {Function} Returns the new function.
-     */
-    function baseArity(func, n) {
-      return n == 2
-        ? function(a, b) { return func.apply(undefined, arguments); }
-        : function(a) { return func.apply(undefined, arguments); };
-    }
-
-    /**
-     * Creates a function that invokes `func`, with up to `n` arguments, ignoring
-     * any additional arguments.
-     *
-     * @private
-     * @param {Function} func The function to cap arguments for.
-     * @param {number} n The arity cap.
-     * @returns {Function} Returns the new function.
-     */
-    function baseAry(func, n) {
-      return n == 2
-        ? function(a, b) { return func(a, b); }
-        : function(a) { return func(a); };
-    }
-
-    /**
-     * Creates a clone of `array`.
-     *
-     * @private
-     * @param {Array} array The array to clone.
-     * @returns {Array} Returns the cloned array.
-     */
-    function cloneArray(array) {
-      var length = array ? array.length : 0,
-          result = Array(length);
-
-      while (length--) {
-        result[length] = array[length];
-      }
-      return result;
-    }
-
-    /**
-     * Creates a function that clones a given object using the assignment `func`.
-     *
-     * @private
-     * @param {Function} func The assignment function.
-     * @returns {Function} Returns the new cloner function.
-     */
-    function createCloner(func) {
-      return function(object) {
-        return func({}, object);
-      };
-    }
-
-    /**
-     * A specialized version of `_.spread` which flattens the spread array into
-     * the arguments of the invoked `func`.
-     *
-     * @private
-     * @param {Function} func The function to spread arguments over.
-     * @param {number} start The start position of the spread.
-     * @returns {Function} Returns the new function.
-     */
-    function flatSpread(func, start) {
-      return function() {
-        var length = arguments.length,
-            lastIndex = length - 1,
-            args = Array(length);
-
-        while (length--) {
-          args[length] = arguments[length];
-        }
-        var array = args[start],
-            otherArgs = args.slice(0, start);
-
-        if (array) {
-          push.apply(otherArgs, array);
-        }
-        if (start != lastIndex) {
-          push.apply(otherArgs, args.slice(start + 1));
-        }
-        return func.apply(this, otherArgs);
-      };
-    }
-
-    /**
-     * Creates a function that wraps `func` and uses `cloner` to clone the first
-     * argument it receives.
-     *
-     * @private
-     * @param {Function} func The function to wrap.
-     * @param {Function} cloner The function to clone arguments.
-     * @returns {Function} Returns the new immutable function.
-     */
-    function wrapImmutable(func, cloner) {
-      return function() {
-        var length = arguments.length;
-        if (!length) {
-          return;
-        }
-        var args = Array(length);
-        while (length--) {
-          args[length] = arguments[length];
-        }
-        var result = args[0] = cloner.apply(undefined, args);
-        func.apply(undefined, args);
-        return result;
-      };
-    }
-
-    /**
-     * The base implementation of `convert` which accepts a `util` object of methods
-     * required to perform conversions.
-     *
-     * @param {Object} util The util object.
-     * @param {string} name The name of the function to convert.
-     * @param {Function} func The function to convert.
-     * @param {Object} [options] The options object.
-     * @param {boolean} [options.cap=true] Specify capping iteratee arguments.
-     * @param {boolean} [options.curry=true] Specify currying.
-     * @param {boolean} [options.fixed=true] Specify fixed arity.
-     * @param {boolean} [options.immutable=true] Specify immutable operations.
-     * @param {boolean} [options.rearg=true] Specify rearranging arguments.
-     * @returns {Function|Object} Returns the converted function or object.
-     */
-    function baseConvert(util, name, func, options) {
-      var setPlaceholder,
-          isLib = typeof name == 'function',
-          isObj = name === Object(name);
-
-      if (isObj) {
-        options = func;
-        func = name;
-        name = undefined;
-      }
-      if (func === null) {
-        throw new TypeError();
-      }
-      options || (options = {});
-
-      var config = {
-        'cap': 'cap' in options ? options.cap : true,
-        'curry': 'curry' in options ? options.curry : true,
-        'fixed': 'fixed' in options ? options.fixed : true,
-        'immutable': 'immutable' in options ? options.immutable : true,
-        'rearg': 'rearg' in options ? options.rearg : true
-      };
-
-      var forceCurry = ('curry' in options) && options.curry,
-          forceFixed = ('fixed' in options) && options.fixed,
-          forceRearg = ('rearg' in options) && options.rearg,
-          placeholder = isLib ? func : fallbackHolder,
-          pristine = isLib ? func.runInContext() : undefined;
-
-      var helpers = isLib ? func : {
-        'ary': util.ary,
-        'assign': util.assign,
-        'clone': util.clone,
-        'curry': util.curry,
-        'forEach': util.forEach,
-        'isArray': util.isArray,
-        'isFunction': util.isFunction,
-        'iteratee': util.iteratee,
-        'keys': util.keys,
-        'rearg': util.rearg,
-        'toInteger': util.toInteger,
-        'toPath': util.toPath
-      };
-
-      var ary = helpers.ary,
-          assign = helpers.assign,
-          clone = helpers.clone,
-          curry = helpers.curry,
-          each = helpers.forEach,
-          isArray = helpers.isArray,
-          isFunction = helpers.isFunction,
-          keys = helpers.keys,
-          rearg = helpers.rearg,
-          toInteger = helpers.toInteger,
-          toPath = helpers.toPath;
-
-      var aryMethodKeys = keys(mapping.aryMethod);
-
-      var wrappers = {
-        'castArray': function(castArray) {
-          return function() {
-            var value = arguments[0];
-            return isArray(value)
-              ? castArray(cloneArray(value))
-              : castArray.apply(undefined, arguments);
-          };
-        },
-        'iteratee': function(iteratee) {
-          return function() {
-            var func = arguments[0],
-                arity = arguments[1],
-                result = iteratee(func, arity),
-                length = result.length;
-
-            if (config.cap && typeof arity == 'number') {
-              arity = arity > 2 ? (arity - 2) : 1;
-              return (length && length <= arity) ? result : baseAry(result, arity);
-            }
-            return result;
-          };
-        },
-        'mixin': function(mixin) {
-          return function(source) {
-            var func = this;
-            if (!isFunction(func)) {
-              return mixin(func, Object(source));
-            }
-            var pairs = [];
-            each(keys(source), function(key) {
-              if (isFunction(source[key])) {
-                pairs.push([key, func.prototype[key]]);
-              }
-            });
-
-            mixin(func, Object(source));
-
-            each(pairs, function(pair) {
-              var value = pair[1];
-              if (isFunction(value)) {
-                func.prototype[pair[0]] = value;
-              } else {
-                delete func.prototype[pair[0]];
-              }
-            });
-            return func;
-          };
-        },
-        'nthArg': function(nthArg) {
-          return function(n) {
-            var arity = n < 0 ? 1 : (toInteger(n) + 1);
-            return curry(nthArg(n), arity);
-          };
-        },
-        'rearg': function(rearg) {
-          return function(func, indexes) {
-            var arity = indexes ? indexes.length : 0;
-            return curry(rearg(func, indexes), arity);
-          };
-        },
-        'runInContext': function(runInContext) {
-          return function(context) {
-            return baseConvert(util, runInContext(context), options);
-          };
-        }
-      };
-
-      /*--------------------------------------------------------------------------*/
-
-      /**
-       * Casts `func` to a function with an arity capped iteratee if needed.
-       *
-       * @private
-       * @param {string} name The name of the function to inspect.
-       * @param {Function} func The function to inspect.
-       * @returns {Function} Returns the cast function.
-       */
-      function castCap(name, func) {
-        if (config.cap) {
-          var indexes = mapping.iterateeRearg[name];
-          if (indexes) {
-            return iterateeRearg(func, indexes);
-          }
-          var n = !isLib && mapping.iterateeAry[name];
-          if (n) {
-            return iterateeAry(func, n);
-          }
-        }
-        return func;
-      }
-
-      /**
-       * Casts `func` to a curried function if needed.
-       *
-       * @private
-       * @param {string} name The name of the function to inspect.
-       * @param {Function} func The function to inspect.
-       * @param {number} n The arity of `func`.
-       * @returns {Function} Returns the cast function.
-       */
-      function castCurry(name, func, n) {
-        return (forceCurry || (config.curry && n > 1))
-          ? curry(func, n)
-          : func;
-      }
-
-      /**
-       * Casts `func` to a fixed arity function if needed.
-       *
-       * @private
-       * @param {string} name The name of the function to inspect.
-       * @param {Function} func The function to inspect.
-       * @param {number} n The arity cap.
-       * @returns {Function} Returns the cast function.
-       */
-      function castFixed(name, func, n) {
-        if (config.fixed && (forceFixed || !mapping.skipFixed[name])) {
-          var data = mapping.methodSpread[name],
-              start = data && data.start;
-
-          return start  === undefined ? ary(func, n) : flatSpread(func, start);
-        }
-        return func;
-      }
-
-      /**
-       * Casts `func` to an rearged function if needed.
-       *
-       * @private
-       * @param {string} name The name of the function to inspect.
-       * @param {Function} func The function to inspect.
-       * @param {number} n The arity of `func`.
-       * @returns {Function} Returns the cast function.
-       */
-      function castRearg(name, func, n) {
-        return (config.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name]))
-          ? rearg(func, mapping.methodRearg[name] || mapping.aryRearg[n])
-          : func;
-      }
-
-      /**
-       * Creates a clone of `object` by `path`.
-       *
-       * @private
-       * @param {Object} object The object to clone.
-       * @param {Array|string} path The path to clone by.
-       * @returns {Object} Returns the cloned object.
-       */
-      function cloneByPath(object, path) {
-        path = toPath(path);
-
-        var index = -1,
-            length = path.length,
-            lastIndex = length - 1,
-            result = clone(Object(object)),
-            nested = result;
-
-        while (nested !== null && ++index < length) {
-          var key = path[index],
-              value = nested[key];
-
-          if (value !== null) {
-            nested[path[index]] = clone(index == lastIndex ? value : Object(value));
-          }
-          nested = nested[key];
-        }
-        return result;
-      }
-
-      /**
-       * Converts `lodash` to an immutable auto-curried iteratee-first data-last
-       * version with conversion `options` applied.
-       *
-       * @param {Object} [options] The options object. See `baseConvert` for more details.
-       * @returns {Function} Returns the converted `lodash`.
-       */
-      function convertLib(options) {
-        return _.runInContext.convert(options)(undefined);
-      }
-
-      /**
-       * Create a converter function for `func` of `name`.
-       *
-       * @param {string} name The name of the function to convert.
-       * @param {Function} func The function to convert.
-       * @returns {Function} Returns the new converter function.
-       */
-      function createConverter(name, func) {
-        var realName = mapping.aliasToReal[name] || name,
-            methodName = mapping.remap[realName] || realName,
-            oldOptions = options;
-
-        return function(options) {
-          var newUtil = isLib ? pristine : helpers,
-              newFunc = isLib ? pristine[methodName] : func,
-              newOptions = assign(assign({}, oldOptions), options);
-
-          return baseConvert(newUtil, realName, newFunc, newOptions);
-        };
-      }
-
-      /**
-       * Creates a function that wraps `func` to invoke its iteratee, with up to `n`
-       * arguments, ignoring any additional arguments.
-       *
-       * @private
-       * @param {Function} func The function to cap iteratee arguments for.
-       * @param {number} n The arity cap.
-       * @returns {Function} Returns the new function.
-       */
-      function iterateeAry(func, n) {
-        return overArg(func, function(func) {
-          return typeof func == 'function' ? baseAry(func, n) : func;
-        });
-      }
-
-      /**
-       * Creates a function that wraps `func` to invoke its iteratee with arguments
-       * arranged according to the specified `indexes` where the argument value at
-       * the first index is provided as the first argument, the argument value at
-       * the second index is provided as the second argument, and so on.
-       *
-       * @private
-       * @param {Function} func The function to rearrange iteratee arguments for.
-       * @param {number[]} indexes The arranged argument indexes.
-       * @returns {Function} Returns the new function.
-       */
-      function iterateeRearg(func, indexes) {
-        return overArg(func, function(func) {
-          var n = indexes.length;
-          return baseArity(rearg(baseAry(func, n), indexes), n);
-        });
-      }
-
-      /**
-       * Creates a function that invokes `func` with its first argument transformed.
-       *
-       * @private
-       * @param {Function} func The function to wrap.
-       * @param {Function} transform The argument transform.
-       * @returns {Function} Returns the new function.
-       */
-      function overArg(func, transform) {
-        return function() {
-          var length = arguments.length;
-          if (!length) {
-            return func();
-          }
-          var args = Array(length);
-          while (length--) {
-            args[length] = arguments[length];
-          }
-          var index = config.rearg ? 0 : (length - 1);
-          args[index] = transform(args[index]);
-          return func.apply(undefined, args);
-        };
-      }
-
-      /**
-       * Creates a function that wraps `func` and applys the conversions
-       * rules by `name`.
-       *
-       * @private
-       * @param {string} name The name of the function to wrap.
-       * @param {Function} func The function to wrap.
-       * @returns {Function} Returns the converted function.
-       */
-      function wrap(name, func) {
-        var result,
-            realName = mapping.aliasToReal[name] || name,
-            wrapped = func,
-            wrapper = wrappers[realName];
-
-        if (wrapper) {
-          wrapped = wrapper(func);
-        }
-        else if (config.immutable) {
-          if (mapping.mutate.array[realName]) {
-            wrapped = wrapImmutable(func, cloneArray);
-          }
-          else if (mapping.mutate.object[realName]) {
-            wrapped = wrapImmutable(func, createCloner(func));
-          }
-          else if (mapping.mutate.set[realName]) {
-            wrapped = wrapImmutable(func, cloneByPath);
-          }
-        }
-        each(aryMethodKeys, function(aryKey) {
-          each(mapping.aryMethod[aryKey], function(otherName) {
-            if (realName == otherName) {
-              var data = mapping.methodSpread[realName],
-                  afterRearg = data && data.afterRearg;
-
-              result = afterRearg
-                ? castFixed(realName, castRearg(realName, wrapped, aryKey), aryKey)
-                : castRearg(realName, castFixed(realName, wrapped, aryKey), aryKey);
-
-              result = castCap(realName, result);
-              result = castCurry(realName, result, aryKey);
-              return false;
-            }
-          });
-          return !result;
-        });
-
-        result || (result = wrapped);
-        if (result == func) {
-          result = forceCurry ? curry(result, 1) : function() {
-            return func.apply(this, arguments);
-          };
-        }
-        result.convert = createConverter(realName, func);
-        if (mapping.placeholder[realName]) {
-          setPlaceholder = true;
-          result.placeholder = func.placeholder = placeholder;
-        }
-        return result;
-      }
-
-      /*--------------------------------------------------------------------------*/
-
-      if (!isObj) {
-        return wrap(name, func);
-      }
-      var _ = func;
-
-      // Convert methods by ary cap.
-      var pairs = [];
-      each(aryMethodKeys, function(aryKey) {
-        each(mapping.aryMethod[aryKey], function(key) {
-          var func = _[mapping.remap[key] || key];
-          if (func) {
-            pairs.push([key, wrap(key, func)]);
-          }
-        });
-      });
-
-      // Convert remaining methods.
-      each(keys(_), function(key) {
-        var func = _[key];
-        if (typeof func == 'function') {
-          var length = pairs.length;
-          while (length--) {
-            if (pairs[length][0] == key) {
-              return;
-            }
-          }
-          func.convert = createConverter(key, func);
-          pairs.push([key, func]);
-        }
-      });
-
-      // Assign to `_` leaving `_.prototype` unchanged to allow chaining.
-      each(pairs, function(pair) {
-        _[pair[0]] = pair[1];
-      });
-
-      _.convert = convertLib;
-      if (setPlaceholder) {
-        _.placeholder = placeholder;
-      }
-      // Assign aliases.
-      each(keys(_), function(key) {
-        each(mapping.realToAlias[key] || [], function(alias) {
-          _[alias] = _[key];
-        });
-      });
-
-      return _;
-    }
-
-    module.exports = baseConvert;
-
-
-/***/ },
-/* 2 */
-/***/ function(module, exports) {
-
-    /** Used to map aliases to their real names. */
-    exports.aliasToReal = {
-
-      // Lodash aliases.
-      'each': 'forEach',
-      'eachRight': 'forEachRight',
-      'entries': 'toPairs',
-      'entriesIn': 'toPairsIn',
-      'extend': 'assignIn',
-      'extendAll': 'assignInAll',
-      'extendAllWith': 'assignInAllWith',
-      'extendWith': 'assignInWith',
-      'first': 'head',
-
-      // Methods that are curried variants of others.
-      'conforms': 'conformsTo',
-      'matches': 'isMatch',
-      'property': 'get',
-
-      // Ramda aliases.
-      '__': 'placeholder',
-      'F': 'stubFalse',
-      'T': 'stubTrue',
-      'all': 'every',
-      'allPass': 'overEvery',
-      'always': 'constant',
-      'any': 'some',
-      'anyPass': 'overSome',
-      'apply': 'spread',
-      'assoc': 'set',
-      'assocPath': 'set',
-      'complement': 'negate',
-      'compose': 'flowRight',
-      'contains': 'includes',
-      'dissoc': 'unset',
-      'dissocPath': 'unset',
-      'dropLast': 'dropRight',
-      'dropLastWhile': 'dropRightWhile',
-      'equals': 'isEqual',
-      'identical': 'eq',
-      'indexBy': 'keyBy',
-      'init': 'initial',
-      'invertObj': 'invert',
-      'juxt': 'over',
-      'omitAll': 'omit',
-      'nAry': 'ary',
-      'path': 'get',
-      'pathEq': 'matchesProperty',
-      'pathOr': 'getOr',
-      'paths': 'at',
-      'pickAll': 'pick',
-      'pipe': 'flow',
-      'pluck': 'map',
-      'prop': 'get',
-      'propEq': 'matchesProperty',
-      'propOr': 'getOr',
-      'props': 'at',
-      'symmetricDifference': 'xor',
-      'symmetricDifferenceBy': 'xorBy',
-      'symmetricDifferenceWith': 'xorWith',
-      'takeLast': 'takeRight',
-      'takeLastWhile': 'takeRightWhile',
-      'unapply': 'rest',
-      'unnest': 'flatten',
-      'useWith': 'overArgs',
-      'where': 'conformsTo',
-      'whereEq': 'isMatch',
-      'zipObj': 'zipObject'
-    };
-
-    /** Used to map ary to method names. */
-    exports.aryMethod = {
-      '1': [
-        'assignAll', 'assignInAll', 'attempt', 'castArray', 'ceil', 'create',
-        'curry', 'curryRight', 'defaultsAll', 'defaultsDeepAll', 'floor', 'flow',
-        'flowRight', 'fromPairs', 'invert', 'iteratee', 'memoize', 'method', 'mergeAll',
-        'methodOf', 'mixin', 'nthArg', 'over', 'overEvery', 'overSome','rest', 'reverse',
-        'round', 'runInContext', 'spread', 'template', 'trim', 'trimEnd', 'trimStart',
-        'uniqueId', 'words', 'zipAll'
-      ],
-      '2': [
-        'add', 'after', 'ary', 'assign', 'assignAllWith', 'assignIn', 'assignInAllWith',
-        'at', 'before', 'bind', 'bindAll', 'bindKey', 'chunk', 'cloneDeepWith',
-        'cloneWith', 'concat', 'conformsTo', 'countBy', 'curryN', 'curryRightN',
-        'debounce', 'defaults', 'defaultsDeep', 'defaultTo', 'delay', 'difference',
-        'divide', 'drop', 'dropRight', 'dropRightWhile', 'dropWhile', 'endsWith', 'eq',
-        'every', 'filter', 'find', 'findIndex', 'findKey', 'findLast', 'findLastIndex',
-        'findLastKey', 'flatMap', 'flatMapDeep', 'flattenDepth', 'forEach',
-        'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'get',
-        'groupBy', 'gt', 'gte', 'has', 'hasIn', 'includes', 'indexOf', 'intersection',
-        'invertBy', 'invoke', 'invokeMap', 'isEqual', 'isMatch', 'join', 'keyBy',
-        'lastIndexOf', 'lt', 'lte', 'map', 'mapKeys', 'mapValues', 'matchesProperty',
-        'maxBy', 'meanBy', 'merge', 'mergeAllWith', 'minBy', 'multiply', 'nth', 'omit',
-        'omitBy', 'overArgs', 'pad', 'padEnd', 'padStart', 'parseInt', 'partial',
-        'partialRight', 'partition', 'pick', 'pickBy', 'propertyOf', 'pull', 'pullAll',
-        'pullAt', 'random', 'range', 'rangeRight', 'rearg', 'reject', 'remove',
-        'repeat', 'restFrom', 'result', 'sampleSize', 'some', 'sortBy', 'sortedIndex',
-        'sortedIndexOf', 'sortedLastIndex', 'sortedLastIndexOf', 'sortedUniqBy',
-        'split', 'spreadFrom', 'startsWith', 'subtract', 'sumBy', 'take', 'takeRight',
-        'takeRightWhile', 'takeWhile', 'tap', 'throttle', 'thru', 'times', 'trimChars',
-        'trimCharsEnd', 'trimCharsStart', 'truncate', 'union', 'uniqBy', 'uniqWith',
-        'unset', 'unzipWith', 'without', 'wrap', 'xor', 'zip', 'zipObject',
-        'zipObjectDeep'
-      ],
-      '3': [
-        'assignInWith', 'assignWith', 'clamp', 'differenceBy', 'differenceWith',
-        'findFrom', 'findIndexFrom', 'findLastFrom', 'findLastIndexFrom', 'getOr',
-        'includesFrom', 'indexOfFrom', 'inRange', 'intersectionBy', 'intersectionWith',
-        'invokeArgs', 'invokeArgsMap', 'isEqualWith', 'isMatchWith', 'flatMapDepth',
-        'lastIndexOfFrom', 'mergeWith', 'orderBy', 'padChars', 'padCharsEnd',
-        'padCharsStart', 'pullAllBy', 'pullAllWith', 'rangeStep', 'rangeStepRight',
-        'reduce', 'reduceRight', 'replace', 'set', 'slice', 'sortedIndexBy',
-        'sortedLastIndexBy', 'transform', 'unionBy', 'unionWith', 'update', 'xorBy',
-        'xorWith', 'zipWith'
-      ],
-      '4': [
-        'fill', 'setWith', 'updateWith'
-      ]
-    };
-
-    /** Used to map ary to rearg configs. */
-    exports.aryRearg = {
-      '2': [1, 0],
-      '3': [2, 0, 1],
-      '4': [3, 2, 0, 1]
-    };
-
-    /** Used to map method names to their iteratee ary. */
-    exports.iterateeAry = {
-      'dropRightWhile': 1,
-      'dropWhile': 1,
-      'every': 1,
-      'filter': 1,
-      'find': 1,
-      'findFrom': 1,
-      'findIndex': 1,
-      'findIndexFrom': 1,
-      'findKey': 1,
-      'findLast': 1,
-      'findLastFrom': 1,
-      'findLastIndex': 1,
-      'findLastIndexFrom': 1,
-      'findLastKey': 1,
-      'flatMap': 1,
-      'flatMapDeep': 1,
-      'flatMapDepth': 1,
-      'forEach': 1,
-      'forEachRight': 1,
-      'forIn': 1,
-      'forInRight': 1,
-      'forOwn': 1,
-      'forOwnRight': 1,
-      'map': 1,
-      'mapKeys': 1,
-      'mapValues': 1,
-      'partition': 1,
-      'reduce': 2,
-      'reduceRight': 2,
-      'reject': 1,
-      'remove': 1,
-      'some': 1,
-      'takeRightWhile': 1,
-      'takeWhile': 1,
-      'times': 1,
-      'transform': 2
-    };
-
-    /** Used to map method names to iteratee rearg configs. */
-    exports.iterateeRearg = {
-      'mapKeys': [1],
-      'reduceRight': [1, 0]
-    };
-
-    /** Used to map method names to rearg configs. */
-    exports.methodRearg = {
-      'assignInAllWith': [1, 0],
-      'assignInWith': [1, 2, 0],
-      'assignAllWith': [1, 0],
-      'assignWith': [1, 2, 0],
-      'differenceBy': [1, 2, 0],
-      'differenceWith': [1, 2, 0],
-      'getOr': [2, 1, 0],
-      'intersectionBy': [1, 2, 0],
-      'intersectionWith': [1, 2, 0],
-      'isEqualWith': [1, 2, 0],
-      'isMatchWith': [2, 1, 0],
-      'mergeAllWith': [1, 0],
-      'mergeWith': [1, 2, 0],
-      'padChars': [2, 1, 0],
-      'padCharsEnd': [2, 1, 0],
-      'padCharsStart': [2, 1, 0],
-      'pullAllBy': [2, 1, 0],
-      'pullAllWith': [2, 1, 0],
-      'rangeStep': [1, 2, 0],
-      'rangeStepRight': [1, 2, 0],
-      'setWith': [3, 1, 2, 0],
-      'sortedIndexBy': [2, 1, 0],
-      'sortedLastIndexBy': [2, 1, 0],
-      'unionBy': [1, 2, 0],
-      'unionWith': [1, 2, 0],
-      'updateWith': [3, 1, 2, 0],
-      'xorBy': [1, 2, 0],
-      'xorWith': [1, 2, 0],
-      'zipWith': [1, 2, 0]
-    };
-
-    /** Used to map method names to spread configs. */
-    exports.methodSpread = {
-      'assignAll': { 'start': 0 },
-      'assignAllWith': { 'start': 0 },
-      'assignInAll': { 'start': 0 },
-      'assignInAllWith': { 'start': 0 },
-      'defaultsAll': { 'start': 0 },
-      'defaultsDeepAll': { 'start': 0 },
-      'invokeArgs': { 'start': 2 },
-      'invokeArgsMap': { 'start': 2 },
-      'mergeAll': { 'start': 0 },
-      'mergeAllWith': { 'start': 0 },
-      'partial': { 'start': 1 },
-      'partialRight': { 'start': 1 },
-      'without': { 'start': 1 },
-      'zipAll': { 'start': 0 }
-    };
-
-    /** Used to identify methods which mutate arrays or objects. */
-    exports.mutate = {
-      'array': {
-        'fill': true,
-        'pull': true,
-        'pullAll': true,
-        'pullAllBy': true,
-        'pullAllWith': true,
-        'pullAt': true,
-        'remove': true,
-        'reverse': true
-      },
-      'object': {
-        'assign': true,
-        'assignAll': true,
-        'assignAllWith': true,
-        'assignIn': true,
-        'assignInAll': true,
-        'assignInAllWith': true,
-        'assignInWith': true,
-        'assignWith': true,
-        'defaults': true,
-        'defaultsAll': true,
-        'defaultsDeep': true,
-        'defaultsDeepAll': true,
-        'merge': true,
-        'mergeAll': true,
-        'mergeAllWith': true,
-        'mergeWith': true,
-      },
-      'set': {
-        'set': true,
-        'setWith': true,
-        'unset': true,
-        'update': true,
-        'updateWith': true
-      }
-    };
-
-    /** Used to track methods with placeholder support */
-    exports.placeholder = {
-      'bind': true,
-      'bindKey': true,
-      'curry': true,
-      'curryRight': true,
-      'partial': true,
-      'partialRight': true
-    };
-
-    /** Used to map real names to their aliases. */
-    exports.realToAlias = (function() {
-      var hasOwnProperty = Object.prototype.hasOwnProperty,
-          object = exports.aliasToReal,
-          result = {};
-
-      for (var key in object) {
-       if (Object.prototype.hasOwnProperty.call(object, key)) {
-        var value = object[key];
-        if (hasOwnProperty.call(result, value)) {
-          result[value].push(key);
-        } else {
-          result[value] = [key];
-        }
-       }
-      }
-      return result;
-    }());
-
-    /** Used to map method names to other names. */
-    exports.remap = {
-      'assignAll': 'assign',
-      'assignAllWith': 'assignWith',
-      'assignInAll': 'assignIn',
-      'assignInAllWith': 'assignInWith',
-      'curryN': 'curry',
-      'curryRightN': 'curryRight',
-      'defaultsAll': 'defaults',
-      'defaultsDeepAll': 'defaultsDeep',
-      'findFrom': 'find',
-      'findIndexFrom': 'findIndex',
-      'findLastFrom': 'findLast',
-      'findLastIndexFrom': 'findLastIndex',
-      'getOr': 'get',
-      'includesFrom': 'includes',
-      'indexOfFrom': 'indexOf',
-      'invokeArgs': 'invoke',
-      'invokeArgsMap': 'invokeMap',
-      'lastIndexOfFrom': 'lastIndexOf',
-      'mergeAll': 'merge',
-      'mergeAllWith': 'mergeWith',
-      'padChars': 'pad',
-      'padCharsEnd': 'padEnd',
-      'padCharsStart': 'padStart',
-      'propertyOf': 'get',
-      'rangeStep': 'range',
-      'rangeStepRight': 'rangeRight',
-      'restFrom': 'rest',
-      'spreadFrom': 'spread',
-      'trimChars': 'trim',
-      'trimCharsEnd': 'trimEnd',
-      'trimCharsStart': 'trimStart',
-      'zipAll': 'zip'
-    };
-
-    /** Used to track methods that skip fixing their arity. */
-    exports.skipFixed = {
-      'castArray': true,
-      'flow': true,
-      'flowRight': true,
-      'iteratee': true,
-      'mixin': true,
-      'rearg': true,
-      'runInContext': true
-    };
-
-    /** Used to track methods that skip rearranging arguments. */
-    exports.skipRearg = {
-      'add': true,
-      'assign': true,
-      'assignIn': true,
-      'bind': true,
-      'bindKey': true,
-      'concat': true,
-      'difference': true,
-      'divide': true,
-      'eq': true,
-      'gt': true,
-      'gte': true,
-      'isEqual': true,
-      'lt': true,
-      'lte': true,
-      'matchesProperty': true,
-      'merge': true,
-      'multiply': true,
-      'overArgs': true,
-      'partial': true,
-      'partialRight': true,
-      'propertyOf': true,
-      'random': true,
-      'range': true,
-      'rangeRight': true,
-      'subtract': true,
-      'zip': true,
-      'zipObject': true,
-      'zipObjectDeep': true
-    };
-
-
-/***/ },
-/* 3 */
-/***/ function(module, exports) {
-
-    /**
-     * The default argument placeholder value for methods.
-     *
-     * @type {Object}
-     */
-    module.exports = {};
-/***/ }
-/******/ ])
-});

+ 2 - 2
src/headless/converse-chatboxes.js

@@ -1104,7 +1104,7 @@ converse.plugins.add('converse-chatboxes', {
                         }
                         return chatbox;
                     }
-                    if (_.isArray(jids)) {
+                    if (Array.isArray(jids)) {
                         return Promise.all(jids.forEach(async jid => {
                             const contact = await _converse.api.contacts.get(jids);
                             attrs.fullname = _.get(contact, 'attributes.fullname');
@@ -1168,7 +1168,7 @@ converse.plugins.add('converse-chatboxes', {
                     if (_.isString(jids)) {
                         const chat = await _converse.api.chats.create(jids, attrs);
                         return chat.maybeShow(force);
-                    } else if (_.isArray(jids)) {
+                    } else if (Array.isArray(jids)) {
                         return Promise.all(jids.map(j => _converse.api.chats.create(j, attrs).then(c => c.maybeShow(force))));
                     }
                     const err_msg = "chats.open: You need to provide at least one JID";

+ 4 - 7
src/headless/converse-core.js

@@ -11,7 +11,6 @@ import Promise from "es6-promise/dist/es6-promise.auto";
 import _ from "./lodash.noconflict";
 import advancedFormat from 'dayjs/plugin/advancedFormat'
 import dayjs from "dayjs";
-import f from "./lodash.fp";
 import i18n from "./i18n";
 import pluggable from "pluggable.js/src/pluggable";
 import polyfill from "./polyfill";
@@ -548,7 +547,7 @@ function cleanup () {
 _converse.initialize = async function (settings, callback) {
     settings = !_.isUndefined(settings) ? settings : {};
     const init_promise = u.getResolveablePromise();
-    _.each(PROMISES, addPromise);
+    PROMISES.forEach(addPromise);
     if (!_.isUndefined(_converse.connection)) {
         cleanup();
     }
@@ -941,7 +940,7 @@ _converse.initialize = async function (settings, callback) {
             _converse.tearDown();
         }
         // Recreate all the promises
-        _.each(Object.keys(_converse.promises), addPromise);
+        Object.keys(_converse.promises).forEach(addPromise);
         /**
          * Triggered once the user has logged out.
          * @event _converse#logout
@@ -1674,8 +1673,8 @@ _converse.api = {
          * @example _converse.api.promises.add('foo-completed');
          */
         'add' (promises) {
-            promises = _.isArray(promises) ? promises : [promises]
-            _.each(promises, addPromise);
+            promises = Array.isArray(promises) ? promises : [promises]
+            promises.forEach(addPromise);
         }
     },
 
@@ -1927,7 +1926,6 @@ const converse = {
      * @property {function} converse.env.Strophe   - The [Strophe](http://strophe.im/strophejs) XMPP library used by Converse.
      * @property {object} converse.env._           - The instance of [lodash](http://lodash.com) used by Converse.
      * @property {function} converse.env.f         - And instance of Lodash with its methods wrapped to produce immutable auto-curried iteratee-first data-last methods.
-     * @property {function} converse.env.b64_sha1  - Utility method from Strophe for creating base64 encoded sha1 hashes.
      * @property {object} converse.env.dayjs       - [DayJS](https://github.com/iamkun/dayjs) date manipulation library.
      * @property {function} converse.env.sizzle    - [Sizzle](https://sizzlejs.com) CSS selector engine.
      * @property {object} converse.env.utils       - Module containing common utility methods used by Converse.
@@ -1941,7 +1939,6 @@ const converse = {
         'Promise': Promise,
         'Strophe': Strophe,
         '_': _,
-        'f': f,
         'b64_sha1':  b64_sha1,
         'dayjs': dayjs,
         'sizzle': sizzle,

+ 3 - 3
src/headless/converse-disco.js

@@ -9,7 +9,7 @@
 import converse from "./converse-core";
 import sizzle from "sizzle";
 
-const { Backbone, Promise, Strophe, $iq, utils, _, f } = converse.env;
+const { Backbone, Promise, Strophe, $iq, utils, _ } = converse.env;
 
 converse.plugins.add('converse-disco', {
 
@@ -584,8 +584,8 @@ converse.plugins.add('converse-disco', {
                             entity.hasFeature(feature)
                         );
                         const result = await Promise.all(promises);
-                        return f.filter(f.isObject, result);
-                    },
+                        return _.filter(result, _.isObject);
+                    }
                 },
 
                 /**

+ 19 - 18
src/headless/converse-muc.js

@@ -19,7 +19,7 @@ const MUC_ROLE_WEIGHTS = {
     'none':         2,
 };
 
-const { Strophe, Backbone, Promise, $iq, $build, $msg, $pres, sizzle, f, dayjs, _ } = converse.env;
+const { Strophe, Backbone, Promise, $iq, $build, $msg, $pres, sizzle, dayjs, _ } = converse.env;
 
 // Add Strophe Namespaces
 Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin");
@@ -84,7 +84,7 @@ converse.plugins.add('converse-muc', {
             const { _converse } = this.__super__,
                   groupchats = this.chatboxes.where({'type': _converse.CHATROOMS_TYPE});
 
-            _.each(groupchats, gc => u.safeSave(gc, {'connection_status': converse.ROOMSTATUS.DISCONNECTED}));
+            groupchats.forEach(gc => u.safeSave(gc, {'connection_status': converse.ROOMSTATUS.DISCONNECTED}));
             this.__super__.tearDown.call(this, arguments);
         },
 
@@ -193,7 +193,7 @@ converse.plugins.add('converse-muc', {
                     'chat_state': undefined,
                     'connection_status': converse.ROOMSTATUS.DISCONNECTED,
                     'description': '',
-                    'hidden': _.includes(['mobile', 'fullscreen'], _converse.view_mode),
+                    'hidden': ['mobile', 'fullscreen'].includes(_converse.view_mode),
                     'message_type': 'groupchat',
                     'name': '',
                     'nick': _converse.xmppstatus.get('nickname') || _converse.nickname,
@@ -248,16 +248,16 @@ converse.plugins.add('converse-muc', {
                  */
                 const room_jid = this.get('jid');
                 this.removeHandlers();
-                this.presence_handler = _converse.connection.addHandler((stanza) => {
-                        _.each(_.values(this.handlers.presence), (callback) => callback(stanza));
+                this.presence_handler = _converse.connection.addHandler(stanza => {
+                        Object.values(this.handlers.presence).forEach(callback => callback(stanza));
                         this.onPresence(stanza);
                         return true;
                     },
                     null, 'presence', null, null, room_jid,
                     {'ignoreNamespaceFragment': true, 'matchBareFromJid': true}
                 );
-                this.message_handler = _converse.connection.addHandler((stanza) => {
-                        _.each(_.values(this.handlers.message), (callback) => callback(stanza));
+                this.message_handler = _converse.connection.addHandler(stanza => {
+                        Object.values(this.handlers.message).forEach(callback => callback(stanza));
                         this.onMessage(stanza);
                         return true;
                     }, null, 'message', 'groupchat', null, room_jid,
@@ -720,11 +720,11 @@ converse.plugins.add('converse-muc', {
              *      groupchat configuration.
              *      The second is the response IQ from the server.
              */
-            sendConfiguration (config, callback, errback) {
+            sendConfiguration (config=[], callback, errback) {
                 const iq = $iq({to: this.get('jid'), type: "set"})
                     .c("query", {xmlns: Strophe.NS.MUC_OWNER})
                     .c("x", {xmlns: Strophe.NS.XFORM, type: "submit"});
-                _.each(config || [], function (node) { iq.cnode(node).up(); });
+                config.forEach(node => iq.cnode(node).up());
                 callback = _.isUndefined(callback) ? _.noop : _.partial(callback, iq.nodeTree);
                 errback = _.isUndefined(errback) ? _.noop : _.partial(errback, iq.nodeTree);
                 return _converse.api.sendIQ(iq).then(callback).catch(errback);
@@ -818,7 +818,7 @@ converse.plugins.add('converse-muc', {
              *      a string if only one affiliation.
              * @param { function } deltaFunc - The function to compute the delta
              *      between old and new member lists.
-             * @returns { promise } 
+             * @returns { promise }
              *  A promise which is resolved once the list has been
              *  updated or once it's been established there's no need
              *  to update the list.
@@ -952,7 +952,8 @@ converse.plugins.add('converse-muc', {
                         'states': [],
                         'show': type !== 'unavailable' ? 'online' : 'offline'
                       };
-                _.each(pres.childNodes, function (child) {
+
+                pres.childNodes.forEach(child => {
                     switch (child.nodeName) {
                         case "status":
                             data.status = child.textContent || null;
@@ -962,7 +963,7 @@ converse.plugins.add('converse-muc', {
                             break;
                         case "x":
                             if (child.getAttribute("xmlns") === Strophe.NS.MUC_USER) {
-                                _.each(child.childNodes, function (item) {
+                                child.childNodes.forEach(item => {
                                     switch (item.nodeName) {
                                         case "item":
                                             data.affiliation = item.getAttribute("affiliation");
@@ -1309,18 +1310,18 @@ converse.plugins.add('converse-muc', {
                 const new_jids = new_members.map(m => m.jid).filter(m => !_.isUndefined(m)),
                       new_nicks = new_members.map(m => !m.jid && m.nick || undefined).filter(m => !_.isUndefined(m)),
                       removed_members = this.filter(m => {
-                          return f.includes(m.get('affiliation'), ['admin', 'member', 'owner']) &&
-                              !f.includes(m.get('nick'), new_nicks) &&
-                                !f.includes(m.get('jid'), new_jids);
+                          return ['admin', 'member', 'owner'].includes(m.get('affiliation')) &&
+                                !new_nicks.includes(m.get('nick')) &&
+                                !new_jids.includes(m.get('jid'));
                       });
 
-                _.each(removed_members, (occupant) => {
+                removed_members.forEach(occupant => {
                     if (occupant.get('jid') === _converse.bare_jid) { return; }
                     if (occupant.get('show') === 'offline') {
                         occupant.destroy();
                     }
                 });
-                _.each(new_members, (attrs) => {
+                new_members.forEach(attrs => {
                     let occupant;
                     if (attrs.jid) {
                         occupant = this.findOccupant({'jid': attrs.jid});
@@ -1447,7 +1448,7 @@ converse.plugins.add('converse-muc', {
              * of strings (groupchat JIDs) or objects (with groupchat JID and other
              * settings).
              */
-            _.each(_converse.auto_join_rooms, function (groupchat) {
+            _converse.auto_join_rooms.forEach(groupchat => {
                 if (_converse.chatboxes.where({'jid': groupchat}).length) {
                     return;
                 }

+ 1 - 1
src/headless/converse-pubsub.js

@@ -7,7 +7,7 @@
 import "./converse-disco";
 import converse from "./converse-core";
 
-const { Strophe, Backbone, Promise, $iq, $build, $msg, $pres, f, dayjs, _ } = converse.env;
+const { Strophe, Backbone, Promise, $iq, $build, $msg, $pres, dayjs, _ } = converse.env;
 
 Strophe.addNamespace('PUBSUB_ERROR', Strophe.NS.PUBSUB+"#errors");
 

+ 0 - 4
src/headless/lodash.fp.js

@@ -1,4 +0,0 @@
-define(['lodash', './3rdparty/lodash.fp'], function (_, lodashConverter) {
-    var fp = lodashConverter(_.runInContext());
-    return fp;
-});

+ 1 - 1
src/headless/utils/core.js

@@ -144,7 +144,7 @@ u.applyUserSettings = function applyUserSettings (context, settings, user_settin
         if (_.isUndefined(user_settings[k])) {
             continue;
         }
-        if (_.isObject(settings[k]) && !_.isArray(settings[k])) {
+        if (_.isObject(settings[k]) && !Array.isArray(settings[k])) {
             applyUserSettings(context[k], settings[k], user_settings[k]);
         } else {
             context[k] = user_settings[k];

+ 1 - 1
src/headless/utils/emoji.js

@@ -203,7 +203,7 @@ u.getEmojisByCategory = function (_converse) {
      * lists of emojis in that category as values.
      */
     if (_.isUndefined(_converse.emojis_by_category)) {
-        const emojis = _.values(_.mapValues(emoji_list, function (value, key, o) {
+        const emojis = Object.values(_.mapValues(emoji_list, function (value, key, o) {
             value._shortname = key;
             return value
         }));