class HeadTailSpliterator<T, U> extends AbstractSpliterator<U> implements TailSpliterator<U> {
    private Spliterator<T> source;
    private BiFunction<? super T, ? super StreamEx<T>, ? extends Stream<U>> mapper;
    private Supplier<? extends Stream<U>> emptyMapper;
    private Spliterator<U> target;
    StreamContext context;
    
    HeadTailSpliterator(Spliterator<T> source, BiFunction<? super T, ? super StreamEx<T>, ? extends Stream<U>> mapper,
            Supplier<? extends Stream<U>> emptyMapper) {
        super(Long.MAX_VALUE, ORDERED);
        this.source = source;
        this.mapper = mapper;
        this.emptyMapper = emptyMapper;
    }
    
    @Override
    public boolean tryAdvance(Consumer<? super U> action) {
        if (!init())
            return false;
        target = TailSpliterator.tryAdvanceWithTail(target, action);
        if (target == null) {
            context = null;
            return false;
        }
        return true;
    }

    @Override
    public Spliterator<U> tryAdvanceOrTail(Consumer<? super U> action) {<FILL_FUNCTION_BODY>}

    @Override
    public void forEachRemaining(Consumer<? super U> action) {
        if (!init())
            return;
        TailSpliterator.forEachWithTail(target, action);
        target = null;
        context = null;
    }

    @Override
    public Spliterator<U> forEachOrTail(Consumer<? super U> action) {
        return tryAdvanceOrTail(action);
    }

    private boolean init() {
        if (context == null)
            return false;
        if (target == null) {
            Box<T> first = new Box<>();
            source = TailSpliterator.tryAdvanceWithTail(source, first);
            Stream<U> stream = source == null ? emptyMapper.get() : mapper.apply(first.a, StreamEx.of(source));
            source = null;
            mapper = null;
            emptyMapper = null;
            if (stream == null) {
                target = Spliterators.emptySpliterator();
            } else {
                StreamContext ctx = StreamContext.of(stream);
                if (ctx.closeHandler != null)
                    context.onClose(ctx.closeHandler);
                target = stream.spliterator();
            }
        }
        return true;
    }
    
    @Override
    public long estimateSize() {
        if (context == null)
            return 0;
        return (target == null ? source : target).estimateSize();
    }
}

        if (!init())
            return null;
        Spliterator<U> tail = target;
        target = null;
        context = null;
        return tail;
    
<methods>public int characteristics() ,public long estimateSize() ,public Spliterator<U> trySplit() <variables>static final int BATCH_UNIT,static final int MAX_BATCH,private int batch,private final int characteristics,private long est