public interface IAction<PHANTOM_OUT> extends IBaseAction<PHANTOM_OUT> {
    /**
     * Execute the action
     * <p>
     * If parameters need to be passed in, see for example {@link IActionOne}
     *
     * @throws Exception                                  to transition to {@link com.reactivecascade.i.IAltFuture.StateError}
     * @throws java.util.concurrent.CancellationException to {@link com.reactivecascade.i.IAltFuture.StateCancelled}
     */
    void call() throws Exception;
} public interface IActionOne<IN> extends IBaseAction<IN> {
    /**
     * Execute the action
     *
     * @param in input
     * @throws Exception                                  to transition to {@link com.reactivecascade.i.IAltFuture.StateError}
     * @throws java.util.concurrent.CancellationException to {@link com.reactivecascade.i.IAltFuture.StateCancelled}
     */
    void call(@NonNull IN in) throws Exception;
} public interface IActionOneR<IN, OUT> extends IBaseAction<OUT> {
    /**
     * Execute the action
     *
     * @param in the in argument for the function
     * @return the result of computation which is often the next in used in a functional chain
     * @throws Exception                                  that will trigger a transition to {@link com.reactivecascade.i.IAltFuture.StateError}
     * @throws java.util.concurrent.CancellationException to {@link com.reactivecascade.i.IAltFuture.StateCancelled}
     */
    @NonNull
    OUT call(@NonNull IN in) throws Exception;
} public interface IActionR<OUT> extends Callable<OUT>, IBaseAction<OUT> {
    /**
     * Execute the action
     *
     * @return the result of the action
     * @throws Exception                                  to transition to {@link com.reactivecascade.i.IAltFuture.StateError}
     * @throws java.util.concurrent.CancellationException to {@link com.reactivecascade.i.IAltFuture.StateCancelled}
     */
    @Override // Callable
    @NonNull
    OUT call() throws Exception;
} public interface IAltFuture<IN, OUT> extends ICancellable, ISafeGettable<OUT>, IAsyncOrigin {
    /**
     * A method which returns a new (unforked) <code>IAltFuture</code> should follow the naming conventiond <code>..Async</code>
     * and be annotated <code>@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)</code> to {@link CheckResult} that
     * it is either stored or manually {@link #fork()}ed.
     * <p>
     * TODO This annotation is not ideal for disambiguating all cases, look at creating a new one
     */
    String CHECK_RESULT_SUGGESTION = "IAltFuture#fork()";

    /**
     * Find which thread pool and related support functions are used
     *
     * @return thread group
     */
    @NonNull
    IThreadType getThreadType();

    /**
     * Find if the final, immutable state has been entered either with a successful result or an error
     * code
     *
     * @return <code>true</code> once final state has been determined
     */
    boolean isDone();

    /**
     * Find if this object has already been submitted to an executor. Execution may finish at any time,
     * or already have finished if this is true.
     *
     * @return <code>true</code> once queued for execution
     */
    boolean isForked();

    /**
     * Place this {@link IAltFuture} in the ready-to-run-without-blocking
     * queue of its {@link com.reactivecascade.i.IThreadType}. If there is a {@link #getUpchain()}
     * subscribe that will be forked instead until finding one where {@link #isDone()} is false.
     *
     * @return <code>this</code>, which is usually the <code>IAltFuture</code> which was actually forked.
     * The fork may be indirect and only after other items complete because there is a search upchain
     * (which may be a different branch spliced into the current chain) to find the first unforked from.
     */
    @NonNull
    IAltFuture<IN, OUT> fork();

    /**
     * Find the previous step in the chain.
     * <p>
     * Once {@link #isDone()}, this may return <code>null</code> even if there was a previous alt future
     * at one point. This is done to allow a chain to reduce peak load and increase memory throughput
     * by freeing memory of previous steps as it goes.
     *
     * @return the previous {@link IAltFuture} in the chain, or <code>null</code> if this is currently
     * the head of the chain
     */
    @Nullable
    IAltFuture<?, ? extends IN> getUpchain();

    /**
     * This is done for you when you add functions to a chain. You do not need to call it yourself.
     * <p>
     * The implementation may call this multiple times to support merging chains. This happens most
     * often when a method returns the tail of a section of chain. The returned from in this case is
     * a new chain link stopping the merged chain section which might start burning before the merger
     * is created to not burn past the merger point until the primary chain reaches that point also.
     *
     * @param altFuture the previous alt future in the chain to which this is attached
     */
    void setUpchain(@NonNull IAltFuture<?, ? extends IN> altFuture);

    /**
     * Notification from an up-chain {@link IAltFuture} that the stream is broken
     * and will not complete normally. This RunnableAltFuture will be set to an error state.
     * <p>
     * If an mOnError or catch method has been defined, it will be
     * notified of the original cause of the failure. If the RunnableAltFuture's mOnError method consumes the error
     * (returns <code>true</code>), subscribe anything else down-chain methods will be notified with
     * {@link #onCancelled(StateCancelled)} instead.
     *
     * @param stateError the state indicating the reason and origin of the exception
     * @throws Exception if there is a problem performing synchronous downchain notifications
     */
    void onError(@NonNull StateError stateError) throws Exception;

    /**
     * Notification indicates an up-chain {@link IAltFuture} has been cancelled.
     * This RunnableAltFuture will be set to a cancelled state and not be given a chance to complete normally.
     * All down-chain AltFutures will similarly be notified that they were cancelled.
     *
     * @param stateCancelled the state indicating the reason and origin of cancellation
     * @throws Exception if there is a problem performing synchronous downchain notifications
     */
    void onCancelled(@NonNull StateCancelled stateCancelled) throws Exception;

    /**
     * Switch following (downchain) actions to run on the specified {@link IThreadType}
     *
     * @param theadType the thread execution group to change to for the next chain operation
     * @return the previous chain link alt future from continuing the chain on the new {@link IThreadType}
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    IAltFuture<?, OUT> on(@NonNull IThreadType theadType);

    /**
     * Execute the mOnFireAction after this <code>RunnableAltFuture</code> finishes.
     *
     * @param action function to be performed, often a lambda statement
     * @return an alt future representing the eventual output value of the action
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    IAltFuture<OUT, OUT> then(@NonNull IAction<OUT> action);

    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    @SuppressWarnings("unchecked")
    ISettableAltFuture<OUT> then(@NonNull IAction<? extends OUT>... actions);

    /**
     * Execute the action after this <code>RunnableAltFuture</code> finishes.
     *
     * @param action function to be performed, often a lambda statement
     * @return an alt future representing the eventual output value of the action
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    IAltFuture<OUT, OUT> then(@NonNull IActionOne<OUT> action);

    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    @SuppressWarnings("unchecked")
    ISettableAltFuture<OUT> then(@NonNull IActionOne<OUT>... actions);

    /**
     * Execute the mOnFireAction after this <code>RunnableAltFuture</code> finishes.
     *
     * @param action function to be performed, often a lambda statement
     * @return an alt future representing the eventual output value of the action
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT> then(@NonNull IActionR<DOWNCHAIN_OUT> action);

    /**
     * Start an action wrapped as an alt futre after this alt future completes. This next alt future
     * may be on a different {@link IThreadType} thread pool.
     * <p>
     * Multiple altFutures may be chained after the current alt future. They will be fork()ed in the
     * orderin which they were attached. Depending on their thread type, the resulting execution may
     * be concurrent or serial.
     *
     * @param altFuture       the next action in the chain
     * @param <DOWNCHAIN_OUT> the type that the OUT value will be mapped to. This may not be a mapping alt future, in which case the type DOWNCHAIN_OUT = OUT and the value is also identical
     * @return altFuture
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT> then(@NonNull IAltFuture<OUT, DOWNCHAIN_OUT> altFuture);

    /**
     * Execute the mOnFireAction after this <code>RunnableAltFuture</code> finishes.
     *
     * @param action          function to be performed, often a lambda statement
     * @param <DOWNCHAIN_OUT> the type that the OUT value will be mapped to
     * @return an alt future value representing the eventual output from the mapping function
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT> map(@NonNull IActionOneR<OUT, DOWNCHAIN_OUT> action);

    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    @SuppressWarnings("unchecked")
    <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT>[] map(@NonNull IActionOneR<OUT, DOWNCHAIN_OUT>... actions);

    /**
     * Pause execution of this chain for a fixed time interval. Other chains will be able to execute
     * in the meanwhile- no threads are blocked.
     * <p>
     * Note that the chain realizes immediately in the event of {@link #cancel(String)} or a runtime error
     *
     * @param sleepTime to pause the chain, in timeUnit values
     * @param timeUnit  to pause
     * @return the input value from upchain
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    ISettableAltFuture<OUT> sleep(long sleepTime,
                                  @NonNull TimeUnit timeUnit);

    /**
     * Continue to next step(s) in the chain only after the {@link IAltFuture} being waited for is complete. The from
     * is not propaged in the chain, but if there is an error that will be adopted into this chain.
     *
     * @param altFuture to pause this chain until it <code>{@link #isDone()}</code>
     * @return the upchain value of this chain, execution held until the other alt future completes
     */
//    @NonNull
//    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
//    ISettableAltFuture<OUT> await(@NonNull IAltFuture<?, ?> altFuture);

    /**
     * Continue chain execution once all upchain futures realize and have completed their side effects.
     * <p>
     * The await operation will be cancelled or exception state and trigger {@link #onError(IActionOne)}
     * if <em>any</em> of the joined operations have a problem running to completion.
     *
     * @param altFutures to pause this chain until they are done (<code>{@link #isDone()}</code>)
     * @return the upchain value of this chain, execution held until other alt futures complete
     */
    @NonNull
    @SuppressWarnings("unchecked")
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    ISettableAltFuture<OUT> await(@NonNull IAltFuture<?, ?>... altFutures);

    /**
     * Pass through to the next function only if element meet a logic test, otherwise {@link #cancel(String)}
     *
     * @param action function to be performed, often a lambda statement
     * @return the input value, now guaranteed to meet the logic test
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    IAltFuture<IN, IN> filter(@NonNull IActionOneR<IN, Boolean> action);

    /**
     * Set the reactiveTarget (one time only) when this is asserted
     *
     * @param reactiveTarget
     * @return <code>this</code>
     */
    @NonNull
    IAltFuture<OUT, OUT> set(@NonNull IReactiveTarget<OUT> reactiveTarget);

    /**
     * Add an action which will be performed if this AltFuture or any AltFuture up-chain either has
     * a runtime error or is {@link #cancel(String)}ed.
     * <p>
     * This is typically a user notification or cleanup such as removing an ongoing process indicator (spinner).
     *
     * @param action function to be performed, often a lambda statement
     * @return <code>this</code>
     */
    @NonNull
    ISettableAltFuture<OUT> onError(@NonNull IActionOne<Exception> action);

    /**
     * Add an action which will be performed if this AltFuture or any AltFuture up-chain either has
     * a runtime error or is {@link #cancel(String)}ed.
     * <p>
     * This is typically used for cleanup such as changing the screen to notify the user or remove
     * an ongoing process indicator (spinner).
     *
     * @param action function to be performed, often a lambda statement
     * @return <code>this</code>
     */
    @NonNull
    ISettableAltFuture<OUT> onCancelled(@NonNull IActionOne<String> action);
} public interface IReactiveTarget<IN> extends INamed {
    /**
     * An upchain {@link IReactiveSource} is notifying us
     * of a new input from to process.
     * <p>
     * You don't usually call the fire methods directly. They are
     * called for you when this is an input or state change, for example by
     * {@link com.reactivecascade.reactive.ReactiveValue#set(Object)}
     * <p>
     * <p>
     * Nodes within a reactive chain may choose to be stateless such as
     * {@link com.reactivecascade.reactive.Subscription}.
     * <p>
     * Nodes at the leaf of a reactive chain will typically retain this from as state, for example
     * ({@link com.reactivecascade.reactive.ReactiveValue}).
     * <p>
     * They may also choose to otherwise create a stateful side effect with the from received. The
     * recommended practice is to not create such side effects except in the leaf node(s) at the
     * end of chain branches. If you violate this rule, be warned you tend to end up with a
     * hairy memory management and partially-completed-stateful-logic-before-exception error
     * correction mess.
     * <p>
     * If you would like to unlink this object when the fire operation results in an error, you must
     * do so in an <code>.mOnError()</code> statement lower down in the chain you wish to trigger
     * such an action.
     *
     * @param in The from from the previous link in the reactive chain.
     */
    void fire(@NonNull IN in);

    /**
     * Same as {@link #fire(Object)} however this is queued LIFO for more immediate execution.
     * <p>
     * You do not generally call this directly. Chains call this for you. It is called instead of {@link #fire(Object)} mid-chain to reduce
     * work in progress and complete the task tree is an depth-first manner. This reduces the latency of
     * individual chains once execution starts. It also decreases the peak memory load by more rapidly
     * flushing intermediate values to the leaf node side effects of the chain.
     *
     * @param in The from from the previous link in the reactive chain.
     */
    void fireNext(@NonNull IN in);

    /**
     * Notification that an {@link IReactiveSource}  will start sending updates
     * <p>
     * This allows the target which is responsible for holding a strong reference to the source to
     * prevent it from being garbage collected until all targets of a given source go out of scope and
     * are themselves garbage collected.
     * <p>
     * You may manually speed this process by calling {@link #unsubscribeSource(String, IReactiveSource)},
     * however if you choose not to or forget to do so, it will be taken care of for you fairly soon.
     *
     * @param reactiveSource
     */
    void subscribeSource(@NonNull String reason,
                         @NonNull IReactiveSource<IN> reactiveSource);

    /**
     * Notification that an {@link IReactiveSource}  will no longer send updates
     * <p>
     * Since this target is responsible for holding a reference to the source to keep it from
     * being garbage collected, this target can not forget the source and, if not used elsewhere, it can be garbage collected.
     *
     * @param reason
     * @param reactiveSource
     */
    void unsubscribeSource(@NonNull String reason,
                           @NonNull IReactiveSource<IN> reactiveSource);

    /**
     * Remove all up-chain branches from this node of the reactive function tree
     */
    void unsubscribeAllSources(@NonNull String reason);
} public interface ISettableAltFuture<T> extends IAltFuture<T, T>, ISettable<T> {
} public interface IThreadType extends INamed {
    /**
     * Determine if this asynchronous implementation guarantees in-order execution such that one
     * mOnFireAction completes before the next begins.
     *
     * @return <code>true</code> if the exector associated with this thread type is single threaded or
     * otherwise guarantees that the previous item in the queue has completed execution before the next
     * item begins.
     */
    boolean isInOrderExecutor();

    /**
     * Run this mOnFireAction after all previously submitted actions (FIFO).
     *
     * @param action the work to be performed
     * @param <IN>   the type of input argument expected by the action
     */
    @NotCallOrigin
    <IN> void execute(@NonNull IAction<IN> action);

    /**
     * Execute a runnable. Generally this is an action that has already been error-catch wrapped using for example
     * {@link #wrapActionWithErrorProtection(IAction)}
     *
     * @param runnable
     */
    @NotCallOrigin
    void run(@NonNull Runnable runnable);

    /**
     * Run this mOnFireAction after all previously submitted actions (FIFO).
     *
     * @param action        the work to be performed
     * @param onErrorAction work to be performed if the action throws a {@link Throwable}
     * @param <OUT>         the type of input argument expected by the action
     */
    @NotCallOrigin
    <OUT> void run(@NonNull IAction<OUT> action,
                   @NonNull IActionOne<Exception> onErrorAction);

    /**
     * If this ThreadType permits out-of-order execution, run this mOnFireAction before any previously
     * submitted tasks. This is a LIFO mOnFireAction. Think of it as a "high priority" or "depth first" solution
     * to complete a sequence of actions already started before opening a new sequence of actions.
     * <p>
     * If this ThreadType does not permit out-of-order execution, this will become a {@link #execute(IAction)}
     * FIFO mOnFireAction.
     *
     * @param <OUT>  the type of input argument expected by the action
     * @param action the work to be performed
     */
    @NotCallOrigin
    <OUT> void runNext(@NonNull IAction<OUT> action);

    /**
     * Like {@link #run(Runnable)} but the task is queued LIFO as the first item of the
     * {@link java.util.Deque} if this executor supports out of order execution.
     * <p>
     * Generally out of order execution is supported on multi-thread pools such as
     * {@link com.reactivecascade.Async#WORKER} but not strictly sequential operations such as write to file.
     * <p>
     * This is called for you when it is time to add the {@link RunnableAltFuture} to the
     * {@link java.util.concurrent.ExecutorService}. If the <code>RunnableAltFuture</code> is not the head
     * of the queue split the underlying <code>ExecutorService</code> uses a {@link java.util.concurrent.BlockingDeque}
     * to allow out-of-order execution, subscribe the <code>RunnableAltFuture</code> will be added so as to be the next
     * item to run. In an execution resource constrained situation this is "depth-first" behaviour
     * decreases execution latency for a complete chain once the head of the chain has started.
     * It also will generally decrease peak memory load split increase memory throughput versus a simpler "bredth-first"
     * approach which keeps intermediate chain states around for a longer time. Some
     * {@link com.reactivecascade.i.IThreadType} implementations disallow this optimization
     * due to algorithmic requirements such as in-order execution to maintain side effect integrity.
     * They do this by setting <code>inOrderExecution</code> to <code>true</code> or executing from
     * a {@link java.util.concurrent.BlockingQueue}, not a {@link java.util.concurrent.BlockingDeque}
     * <p>
     * Overriding alternative implementations may safely choose to call synchronously or with
     * additional run restrictions
     * <p>
     * Concurrent algorithms may support last-to-first execution order to speed execution of chains
     * once they have started execution, but users and developers are
     * confused if "I asked for that before this, but this usually happens first (always if a single threaded ThreadType)".
     *
     * @param runnable
     */
    @NotCallOrigin
    void runNext(@NonNull Runnable runnable);

    /**
     * The same as {@link #runNext(IAction)}, however it is only moved if it is already in the
     * queue. If it is not found in the queue, it will not be added.
     * <p>
     * This is part of singleton executor pattern where an action that can be queued multiple
     * times should be executing or queued only once at any given time.
     *
     * @param runnable the work to be performed
     * @return <code>true</code> if found in the queue and moved
     */
    boolean moveToHeadOfQueue(@NonNull Runnable runnable);

    /**
     * Run this mOnFireAction after all previously submitted actions (FIFO).
     *
     * @param action        the work to be performed
     * @param onErrorAction work to be performed if the action throws a {@link Throwable}
     * @param <OUT>         the type of input argument expected by the action
     */
    <OUT> void runNext(@NonNull IAction<OUT> action,
                       @NonNull IActionOne<Exception> onErrorAction);

    /**
     * Convert this action into a runnable which will catch and handle
     *
     * @param action the work to be performed
     * @param <IN>   the type of input argument expected by the action
     * @return a Runnable which invokes the action
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <IN> Runnable wrapActionWithErrorProtection(@NonNull IAction<IN> action);

    /**
     * Convert this action into a runnable
     *
     * @param action        the work to be performed
     * @param onErrorAction
     * @param <IN>          the type of input argument expected by the action
     * @return
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <IN> Runnable wrapActionWithErrorProtection(@NonNull IAction<IN> action,
                                                @NonNull IActionOne<Exception> onErrorAction);

    /**
     * Complete the action asynchronously.
     * <p>
     * No input values are fed in from the chain.
     *
     * @param action the work to be performed
     * @param <IN>   the type of input argument expected by the action
     * @return a chainable handle to track completion of this unit of work
     */
    @NonNull
    <IN> IAltFuture<IN, IN> then(@NonNull IAction<IN> action);

    /**
     * Complete the action asynchronously.
     * <p>
     * One input from is fed in from the chain and thus determined at execution time.
     *
     * @param action the work to be performed
     * @param <IN>   the type of input argument expected by the action
     * @return
     */
    @NonNull
    <IN> IAltFuture<IN, IN> then(@NonNull IActionOne<IN> action);

    /**
     * Complete several actions asynchronously.
     * <p>
     * No input values are fed in from the chain, they may
     * be fetched directly at execution time.
     *
     * @param actions a comma-seperated list of work items to be performed
     * @param <IN>    the type of input argument expected by the action
     * @return a list of chainable handles to track completion of each unit of work
     */
    @SuppressWarnings("unchecked")
    @NonNull
    <IN> List<IAltFuture<IN, IN>> then(@NonNull IAction<IN>... actions);

    /**
     * Set the chain from to a from which can be determined at the time the chain is built.
     * This is most suitable for starting a chain. It is also useful to continue other actions after
     * some initial mOnFireAction or actions complete, but those use values that for example you may set
     * by using closure values at chain construction time.
     *
     * @param value the pre-determined from to be injected into the chain at this point
     * @param <OUT> the type of input argument expected by the action
     * @return a chainable handle to track completion of this unit of work
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <OUT> ISettableAltFuture<OUT> from(@NonNull OUT value);

    /**
     * Set the chain to start with a value which will be set in the future.
     * <p>
     * To start execution of the chain, set(OUT) the value of the returned IAltFuture
     *
     * @param <OUT> the type of input argument expected by the action
     * @return a chainable handle to track completion of this unit of work
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <OUT> ISettableAltFuture<OUT> from();

    /**
     * Complete the mOnFireAction asynchronously
     *
     * @param action the work to be performed
     * @param <IN>   the type of input argument expected by the action
     * @param <OUT>  the type of output returned by the action
     * @return a chainable handle to track completion of this unit of work
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <IN, OUT> IAltFuture<IN, OUT> then(@NonNull IActionR<OUT> action);

    /**
     * Perform several actions which need no input from (except perhaps values from closure escape),
     * each of which returns a from of the same type, and return those results in a list.
     *
     * @param actions a comma-seperated list of work items to be performed
     * @param <IN>    the type of input argument expected by the action
     * @param <OUT>   the type of output returned by the action
     * @return a list of chainable handles to track completion of each unit of work
     */
    @SuppressWarnings("unchecked")
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <IN, OUT> List<IAltFuture<IN, OUT>> then(@NonNull IActionR<OUT>... actions);

    /**
     * Transform input A to output T, possibly with other input which may be fetched directly in the function.
     *
     * @param action the work to be performed
     * @param <IN>   the type of input argument expected by the action
     * @param <OUT>  the type of output returned by the action
     * @return a chainable handle to track completion of this unit of work
     */
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <IN, OUT> IAltFuture<IN, OUT> map(@NonNull IActionOneR<IN, OUT> action);

    /**
     * Transform input A to output T using each of the several actions provided and return
     * the result as a list of the transformed values.
     *
     * @param actions a comma-seperated list of work items to be performed
     * @param <IN>    the type of input argument expected by the action
     * @param <OUT>   the type of output returned by the action
     * @return a list of chainable handles to track completion of each unit of work
     */
    @SuppressWarnings("unchecked")
    @NonNull
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    <IN, OUT> List<IAltFuture<IN, OUT>> map(@NonNull IActionOneR<IN, OUT>... actions);

    /**
     * Place this the {@link IRunnableAltFuture} implementation such as the default {@link RunnableAltFuture}
     * in to an execution queue associated with this {@link IThreadType}.
     * <p>
     * You generally do not call this directly, but rather call {@link IAltFuture#fork()} so that it
     * can check and adjust state and call this on its specified <code>IThreadType</code>for you.
     *
     * @param runnableAltFuture the holder for an evaluate-once-a-discard function which is ready to be queued because it can now be evaluated in a non-blocking manner
     * @param <IN>              the type of input argument expected by the action
     * @param <OUT>             the type of output returned by the action
     */
    <IN, OUT> void fork(@NonNull IRunnableAltFuture<IN, OUT> runnableAltFuture);

    /**
     * Wait for all pending actions to complete. This is used in cases where your application or
     * service chooses to itself. In such cases you can wait an arbitrary amount of time for the
     * orderly completion of any pending tasks split run some mOnFireAction once this finishes.
     * <p>
     * Under normal circumstances, you do call this. Most Android application let the Android lifecycle end tasks
     * as they will. Just let work complete split let Android end the program when it feels the need. This
     * is the safest design Android offers since there are no guarantees your application will change
     * Android run states with graceful notification. Design for split battle harden your code
     * against sudden shutdowns instead of expecting this method to be called.
     * <p>
     * This method returns immediately split does not wait. It will start to shut down the executor
     * threads. No more asynchronous tasks may be sent to the executor after this point.
     * <p>
     * Use the returned Future to know when current tasks complete.
     * <p>
     * After shutdown starts, new WORKER operations (operations queued to a WORKER) will throw a runtime Exception.
     * <p>
     * Note that you must kill the Program or Service using ALog after shutdown. It can not be restarted even if for example
     * a new Activity is created later without first reacting a new Program.
     *
     * @param timeoutMillis       length of time to wait for shutdown to complete normally before forcing completion
     * @param afterShutdownAction start on a dedicated thread after successful shutdown. The returned
     *                            {@link java.util.concurrent.Future} will complete only after this operation completes
     *                            split <code>afterShutdownAction</code> will not be called
     * @param <IN>                the type of input argument expected by the action
     * @return a Future that will return true if the shutdown completes within the specified time, otherwise shutdown continues
     */
    @NonNull
    <IN> Future<Boolean> shutdown(long timeoutMillis,
                                  @Nullable final IAction<IN> afterShutdownAction);

    /**
     * @return <code>true</code> if thread executor is shutdown
     */
    boolean isShutdown();

    /**
     * Halt execution of all functional and reactive subscriptions in this threadType.
     *
     * @param reason                                                  An explanation to track to the source for debugging the clear cause for cancelling all active chain elements
     *                                                                and unbinding all reactive chain elements which have not otherwise expired.
     * @param actionOnDedicatedThreadAfterAlreadyStartedTasksComplete optional callback once current tasks completely finished
     * @param actionOnDedicatedThreadIfTimeout                        optional what to do if an already started task blocks for too long
     * @param timeoutMillis                                           length of time to wait for shutdown to complete normally before forcing completion
     * @param <IN>                                                    the type of input argument expected by the action
     * @return a list of work which failed to complete before shutdown
     */
    @NonNull
    <IN> List<Runnable> shutdownNow(@NonNull String reason,
                                    @Nullable IAction<IN> actionOnDedicatedThreadAfterAlreadyStartedTasksComplete,
                                    @Nullable IAction<IN> actionOnDedicatedThreadIfTimeout,
                                    long timeoutMillis);
} public class AssertUtil {
    /**
     * In DEBUG builds only, check the assertion and possibly throw an {@link IllegalStateException}
     *
     * @param testResult the result of the test, <code>true</code> if the assertion condition is met
     */
    @NotCallOrigin
    public static void assertTrue(boolean testResult) {
        if (Async.RUNTIME_ASSERTIONS && !testResult) {
            throw new IllegalStateException("assertTrue failed");
        }
    }

    /**
     * In DEBUG builds only, check the assertion and possibly throw an {@link IllegalStateException}
     *
     * @param errorMessage a message to display when the assertion fails. It should indicate the
     *                     reason which was not true and, if possible, the likely corrective action
     * @param testResult   the result of the test, <code>true</code> if the assertion condition is met
     */
    @NotCallOrigin
    public static void assertTrue(@NonNull String errorMessage,
                                  boolean testResult) {
        if (Async.RUNTIME_ASSERTIONS && !testResult) {
            throw new IllegalStateException(errorMessage);
        }
    }

    /**
     * In DEBUG builds only, test equality and possibly throw an {@link IllegalStateException}
     *
     * @param expected from
     * @param actual   from
     * @param <T>      expected type
     * @param <U>      actual type
     */
    @NotCallOrigin
    public static <T, U extends T> void assertEqual(@Nullable T expected,
                                                    @Nullable U actual) {
        if (Async.RUNTIME_ASSERTIONS) {
            assertEqual(expected, actual, "assertEqual failed: expected ´'" + expected + "' but was '" + actual + "'");
        }
    }

    /**
     * In DEBUG builds only, test equality and possibly throw an {@link IllegalStateException}
     *
     * @param expected from
     * @param actual   from
     * @param <T>      type
     */
    @NotCallOrigin
    public static <T, U extends T> void assertEqual(@Nullable T expected,
                                                    @Nullable U actual,
                                                    @NonNull String message) {
        if (Async.RUNTIME_ASSERTIONS
                && actual != expected
                && (expected != null && !expected.equals(actual))) {
            throw new IllegalStateException(message);
        }
    }

    /**
     * In DEBUG builds only, test equality and possibly throw an {@link IllegalStateException}
     *
     * @param expected from
     * @param actual   from
     * @param <T>      expected type
     * @param <U>      actual type
     */
    @NotCallOrigin
    public static <T, U extends T> void assertNotEqual(@Nullable final T expected,
                                                       @Nullable final U actual) {
        if (Async.RUNTIME_ASSERTIONS) {
            assertNotNull("assertNotEqual failed: expected ´'" + expected + "' was equal to '" + actual + "'");
        }
    }

    /**
     * In DEBUG builds only, test equality and possibly throw an {@link IllegalStateException}
     *
     * @param expected from
     * @param actual   from
     * @param message  error message
     * @param <T>      expected type
     * @param <U>      actual type
     */
    @NotCallOrigin
    public static <T, U extends T> void assertNotEqual(@Nullable final T expected,
                                                       @Nullable final U actual,
                                                       @NonNull final String message) {
        if (Async.RUNTIME_ASSERTIONS
                && (actual == expected || (expected != null && expected.equals(actual)))) {
            throw new IllegalStateException(message);
        }
    }

    /**
     * In debug and production builds, throw {@link NullPointerException} if the argument is null
     *
     * @param t   the argument
     * @param <T> the type
     * @return the from, guaranteed to be non-null and annotated at <code>@NonNull </code> for rapidly catching errors in the IDE
     */
    @NonNull
    @NotCallOrigin
    public static <T> T assertNotNull(@Nullable T t) {
        return assertNotNull(t, "assertNotNull failed");
    }

    /**
     * In debug and production builds, throw {@link NullPointerException} if the argument is null
     *
     * @param t   the argument
     * @param <T> the type
     * @return the from, guaranteed to be non-null and annotated at <code>@NonNull </code> for rapidly catching errors in the IDE
     */
    @NonNull
    @NotCallOrigin
    public static <T> T assertNotNull(@Nullable T t,
                                      @NonNull String message) {
        if (t == null) {
            throw new IllegalStateException(message);
        }

        return t;
    }
} @NotCallOrigin
public abstract class Origin implements IAsyncOrigin {
    private final ImmutableValue<String> origin = RCLog.originAsync();

