// Path: crate-sample/src/main/java/me/oriley/cratesample/fragments/BaseFragment.java
// public abstract class BaseFragment extends Fragment {
// 
//     @Nullable
//     private Unbinder mUnbinder;
// 
//     @Override
//     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
//         super.onViewCreated(view, savedInstanceState);
//         mUnbinder = ButterKnife.bind(this, view);
//     }
// 
//     @Override
//     @CallSuper
//     public void onDestroyView() {
//         if (mUnbinder != null) {
//             mUnbinder.unbind();
//             mUnbinder = null;
//         }
//         super.onDestroyView();
//     }
// 
//     @Nullable
//     protected BaseActivity getBaseActivity() {
//         Activity activity = getActivity();
//         if (activity instanceof BaseActivity) {
//             return (BaseActivity) activity;
//         } else {
//             return null;
//         }
//     }
// 
//     @Override
//     public Animation onCreateAnimation(int transit, final boolean enter, int nextAnim) {
//         if (nextAnim <= 0) {
//             return super.onCreateAnimation(transit, enter, nextAnim);
//         }
// 
//         final Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
//         anim.setAnimationListener(new Animation.AnimationListener() {
//             @Override
//             public void onAnimationStart(Animation animation) {
//             }
// 
//             @Override
//             public void onAnimationEnd(Animation animation) {
//                 BaseActivity baseActivity = getBaseActivity();
//                 if (baseActivity != null) {
//                     baseActivity.onFragmentAnimationComplete();
//                 }
//                 anim.setAnimationListener(null);
//             }
// 
//             @Override
//             public void onAnimationRepeat(Animation animation) {
// 
//             }
//         });
//         return anim;
//     }
// }
// 
// Path: crate-sample/src/main/java/me/oriley/cratesample/utils/FlagUtils.java
// public static boolean hasFlag(int flags, int flag) {
//     return (flags & flag) == flag;
// }


import android.support.annotation.*;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import me.oriley.cratesample.fragments.BaseFragment;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static me.oriley.cratesample.utils.FlagUtils.hasFlag;
            int exitAnim = hasFlag(animationFlags, FLAG_ANIM_EXIT) ? mOutAnimation : 0;
            int enterPopAnim = hasFlag(animationFlags, FLAG_ANIM_POP_ENTER) ? mInPopAnimation : 0;
            int exitPopAnim = hasFlag(animationFlags, FLAG_ANIM_POP_EXIT) ? mOutPopAnimation : 0;

            ft.setCustomAnimations(enterAnim, exitAnim, enterPopAnim, exitPopAnim);
            if (addToBackStack) {
                ft.addToBackStack(fragmentName);
            }
            if (replace) {
                ft.replace(mFragmentContainerId, fragment, defaultTag(fragment.getClass()));
            } else {
                ft.add(mFragmentContainerId, fragment, defaultTag(fragment.getClass()));
            }
            ft.commitAllowingStateLoss();
        }
    }

    @NonNull
    public final <T extends BaseFragment> T findOrCreate(@NonNull Class<T> fragmentClass) {
        return findByTagOrCreate(fragmentClass);
    }

    @Nullable
    @SuppressWarnings("unchecked")
    public final <T extends BaseFragment> T findByTag(@NonNull Class<? extends BaseFragment> fragmentClass) {
        return findByTag(defaultTag(fragmentClass));
    }

    @Nullable
    @SuppressWarnings("unchecked")
// Path: crate-sample/src/main/java/me/oriley/cratesample/fragments/BaseFragment.java
// public abstract class BaseFragment extends Fragment {
// 
//     @Nullable
//     private Unbinder mUnbinder;
// 
//     @Override
//     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
//         super.onViewCreated(view, savedInstanceState);
//         mUnbinder = ButterKnife.bind(this, view);
//     }
// 
//     @Override
//     @CallSuper
//     public void onDestroyView() {
//         if (mUnbinder != null) {
//             mUnbinder.unbind();
//             mUnbinder = null;
//         }
//         super.onDestroyView();
//     }
// 
//     @Nullable
//     protected BaseActivity getBaseActivity() {
//         Activity activity = getActivity();
//         if (activity instanceof BaseActivity) {
//             return (BaseActivity) activity;
//         } else {
//             return null;
//         }
//     }
// 
//     @Override
//     public Animation onCreateAnimation(int transit, final boolean enter, int nextAnim) {
//         if (nextAnim <= 0) {
//             return super.onCreateAnimation(transit, enter, nextAnim);
//         }
// 
//         final Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
//         anim.setAnimationListener(new Animation.AnimationListener() {
//             @Override
//             public void onAnimationStart(Animation animation) {
//             }
// 
//             @Override
//             public void onAnimationEnd(Animation animation) {
//                 BaseActivity baseActivity = getBaseActivity();
//                 if (baseActivity != null) {
//                     baseActivity.onFragmentAnimationComplete();
//                 }
//                 anim.setAnimationListener(null);
//             }
// 
//             @Override
//             public void onAnimationRepeat(Animation animation) {
// 
//             }
//         });
//         return anim;
//     }
// }
// 
// Path: crate-sample/src/main/java/me/oriley/cratesample/utils/FlagUtils.java
// public static boolean hasFlag(int flags, int flag) {
//     return (flags & flag) == flag;
// }


// Path: crate-sample/src/main/java/me/oriley/cratesample/activities/FragmentHelper.java
import android.support.annotation.*;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import me.oriley.cratesample.fragments.BaseFragment;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static me.oriley.cratesample.utils.FlagUtils.hasFlag;

            int exitAnim = hasFlag(animationFlags, FLAG_ANIM_EXIT) ? mOutAnimation : 0;
            int enterPopAnim = hasFlag(animationFlags, FLAG_ANIM_POP_ENTER) ? mInPopAnimation : 0;
            int exitPopAnim = hasFlag(animationFlags, FLAG_ANIM_POP_EXIT) ? mOutPopAnimation : 0;

            ft.setCustomAnimations(enterAnim, exitAnim, enterPopAnim, exitPopAnim);
            if (addToBackStack) {
                ft.addToBackStack(fragmentName);
            }
            if (replace) {
                ft.replace(mFragmentContainerId, fragment, defaultTag(fragment.getClass()));
            } else {
                ft.add(mFragmentContainerId, fragment, defaultTag(fragment.getClass()));
            }
            ft.commitAllowingStateLoss();
        }
    }

    @NonNull
    public final <T extends BaseFragment> T findOrCreate(@NonNull Class<T> fragmentClass) {
        return findByTagOrCreate(fragmentClass);
    }

    @Nullable
    @SuppressWarnings("unchecked")
    public final <T extends BaseFragment> T findByTag(@NonNull Class<? extends BaseFragment> fragmentClass) {
        return findByTag(defaultTag(fragmentClass));
    }

    @Nullable
    @SuppressWarnings("unchecked")
    public final <T extends BaseFragment> T findByTag(@NonNull String tag) {