function multiremoteModifier(client) {
    var multibrowser = this;
    var browserNames = (0, _keys2.default)(multibrowser.instances);

    client.getInstances = function () {
        return browserNames;
    };

    client.next = function () {
        var _this = this;

        var promises = [];

        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
        }

        var fnName = args.pop();

        /**
         * no need for actual function here
         */
        args.shift();

        /**
         * flush promise bucket
         */
        multibrowser.promiseBucket = [];
        var commandArgs = args.pop();
        return this.lastPromise.done(function () {
            browserNames.forEach(function (browserName) {
                var instance = multibrowser.instances[browserName];
                promises.push(instance[fnName].apply(instance, commandArgs).promise);
            });

            return _promise2.default.all(promises).then(function (result) {
                /**
                 * custom event handling since multibrowser instance
                 * actually never executes any command
                 */
                var payload = {
                    fnName: fnName
                };

                for (var i = 0; i < browserNames.length; ++i) {
                    payload[browserNames[i]] = result[i];
                }

                if (fnName.match(/(init|end)/)) {
                    _this.emit(fnName, payload);
                }

                _this.emit('result', payload);
                _this.defer.resolve(result);
            }, function (err) {
                _this.emit('error', err);
                _this.defer.reject(err);
            });
        });
    };

    var _then = client.then;
    client.then = function (onFulfilled, onRejected) {
        /**
         * curry arguments
         * as multibrowser commands return with an array of results for each instance
         * respectively (see q.all) we need to curry them (expand arguments) to help
         * users to better work with the results
         *
         * uncurried original version:
         * ```js
         * matrix.getTitle().then(function (result) {
         *     expect(result[0]).to.be.equal('title of browser A')
         *     expect(result[1]).to.be.equal('title of browser B')
         * })
         * ```
         *
         * curried version:
         * ```js
         * matrix.getTitle().then(function (result) {
         *     expect(result.browserA).to.be.equal('title of browser A')
         *     expect(result.browserB).to.be.equal('title of browser B')
         * })
         * ```
         */
        var curryArguments = function curryArguments(args) {
            /**
             * when returning with a promise within a multibrowser promise like
             *
             * ```js
             * matrix.url(...).getTitle().then(function () {
             *     return matrix.getSource()
             * })
             * ```
             *
             * we will have problems as we are running through curryArguments twice.
             * Therefor check if the onFulFilled handler is from the Q library and
             * handle that promise as usual here.
             * It's an ugly hack but the only way to get around with this and having
             * nice curried arguments.
             *
             */
            if (onFulfilled.toString() === multibrowser.qResolve) {
                return onFulfilled.apply(this, arguments);
            }
            if (arguments.length === 1 && !Array.isArray(args)) {
                return onFulfilled.call(this, args);
            }

            if (arguments.length > 1) {
                args = Array.prototype.slice.call(arguments);
            }

            var result = {};
            for (var i = 0; i < browserNames.length; ++i) {
                result[browserNames[i]] = args[i];
            }
            return onFulfilled.call(this, result);
        };

        if (!onFulfilled && !onRejected) {
            return this;
        }

        if (onFulfilled && !onRejected) {
            return _then.call(this, curryArguments);
        }

        if (onFulfilled && onRejected) {
            return _then.call(this, curryArguments, onRejected);
        }

        return _then.call(this, undefined, onRejected);
    };

    client.select = function (browserName) {
        var instance = multibrowser.instances[browserName];

        if (!instance) {
            throw new Error(`browser name "${browserName}" was not defined`);
        }

        instance.isMultibrowser = false;
        return instance;
    };

    client.sync = function () {
        var bucket = multibrowser.flushPromiseBucket();
        return this.call(function () {
            return _promise2.default.all(bucket);
        });
    };

    var _addCommand = client.addCommand;
    client.addCommand = function (fnName, fn, forceOverwrite) {
        var _this2 = this;

        var args = arguments;
        _addCommand.apply(this, args);
        (0, _keys2.default)(multibrowser.instances).forEach(function (browserName) {
            var instance = multibrowser.instances[browserName];
            instance.addCommand.apply(_this2, args);
        });
        return this;
    };

    return client;
}
Overwrite next (bind) method to put each command into a bucket.
This provides us useful information about all current running
commands.