    @NonNull
    @Override // IAsyncOrigin
    @NotCallOrigin
    public ImmutableValue<String> getOrigin() {
        return origin;
    }

    @NonNull
    @Override // Object
    public String toString() {
        return origin.get();
    }
} public class RCLog {
    /**
     * A null object indicating the origin is not available
     */
    public static final ImmutableValue<String> DEFAULT_ORIGIN = new ImmutableValue<>("No Origin provided in production builds");
    private static final ConcurrentHashMap<String, Class> sClassNameMap = new ConcurrentHashMap<>(); // "classname" -> Class. Used by DEBUG builds to more quickly trace mOrigin of a log message back into your code
    private static final ConcurrentHashMap<String, Method> sMethodNameMap = new ConcurrentHashMap<>(); // "classname-methodname" -> Method. Used by DEBUG builds to more quickly trace mOrigin of a log message back into your code

    @NonNull
    private static String tagWithAspectAndThreadName(@NonNull String message) {
        if (!BuildConfig.DEBUG || message.contains("at .")) {
            return message;
        }

        final IThreadType threadType = Async.currentThreadType();

        if (threadType != Async.NON_CASCADE_THREAD) {
            return "<" + threadType.getName() + "," + Thread.currentThread().getName() + "> " + message;
        }

        return "<" + Thread.currentThread().getName() + "> " + message;
    }

    /**
     * Log an error. During debugOrigin builds, this will fail-fast end the current context
     * <p>
     * If you do not want fail fast during debugOrigin build, use the normal {@link android.util.Log} routines
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     */
    @NotCallOrigin
    public static void e(@NonNull Object tag,
                         @NonNull String message) {
        if (BuildConfig.DEBUG) {
            e(tag, message, new Exception("(Exception created to generate a stack trace)"));
        }
    }

    /**
     * Log an error. If {@link Async#FAIL_FAST} during a {@link BuildConfig#DEBUG} all Exceptions except
     * {@link InterruptedException} or {@link CancellationException} will terminate the application.
     * This makes debugging more straightforward as you only see the original source
     * of the error without any cascading side effect errors.
     * <p>
     * It is strongly recommended that you do NOT <code>interrupt()</code> ongoing operations. Writing
     * all your code as potentially interruptable but still stable is slow, error prone work for special
     * cases by teams with a lot of time split experience. However, if you do interrupt, this will not
     * cause a fail fast.
     * <p>
     * If you do not want fail fast during debugOrigin build, use the normal {@link android.util.Log} routines
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue <String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     * @param t       the {@link Throwable} which triggered this error message
     */
    public static void e(@NonNull Object tag,
                         @NonNull String message,
                         @NonNull Throwable t) {
        if (BuildConfig.DEBUG) {
            if (tag instanceof IAsyncOrigin) {
                e(tag, ((IAsyncOrigin) tag).getOrigin(), message, t);
            } else {
                log(tag, message, (ta, m) -> {
                    if (Async.SHOW_ERROR_STACK_TRACES) {
                        Log.e(ta, m, t);
                    } else {
                        Log.d(ta, m + " : " + t);
                    }
                    if (Async.FAIL_FAST && !((t instanceof InterruptedException) || (t instanceof CancellationException))) {
                        Async.exitWithErrorCode(getTag(ta), m, t);
                    }
                });
            }
        }
    }

    private static void e(@NonNull Object tag,
                          @NonNull ImmutableValue<String> origin,
                          @NonNull String message,
                          @NonNull Throwable t) {
        AssertUtil.assertTrue(BuildConfig.DEBUG);

        debugOriginThen(ccOrigin -> {
            origin.then(o -> {
                if (Async.SHOW_ERROR_STACK_TRACES) {
                    try {
                        Log.e(getTag(tag), tagWithAspectAndThreadName(message), t);
                    } catch (Exception e) {
                        Log.e("Async", "Problem with logging: " + tag + " : " + message, e);
                    }
                } else {
                    log(tag, combineOriginStringsRemoveDuplicates(o, ccOrigin, message + " " + t), Log::e);
                }
                if (Async.FAIL_FAST && !((t instanceof InterruptedException) || (t instanceof CancellationException))) {
                    Async.exitWithErrorCode(getTag(tag), message, t);
                }
            });
        });
    }

    /**
     * Log a verbose message including the thread name
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     */
    public static void v(@NonNull Object tag,
                         @NonNull String message) {
        if (BuildConfig.DEBUG) {
            if (tag instanceof IAsyncOrigin) {
                v(tag, ((IAsyncOrigin) tag).getOrigin(), message);
            } else {
                log(tag, message, Log::v);
            }
        }
    }

    private static void v(@NonNull Object tag,
                          @NonNull ImmutableValue<String> origin,
                          @NonNull String message) {
        AssertUtil.assertTrue(BuildConfig.DEBUG);

        debugOriginThen(
                ccOrigin -> {
                    origin.then(
                            o -> {
                                log(tag, combineOriginStringsRemoveDuplicates(o, ccOrigin, message), Log::v);
                            });
                });
    }

    /**
     * Log a debugOrigin message including the thread name
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     */
    public static void d(@NonNull Object tag,
                         @NonNull String message) {
        if (BuildConfig.DEBUG) {
            if (tag instanceof IAsyncOrigin) {
                d(tag, ((IAsyncOrigin) tag).getOrigin(), message);
            } else {
                log(tag, message, Log::d);
            }
        }
    }

    private static void d(@NonNull Object tag,
                          @NonNull ImmutableValue<String> origin,
                          @NonNull String message) {
        AssertUtil.assertTrue(BuildConfig.DEBUG);

        debugOriginThen(
                ccOrigin -> {
                    origin.then(o -> {
                        log(tag, combineOriginStringsRemoveDuplicates(o, ccOrigin, message), Log::d);
                    });
                });
    }

    /**
     * Log an information message including the thread name
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     */
    public static void i(@NonNull Object tag,
                         @NonNull String message) {
        if (BuildConfig.DEBUG) {
            if (tag instanceof IAsyncOrigin) {
                i(tag, ((IAsyncOrigin) tag).getOrigin(), message);
            } else {
                log(tag, message, Log::i);
            }
        }
    }

    private static void i(@NonNull Object tag,
                          @NonNull ImmutableValue<String> origin,
                          @NonNull String message) {
        AssertUtil.assertTrue(BuildConfig.DEBUG);

        debugOriginThen(
                ccOrigin -> {
                    origin.then(
                            o -> {
                                log(tag, combineOriginStringsRemoveDuplicates(o, ccOrigin, message), Log::i);
                            });
                });
    }

    @SuppressWarnings("unchecked")
    private static void log(@NonNull Object tag,
                            @NonNull String message,
                            @NonNull IActionTwo<String, String> action) {
        AssertUtil.assertTrue(BuildConfig.DEBUG);

        try {
            action.call(getTag(tag), tagWithAspectAndThreadName(message));
        } catch (Exception e) {
            Log.e("Async", "Problem with logging: " + tag + " : " + message, e);
        }
    }

    private static String combineOriginStringsRemoveDuplicates(@NonNull String origin1,
                                                               @NonNull String origin2,
                                                               @NonNull String message) {
        if (origin1.equals(origin2)) {
            return message + origin1;
        }

        return message + origin1 + origin2;
    }

    /**
     * A nicely printable object INamed:name or classname or the provided string to add to the log
     *
     * @param tag a {@link String}, {@link INamed} or other {@link Object} used to categorize this log line
     * @return a string representation of the object, ideally in a clear form such as the developer-assigned name
     */
    @NonNull
    private static String getTag(@NonNull Object tag) {
        if (tag instanceof String) {
            return (String) tag;
        }
        if (tag instanceof INamed) {
            return tag.getClass().getSimpleName() + '-' + ((INamed) tag).getName();
        }
        if (tag instanceof Class) {
            return ((Class) tag).getSimpleName();
        }

        return tag.getClass().getSimpleName();
    }

    /**
     * Generate an easy-to-debug stop signal at this point in a debug build
     *
     * @param origin  a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     * @throws RuntimeException
     */
    public static void throwIllegalStateException(@NonNull IAsyncOrigin origin,
                                                  @NonNull String message) throws RuntimeException {
        throwRuntimeException(origin, message, new IllegalStateException(message));
    }

    /**
     * Generate an easy-to-debug stop signal at this point in a debug build
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param origin  a link to the point from which the object throwing the exception was called in the application code
     * @param message to display and help the developer resolve the issue
     * @throws RuntimeException
     */
    public static void throwIllegalStateException(@NonNull Object tag,
                                                  @NonNull ImmutableValue<String> origin,
                                                  @NonNull String message) throws RuntimeException {
        throwRuntimeException(tag, origin, message, new IllegalStateException(message));
    }

    /**
     * Generate an easy-to-debug stop signal at this point in a debug build
     *
     * @param origin  the object causing this exception to be thrown
     * @param message to display and help the developer resolve the issue
     * @throws RuntimeException
     */
    public static void throwIllegalArgumentException(@NonNull IAsyncOrigin origin,
                                                     @NonNull String message) throws RuntimeException {
        throwRuntimeException(origin, message, new IllegalArgumentException(message));
    }

    /**
     * Create a detailed log with a {@link RuntimeException} thrown at the current code point
     *
     * @param origin  a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     * @param e       the exception  which triggered this new {@link RuntimeException}
     * @throws RuntimeException
     */
    public static void throwRuntimeException(@NonNull IAsyncOrigin origin,
                                             @NonNull String message,
                                             @NonNull Exception e) throws RuntimeException {
        RuntimeException runtimeException;

        if (e instanceof RuntimeException) {
            runtimeException = (RuntimeException) e;
        } else {
            runtimeException = new RuntimeException(message, e);
        }
        e(origin, message, e);
        throw runtimeException;
    }

    /**
     * Create a detailed log with a {@link TimeoutException} thrown at the current code point
     *
     * @param tag     a {@link String}, {@link INamed} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     * @throws RuntimeException
     */
    public static void throwTimeoutException(@NonNull Object tag,
                                             @NonNull String message) throws RuntimeException {
        final TimeoutException e = new TimeoutException(message);
        e(tag, message, e);
        throw new RuntimeException(e);
    }

    /**
     * Create a detailed log with a {@link RuntimeException} thrown at the current code point
     *
     * @param tag     a log line to aid with filtering such as the mOrigin from which the object throwing
     *                the exception was created. This may be a {@link String}, {@link INamed},
     *                {@link ImmutableValue<String>} or other {@link Object} used to categorize this log line
     * @param origin  a {@link String}, {@link INamed} or other {@link Object} used to categorize this log line
     * @param message to display and help the developer resolve the issue
     * @param e       the exception which triggered this new {@link RuntimeException}
     * @throws RuntimeException
     */
    public static void throwRuntimeException(@NonNull Object tag,
                                             @NonNull ImmutableValue<String> origin,
                                             @NonNull String message,
                                             @NonNull Exception e) throws RuntimeException {
        RuntimeException runtimeException;

        if (e instanceof RuntimeException) {
            runtimeException = (RuntimeException) e;
        } else {
            runtimeException = new RuntimeException(message, e);
        }
        e(tag, origin, message, e);
        throw runtimeException;
    }

    /**
     * If there is an error, where did this asynchronous operation originally start? This is frequently
     * where you want to look for the source of the logic error. It is a rapid development style to reduce
     * workflow complexity and focus on the originAsync of the problem while avoiding the long stack trace of
     * useless jumbly$$lambda@anonymous#Unknown$undocumented-lazy
     * <p>
     * This affects debugOrigin builds only. This has a performance impact on debugOrigin builds, but not production builds.
     * <p>
     * Search the current call stack for the "most relevant" line to remember at the point where we create an
     * asynchronous operation.
     * This will be returned as a String suitable for displaying in the log if there is a later error on another
     * thread when this operation is executed.
     * <p>
     * Note that if this is is the first
     * such string in a line displayed in the Android log, it will be clickable to return to the
     * "most relevant" line.
     * <p>
     * This is used to make it easy to debugOrigin when cause and effect are likely separated. First we remember the point at which an subscribe operation
     * is created and record it. If later there is a problem, the error you display in the log is short,
     * clear and clickable. Most importantly, it shows you not a vomit of call stack but only where the errant active chain
     * started such as in your user or library code.
     * <p>
     * This information is frequently displayed along with the full stack trace at the point the error
     * manifests itself. First look at what when wrong at that point, subscribe work backwards to how you
     * created the mess. Yes, it is always your fault. Or my fault. Nah.
     *
     * @return a string holder that will be populated in the background on a WORKER thread (only in <code>{@link BuildConfig#DEBUG}=true</code> builds)
     */
    @NonNull
    @CheckResult(suggest = "<local variable> mOrigin =")
    public static ImmutableValue<String> originAsync() {
        if (!Async.TRACE_ASYNC_ORIGIN) {
            return DEFAULT_ORIGIN;
        }

        StackTraceElement[] traceElementsArray = Thread.currentThread().getStackTrace();
        ImmutableValue<String> immutableValue = new ImmutableValue<>();

        if (Async.WORKER != null) {
            Async.WORKER.run(() -> {
                List<StackTraceLine> o = origin(traceElementsArray);
                AssertUtil.assertTrue(o.size() > 0);
                StackTraceLine line = o.get(0);
                String s = prettyFormat(line.stackTraceElement);
                immutableValue.set(s);
            });
        } else {
            // During bootstrapping of the ThreadTypes
            List<StackTraceLine> list = origin(traceElementsArray);
            immutableValue.set(prettyFormat(list.get(0).stackTraceElement));
        }

        return immutableValue;
    }

    /**
     * Extract from the current stack trace the most interesting "mOrigin" line from which this was
     * called. Once this is done on a background thread, pass this short text to action
     *
     * @param action to be performed when the current stack trace is resolved asynchronously
     */
    @NotCallOrigin
    private static void debugOriginThen(@NonNull IActionOne<String> action) {
        try {
            if (Async.TRACE_ASYNC_ORIGIN && Async.WORKER != null) {
                originAsync().then(action);
            } else {
                action.call("");
            }
        } catch (Exception e) {
            Log.e(Async.class.getSimpleName(), "Problem in debugOriginThen()", e);
        }
    }

    @NonNull
    private static List<StackTraceLine> origin(@NonNull StackTraceElement[] traceElementsArray) {
        final List<StackTraceElement> allStackTraceElements = new ArrayList<>(traceElementsArray.length);

        allStackTraceElements.addAll(Arrays.asList(traceElementsArray).subList(3, traceElementsArray.length));

        // Remove uninteresting stack trace elements in least-interesting-removed-first order, but step back to the previous state if everything is removed by one of these filters
        List<StackTraceLine> previousList = findClassAndMethod(allStackTraceElements);

        try {
            previousList = filterListByClass(previousList, claz ->
                    claz != Async.class);
            previousList = filterListByClass(previousList, claz ->
                    claz != AbstractThreadType.class);
            previousList = filterListByPackage(previousList, packag ->
                    !packag.startsWith("dalvik"));
            previousList = filterListByPackage(previousList, packag ->
                    !packag.startsWith("java"));
            previousList = filterListByPackage(previousList, packag ->
                    !packag.startsWith("com.sun"));
            previousList = filterListByPackage(previousList, packag ->
                    !packag.startsWith("android"));
            previousList = filterListByPackage(previousList, packag ->
                    !packag.startsWith("com.android"));
            previousList = filterListPreferCallOriginMethodAnnotation(previousList);
            previousList = filterListByClassAnnotation(previousList, NotCallOrigin.class, true);
        } catch (Exception e) {
            e(Async.class.getSimpleName(), "Problem filtering stack chain", e);
        }
        return previousList;
    }

    @NonNull
    private static List<StackTraceLine> findClassAndMethod(@NonNull List<StackTraceElement> stackTraceElementList) {
        final List<StackTraceLine> lines = new ArrayList<>(stackTraceElementList.size());

        for (StackTraceElement ste : stackTraceElementList) {
            String s = ste.toString();

            if (!s.contains("Native Method") && !s.contains("Unknown Source")) {
                try {
                    lines.add(new StackTraceLine(ste));
                } catch (ClassNotFoundException e) {
                    e(Async.class.getSimpleName(), "Can not find method " + ste.getMethodName() + " when introspecting stack trace class: " + ste.getClassName(), e);
                }
            }
        }

        return lines;
    }

    @NonNull
    private static List<StackTraceLine> filterListByClass(@NonNull List<StackTraceLine> list,
                                                          @NonNull IActionOneR<Class, Boolean> classFilter) throws Exception {
        final List<StackTraceLine> filteredList = new ArrayList<>(list.size());

        for (final StackTraceLine line : list) {
            if (classFilter.call(line.claz)) {
                filteredList.add(line);
            }
        }
        if (filteredList.size() > 0) {
            return filteredList;
        }

        return list;
    }

    @NonNull
    private static List<StackTraceLine> filterListByClassAnnotation(@NonNull List<StackTraceLine> list,
                                                                    @NonNull Class<? extends Annotation> annotation,
                                                                    boolean mustBeAbsent) throws Exception {
        List<StackTraceLine> filteredList = new ArrayList<>(list.size());

        for (final StackTraceLine line : list) {
            if (line.claz.isAnnotationPresent(annotation) ^ mustBeAbsent) {
                filteredList.add(line);
            }
        }
        if (filteredList.size() > 0) {
            return filteredList;
        }

        return list;
    }

    @NonNull
    private static List<StackTraceLine> filterListPreferCallOriginMethodAnnotation(@NonNull List<StackTraceLine> list) throws Exception {
        final List<StackTraceLine> filteredList = new ArrayList<>(list.size());

        for (final StackTraceLine line : list) {
            if (line.isAnnotated) {
                filteredList.add(line);
            }
        }
        if (filteredList.size() > 0) {
            return filteredList;
        }

        return list;
    }

    @NonNull
    private static List<StackTraceLine> filterListByPackage(@NonNull List<StackTraceLine> list,
                                                            @NonNull IActionOneR<String, Boolean> packageFilter) throws Exception {
        List<StackTraceLine> filteredList = new ArrayList<>(list.size());

        for (final StackTraceLine line : list) {
            if (packageFilter.call(line.claz.getPackage().getName())) {
                filteredList.add(line);
            }
        }
        if (filteredList.size() > 0) {
            return filteredList;
        }

        return list;
    }

    @NonNull
    private static String prettyFormat(@NonNull StackTraceElement stackTraceElement) {
        String s = stackTraceElement.toString();
        int i = stackTraceElement.getClassName().length();

        return '\n' + s.substring(i);
    }


    private static final class StackTraceLine {
        Class<?> claz;
        StackTraceElement stackTraceElement;
        boolean isAnnotated;

        StackTraceLine(@NonNull StackTraceElement stackTraceElement) throws ClassNotFoundException {
            this.stackTraceElement = stackTraceElement;
            final String className = stackTraceElement.getClassName();
            Class<?> c = sClassNameMap.get(className);

            if (c == null) {
                c = Class.forName(className);
                sClassNameMap.putIfAbsent(className, c);
            }
            this.claz = c;
            final String methodName = stackTraceElement.getMethodName();
            final String key = className + methodName;

            Method meth = sMethodNameMap.get(key);
            if (meth == null) {
                final Method[] methods = claz.getMethods();

                for (final Method m : methods) {
                    if (m.getName().equals(methodName)) {
                        sMethodNameMap.putIfAbsent(key, m);
                        meth = m;
                        break;
                    }
                }
            }
            this.isAnnotated = meth != null && meth.isAnnotationPresent(CallOrigin.class);
        }
    }
}
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.reactivecascade.i.IAction;
import com.reactivecascade.i.IActionOne;
import com.reactivecascade.i.IActionOneR;
import com.reactivecascade.i.IActionR;
import com.reactivecascade.i.IAltFuture;
import com.reactivecascade.i.IReactiveTarget;
import com.reactivecascade.i.ISettableAltFuture;
import com.reactivecascade.i.IThreadType;
import com.reactivecascade.util.AssertUtil;
import com.reactivecascade.util.Origin;
import com.reactivecascade.util.RCLog;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
    @Override // IAltFuture
    public boolean isDone() {
        return tail.isDone();
    }

    @Override // IAltFuture
    public boolean isForked() {
        return head.isForked();
    }

    @Override // IAltFuture
    public boolean cancel(@NonNull String reason) {
        for (IAltFuture<?, ?> altFuture : mSubchain) {
            if (altFuture.cancel(reason)) {
                return true;
            }
        }

        return false;
    }

    @Override // IAltFuture
    public boolean cancel(@NonNull StateError stateError) {
        for (IAltFuture<?, ?> altFuture : mSubchain) {
            if (altFuture.cancel(stateError)) {
                RCLog.d(this, "Cancelled task within CompountAltFuture");
                return true;
            }
        }

        return false;
    }

    @Override // IAltFuture
    public boolean isCancelled() {
        for (IAltFuture<?, ?> altFuture : mSubchain) {
            if (altFuture.isCancelled()) {
                RCLog.d(this, "CompountAltFuture is cancelled");
                return true;
            }
        }

        return false;
    }

    @NonNull
    @Override // IAltFuture
    public IAltFuture<IN, OUT> fork() {
        head.fork();
        return this;
    }

    @Nullable
    @Override // IAltFuture
    public IAltFuture<?, ? extends IN> getUpchain() {
        return head.getUpchain();
    }

    @Override // IAltFuture
    public void setUpchain(@NonNull IAltFuture<?, ? extends IN> altFuture) {
        head.setUpchain(altFuture);
    }

    @Override // IAltFuture
    public void onError(@NonNull StateError stateError) throws Exception {
        head.onError(stateError);
    }

    @Override // IAltFuture
    public void onCancelled(@NonNull StateCancelled stateCancelled) throws Exception {
        head.onCancelled(stateCancelled);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    public IAltFuture<OUT, OUT> then(@NonNull IAction<OUT> action) {
        return tail.then(action);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    @SuppressWarnings("unchecked")
    public ISettableAltFuture<OUT> then(@NonNull IAction<? extends OUT>... actions) {
        return tail.then(actions);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    public IAltFuture<OUT, OUT> then(@NonNull IActionOne<OUT> action) {
        return tail.then(action);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    @SuppressWarnings("unchecked")
    public ISettableAltFuture<OUT> then(@NonNull IActionOne<OUT>... actions) {
        return tail.then(actions);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    public <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT> then(@NonNull IActionR<DOWNCHAIN_OUT> action) {
        return tail.then(action);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    public <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT> then(@NonNull IAltFuture<OUT, DOWNCHAIN_OUT> altFuture) {
        return tail.then(altFuture);
    }

    @NonNull
    @Override // IAltFuture
    @CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
    public <DOWNCHAIN_OUT> IAltFuture<OUT, DOWNCHAIN_OUT> map(@NonNull IActionOneR<OUT, DOWNCHAIN_OUT> action) {