// 
// Decompiled by Procyon v0.6.0
// 

package io.sentry;

import io.sentry.logger.ILoggerApi;
import io.sentry.protocol.User;
import io.sentry.protocol.Feedback;
import org.jetbrains.annotations.Nullable;
import io.sentry.protocol.SentryId;
import java.util.Properties;
import java.util.List;
import io.sentry.cache.IEnvelopeCache;
import io.sentry.backpressure.IBackpressureMonitor;
import io.sentry.backpressure.BackpressureMonitor;
import io.sentry.backpressure.NoOpBackpressureMonitor;
import io.sentry.util.thread.IThreadChecker;
import io.sentry.util.thread.ThreadChecker;
import io.sentry.util.thread.NoOpThreadChecker;
import io.sentry.util.DebugMetaPropertiesApplier;
import io.sentry.internal.debugmeta.IDebugMetaLoader;
import io.sentry.internal.debugmeta.ResourcesDebugMetaLoader;
import io.sentry.internal.debugmeta.NoOpDebugMetaLoader;
import io.sentry.internal.modules.CompositeModulesLoader;
import java.util.Arrays;
import io.sentry.internal.modules.ResourcesModulesLoader;
import io.sentry.internal.modules.ManifestModulesLoader;
import io.sentry.internal.modules.IModulesLoader;
import io.sentry.internal.modules.NoOpModulesLoader;
import java.util.concurrent.TimeUnit;
import io.sentry.cache.EnvelopeCache;
import io.sentry.transport.NoOpEnvelopeCache;
import io.sentry.config.PropertiesProviderFactory;
import io.sentry.cache.PersistingScopeObserver;
import java.util.Map;
import io.sentry.util.SentryRandom;
import java.io.OutputStream;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import io.sentry.util.FileUtils;
import java.io.File;
import io.sentry.opentelemetry.OpenTelemetryUtil;
import io.sentry.util.LoadClass;
import java.util.Iterator;
import java.util.concurrent.RejectedExecutionException;
import io.sentry.util.InitUtil;
import io.sentry.util.Platform;
import java.lang.reflect.InvocationTargetException;
import io.sentry.util.AutoClosableReentrantLock;
import java.nio.charset.Charset;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

public final class Sentry
{
    @NotNull
    private static volatile IScopesStorage scopesStorage;
    @NotNull
    private static volatile IScopes rootScopes;
    @NotNull
    private static final IScope globalScope;
    private static final boolean GLOBAL_HUB_DEFAULT_MODE = false;
    private static volatile boolean globalHubMode;
    @ApiStatus.Internal
    @NotNull
    public static final String APP_START_PROFILING_CONFIG_FILE_NAME = "app_start_profiling_config";
    private static final Charset UTF_8;
    private static final long classCreationTimestamp;
    private static final AutoClosableReentrantLock lock;
    
    private Sentry() {
    }
    
    @Deprecated
    @ApiStatus.Internal
    @NotNull
    public static IHub getCurrentHub() {
        return new HubScopesWrapper(getCurrentScopes());
    }
    
    @ApiStatus.Internal
    @NotNull
    public static IScopes getCurrentScopes() {
        return getCurrentScopes(true);
    }
    
    @ApiStatus.Internal
    @NotNull
    public static IScopes getCurrentScopes(final boolean ensureForked) {
        if (Sentry.globalHubMode) {
            return Sentry.rootScopes;
        }
        IScopes scopes = getScopesStorage().get();
        if (scopes == null || scopes.isNoOp()) {
            if (!ensureForked) {
                return NoOpScopes.getInstance();
            }
            scopes = Sentry.rootScopes.forkedScopes("getCurrentScopes");
            getScopesStorage().set(scopes);
        }
        return scopes;
    }
    
    @NotNull
    private static IScopesStorage getScopesStorage() {
        return Sentry.scopesStorage;
    }
    
