class PubSubCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {

    static final String MUST_NOT_BE_EMPTY = "must not be empty";

    PubSubCommandBuilder(RedisCodec<K, V> codec) {
        super(codec);
    }

    Command<K, V, Long> publish(K channel, V message) {
        CommandArgs<K, V> args = new PubSubCommandArgs<>(codec).addKey(channel).addValue(message);
        return createCommand(PUBLISH, new IntegerOutput<>(codec), args);
    }

    Command<K, V, List<K>> pubsubChannels(K pattern) {
        CommandArgs<K, V> args = new PubSubCommandArgs<>(codec).add(CHANNELS).addKey(pattern);
        return createCommand(PUBSUB, new KeyListOutput<>(codec), args);
    }

    @SafeVarargs
    @SuppressWarnings({ "unchecked", "rawtypes" })
    final Command<K, V, Map<K, Long>> pubsubNumsub(K... channels) {
        LettuceAssert.notEmpty(channels, "Channels " + MUST_NOT_BE_EMPTY);

        CommandArgs<K, V> args = new PubSubCommandArgs<>(codec).add(NUMSUB).addKeys(channels);
        return createCommand(PUBSUB, new MapOutput<>((RedisCodec) codec), args);
    }

    Command<K, V, List<K>> pubsubShardChannels(K pattern) {
        CommandArgs<K, V> args = new PubSubCommandArgs<>(codec).add(SHARDCHANNELS).addKey(pattern);
        return createCommand(PUBSUB, new KeyListOutput<>(codec), args);
    }

    @SafeVarargs
    @SuppressWarnings({ "unchecked", "rawtypes" })
    final Command<K, V, Map<K, Long>> pubsubShardNumsub(K... shardChannels) {<FILL_FUNCTION_BODY>}

    @SafeVarargs
    final Command<K, V, V> psubscribe(K... patterns) {
        LettuceAssert.notEmpty(patterns, "Patterns " + MUST_NOT_BE_EMPTY);

        return pubSubCommand(PSUBSCRIBE, new PubSubOutput<>(codec), patterns);
    }

    @SafeVarargs
    final Command<K, V, V> punsubscribe(K... patterns) {
        return pubSubCommand(PUNSUBSCRIBE, new PubSubOutput<>(codec), patterns);
    }

    @SafeVarargs
    final Command<K, V, V> subscribe(K... channels) {
        LettuceAssert.notEmpty(channels, "Channels " + MUST_NOT_BE_EMPTY);

        return pubSubCommand(SUBSCRIBE, new PubSubOutput<>(codec), channels);
    }

    @SafeVarargs
    final Command<K, V, V> unsubscribe(K... channels) {
        return pubSubCommand(UNSUBSCRIBE, new PubSubOutput<>(codec), channels);
    }

    @SafeVarargs
    final Command<K, V, V> ssubscribe(K... shardChannels) {
        LettuceAssert.notEmpty(shardChannels, "Shard channels " + MUST_NOT_BE_EMPTY);

        CommandArgs<K, V> args = new CommandArgs<>(codec).addKeys(shardChannels);
        return createCommand(SSUBSCRIBE, new PubSubOutput<>(codec), args);
    }

    @SafeVarargs
    final <T> Command<K, V, T> pubSubCommand(CommandType type, CommandOutput<K, V, T> output, K... keys) {
        return new Command<>(type, output, new PubSubCommandArgs<>(codec).addKeys(keys));
    }

}

        LettuceAssert.notEmpty(shardChannels, "Shard channels " + MUST_NOT_BE_EMPTY);

        CommandArgs<K, V> args = new PubSubCommandArgs<>(codec).add(SHARDNUMSUB).addKeys(shardChannels);
        return createCommand(PUBSUB, new MapOutput<>((RedisCodec) codec), args);
    
<methods>public void <init>(RedisCodec<K,V>) <variables>protected final non-sealed RedisCodec<K,V> codec