    @ApiStatus.Internal
    @NotNull
    public static IScopes forkedRootScopes(@NotNull final String creator) {
        if (Sentry.globalHubMode) {
            return Sentry.rootScopes;
        }
        return Sentry.rootScopes.forkedScopes(creator);
    }
    
    @NotNull
    public static IScopes forkedScopes(@NotNull final String creator) {
        return getCurrentScopes().forkedScopes(creator);
    }
    
    @NotNull
    public static IScopes forkedCurrentScope(@NotNull final String creator) {
        return getCurrentScopes().forkedCurrentScope(creator);
    }
    
    @Deprecated
    @ApiStatus.Internal
    @NotNull
    public static ISentryLifecycleToken setCurrentHub(@NotNull final IHub hub) {
        return setCurrentScopes(hub);
    }
    
    @ApiStatus.Internal
    @NotNull
    public static ISentryLifecycleToken setCurrentScopes(@NotNull final IScopes scopes) {
        return getScopesStorage().set(scopes);
    }
    
    @NotNull
    public static IScope getGlobalScope() {
        return Sentry.globalScope;
    }
    
    public static boolean isEnabled() {
        return getCurrentScopes().isEnabled();
    }
    
    public static void init() {
        init(options -> options.setEnableExternalConfiguration(true), false);
    }
    
    public static void init(@NotNull final String dsn) {
        init(options -> options.setDsn(dsn));
    }
    
    public static <T extends SentryOptions> void init(@NotNull final OptionsContainer<T> clazz, @NotNull final OptionsConfiguration<T> optionsConfiguration) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        init(clazz, optionsConfiguration, false);
    }
    
    public static <T extends SentryOptions> void init(@NotNull final OptionsContainer<T> clazz, @NotNull final OptionsConfiguration<T> optionsConfiguration, final boolean globalHubMode) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        final T options = clazz.createInstance();
        applyOptionsConfiguration(optionsConfiguration, options);
        init(options, globalHubMode);
    }
    
    public static void init(@NotNull final OptionsConfiguration<SentryOptions> optionsConfiguration) {
        init(optionsConfiguration, false);
    }
    
    public static void init(@NotNull final OptionsConfiguration<SentryOptions> optionsConfiguration, final boolean globalHubMode) {
        final SentryOptions options = new SentryOptions();
        applyOptionsConfiguration(optionsConfiguration, options);
        init(options, globalHubMode);
    }
    
    private static <T extends SentryOptions> void applyOptionsConfiguration(final OptionsConfiguration<T> optionsConfiguration, final T options) {
        try {
            optionsConfiguration.configure(options);
        }
        catch (final Throwable t) {
            options.getLogger().log(SentryLevel.ERROR, "Error in the 'OptionsConfiguration.configure' callback.", t);
        }
    }
    
    @ApiStatus.Internal
    public static void init(@NotNull final SentryOptions options) {
        init(options, false);
    }
    
    private static void init(@NotNull final SentryOptions options, final boolean globalHubMode) {
        try (final ISentryLifecycleToken ignored = Sentry.lock.acquire()) {
            if (!options.getClass().getName().equals("io.sentry.android.core.SentryAndroidOptions") && Platform.isAndroid()) {
                throw new IllegalArgumentException("You are running Android. Please, use SentryAndroid.init. " + options.getClass().getName());
            }
            if (!preInitConfigurations(options)) {
                if (ignored != null) {
                    ignored.close();
                }
                return;
            }
            final Boolean globalHubModeFromOptions = options.isGlobalHubMode();
            final boolean globalHubModeToUse = (globalHubModeFromOptions != null) ? globalHubModeFromOptions : globalHubMode;
            options.getLogger().log(SentryLevel.INFO, "GlobalHubMode: '%s'", String.valueOf(globalHubModeToUse));
            Sentry.globalHubMode = globalHubModeToUse;
            initFatalLogger(options);
            final boolean shouldInit = InitUtil.shouldInit(Sentry.globalScope.getOptions(), options, isEnabled());
            if (shouldInit) {
                if (isEnabled()) {
                    options.getLogger().log(SentryLevel.WARNING, "Sentry has been already initialized. Previous configuration will be overwritten.", new Object[0]);
                }
                final IScopes scopes = getCurrentScopes();
                scopes.close(true);
                Sentry.globalScope.replaceOptions(options);
                final IScope rootScope = new Scope(options);
                final IScope rootIsolationScope = new Scope(options);
                Sentry.rootScopes = new Scopes(rootScope, rootIsolationScope, Sentry.globalScope, "Sentry.init");
                initLogger(options);
                initForOpenTelemetryMaybe(options);
                getScopesStorage().set(Sentry.rootScopes);
                initConfigurations(options);
                Sentry.globalScope.bindClient(new SentryClient(options));
                if (options.getExecutorService().isClosed()) {
                    options.setExecutorService(new SentryExecutorService(options));
                    options.getExecutorService().prewarm();
                }
                try {
                    options.getExecutorService().submit(() -> options.loadLazyFields());
                }
                catch (final RejectedExecutionException e) {
                    options.getLogger().log(SentryLevel.DEBUG, "Failed to call the executor. Lazy fields will not be loaded. Did you call Sentry.close()?", e);
                }
                movePreviousSession(options);
                for (final Integration integration : options.getIntegrations()) {
                    try {
                        integration.register(ScopesAdapter.getInstance(), options);
                    }
                    catch (final Throwable t) {
                        options.getLogger().log(SentryLevel.WARNING, "Failed to register the integration " + integration.getClass().getName(), t);
                    }
                }
                notifyOptionsObservers(options);
                finalizePreviousSession(options, ScopesAdapter.getInstance());
                handleAppStartProfilingConfig(options, options.getExecutorService());
                options.getLogger().log(SentryLevel.DEBUG, "Using openTelemetryMode %s", options.getOpenTelemetryMode());
                options.getLogger().log(SentryLevel.DEBUG, "Using span factory %s", options.getSpanFactory().getClass().getName());
                options.getLogger().log(SentryLevel.DEBUG, "Using scopes storage %s", Sentry.scopesStorage.getClass().getName());
            }
            else {
                options.getLogger().log(SentryLevel.WARNING, "This init call has been ignored due to priority being too low.", new Object[0]);
            }
        }
    }
    
    private static void initForOpenTelemetryMaybe(final SentryOptions options) {
        OpenTelemetryUtil.updateOpenTelemetryModeIfAuto(options, new LoadClass());
        if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) {
            options.setSpanFactory(new DefaultSpanFactory());
        }
        initScopesStorage(options);
        OpenTelemetryUtil.applyIgnoredSpanOrigins(options);
    }
    
    private static void initLogger(@NotNull final SentryOptions options) {
        if (options.isDebug() && options.getLogger() instanceof NoOpLogger) {
            options.setLogger(new SystemOutLogger());
        }
    }
    
    private static void initFatalLogger(@NotNull final SentryOptions options) {
        if (options.getFatalLogger() instanceof NoOpLogger) {
            options.setFatalLogger(new SystemOutLogger());
        }
    }
    
    private static void initScopesStorage(final SentryOptions options) {
        getScopesStorage().close();
        if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) {
            Sentry.scopesStorage = new DefaultScopesStorage();
        }
        else {
            Sentry.scopesStorage = ScopesStorageFactory.create(new LoadClass(), NoOpLogger.getInstance());
        }
    }
    
    private static void handleAppStartProfilingConfig(@NotNull final SentryOptions options, @NotNull final ISentryExecutorService sentryExecutorService) {
        try {
            sentryExecutorService.submit(() -> {
                final String cacheDirPath = options.getCacheDirPathWithoutDsn();
                if (cacheDirPath != null) {
                    final File appStartProfilingConfigFile = new File(cacheDirPath, "app_start_profiling_config");
                    try {
                        FileUtils.deleteRecursively(appStartProfilingConfigFile);
                        if (options.isEnableAppStartProfiling() || options.isStartProfilerOnAppStart()) {
                            if (!options.isStartProfilerOnAppStart() && !options.isTracingEnabled()) {
                                options.getLogger().log(SentryLevel.INFO, "Tracing is disabled and app start profiling will not start.", new Object[0]);
                            }
                            else if (appStartProfilingConfigFile.createNewFile()) {
                                TracesSamplingDecision sampleAppStartProfiling = null;
                                if (options.isEnableAppStartProfiling()) {
                                    sampleAppStartProfiling = sampleAppStartProfiling(options);
                                }
                                else {
                                    new(io.sentry.TracesSamplingDecision.class)();
                                    new TracesSamplingDecision(false);
                                }
                                final TracesSamplingDecision appStartSamplingDecision = sampleAppStartProfiling;
                                final SentryAppStartProfilingOptions appStartProfilingOptions = new SentryAppStartProfilingOptions(options, appStartSamplingDecision);
                                try (final OutputStream outputStream = new FileOutputStream(appStartProfilingConfigFile)) {
                                    new BufferedWriter(new OutputStreamWriter(outputStream, Sentry.UTF_8));
                                    final BufferedWriter bufferedWriter;
                                    try (final Writer writer = bufferedWriter) {
                                        options.getSerializer().serialize(appStartProfilingOptions, writer);
                                    }
                                }
                            }
                        }
                    }
                    catch (final Throwable e2) {
                        options.getLogger().log(SentryLevel.ERROR, "Unable to create app start profiling config file. ", e2);
                    }
                }
            });
        }
        catch (final Throwable e) {
            options.getLogger().log(SentryLevel.ERROR, "Failed to call the executor. App start profiling config will not be changed. Did you call Sentry.close()?", e);
        }
    }
    
    @NotNull
    private static TracesSamplingDecision sampleAppStartProfiling(@NotNull final SentryOptions options) {
        final TransactionContext appStartTransactionContext = new TransactionContext("app.launch", "profile");
        appStartTransactionContext.setForNextAppStart(true);
        final SamplingContext appStartSamplingContext = new SamplingContext(appStartTransactionContext, null, SentryRandom.current().nextDouble(), null);
        return options.getInternalTracesSampler().sample(appStartSamplingContext);
    }
    
    private static void movePreviousSession(@NotNull final SentryOptions options) {
        try {
            options.getExecutorService().submit(new MovePreviousSession(options));
        }
        catch (final Throwable e) {
            options.getLogger().log(SentryLevel.DEBUG, "Failed to move previous session.", e);
        }
    }
    
    private static void finalizePreviousSession(@NotNull final SentryOptions options, @NotNull final IScopes scopes) {
        try {
            options.getExecutorService().submit(new PreviousSessionFinalizer(options, scopes));
        }
        catch (final Throwable e) {
            options.getLogger().log(SentryLevel.DEBUG, "Failed to finalize previous session.", e);
        }
    }
    
    private static void notifyOptionsObservers(@NotNull final SentryOptions options) {
        try {
            options.getExecutorService().submit(() -> {
                options.getOptionsObservers().iterator();
                final Iterator iterator;
                while (iterator.hasNext()) {
                    final IOptionsObserver observer = iterator.next();
                    observer.setRelease(options.getRelease());
                    observer.setProguardUuid(options.getProguardUuid());
                    observer.setSdkVersion(options.getSdkVersion());
                    observer.setDist(options.getDist());
                    observer.setEnvironment(options.getEnvironment());
                    observer.setTags(options.getTags());
                    observer.setReplayErrorSampleRate(options.getSessionReplay().getOnErrorSampleRate());
                }
                final PersistingScopeObserver scopeCache = options.findPersistingScopeObserver();
                if (scopeCache != null) {
                    scopeCache.resetCache();
                }
            });
        }
        catch (final Throwable e) {
            options.getLogger().log(SentryLevel.DEBUG, "Failed to notify options observers.", e);
        }
    }
    
    private static boolean preInitConfigurations(@NotNull final SentryOptions options) {
        if (options.isEnableExternalConfiguration()) {
            options.merge(ExternalOptions.from(PropertiesProviderFactory.create(), options.getLogger()));
        }
        final String dsn = options.getDsn();
        if (!options.isEnabled() || (dsn != null && dsn.isEmpty())) {
            close();
            return false;
        }
        if (dsn == null) {
            throw new IllegalArgumentException("DSN is required. Use empty string or set enabled to false in SentryOptions to disable SDK.");
        }
        options.retrieveParsedDsn();
        return true;
    }
    
    private static void initConfigurations(@NotNull final SentryOptions options) {
        final ILogger logger = options.getLogger();
        logger.log(SentryLevel.INFO, "Initializing SDK with DSN: '%s'", options.getDsn());
        final String outboxPath = options.getOutboxPath();
        if (outboxPath != null) {
            final File outboxDir = new File(outboxPath);
            options.getRuntimeManager().runWithRelaxedPolicy(() -> outboxDir.mkdirs());
        }
        else {
            logger.log(SentryLevel.INFO, "No outbox dir path is defined in options.", new Object[0]);
        }
        final String cacheDirPath = options.getCacheDirPath();
        if (cacheDirPath != null) {
            final File cacheDir = new File(cacheDirPath);
            options.getRuntimeManager().runWithRelaxedPolicy(() -> cacheDir.mkdirs());
            final IEnvelopeCache envelopeCache = options.getEnvelopeDiskCache();
            if (envelopeCache instanceof NoOpEnvelopeCache) {
                options.setEnvelopeDiskCache(EnvelopeCache.create(options));
            }
        }
        final String profilingTracesDirPath = options.getProfilingTracesDirPath();
        if ((options.isProfilingEnabled() || options.isContinuousProfilingEnabled()) && profilingTracesDirPath != null) {
            final File profilingTracesDir = new File(profilingTracesDirPath);
            options.getRuntimeManager().runWithRelaxedPolicy(() -> profilingTracesDir.mkdirs());
            try {
                options.getExecutorService().submit(() -> {
                    final File[] oldTracesDirContent = profilingTracesDir.listFiles();
                    if (oldTracesDirContent == null) {
                        return;
                    }
                    else {
                        final File[] array;
                        int i = 0;
                        for (int length = array.length; i < length; ++i) {
                            final File f = array[i];
                            if (f.lastModified() < Sentry.classCreationTimestamp - TimeUnit.MINUTES.toMillis(5L)) {
                                FileUtils.deleteRecursively(f);
                            }
                        }
                        return;
                    }
                });
            }
            catch (final RejectedExecutionException e) {
                options.getLogger().log(SentryLevel.ERROR, "Failed to call the executor. Old profiles will not be deleted. Did you call Sentry.close()?", e);
            }
        }
        final IModulesLoader modulesLoader = options.getModulesLoader();
        if (!options.isSendModules()) {
            options.setModulesLoader(NoOpModulesLoader.getInstance());
        }
        else if (modulesLoader instanceof NoOpModulesLoader) {
            options.setModulesLoader(new CompositeModulesLoader(Arrays.asList(new ManifestModulesLoader(options.getLogger()), new ResourcesModulesLoader(options.getLogger())), options.getLogger()));
        }
        if (options.getDebugMetaLoader() instanceof NoOpDebugMetaLoader) {
            options.setDebugMetaLoader(new ResourcesDebugMetaLoader(options.getLogger()));
        }
        final List<Properties> propertiesList = options.getDebugMetaLoader().loadDebugMeta();
        DebugMetaPropertiesApplier.apply(options, propertiesList);
        final IThreadChecker threadChecker = options.getThreadChecker();
        if (threadChecker instanceof NoOpThreadChecker) {
            options.setThreadChecker(ThreadChecker.getInstance());
        }
        if (options.getPerformanceCollectors().isEmpty()) {
            options.addPerformanceCollector(new JavaMemoryCollector());
        }
        if (options.isEnableBackpressureHandling() && Platform.isJvm()) {
            if (options.getBackpressureMonitor() instanceof NoOpBackpressureMonitor) {
                options.setBackpressureMonitor(new BackpressureMonitor(options, ScopesAdapter.getInstance()));
            }
            options.getBackpressureMonitor().start();
        }
        initJvmContinuousProfiling(options);
        options.getLogger().log(SentryLevel.INFO, "Continuous profiler is enabled %s mode: %s", options.isContinuousProfilingEnabled(), options.getProfileLifecycle());
    }
    
    private static void initJvmContinuousProfiling(@NotNull final SentryOptions options) {
        InitUtil.initializeProfiler(options);
        InitUtil.initializeProfileConverter(options);
    }
    
    public static void close() {
        try (final ISentryLifecycleToken ignored = Sentry.lock.acquire()) {
            final IScopes scopes = getCurrentScopes();
            Sentry.rootScopes = NoOpScopes.getInstance();
            getScopesStorage().close();
            scopes.close(false);
        }
    }
    
    @NotNull
    public static SentryId captureEvent(@NotNull final SentryEvent event) {
        return getCurrentScopes().captureEvent(event);
    }
    
    @NotNull
    public static SentryId captureEvent(@NotNull final SentryEvent event, @NotNull final ScopeCallback callback) {
        return getCurrentScopes().captureEvent(event, callback);
    }
    
    @NotNull
    public static SentryId captureEvent(@NotNull final SentryEvent event, @Nullable final Hint hint) {
        return getCurrentScopes().captureEvent(event, hint);
    }
    
    @NotNull
    public static SentryId captureEvent(@NotNull final SentryEvent event, @Nullable final Hint hint, @NotNull final ScopeCallback callback) {
        return getCurrentScopes().captureEvent(event, hint, callback);
    }
    
    @NotNull
    public static SentryId captureMessage(@NotNull final String message) {
        return getCurrentScopes().captureMessage(message);
    }
    
    @NotNull
    public static SentryId captureMessage(@NotNull final String message, @NotNull final ScopeCallback callback) {
        return getCurrentScopes().captureMessage(message, callback);
    }
    
    @NotNull
    public static SentryId captureMessage(@NotNull final String message, @NotNull final SentryLevel level) {
        return getCurrentScopes().captureMessage(message, level);
    }
    
    @NotNull
    public static SentryId captureMessage(@NotNull final String message, @NotNull final SentryLevel level, @NotNull final ScopeCallback callback) {
        return getCurrentScopes().captureMessage(message, level, callback);
    }
    
    @NotNull
    public static SentryId captureFeedback(@NotNull final Feedback feedback) {
        return getCurrentScopes().captureFeedback(feedback);
    }
    
    @NotNull
    public static SentryId captureFeedback(@NotNull final Feedback feedback, @Nullable final Hint hint) {
        return getCurrentScopes().captureFeedback(feedback, hint);
    }
    
    @NotNull
    public static SentryId captureFeedback(@NotNull final Feedback feedback, @Nullable final Hint hint, @Nullable final ScopeCallback callback) {
        return getCurrentScopes().captureFeedback(feedback, hint, callback);
    }
    
    @NotNull
    public static SentryId captureException(@NotNull final Throwable throwable) {
        return getCurrentScopes().captureException(throwable);
    }
    
    @NotNull
    public static SentryId captureException(@NotNull final Throwable throwable, @NotNull final ScopeCallback callback) {
        return getCurrentScopes().captureException(throwable, callback);
    }
    
    @NotNull
    public static SentryId captureException(@NotNull final Throwable throwable, @Nullable final Hint hint) {
        return getCurrentScopes().captureException(throwable, hint);
    }
    
    @NotNull
    public static SentryId captureException(@NotNull final Throwable throwable, @Nullable final Hint hint, @NotNull final ScopeCallback callback) {
        return getCurrentScopes().captureException(throwable, hint, callback);
    }
    
    public static void captureUserFeedback(@NotNull final UserFeedback userFeedback) {
        getCurrentScopes().captureUserFeedback(userFeedback);
    }
    
    public static void addBreadcrumb(@NotNull final Breadcrumb breadcrumb, @Nullable final Hint hint) {
        getCurrentScopes().addBreadcrumb(breadcrumb, hint);
    }
    
    public static void addBreadcrumb(@NotNull final Breadcrumb breadcrumb) {
        getCurrentScopes().addBreadcrumb(breadcrumb);
    }
    
    public static void addBreadcrumb(@NotNull final String message) {
        getCurrentScopes().addBreadcrumb(message);
    }
    
    public static void addBreadcrumb(@NotNull final String message, @NotNull final String category) {
        getCurrentScopes().addBreadcrumb(message, category);
    }
    
    public static void setLevel(@Nullable final SentryLevel level) {
        getCurrentScopes().setLevel(level);
    }
    
    public static void setTransaction(@Nullable final String transaction) {
        getCurrentScopes().setTransaction(transaction);
    }
    
    public static void setUser(@Nullable final User user) {
        getCurrentScopes().setUser(user);
    }
    
    public static void setFingerprint(@NotNull final List<String> fingerprint) {
        getCurrentScopes().setFingerprint(fingerprint);
    }
    
    public static void clearBreadcrumbs() {
        getCurrentScopes().clearBreadcrumbs();
    }
    
    public static void setTag(@Nullable final String key, @Nullable final String value) {
        getCurrentScopes().setTag(key, value);
    }
    
    public static void removeTag(@Nullable final String key) {
        getCurrentScopes().removeTag(key);
    }
    
    public static void setExtra(@Nullable final String key, @Nullable final String value) {
        getCurrentScopes().setExtra(key, value);
    }
    
    public static void removeExtra(@Nullable final String key) {
        getCurrentScopes().removeExtra(key);
    }
    
    @NotNull
    public static SentryId getLastEventId() {
        return getCurrentScopes().getLastEventId();
    }
    
    @NotNull
    public static ISentryLifecycleToken pushScope() {
        if (!Sentry.globalHubMode) {
            return getCurrentScopes().pushScope();
        }
        return NoOpScopesLifecycleToken.getInstance();
    }
    
    @NotNull
    public static ISentryLifecycleToken pushIsolationScope() {
        if (!Sentry.globalHubMode) {
            return getCurrentScopes().pushIsolationScope();
        }
        return NoOpScopesLifecycleToken.getInstance();
    }
    
    @Deprecated
    public static void popScope() {
        if (!Sentry.globalHubMode) {
            getCurrentScopes().popScope();
        }
    }
    
    public static void withScope(@NotNull final ScopeCallback callback) {
        getCurrentScopes().withScope(callback);
    }
    
    public static void withIsolationScope(@NotNull final ScopeCallback callback) {
        getCurrentScopes().withIsolationScope(callback);
    }
    
    public static void configureScope(@NotNull final ScopeCallback callback) {
        configureScope(null, callback);
    }
    
    public static void configureScope(@Nullable final ScopeType scopeType, @NotNull final ScopeCallback callback) {
        getCurrentScopes().configureScope(scopeType, callback);
    }
    
    public static void bindClient(@NotNull final ISentryClient client) {
        getCurrentScopes().bindClient(client);
    }
    
    public static boolean isHealthy() {
        return getCurrentScopes().isHealthy();
    }
    
    public static void flush(final long timeoutMillis) {
        getCurrentScopes().flush(timeoutMillis);
    }
    
    public static void startSession() {
        getCurrentScopes().startSession();
    }
    
    public static void endSession() {
        getCurrentScopes().endSession();
    }
    
    @NotNull
    public static ITransaction startTransaction(@NotNull final String name, @NotNull final String operation) {
        return getCurrentScopes().startTransaction(name, operation);
    }
    
    @NotNull
    public static ITransaction startTransaction(@NotNull final String name, @NotNull final String operation, @NotNull final TransactionOptions transactionOptions) {
        return getCurrentScopes().startTransaction(name, operation, transactionOptions);
    }
    
    @NotNull
    public static ITransaction startTransaction(@NotNull final String name, @NotNull final String operation, @Nullable final String description, @NotNull final TransactionOptions transactionOptions) {
        final ITransaction transaction = getCurrentScopes().startTransaction(name, operation, transactionOptions);
        transaction.setDescription(description);
        return transaction;
    }
    
    @NotNull
    public static ITransaction startTransaction(@NotNull final TransactionContext transactionContexts) {
        return getCurrentScopes().startTransaction(transactionContexts);
    }
    
    @NotNull
    public static ITransaction startTransaction(@NotNull final TransactionContext transactionContext, @NotNull final TransactionOptions transactionOptions) {
        return getCurrentScopes().startTransaction(transactionContext, transactionOptions);
    }
    
    @ApiStatus.Experimental
    public static void startProfiler() {
        getCurrentScopes().startProfiler();
    }
    
    @ApiStatus.Experimental
    public static void stopProfiler() {
        getCurrentScopes().stopProfiler();
    }
    
    @Nullable
    public static ISpan getSpan() {
        if (Sentry.globalHubMode && Platform.isAndroid()) {
            return getCurrentScopes().getTransaction();
        }
        return getCurrentScopes().getSpan();
    }
    
    @Nullable
    public static Boolean isCrashedLastRun() {
        return getCurrentScopes().isCrashedLastRun();
    }
    
    public static void reportFullyDisplayed() {
        getCurrentScopes().reportFullyDisplayed();
    }
    
    @Nullable
    public static TransactionContext continueTrace(@Nullable final String sentryTrace, @Nullable final List<String> baggageHeaders) {
        return getCurrentScopes().continueTrace(sentryTrace, baggageHeaders);
    }
    
    @Nullable
    public static SentryTraceHeader getTraceparent() {
        return getCurrentScopes().getTraceparent();
    }
    
    @Nullable
    public static BaggageHeader getBaggage() {
        return getCurrentScopes().getBaggage();
    }
    
    @NotNull
    public static SentryId captureCheckIn(@NotNull final CheckIn checkIn) {
        return getCurrentScopes().captureCheckIn(checkIn);
    }
    
    @NotNull
    public static ILoggerApi logger() {
        return getCurrentScopes().logger();
    }
    
    @NotNull
    public static IReplayApi replay() {
        return getCurrentScopes().getScope().getOptions().getReplayController();
    }
    
    @NotNull
    public static IDistributionApi distribution() {
        return getCurrentScopes().getScope().getOptions().getDistributionController();
    }
    
    public static void showUserFeedbackDialog() {
        showUserFeedbackDialog(null);
    }
    
    public static void showUserFeedbackDialog(@Nullable final SentryFeedbackOptions.OptionsConfigurator configurator) {
        showUserFeedbackDialog(null, configurator);
    }
    
    public static void showUserFeedbackDialog(@Nullable final SentryId associatedEventId, @Nullable final SentryFeedbackOptions.OptionsConfigurator configurator) {
        final SentryOptions options = getCurrentScopes().getOptions();
        options.getFeedbackOptions().getDialogHandler().showDialog(associatedEventId, configurator);
    }
    
    public static void addFeatureFlag(@Nullable final String flag, @Nullable final Boolean result) {
        getCurrentScopes().addFeatureFlag(flag, result);
    }
    
    static {
        Sentry.scopesStorage = NoOpScopesStorage.getInstance();
        Sentry.rootScopes = NoOpScopes.getInstance();
        globalScope = new Scope(SentryOptions.empty());
        Sentry.globalHubMode = false;
        UTF_8 = Charset.forName("UTF-8");
        classCreationTimestamp = System.currentTimeMillis();
        lock = new AutoClosableReentrantLock();
    }
    
    public interface OptionsConfiguration<T extends SentryOptions>
    {
        void configure(@NotNull final T p0);
    }
}
