diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index d9867073..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,34 +0,0 @@ -version: 2 -jobs: - build: - working_directory: ~/code - docker: - - image: cimg/android:2024.01 - environment: - JVM_OPTS: -Xmx3200m - steps: - - checkout - - restore_cache: - key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} - # - run: - # name: Chmod permissions #if permission for Gradlew Dependencies fail, use this. - # command: sudo chmod +x ./gradlew - - run: - name: Create local.properties - command: touch local.properties - - run: - name: Add dummy api Key - command: echo "dropbox_key=\"foo\"" >> local.properties - - save_cache: - paths: - - ~/.gradle - key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} - - run: - name: Run Tests - command: ./gradlew lint test - - store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/ - path: app/build/reports - destination: reports - - store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/ - path: app/build/test-results - # See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples diff --git a/.github/workflows/detekt.yml b/.github/workflows/detekt.yml index 974e48a9..6fff1d30 100644 --- a/.github/workflows/detekt.yml +++ b/.github/workflows/detekt.yml @@ -1,116 +1,76 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow performs a static analysis of your Kotlin source code using -# Detekt. -# -# Scans are triggered: -# 1. On every push to default and protected branches -# 2. On every Pull Request targeting the default branch -# 3. On a weekly schedule -# 4. Manually, on demand, via the "workflow_dispatch" event -# -# The workflow should work with no modifications, but you might like to use a -# later version of the Detekt CLI by modifying the $DETEKT_RELEASE_TAG -# environment variable. -name: Scan with Detekt +name: Detekt Analysis on: - # Triggers the workflow on push or pull request events but only for default and protected branches + # Triggers on push to key branches push: - branches: [ "master" ] + branches: #[ "master", "stable", "next", "feature/major-refactor-ui-changes" ] + - '**' # Triggers on pull requests to any branch pull_request: - branches: [ "master" ] - schedule: + branches: + - '**' # Triggers on pull requests to any branch + schedule: # Scheduled weekly scan - cron: '35 5 * * 0' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -env: - # Release tag associated with version of Detekt to be installed - # SARIF support (required for this workflow) was introduced in Detekt v1.15.0 - DETEKT_RELEASE_TAG: v1.22.0 - DETEKT_RELEASE: 1.22.0 - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - # This workflow contains a single job called "scan" - scan: - name: Scan - # The type of runner that the job will run on + detekt: + name: Static Code Analysis with Detekt runs-on: ubuntu-latest - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + # ✅ Step 1: Checkout Repository + - name: Check out code + uses: actions/checkout@v4 - # Gets the download URL associated with the $DETEKT_RELEASE_TAG - - name: Get Detekt download URL - id: detekt_info - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh api graphql --field tagName=$DETEKT_RELEASE_TAG --raw-field query=' - query getReleaseAssetDownloadUrl($tagName: String!) { - repository(name: "detekt", owner: "detekt") { - release(tagName: $tagName) { - releaseAssets(name: "detekt", first: 1) { - nodes { - downloadUrl - } - } - tagCommit { - oid - } - } - } - } - ' 1> gh_response.json + # ✅ Step 2: Set up Java 17 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' - DETEKT_RELEASE_SHA=$(jq --raw-output '.data.repository.release.releaseAssets' gh_response.json) - if [ $DETEKT_RELEASE_SHA != "4b1da0d5feb53d9ae9b80193ad49c5597d7c4b42" ]; then - echo "Release tag doesn't match expected commit SHA" - exit 1 - fi - cat gh_response.json - DETEKT_DOWNLOAD_URL=https://github.com/detekt/detekt/releases/download/$DETEKT_RELEASE_TAG/detekt-cli-$DETEKT_RELEASE-all.jar - echo $DETEKT_DOWNLOAD_URL - echo "download_url=$DETEKT_DOWNLOAD_URL" >> $GITHUB_OUTPUT + # ✅ Step 3: Install Ruby and Bundler (Required for Fastlane) + - name: Install Ruby and Bundler + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3' + bundler-cache: true - # Sets up and runs the detekt cli - - name: Setup and Run Detekt - continue-on-error: true - id: detekt_setup_and_run + - name: Create local.properties file run: | - curl --request GET \ - --url ${{ steps.detekt_info.outputs.download_url }} \ - --silent \ - --location \ - --output detekt.jar - chmod a+x detekt.jar - # Performs static analysis using Detekt - java -jar "detekt.jar" --input ${{ github.workspace }} --all-rules --report sarif:${{ github.workspace }}/detekt.sarif.json + echo "MIXPANEL_KEY=${{ secrets.MIXPANEL_KEY }}" >> local.properties + echo "STOREFILE=${{ secrets.STOREFILE }}" >> local.properties + echo "STOREPASSWORD=${{ secrets.STOREPASSWORD }}" >> local.properties + echo "KEYALIAS=${{ secrets.KEYALIAS }}" >> local.properties + echo "KEYPASSWORD=${{ secrets.KEYPASSWORD }}" >> local.properties + - # Modifies the SARIF output produced by Detekt so that absolute URIs are relative - # This is so we can easily map results onto their source files - # This can be removed once relative URI support lands in Detekt: https://git.io/JLBbA - - name: Make artifact location URIs relative - continue-on-error: true + # ✅ Step 4: Install Fastlane Dependencies + - name: Install Fastlane dependencies run: | - echo "$( - jq \ - --arg github_workspace ${{ github.workspace }} \ - '. | ( .runs[].results[].locations[].physicalLocation.artifactLocation.uri |= if test($github_workspace) then .[($github_workspace | length | . + 1):] else . end )' \ - ${{ github.workspace }}/detekt.sarif.json - )" > ${{ github.workspace }}/detekt.sarif.json + bundle config path vendor/bundle + bundle install --jobs 4 --retry 3 + + # ✅ Step 5: Run Detekt via Fastlane + - name: Run Detekt + run: | + bundle exec fastlane detekt + + # ✅ Step 6: Upload SARIF report for GitHub Security Code Scanning + - name: Upload SARIF report for GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: "app/build/reports/detekt/detekt.sarif" + category: detekt-analysis - # Uploads results to GitHub repository using the upload-sarif action - - uses: github/codeql-action/upload-sarif@v2 + # ✅ Step 7: Upload Detekt Reports as Artifacts for Download + - name: Upload Detekt Reports as Artifacts + uses: actions/upload-artifact@v4 with: - # Path to SARIF file relative to the root of the repository - sarif_file: ${{ github.workspace }}/detekt.sarif.json - checkout_path: ${{ github.workspace }} + name: detekt-reports + path: | + */build/reports/detekt/*.html + */build/reports/detekt/*.md + */build/reports/detekt/*.xml \ No newline at end of file diff --git a/.gitignore b/.gitignore index f574ebe4..8f64e328 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,10 @@ fastlane/test_output fastlane/README.md fastlane/.env .env.default +/app/release/baselineProfiles/0/save-unspecified-release.dm +/app/release/baselineProfiles/1/save-unspecified-release.dm +/app/release/output-metadata.json +/app/src/main/assets/.env +/.kotlin/sessions/kotlin-compiler-1215430679833621634.salive +/.kotlin/ +/app/release/ diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index a9599c4f..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,213 +0,0 @@ -apply plugin: "com.android.application" -apply plugin: "kotlin-android" -apply plugin: "org.jetbrains.kotlin.android" - -android { - compileOptions { - sourceCompatibility 1.8 - targetCompatibility 1.8 - } - - signingConfigs { - debug { - def props = new Properties() - def localPropsFile = rootProject.file('local.properties') - if (localPropsFile.exists()) { - localPropsFile.withInputStream { props.load(it) } - } - - storeFile = file(props['storeFile'] ?: "") - storePassword = props['storePassword'] ?: "" - keyAlias = props['keyAlias'] ?: "" - keyPassword = props['keyPassword'] ?: "" - } - } - - compileSdk 34 - defaultConfig { - applicationId "net.opendasharchive.openarchive" - minSdkVersion 29 - //noinspection OldTargetApi - targetSdkVersion 34 - versionCode 30005 - versionName "0.7.7" - archivesBaseName = "Save-$versionName" - multiDexEnabled true - vectorDrawables.useSupportLibrary = true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - flavorDimensions += "free" - buildTypes { - release { - signingConfig signingConfigs.debug - minifyEnabled false - shrinkResources false - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - - debug { - signingConfig signingConfigs.debug - } - } - packagingOptions { - resources { - excludes += ["META-INF/LICENSE.txt", "META-INF/NOTICE.txt", "META-INF/LICENSE", "META-INF/NOTICE", "META-INF/DEPENDENCIES", "LICENSE.txt"] - } - } - productFlavors { - releaseflavor { - dimension "free" - applicationId "net.opendasharchive.openarchive.release" - } - } - - kotlinOptions { - jvmTarget = "1.8" - } - - buildFeatures { - viewBinding true - buildConfig true - compose true - } - - lint { - abortOnError false - } - - composeOptions { - kotlinCompilerExtensionVersion "1.5.13" - } - - namespace "net.opendasharchive.openarchive" -} - -dependencies { - - implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.23" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0" - -// implementation "androidx.core:core-ktx:1.13.1" - implementation "androidx.recyclerview:recyclerview:1.3.2" - implementation "androidx.appcompat:appcompat:1.6.1" - implementation "androidx.biometric:biometric:1.1.0" - implementation "androidx.security:security-crypto-ktx:1.1.0-alpha06" - implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0" - implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.7" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7" - implementation "androidx.preference:preference-ktx:1.2.1" - implementation "androidx.work:work-runtime:2.9.0" - implementation "androidx.work:work-runtime-ktx:2.9.0" - implementation "androidx.work:work-testing:2.9.0" - - implementation "androidx.compose.ui:ui:1.6.7" - implementation "androidx.compose.material3:material3:1.2.1" - implementation "androidx.compose.foundation:foundation:1.6.7" - implementation "androidx.compose.ui:ui-tooling-preview:1.6.7" - implementation "androidx.activity:activity-compose:1.9.0" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7" - implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7" - - implementation "io.insert-koin:koin-core:4.0.2" - implementation "io.insert-koin:koin-android:4.0.2" - implementation "io.insert-koin:koin-androidx-compose:4.0.2" - - implementation "com.github.satyan:sugar:1.5" - - implementation "com.google.code.gson:gson:2.10.1" - implementation "com.squareup.okhttp3:okhttp:4.12.0" - - // adding web dav support: https://github.com/thegrizzlylabs/sardine-android' - implementation "com.github.guardianproject:sardine-android:89f7eae512" - - implementation "com.google.android.material:material:1.11.0" - implementation "androidx.compose.material:material-icons-extended:1.6.7" - - implementation "com.github.bumptech.glide:glide:4.16.0" - annotationProcessor "com.github.bumptech.glide:compiler:4.16.0" - implementation "com.github.derlio:audio-waveform:v1.0.1" - implementation "com.github.esafirm:android-image-picker:3.0.0" - implementation "com.facebook.fresco:fresco:3.5.0" - implementation "com.squareup.picasso:picasso:2.5.2" - - implementation "com.github.abdularis:circularimageview:1.4" - - implementation "org.cleaninsights.sdk:clean-insights-sdk:2.8.0" - implementation "info.guardianproject.netcipher:netcipher:2.2.0-alpha" - - //from here: https://github.com/guardianproject/proofmode - implementation("org.proofmode:android-libproofmode:1.0.27") { - - transitive = false - - exclude group: "org.bitcoinj" - exclude group: "com.google.protobuf" - exclude group: "org.slf4j" - exclude group: "net.jcip" - exclude group: "commons-cli" - exclude group: "org.json" - exclude group: "com.google.guava" - exclude group: "com.google.guava", module: "guava-jdk5" - exclude group: "com.google.code.findbugs", module: "annotations" - exclude group: "com.squareup.okio", module: "okio" - } - - implementation "com.google.guava:guava:31.0.1-jre" - implementation "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" - - implementation "org.bouncycastle:bcpkix-jdk15to18:1.72" - implementation "org.bouncycastle:bcprov-jdk15to18:1.72" - api "org.bouncycastle:bcpg-jdk15to18:1.71" - - implementation "com.tbuonomo:dotsindicator:5.0" - implementation "com.guolindev.permissionx:permissionx:1.6.4" - - implementation "com.jakewharton.timber:timber:5.0.1" - - // Google Drive API - implementation "com.google.android.gms:play-services-auth:21.1.1" - implementation "com.google.http-client:google-http-client-gson:1.42.1" - implementation "com.google.api-client:google-api-client-android:1.26.0" - implementation "com.google.apis:google-api-services-drive:v3-rev136-1.25.0" - - // Tor - implementation "info.guardianproject:tor-android:0.4.7.14" - implementation "info.guardianproject:jtorctl:0.4.5.7" - - // New Play libraries - implementation "com.google.android.play:asset-delivery:2.2.2" - implementation "com.google.android.play:asset-delivery-ktx:2.2.2" - - implementation "com.google.android.play:feature-delivery:2.1.0" - implementation "com.google.android.play:feature-delivery-ktx:2.1.0" - - implementation "com.google.android.play:review:2.0.1" - implementation "com.google.android.play:review-ktx:2.0.1" - - implementation "com.google.android.play:app-update:2.1.0" - implementation "com.google.android.play:app-update-ktx:2.1.0" - - // Tests - testImplementation "junit:junit:4.13.2" - testImplementation "org.robolectric:robolectric:4.7.3" - androidTestImplementation "androidx.test.ext:junit:1.1.5" - androidTestImplementation "androidx.test:runner:1.5.2" - - // Pretty Logging - implementation "com.orhanobut:logger:2.2.0" -} - -configurations { - all*.exclude group: "com.google.guava", module: "listenablefuture" -} - -/** - testdroid {username '$bbusername' - password '$bbpassword' - deviceGroup 'gpdevices' - mode "FULL_RUN" - projectName "OASave"}**/ - diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..61b8832e --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,310 @@ +import java.io.FileInputStream +import java.util.Properties + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.compose") + id("org.jetbrains.kotlin.plugin.serialization") + id("com.google.devtools.ksp") + id("androidx.navigation.safeargs.kotlin") + alias(libs.plugins.detekt.plugin) +} + +fun loadLocalProperties(): Properties = Properties().apply { + val localPropsFile = rootProject.file("local.properties") + if (localPropsFile.exists()) { + FileInputStream(localPropsFile).use { load(it) } + } else { + setProperty("MIXPANELKEY", System.getenv("MIXPANEL_KEY") ?: "") + setProperty("STOREFILE", System.getenv("STOREFILE") ?: "") + setProperty("STOREPASSWORD", System.getenv("STOREPASSWORD") ?: "") + setProperty("KEYALIAS", System.getenv("KEYALIAS") ?: "") + setProperty("KEYPASSWORD", System.getenv("KEYPASSWORD") ?: "") + } +} + +android { + + //noinspection GradleDependency + compileSdk = 34 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + } + + defaultConfig { + applicationId = "net.opendasharchive.openarchive" + minSdk = 29 + //noinspection OldTargetApi + targetSdk = 34 + versionCode = 30006 + versionName = "0.7.8" + multiDexEnabled = true + vectorDrawables.useSupportLibrary = true + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + val localProps = loadLocalProperties() + resValue("string", "mixpanel_key", localProps.getProperty("MIXPANELKEY") ?: "") + } + + base { + archivesName.set("save-${project.version}") + } + + buildFeatures { + viewBinding = true + buildConfig = true + compose = true + } + + buildTypes { + + getByName("release") { + signingConfig = signingConfigs.getByName("debug") + isMinifyEnabled = false + isShrinkResources = false + applicationIdSuffix = ".release" + proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") + } + + getByName("debug") { + signingConfig = signingConfigs.getByName("debug") + applicationIdSuffix = ".debug" + isMinifyEnabled = false + } + } + + signingConfigs { + getByName("debug") { + val props = loadLocalProperties() + storeFile = file(props["STOREFILE"] as? String ?: "") + storePassword = props["STOREPASSWORD"] as? String ?: "" + keyAlias = props["KEYALIAS"] as? String ?: "" + keyPassword = props["KEYPASSWORD"] as? String ?: "" + } + } + + packaging { + resources { + excludes.addAll( + listOf( + "META-INF/LICENSE.txt", "META-INF/NOTICE.txt", "META-INF/LICENSE", + "META-INF/NOTICE", "META-INF/DEPENDENCIES", "LICENSE.txt" + ) + ) + } + } + + lint { + abortOnError = false + } + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } + + namespace = "net.opendasharchive.openarchive" + + configurations.all { + resolutionStrategy { + force("org.bouncycastle:bcprov-jdk15to18:1.72") + exclude(group = "org.bouncycastle", module = "bcprov-jdk15on") + } + } +} + +dependencies { + + // Core Kotlin and Coroutines + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + + + // AndroidX Libraries + implementation(libs.androidx.appcompat) + implementation(libs.androidx.recyclerview) + implementation(libs.androidx.viewpager2) + implementation(libs.androidx.recyclerview.selection) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.constraintlayout.compose) + implementation(libs.androidx.coordinatorlayout) + implementation(libs.androidx.core.splashscreen) + + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.androidx.lifecycle.viewmodel.compose) + implementation(libs.androidx.lifecycle.livedata) + implementation(libs.androidx.lifecycle.runtime.compose) + + implementation(libs.androidx.preferences) + implementation(libs.androidx.biometric) + implementation(libs.androidx.work) + implementation(libs.androidx.security.crypto) + + implementation(libs.androidx.fragment.ktx) + implementation(libs.androidx.fragment.compose) + + // Compose Preferences + implementation(libs.compose.preferences) + + // Material Design + implementation(libs.google.material) + + // AndroidX SwipeRefreshLayout + implementation(libs.androidx.swiperefresh) + + // Compose Libraries + implementation(libs.androidx.activity.ktx) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.foundation) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.icons.extended) + debugImplementation(libs.androidx.compose.ui.tooling) + + implementation(libs.androidx.compose.runtime) + implementation(libs.androidx.compose.runtime.livedata) + + // Navigation + implementation(libs.androidx.navigation.compose) + implementation(libs.androidx.navigation.ui) + implementation(libs.androidx.navigation.fragment) + implementation(libs.androidx.navigation.fragment.compose) + + // Preference + implementation(libs.androidx.preferences) + + // Dependency Injection + implementation(libs.koin.core) + implementation(libs.koin.android) + implementation(libs.koin.androidx.compose) + implementation(libs.koin.androidx.navigation) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + implementation(libs.koin.compose.viewmodel.navigation) + + // Image Libraries + implementation(libs.glide) + annotationProcessor(libs.glide.compiler) + implementation(libs.asafirm.image.picker) + implementation(libs.picasso) + implementation(libs.coil) + implementation(libs.coil.compose) + implementation(libs.coil.video) + + // Networking and Data + // Networking + implementation(libs.retrofit) + implementation(libs.retrofit.gson) + implementation(libs.gson) + implementation(libs.okhttp) + implementation(libs.okhttp.logging) + implementation(libs.guardianproject.sardine) + + // Utility Libraries + implementation(libs.timber) + implementation(libs.orhanobut.logger) + implementation("com.github.abdularis:circularimageview:1.4") + implementation("com.tbuonomo:dotsindicator:5.1.0") + implementation("com.guolindev.permissionx:permissionx:1.6.4") + + // Barcode Scanning + //implementation("com.google.zxing:core:3.5.3") + //implementation("com.journeyapps:zxing-android-embedded:4.3.0") + + // Security and Encryption + implementation("org.bouncycastle:bcpkix-jdk15to18:1.72") + implementation("org.bouncycastle:bcprov-jdk15to18:1.72") + api("org.bouncycastle:bcpg-jdk15to18:1.71") + + // Google Play Services + implementation("com.google.android.gms:play-services-auth:21.3.0") +// implementation("com.google.android.play:core-ktx:1.8.1") +// implementation("com.google.android.play:asset-delivery-ktx:2.3.0") +// implementation("com.google.android.play:feature-delivery-ktx:2.1.0") +// implementation("com.google.android.play:review-ktx:2.0.2") +// implementation("com.google.android.play:app-update-ktx:2.1.0") + + // Google Drive API + implementation("com.google.http-client:google-http-client-gson:1.42.3") + implementation("com.google.api-client:google-api-client-android:1.26.0") + implementation("com.google.apis:google-api-services-drive:v3-rev136-1.25.0") + + // Tor Libraries + implementation("info.guardianproject:tor-android:0.4.7.14") + implementation("info.guardianproject:jtorctl:0.4.5.7") + + implementation("org.bitcoinj:bitcoinj-core:0.16.2") + implementation("com.eclipsesource.j2v8:j2v8:6.2.1@aar") + + // ProofMode //from here: https://github.com/guardianproject/proofmode + implementation("org.proofmode:android-libproofmode:1.0.26") { + //transitive = false + exclude(group = "org.bitcoinj") + exclude(group = "com.google.protobuf") + exclude(group = "org.slf4j") + exclude(group = "net.jcip") + exclude(group = "commons-cli") + exclude(group = "org.json") + exclude(group = "com.google.guava") + exclude(group = "com.google.guava", module = "guava-jdk5") + exclude(group = "com.google.code.findbugs", module = "annotations") + exclude(group = "com.squareup.okio", module = "okio") + } + + // Guava Conflicts + implementation("com.google.guava:guava:31.0.1-jre") + implementation("com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava") + + implementation("com.github.satyan:sugar:1.5") + + // adding web dav support: https://github.com/thegrizzlylabs/sardine-android' + implementation("com.github.guardianproject:sardine-android:89f7eae512") + + implementation("com.github.derlio:audio-waveform:v1.0.1") + + implementation("org.cleaninsights.sdk:clean-insights-sdk:2.8.0") + implementation("info.guardianproject.netcipher:netcipher:2.2.0-alpha") + + // Mixpanel analytics + implementation("com.mixpanel.android:mixpanel-android:8.0.2") + + // Tests + testImplementation("junit:junit:4.13.2") + testImplementation("org.robolectric:robolectric:4.14.1") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + androidTestImplementation("androidx.test:runner:1.6.2") + testImplementation("androidx.work:work-testing:2.9.1") + + // Detekt + detektPlugins(libs.detekt.formatting) + detektPlugins(libs.detekt.rules.authors) + detektPlugins(libs.detekt.rules.libraries) + detektPlugins(libs.detekt.compose) + detektPlugins(libs.detekt.rules.compose) + + debugImplementation("com.squareup.leakcanary:leakcanary-android:3.0-alpha-8") +} + +configurations.all { + exclude(group = "com.google.guava", module = "listenablefuture") +} + +detekt { + config.setFrom(file("$rootDir/config/detekt-config.yml")) + baseline = file("$rootDir/config/baseline.xml") + source.setFrom( + files("$rootDir/app/src") + ) + buildUponDefaultConfig = true + allRules = false + autoCorrect = false + ignoreFailures = true +} \ No newline at end of file diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml new file mode 100644 index 00000000..e46e32ce --- /dev/null +++ b/app/detekt-baseline.xml @@ -0,0 +1,1924 @@ + + + + + AnnotationOnSeparateLine:Hbks.kt$Hbks.Availability.Enroll$@RequiresApi(Build.VERSION_CODES.R) data + ArgumentListWrapping:AlertHelper.kt$AlertHelper.Companion$( context, if (message != null) context.getString(message) else null, title, icon, buttons ) + ArgumentListWrapping:BaseButton.kt$( modifier = modifier, text = text, style = MaterialTheme.typography.bodyLarge.copy( fontSize = fontSize, fontWeight = fontWeight, color = color )) + ArgumentListWrapping:BrowseFoldersAdapter.kt$BrowseFoldersAdapter.FolderViewHolder$( binding.root) + ArgumentListWrapping:BrowseFoldersAdapter.kt$BrowseFoldersAdapter.FolderViewHolder$(binding.root) + ArgumentListWrapping:Collection.kt$Collection.Companion$( Collection::class.java, "project_id = ?", arrayOf(projectId.toString()), null, "id ASC", null) + ArgumentListWrapping:Collection.kt$Collection.Companion$(Collection::class.java, "project_id = ?", arrayOf(projectId.toString()), null, "id ASC", null) + ArgumentListWrapping:Context.kt$( this, getString(R.string.no_webbrowser_found_error), Toast.LENGTH_LONG) + ArgumentListWrapping:Context.kt$(this, getString(R.string.no_webbrowser_found_error), Toast.LENGTH_LONG) + ArgumentListWrapping:CreateNewFolderFragment.kt$CreateNewFolderFragment$( requireContext(), getString(R.string.folder_name_already_exists), Toast.LENGTH_LONG ) + ArgumentListWrapping:Drawable.kt$( TypedValue.COMPLEX_UNIT_DIP, biggerSideDipLength.toFloat(), context.resources.displayMetrics ) + ArgumentListWrapping:DrawableExtensions.kt$( (intrinsicWidth * factor).roundToInt(), (intrinsicHeight * factor).roundToInt(), context) + ArgumentListWrapping:DrawableExtensions.kt$( TypedValue.COMPLEX_UNIT_DIP, biggerSideDipLength.toFloat(), context.resources.displayMetrics) + ArgumentListWrapping:DrawableExtensions.kt$((intrinsicWidth * factor).roundToInt(), (intrinsicHeight * factor).roundToInt(), context) + ArgumentListWrapping:DrawableExtensions.kt$(TypedValue.COMPLEX_UNIT_DIP, biggerSideDipLength.toFloat(), context.resources.displayMetrics) + ArgumentListWrapping:EditFolderActivity.kt$EditFolderActivity$( this, R.string.action_remove_project, R.string.remove_from_app, buttons = listOf( AlertHelper.positiveButton(R.string.remove) { _, _ -> mProject.delete() finish() }, AlertHelper.negativeButton() ) ) + ArgumentListWrapping:FileUtils.kt$FileUtils$( Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)) + ArgumentListWrapping:FileUtils.kt$FileUtils$("$TAG File -", "Authority: " + uri.authority + ", Fragment: " + uri.fragment + ", Port: " + uri.port + ", Query: " + uri.query + ", Scheme: " + uri.scheme + ", Host: " + uri.host + ", Segments: " + uri.pathSegments.toString() ) + ArgumentListWrapping:FolderAdapter.kt$FolderAdapter$( LayoutInflater.from(parent.context), parent, false ) + ArgumentListWrapping:FullscreenDimmingOverlay.kt$FullScreenCreateGroupDimmingOverlay$( context, title = "Confirm", message = "Do you want to cancel?", positiveButtonText = "Yes", negativeButtonText = "No") + ArgumentListWrapping:FullscreenDimmingOverlay.kt$FullScreenDimmingOverlay$( context, title = "Confirm", message = "Do you want to cancel?", positiveButtonText = "Yes", negativeButtonText = "No") + ArgumentListWrapping:GDriveActivity.kt$GDriveActivity$( AlertHelper.positiveButton(R.string.remove) { _, _ -> // delete sign-in from database space.delete() // google logout val googleSignInClient = GoogleSignIn.getClient(applicationContext, GoogleSignInOptions.DEFAULT_SIGN_IN) googleSignInClient.revokeAccess().addOnCompleteListener { googleSignInClient.signOut() } // leave activity Space.navigate(this) }, AlertHelper.negativeButton()) + ArgumentListWrapping:GDriveConduit.kt$GDriveConduit$( "the createFolder calls defined in Conduit don't map to GDrive API. use GDriveConduit.createFolder instead") + ArgumentListWrapping:GDriveConduit.kt$GDriveConduit$("the createFolder calls defined in Conduit don't map to GDrive API. use GDriveConduit.createFolder instead") + ArgumentListWrapping:GDriveConduit.kt$GDriveConduit.Companion$( "mimeType='application/vnd.google-apps.folder' and 'root' in parents and trashed = false") + ArgumentListWrapping:GDriveConduit.kt$GDriveConduit.Companion$( "mimeType='application/vnd.google-apps.folder' and name = '$folderName' and trashed = false and '$parentId' in parents") + ArgumentListWrapping:GDriveConduit.kt$GDriveConduit.Companion$("mimeType='application/vnd.google-apps.folder' and 'root' in parents and trashed = false") + ArgumentListWrapping:GDriveConduit.kt$GDriveConduit.Companion$("mimeType='application/vnd.google-apps.folder' and name = '$folderName' and trashed = false and '$parentId' in parents") + ArgumentListWrapping:IaConduit.kt$IaConduit$( mContext.contentResolver, Uri.fromFile(uploadFile), uploadFile.length(), textMediaType, createListener(cancellable = { !mCancelled }) ) + ArgumentListWrapping:InternetArchiveFragment.kt$InternetArchiveFragment$( message) + ArgumentListWrapping:InternetArchiveFragment.kt$InternetArchiveFragment$(message) + ArgumentListWrapping:InternetArchiveLoginScreen.kt$( Intent.ACTION_VIEW, Uri.parse(CreateLogin.URI) ) + ArgumentListWrapping:InternetArchiveLoginScreen.kt$( contract = ActivityResultContracts.StartActivityForResult(), onResult = {}) + ArgumentListWrapping:InternetArchiveLoginScreen.kt$( modifier = Modifier .weight(1f) .heightIn(ThemeDimensions.touchable) .padding(ThemeDimensions.spacing.small), shape = RoundedCornerShape(ThemeDimensions.roundedCorner), onClick = { dispatch(Action.Cancel) }) + ArgumentListWrapping:InternetArchiveLoginScreen.kt$( modifier = Modifier.heightIn(ThemeDimensions.touchable), onClick = { dispatch(CreateLogin) }) + ArgumentListWrapping:InternetArchiveLoginScreen.kt$( modifier = Modifier.sizeIn(ThemeDimensions.touchable), onClick = { showPassword = !showPassword }) + ArgumentListWrapping:InternetArchiveLoginScreen.kt$( username = "user@example.org", password = "abc123" ) + ArgumentListWrapping:InternetArchiveMapper.kt$InternetArchiveMapper$( access = response.access, secret = response.secret ) + ArgumentListWrapping:MainActivity.kt$MainActivity$( AddMediaDialogFragment.RESP_FILES, this@MainActivity ) + ArgumentListWrapping:MainActivity.kt$MainActivity$( AddMediaDialogFragment.RESP_PHOTO_GALLERY, this@MainActivity ) + ArgumentListWrapping:MainActivity.kt$MainActivity$( AddMediaDialogFragment.RESP_TAKE_PHOTO, this@MainActivity ) + ArgumentListWrapping:MainActivity.kt$MainActivity$( Context.INPUT_METHOD_SERVICE) + ArgumentListWrapping:MainActivity.kt$MainActivity$( Manifest.permission.POST_NOTIFICATIONS) + ArgumentListWrapping:MainActivity.kt$MainActivity$(Context.INPUT_METHOD_SERVICE) + ArgumentListWrapping:MainActivity.kt$MainActivity$(Manifest.permission.POST_NOTIFICATIONS) + ArgumentListWrapping:Media.kt$Media.Companion$( Media::class.java, statuses.joinToString(" OR ") { "status = ?" }, statuses.map { it.id.toString() }.toTypedArray(), null, order, null ) + ArgumentListWrapping:MediaAdapter.kt$MediaAdapter$( it, it.getString(R.string.upload_unsuccessful_description), R.string.upload_unsuccessful, R.drawable.ic_error, listOf( AlertHelper.positiveButton(R.string.retry) { _, _ -> media[pos].apply { sStatus = Media.Status.Queued statusMessage = "" save() BroadcastManager.postChange(it, collectionId, id) } UploadService.startUploadService(it) }, AlertHelper.negativeButton(R.string.remove) { _, _ -> deleteItem(pos) }, AlertHelper.neutralButton() ) ) + ArgumentListWrapping:MediaViewHolder.kt$MediaViewHolder$( "Binding media item ${media?.id} with status ${media?.sStatus} and progress ${media?.uploadPercentage}") + ArgumentListWrapping:MediaViewHolder.kt$MediaViewHolder$("Binding media item ${media?.id} with status ${media?.sStatus} and progress ${media?.uploadPercentage}") + ArgumentListWrapping:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity$( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE ) + ArgumentListWrapping:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity.<no name provided>$( mBinding.fab.context, R.drawable.ic_arrow_right, ) + ArgumentListWrapping:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity.<no name provided>$( mBinding.fab.context, com.esafirm.imagepicker.R.drawable.ef_ic_done_white, ) + ArgumentListWrapping:PasscodeEntryScreen.kt$( text = "Enter Your Passcode", style = TextStyle( fontSize = 18.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground ) ) + ArgumentListWrapping:Picker.kt$Picker$( Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO) + ArgumentListWrapping:Picker.kt$Picker$( context, "${context.packageName}.provider", it ) + ArgumentListWrapping:ProofModeScreen.kt$( stringResource( R.string.prefs_use_proofmode_description, "https://www.google.com" ), HtmlCompat.FROM_HTML_MODE_COMPACT ) + ArgumentListWrapping:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$( R.string.pref_key_use_proof_mode) + ArgumentListWrapping:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$(R.string.pref_key_use_proof_mode) + ArgumentListWrapping:SaveClient.kt$SaveClient.Companion.<no name provided>$( Result.failure(OrbotException(context.getString(R.string.tor_connection_invalid)))) + ArgumentListWrapping:SaveClient.kt$SaveClient.Companion.<no name provided>$( Result.failure(OrbotException(context.getString(R.string.tor_connection_timeout)))) + ArgumentListWrapping:SaveClient.kt$SaveClient.Companion.<no name provided>$( Result.failure(e ?: OrbotException(context.getString(R.string.tor_connection_exception)))) + ArgumentListWrapping:SaveClient.kt$SaveClient.Companion.<no name provided>$(Result.failure(OrbotException(context.getString(R.string.tor_connection_invalid)))) + ArgumentListWrapping:SaveClient.kt$SaveClient.Companion.<no name provided>$(Result.failure(OrbotException(context.getString(R.string.tor_connection_timeout)))) + ArgumentListWrapping:SaveClient.kt$SaveClient.Companion.<no name provided>$(Result.failure(e ?: OrbotException(context.getString(R.string.tor_connection_exception)))) + ArgumentListWrapping:SettingsScreen.kt$( "light" to "Light", "dark" to "Dark", "system" to "System Default" ) + ArgumentListWrapping:SettingsScreen.kt$( key = "about_app", title = { Text("Save by Open Archive") }, summary = { Text("Tap to view about Save App") }, onClick = { // Handle URL intent openUrl(context, "https://open-archive.org/save") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "pref_app_passcode", defaultValue = false, title = { Text("Lock app with passcode") }, summary = { Text("6 digit passcode") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "pref_media_folders", title = { Text("Media Folders") }, summary = { Text("Add or remove media folders") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "pref_media_servers", title = { Text("Media Servers") }, summary = { Text("Add or remove media servers") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "privacy_policy", title = { Text("Terms & Privacy Policy") }, summary = { Text("Tap to view our Terms & Privacy Policy") }, onClick = { // Handle URL intent openUrl(context, "https://open-archive.org/privacy") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "proof_mode", title = { Text("Proof Mode") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "upload_wifi_only", defaultValue = false, title = { Text("Upload over Wi-Fi only") }, summary = { Text("Only upload media when connected to Wi-Fi") }) + ArgumentListWrapping:SettingsScreen.kt$( key = "use_tor", defaultValue = false, title = { Text("Use Tor") }, summary = { Text("Enable Tor for encryption") }) + ArgumentListWrapping:SmartFragmentStatePagerAdapter.kt$SmartFragmentStatePagerAdapter$( fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) + ArgumentListWrapping:SmartFragmentStatePagerAdapter.kt$SmartFragmentStatePagerAdapter$(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) + ArgumentListWrapping:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment$( group.key, viewBinding.repoNameTextfield.text.toString() ) + ArgumentListWrapping:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$( ContextCompat.getDrawable(context, R.drawable.outline_cloud_done_24)?.scaled(40, context)) + ArgumentListWrapping:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$( ContextCompat.getDrawable(context, R.drawable.outline_cloud_download_24)?.scaled(40, context)) + ArgumentListWrapping:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$(ContextCompat.getDrawable(context, R.drawable.outline_cloud_done_24)?.scaled(40, context)) + ArgumentListWrapping:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$(ContextCompat.getDrawable(context, R.drawable.outline_cloud_download_24)?.scaled(40, context)) + ArgumentListWrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$( ActivityResultContracts.GetMultipleContents()) + ArgumentListWrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$( R.color.colorPrimary, R.color.colorPrimaryDark ) + ArgumentListWrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$( requireContext(), title = "Download Media?", message = "Are you sure you want to download this media?", positiveButtonText = "Yes", negativeButtonText = "No") + ArgumentListWrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$( requireContext(), title = "Success", message = "File successfully downloaded") + ArgumentListWrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$(ActivityResultContracts.GetMultipleContents()) + ArgumentListWrapping:SnowbirdGroup.kt$SnowbirdGroup.Companion$( SnowbirdGroup::class.java, whereClause, whereArgs.toTypedArray(), null, null, null) + ArgumentListWrapping:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$( RESULT_REQUEST_KEY, bundleOf( RESULT_BUNDLE_NAVIGATION_KEY to RESULT_VAL_RAVEN_REPO_LIST_SCREEN, RESULT_BUNDLE_GROUP_KEY to groupKey ) ) + ArgumentListWrapping:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$( groupKey) + ArgumentListWrapping:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$(groupKey) + ArgumentListWrapping:SnowbirdRepo.kt$SnowbirdRepo.Companion$( SnowbirdRepo::class.java, whereClause, whereArgs.toTypedArray(), null, null, null ) + ArgumentListWrapping:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$( R.color.colorPrimary, R.color.colorPrimaryDark ) + ArgumentListWrapping:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$( object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_snowbird, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when (menuItem.itemId) { R.id.action_add -> { Utility.showMaterialWarning( context = requireContext(), message = "Feature not implemented yet.", positiveButtonText = "OK" ) true } else -> false } } }, viewLifecycleOwner, Lifecycle.State.RESUMED ) + ArgumentListWrapping:Space.kt$Space.Companion$( Space::class.java, whereClause, whereArgs.toTypedArray(), null, null, null ) + ArgumentListWrapping:SpaceAdapter.kt$SpaceAdapter$( DIFF_CALLBACK) + ArgumentListWrapping:SpaceAdapter.kt$SpaceAdapter$( LayoutInflater.from(parent.context), parent, false ) + ArgumentListWrapping:SpaceAdapter.kt$SpaceAdapter$(DIFF_CALLBACK) + ArgumentListWrapping:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$( DIFF_CALLBACK) + ArgumentListWrapping:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$(DIFF_CALLBACK) + ArgumentListWrapping:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$( ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.START) + ArgumentListWrapping:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.START) + ArgumentListWrapping:TextView.kt$( Position.Start.get(drawables), Position.Top.get(drawables), Position.End.get(drawables), Position.Bottom.get(drawables)) + ArgumentListWrapping:TorStatusDatabase.kt$TorStatusDatabase$( context, DATABASE_NAME, null, DATABASE_VERSION) + ArgumentListWrapping:TorStatusDatabase.kt$TorStatusDatabase$(context, DATABASE_NAME, null, DATABASE_VERSION) + ArgumentListWrapping:UnixSocketClient.kt$UnixSocketClient$( endpoint, method, body, { json.encodeToString(it) }, { json.decodeFromString<RESPONSE>(it) }) + ArgumentListWrapping:UnixSocketClient.kt$UnixSocketClient$( socket, endpoint, method, body, serialize) + ArgumentListWrapping:UnixSocketClient.kt$UnixSocketClient$(endpoint, method, body, { json.encodeToString(it) }, { json.decodeFromString<RESPONSE>(it) }) + ArgumentListWrapping:UnixSocketClient.kt$UnixSocketClient$(socket, endpoint, method, body, serialize) + ArgumentListWrapping:UploadService.kt$UploadService$( NOTIFICATION_CHANNEL_ID, getString(R.string.uploads), NotificationManager.IMPORTANCE_LOW ) + ArgumentListWrapping:UploadService.kt$UploadService$( this, 0, Intent(this, MainActivity::class.java), PendingIntent.FLAG_IMMUTABLE ) + ArgumentListWrapping:WebDavConduit.kt$WebDavConduit$( chunkPath, buffer, mMedia.mimeType, object : SardineListener { override fun transferred(bytes: Long) { jobProgress(offset.toLong() + bytes) } override fun continueUpload(): Boolean { return !mCancelled } }) + ArgumentListWrapping:WebDavConduit.kt$WebDavConduit$( construct(base, path, file.name), file, "text/plain", false, null) + ArgumentListWrapping:WebDavConduit.kt$WebDavConduit$( mContext.contentResolver, fullPath, mMedia.fileUri, mMedia.contentLength, mMedia.mimeType, false, object : SardineListener { var lastBytes: Long = 0 override fun transferred(bytes: Long) { if (bytes > lastBytes) { jobProgress(bytes) lastBytes = bytes } AppLogger.i("Bytes transferred for for ${mMedia.id}: ", "$bytes") } override fun continueUpload(): Boolean { AppLogger.i("Should continue upload for ${mMedia.id}?", "$mCancelled") return !mCancelled } }) + ArgumentListWrapping:WebDavConduit.kt$WebDavConduit$(mContext.contentResolver, fullPath, mMedia.fileUri, mMedia.contentLength, mMedia.mimeType, false, object : SardineListener { var lastBytes: Long = 0 override fun transferred(bytes: Long) { if (bytes > lastBytes) { jobProgress(bytes) lastBytes = bytes } AppLogger.i("Bytes transferred for for ${mMedia.id}: ", "$bytes") } override fun continueUpload(): Boolean { AppLogger.i("Should continue upload for ${mMedia.id}?", "$mCancelled") return !mCancelled } }) + ArgumentListWrapping:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$( message = getString(R.string.you_have_successfully_connected_to_a_private_server)) + ArgumentListWrapping:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$(message = getString(R.string.you_have_successfully_connected_to_a_private_server)) + ChainWrapping:Media.kt$Media$|| + ChainWrapping:Picker.kt$Picker$&& + ChainWrapping:PreviewAdapter.kt$PreviewAdapter.Companion.<no name provided>$&& + CommentSpacing:AddFolderActivity.kt$AddFolderActivity$//mBinding = ActivityAddFolderBinding.inflate(layoutInflater) + CommentSpacing:AddFolderActivity.kt$AddFolderActivity$//mBinding.browseFolderContainer.hide() + CommentSpacing:AddFolderActivity.kt$AddFolderActivity$//setContentView(mBinding.root) + CommentSpacing:BadgeDrawable.kt$BadgeDrawable$//NO-OP + CommentSpacing:BaseSnowbirdFragment.kt$BaseSnowbirdFragment$//FullScreenOverlayManager.hide() + CommentSpacing:BaseSnowbirdFragment.kt$BaseSnowbirdFragment$//FullScreenOverlayManager.show(this@BaseSnowbirdFragment) + CommentSpacing:DialogConfigBuilder.kt$DialogBuilder$//?: ButtonData(defaultPositiveTextFor(type)), + CommentSpacing:HomeActivity.kt$HomeActivity$//TODO: Refresh projects in MainViewModel + CommentSpacing:HomeScreen.kt$//@Composable + CommentSpacing:HomeScreen.kt$//fun MainMediaScreen(projectId: Long) { + CommentSpacing:HomeScreen.kt$//} + CommentSpacing:IaConduit.kt$IaConduit$/// Upload ProofMode metadata, if enabled and successfully created. + CommentSpacing:IaConduit.kt$IaConduit$/// headers for meta-data and proof mode + CommentSpacing:IaConduit.kt$IaConduit$/// upload proof mode + CommentSpacing:InternetArchiveActivity.kt$//fun Activity.measureNewBackend(type: Space.Type) { + CommentSpacing:InternetArchiveActivity.kt$//} + CommentSpacing:InternetArchiveDetailsScreen.kt$//InternetArchiveHeader() + CommentSpacing:InternetArchiveDetailsScreen.kt$//dismiss + CommentSpacing:InternetArchiveDetailsScreen.kt$//isRemoving = true + CommentSpacing:InternetArchiveLoginScreen.kt$//focusedIndicatorColor = Color.Transparent, + CommentSpacing:InternetArchiveLoginScreen.kt$//unfocusedIndicatorColor = Color.Transparent, + CommentSpacing:MainActivity.kt$MainActivity$///enableEdgeToEdge() + CommentSpacing:MainActivity.kt$MainActivity$//binding.contentMain.tvSelectedCount.text = if (count > 0) "Selected: $count" else "Select Media" + CommentSpacing:MainMediaFragment.kt$MainMediaFragment$//update selection UI by summing selected counts from all adapters. + CommentSpacing:MediaAdapter.kt$MediaAdapter$//CleanInsightsManager.measureEvent("backend", "upload-error", media[pos].space?.friendlyName) + CommentSpacing:MediaViewHolder.kt$MediaViewHolder.Box$//(binding as RvMediaBoxBinding).fileInfo + CommentSpacing:MediaViewHolder.kt$MediaViewHolder.Box$//(binding as RvMediaBoxBinding).title + CommentSpacing:PasscodeSetupActivity.kt$PasscodeSetupActivity$//onBackPressedCallback.handleOnBackPressed() + CommentSpacing:PasscodeSetupActivity.kt$PasscodeSetupActivity$//onBackPressedDispatcher.addCallback(onBackPressedCallback) + CommentSpacing:PreviewActivity.kt$PreviewActivity$//mBinding.addMenu.container.show(animate = true) + CommentSpacing:SettingsFragment.kt$SettingsFragment$//torViewModel.updateTorServiceState() + CommentSpacing:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$//button.setBackgroundResource(R.drawable.button_outlined_ripple) + CommentSpacing:SnowbirdGroupListAdapter.kt$//interface SnowbirdGroupsAdapterListener { + CommentSpacing:SnowbirdGroupListAdapter.kt$//} + CommentSpacing:SnowbirdGroupListAdapter.kt$SnowbirdGroupsAdapter.ViewHolder$//binding.button.setBackgroundResource(R.drawable.button_outlined_ripple) + CommentSpacing:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$//findNavController().navigate(SnowbirdGroupListFragmentDirections.navigateToSnowbirdShareScreen(groupKey)) + CommentSpacing:SnowbirdRepoListAdapter.kt$SnowbirdRepoListAdapter.SnowbirdRepoListViewHolder$//binding.button.setBackgroundResource(R.drawable.button_outlined_ripple) + CommentSpacing:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$//findNavController().navigate(SnowbirdRepoListFragmentDirections.navigateToSnowbirdListFilesScreen(groupKey, repoKey)) + CommentSpacing:SpaceAdapter.kt$SpaceAdapter$//@Suppress("NAME_SHADOWING") + CommentSpacing:SpaceAdapter.kt$SpaceAdapter$//spaces.add(Space(ADD_SPACE_ID)) + CommentSpacing:SpaceAdapter.kt$SpaceAdapter$//val spaces = spaces.toMutableList() + CommentSpacing:UnixSocketClient.kt$//sealed class ClientResponse<out T> { + CommentSpacing:UnixSocketClient.kt$//} + CommentSpacing:WebDavConduit.kt$WebDavConduit$/// Upload ProofMode metadata, if enabled and successfully created. + CommentSpacing:WebDavFragment.kt$WebDavFragment$//Refresh menu to hide confirm btn again + CommentSpacing:WebDavFragment.kt$WebDavFragment$//attemptLogin() + CommentSpacing:WebDavFragment.kt$WebDavFragment.<no name provided>$//todo: save changes here and show success dialog + CommentWrapping:MainMediaScreen.kt$/* no op */ + ComplexCondition:Hbks.kt$Hbks$key == null || cipher == null || ciphertext == null || ciphertext.size < 12 + ComposableParamOrder:Accordion.kt$Accordion + ComposableParamOrder:BaseDialog.kt$BaseDialog + ComposableParamOrder:ExpandableSpaceList.kt$ExpandableSpaceList + ComposableParamOrder:FolderOptionsPopup.kt$FolderOptionsPopup + ComposableParamOrder:HomeScreen.kt$HomeScreen + ComposableParamOrder:HomeScreen.kt$SaveNavGraph + ComposableParamOrder:InternetArchiveLoginScreen.kt$CustomSecureField + ComposableParamOrder:InternetArchiveLoginScreen.kt$CustomTextField + ComposableParamOrder:NumericKeypad.kt$NumberButton + ComposableParamOrder:NumericKeypad.kt$NumericKeypad + ComposableParamOrder:PrimaryButton.kt$PrimaryButton + ComposableParamOrder:UiImage.kt$UiImage$asIcon + CompositionLocalAllowlist:Colors.kt$LocalColors + CompositionLocalAllowlist:Dimensions.kt$LocalDimensions + ContentSlotReused:Accordion.kt$bodyContent + CyclomaticComplexMethod:DialogConfigBuilder.kt$DialogBuilder$@Composable fun build(): DialogConfig + CyclomaticComplexMethod:DialogConfigBuilder.kt$DialogBuilder$fun build(resourceProvider: ResourceProvider): DialogConfig + CyclomaticComplexMethod:FileUtils.kt$FileUtils$@SuppressLint("NewAPI", "LogNotTimber") fun getPath(context: Context, uri: Uri): String? + CyclomaticComplexMethod:HomeScreen.kt$@Composable fun HomeScreenContent( onExit: () -> Unit, state: HomeScreenState, onAction: (HomeScreenAction) -> Unit, onNavigateToCache: () -> Unit = {} ) + CyclomaticComplexMethod:IaConduit.kt$IaConduit$private fun mainHeader(): Headers + CyclomaticComplexMethod:MainMediaViewHolder.kt$MainMediaViewHolder$fun bind(media: Media? = null, isInSelectionMode: Boolean = false, doImageFade: Boolean = true) + CyclomaticComplexMethod:MediaAdapter.kt$MediaAdapter$override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaViewHolder + CyclomaticComplexMethod:MediaViewHolder.kt$MediaViewHolder$@SuppressLint("SetTextI18n") fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) + CyclomaticComplexMethod:NumericKeypad.kt$@Composable private fun NumberButton( label: String, enabled: Boolean = true, onClick: () -> Unit, hapticManager: HapticManager = koinInject() ) + CyclomaticComplexMethod:PreviewViewHolder.kt$PreviewViewHolder$@SuppressLint("SetTextI18n") fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) + CyclomaticComplexMethod:ReviewActivity.kt$ReviewActivity$private fun refresh() + CyclomaticComplexMethod:UnixSocketClientUtilityExtensions.kt$suspend fun UnixSocketClient.readBinaryResponseWithCancellation( inputStream: InputStream, onProgress: ((Long) -> Unit)? = null ): Triple<Int, Map<String, String>, ByteArray> + CyclomaticComplexMethod:WebDavConduit.kt$WebDavConduit$@Throws(IOException::class) private suspend fun uploadChunked(base: HttpUrl, path: List<String>, fileName: String): Boolean + EmptyFunctionBlock:CreateNewFolderFragment.kt$CreateNewFolderFragment.<no name provided>${} + EmptyFunctionBlock:PasscodeEntryViewModel.kt$PasscodeEntryViewModel${ } + EmptyFunctionBlock:ReviewActivity.kt$ReviewActivity.<no name provided>${ } + EmptyFunctionBlock:TorStatusDatabase.kt$TorStatusDatabase${ } + EmptyFunctionBlock:WebDavFragment.kt$WebDavFragment.<no name provided>${} + Filename:SnowbirdGroupListAdapter.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupListAdapter.kt + FinalNewline:ActivityExtension.kt$net.opendasharchive.openarchive.extensions.ActivityExtension.kt + FinalNewline:AddFolderActivity.kt$net.opendasharchive.openarchive.features.folders.AddFolderActivity.kt + FinalNewline:AddFolderScreen.kt$net.opendasharchive.openarchive.features.folders.AddFolderScreen.kt + FinalNewline:AddMediaDialogFragment.kt$net.opendasharchive.openarchive.features.media.AddMediaDialogFragment.kt + FinalNewline:AddMediaType.kt$net.opendasharchive.openarchive.features.media.AddMediaType.kt + FinalNewline:AlertHelper.kt$net.opendasharchive.openarchive.util.AlertHelper.kt + FinalNewline:ApiError.kt$net.opendasharchive.openarchive.db.ApiError.kt + FinalNewline:ApiResponse.kt$net.opendasharchive.openarchive.services.snowbird.service.ApiResponse.kt + FinalNewline:AppConfig.kt$net.opendasharchive.openarchive.features.settings.passcode.AppConfig.kt + FinalNewline:AppLogger.kt$net.opendasharchive.openarchive.core.logger.AppLogger.kt + FinalNewline:ApplicationExtensions.kt$net.opendasharchive.openarchive.extensions.ApplicationExtensions.kt + FinalNewline:BackoffStrategy.kt$net.opendasharchive.openarchive.services.snowbird.service.BackoffStrategy.kt + FinalNewline:BadgeDrawable.kt$net.opendasharchive.openarchive.util.BadgeDrawable.kt + FinalNewline:BaseActivity.kt$net.opendasharchive.openarchive.features.core.BaseActivity.kt + FinalNewline:BaseButton.kt$net.opendasharchive.openarchive.features.core.BaseButton.kt + FinalNewline:BaseComposeActivity.kt$net.opendasharchive.openarchive.features.core.BaseComposeActivity.kt + FinalNewline:BaseDialog.kt$net.opendasharchive.openarchive.features.core.dialog.BaseDialog.kt + FinalNewline:BaseFragment.kt$net.opendasharchive.openarchive.features.core.BaseFragment.kt + FinalNewline:BaseViewModel.kt$net.opendasharchive.openarchive.util.BaseViewModel.kt + FinalNewline:BasicAuthInterceptor.kt$net.opendasharchive.openarchive.services.webdav.BasicAuthInterceptor.kt + FinalNewline:BiometricAuthenticator.kt$net.opendasharchive.openarchive.features.settings.passcode.BiometricAuthenticator.kt + FinalNewline:BottomSheetExtensions.kt$net.opendasharchive.openarchive.extensions.BottomSheetExtensions.kt + FinalNewline:BrowseFolderScreen.kt$net.opendasharchive.openarchive.features.folders.BrowseFolderScreen.kt + FinalNewline:BrowseFoldersAdapter.kt$net.opendasharchive.openarchive.features.folders.BrowseFoldersAdapter.kt + FinalNewline:BrowseFoldersFragment.kt$net.opendasharchive.openarchive.features.folders.BrowseFoldersFragment.kt + FinalNewline:BrowseFoldersViewModel.kt$net.opendasharchive.openarchive.features.folders.BrowseFoldersViewModel.kt + FinalNewline:Collection.kt$net.opendasharchive.openarchive.db.Collection.kt + FinalNewline:Colors.kt$net.opendasharchive.openarchive.core.presentation.theme.Colors.kt + FinalNewline:Conduit.kt$net.opendasharchive.openarchive.services.Conduit.kt + FinalNewline:ConsentActivity.kt$net.opendasharchive.openarchive.features.settings.ConsentActivity.kt + FinalNewline:ContentPickerFragment.kt$net.opendasharchive.openarchive.features.media.ContentPickerFragment.kt + FinalNewline:Context.kt$net.opendasharchive.openarchive.util.extensions.Context.kt + FinalNewline:CreativeCommonsLicenseManager.kt$net.opendasharchive.openarchive.features.settings.CreativeCommonsLicenseManager.kt + FinalNewline:CustomBottomNavBar.kt$net.opendasharchive.openarchive.core.presentation.components.CustomBottomNavBar.kt + FinalNewline:CustomButton.kt$net.opendasharchive.openarchive.features.main.ui.CustomButton.kt + FinalNewline:DefaultScaffold.kt$net.opendasharchive.openarchive.features.settings.passcode.components.DefaultScaffold.kt + FinalNewline:DialogConfigBuilder.kt$net.opendasharchive.openarchive.features.core.dialog.DialogConfigBuilder.kt + FinalNewline:Drawable.kt$net.opendasharchive.openarchive.util.extensions.Drawable.kt + FinalNewline:DrawableExtensions.kt$net.opendasharchive.openarchive.extensions.DrawableExtensions.kt + FinalNewline:DrawableUtil.kt$net.opendasharchive.openarchive.util.DrawableUtil.kt + FinalNewline:DriveServiceHelper.kt$net.opendasharchive.openarchive.util.DriveServiceHelper.kt + FinalNewline:DurationExtensions.kt$net.opendasharchive.openarchive.extensions.DurationExtensions.kt + FinalNewline:EditFolderActivity.kt$net.opendasharchive.openarchive.features.settings.EditFolderActivity.kt + FinalNewline:Effects.kt$net.opendasharchive.openarchive.core.state.Effects.kt + FinalNewline:EmptyableRecyclerView.kt$net.opendasharchive.openarchive.features.main.ui.EmptyableRecyclerView.kt + FinalNewline:ExpandableSpaceList.kt$net.opendasharchive.openarchive.features.main.ui.components.ExpandableSpaceList.kt + FinalNewline:FeaturesModule.kt$net.opendasharchive.openarchive.core.di.FeaturesModule.kt + FinalNewline:FileUploadResult.kt$net.opendasharchive.openarchive.db.FileUploadResult.kt + FinalNewline:FileUtils.kt$net.opendasharchive.openarchive.util.FileUtils.kt + FinalNewline:FolderAdapter.kt$net.opendasharchive.openarchive.FolderAdapter.kt + FinalNewline:FolderDrawerAdapter.kt$net.opendasharchive.openarchive.features.main.adapters.FolderDrawerAdapter.kt + FinalNewline:FolderOptionsPopup.kt$net.opendasharchive.openarchive.features.main.ui.components.FolderOptionsPopup.kt + FinalNewline:FoldersActivity.kt$net.opendasharchive.openarchive.features.settings.FoldersActivity.kt + FinalNewline:FullscreenDimmingOverlay.kt$net.opendasharchive.openarchive.util.FullscreenDimmingOverlay.kt + FinalNewline:FullscreenOverlayManager.kt$net.opendasharchive.openarchive.util.FullscreenOverlayManager.kt + FinalNewline:GDriveActivity.kt$net.opendasharchive.openarchive.services.gdrive.GDriveActivity.kt + FinalNewline:GDriveConduit.kt$net.opendasharchive.openarchive.services.gdrive.GDriveConduit.kt + FinalNewline:GDriveFragment.kt$net.opendasharchive.openarchive.services.gdrive.GDriveFragment.kt + FinalNewline:GeneralSettingsActivity.kt$net.opendasharchive.openarchive.features.settings.GeneralSettingsActivity.kt + FinalNewline:HapticManager.kt$net.opendasharchive.openarchive.features.settings.passcode.HapticManager.kt + FinalNewline:HashingStrategy.kt$net.opendasharchive.openarchive.features.settings.passcode.HashingStrategy.kt + FinalNewline:Hbks.kt$net.opendasharchive.openarchive.util.Hbks.kt + FinalNewline:HomeActivity.kt$net.opendasharchive.openarchive.features.main.HomeActivity.kt + FinalNewline:HomeAppBar.kt$net.opendasharchive.openarchive.features.main.ui.components.HomeAppBar.kt + FinalNewline:HomeScreen.kt$net.opendasharchive.openarchive.features.main.ui.HomeScreen.kt + FinalNewline:HttpLikeException.kt$net.opendasharchive.openarchive.services.snowbird.service.HttpLikeException.kt + FinalNewline:ISnowbirdAPI.kt$net.opendasharchive.openarchive.services.snowbird.service.ISnowbirdAPI.kt + FinalNewline:InternetArchiveLocalSource.kt$net.opendasharchive.openarchive.features.internetarchive.infrastructure.datasource.InternetArchiveLocalSource.kt + FinalNewline:InternetArchiveScreen.kt$net.opendasharchive.openarchive.features.internetarchive.presentation.InternetArchiveScreen.kt + FinalNewline:JoinGroupResponse.kt$net.opendasharchive.openarchive.db.JoinGroupResponse.kt + FinalNewline:Listener.kt$net.opendasharchive.openarchive.core.state.Listener.kt + FinalNewline:MainBottomBar.kt$net.opendasharchive.openarchive.features.main.ui.components.MainBottomBar.kt + FinalNewline:MainDrawerContent.kt$net.opendasharchive.openarchive.features.main.ui.components.MainDrawerContent.kt + FinalNewline:MainMediaAdapter.kt$net.opendasharchive.openarchive.features.main.adapters.MainMediaAdapter.kt + FinalNewline:MainMediaAdapterTest.kt$net.opendasharchive.openarchive.MainMediaAdapterTest.kt + FinalNewline:MainMediaScreen.kt$net.opendasharchive.openarchive.features.main.ui.MainMediaScreen.kt + FinalNewline:MainViewModel.kt$net.opendasharchive.openarchive.features.main.MainViewModel.kt + FinalNewline:MediaAdapter.kt$net.opendasharchive.openarchive.db.MediaAdapter.kt + FinalNewline:MediaCacheScreen.kt$net.opendasharchive.openarchive.features.main.ui.MediaCacheScreen.kt + FinalNewline:MediaLaunchers.kt$net.opendasharchive.openarchive.features.media.MediaLaunchers.kt + FinalNewline:Notifier.kt$net.opendasharchive.openarchive.core.state.Notifier.kt + FinalNewline:NumericKeypad.kt$net.opendasharchive.openarchive.features.settings.passcode.components.NumericKeypad.kt + FinalNewline:Onboarding23Activity.kt$net.opendasharchive.openarchive.features.onboarding.Onboarding23Activity.kt + FinalNewline:Onboarding23FragmentStateAdapter.kt$net.opendasharchive.openarchive.features.onboarding.Onboarding23FragmentStateAdapter.kt + FinalNewline:Onboarding23InstructionsActivity.kt$net.opendasharchive.openarchive.features.onboarding.Onboarding23InstructionsActivity.kt + FinalNewline:Onboarding23SlideFragment.kt$net.opendasharchive.openarchive.features.onboarding.Onboarding23SlideFragment.kt + FinalNewline:PBKDF2HashingStrategy.kt$net.opendasharchive.openarchive.features.settings.passcode.PBKDF2HashingStrategy.kt + FinalNewline:PasscodeDots.kt$net.opendasharchive.openarchive.features.settings.passcode.components.PasscodeDots.kt + FinalNewline:PasscodeEntryActivity.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryActivity.kt + FinalNewline:PasscodeEntryScreen.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryScreen.kt + FinalNewline:PasscodeEntryViewModel.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryViewModel.kt + FinalNewline:PasscodeManager.kt$net.opendasharchive.openarchive.features.settings.passcode.PasscodeManager.kt + FinalNewline:PasscodeModule.kt$net.opendasharchive.openarchive.core.di.PasscodeModule.kt + FinalNewline:PasscodeRepository.kt$net.opendasharchive.openarchive.features.settings.passcode.PasscodeRepository.kt + FinalNewline:PasscodeSetupActivity.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupActivity.kt + FinalNewline:PasscodeSetupScreen.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupScreen.kt + FinalNewline:PasscodeSetupViewModel.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupViewModel.kt + FinalNewline:Picker.kt$net.opendasharchive.openarchive.features.media.Picker.kt + FinalNewline:Preview.kt$net.opendasharchive.openarchive.core.presentation.theme.Preview.kt + FinalNewline:PreviewActivity.kt$net.opendasharchive.openarchive.features.media.PreviewActivity.kt + FinalNewline:PreviewAdapter.kt$net.opendasharchive.openarchive.features.media.PreviewAdapter.kt + FinalNewline:PreviewViewHolder.kt$net.opendasharchive.openarchive.features.media.adapter.PreviewViewHolder.kt + FinalNewline:PrimaryButton.kt$net.opendasharchive.openarchive.core.presentation.components.PrimaryButton.kt + FinalNewline:ProcessingTracker.kt$net.opendasharchive.openarchive.util.ProcessingTracker.kt + FinalNewline:Project.kt$net.opendasharchive.openarchive.db.Project.kt + FinalNewline:ProofModeHelper.kt$net.opendasharchive.openarchive.util.ProofModeHelper.kt + FinalNewline:ProofModeScreen.kt$net.opendasharchive.openarchive.features.settings.ProofModeScreen.kt + FinalNewline:QRScannerActivity.kt$net.opendasharchive.openarchive.features.main.QRScannerActivity.kt + FinalNewline:Reducer.kt$net.opendasharchive.openarchive.core.state.Reducer.kt + FinalNewline:RequestListener.kt$net.opendasharchive.openarchive.services.internetarchive.RequestListener.kt + FinalNewline:RequestNameDTO.kt$net.opendasharchive.openarchive.db.RequestNameDTO.kt + FinalNewline:RestEndpointTask.kt$net.opendasharchive.openarchive.features.main.RestEndpointTask.kt + FinalNewline:RetrofitAPI.kt$net.opendasharchive.openarchive.services.snowbird.service.RetrofitAPI.kt + FinalNewline:RetrofitClient.kt$net.opendasharchive.openarchive.services.snowbird.service.RetrofitClient.kt + FinalNewline:RetrofitModule.kt$net.opendasharchive.openarchive.core.di.RetrofitModule.kt + FinalNewline:RetryConfig.kt$net.opendasharchive.openarchive.services.snowbird.service.RetryConfig.kt + FinalNewline:SaveApp.kt$net.opendasharchive.openarchive.SaveApp.kt + FinalNewline:ScryptHashingStrategy.kt$net.opendasharchive.openarchive.features.settings.passcode.ScryptHashingStrategy.kt + FinalNewline:SectionViewHolder.kt$net.opendasharchive.openarchive.features.main.SectionViewHolder.kt + FinalNewline:SerializableMarker.kt$net.opendasharchive.openarchive.db.SerializableMarker.kt + FinalNewline:ServerOptionItem.kt$net.opendasharchive.openarchive.features.spaces.ServerOptionItem.kt + FinalNewline:SettingsFragment.kt$net.opendasharchive.openarchive.features.settings.SettingsFragment.kt + FinalNewline:SettingsScreen.kt$net.opendasharchive.openarchive.features.settings.SettingsScreen.kt + FinalNewline:Shape.kt$net.opendasharchive.openarchive.core.presentation.theme.Shape.kt + FinalNewline:SmartFragmentStatePagerAdapter.kt$net.opendasharchive.openarchive.util.SmartFragmentStatePagerAdapter.kt + FinalNewline:SnowbirdBridge.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdBridge.kt + FinalNewline:SnowbirdConduit.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdConduit.kt + FinalNewline:SnowbirdCreateGroupFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdCreateGroupFragment.kt + FinalNewline:SnowbirdError.kt$net.opendasharchive.openarchive.db.SnowbirdError.kt + FinalNewline:SnowbirdFileListAdapter.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdFileListAdapter.kt + FinalNewline:SnowbirdFileListFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdFileListFragment.kt + FinalNewline:SnowbirdFileRepository.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdFileRepository.kt + FinalNewline:SnowbirdFileViewModel.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdFileViewModel.kt + FinalNewline:SnowbirdFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdFragment.kt + FinalNewline:SnowbirdGroup.kt$net.opendasharchive.openarchive.db.SnowbirdGroup.kt + FinalNewline:SnowbirdGroupListAdapter.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupListAdapter.kt + FinalNewline:SnowbirdGroupListFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupListFragment.kt + FinalNewline:SnowbirdGroupOverviewFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupOverviewFragment.kt + FinalNewline:SnowbirdGroupRepository.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupRepository.kt + FinalNewline:SnowbirdGroupViewModel.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupViewModel.kt + FinalNewline:SnowbirdJoinGroupFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdJoinGroupFragment.kt + FinalNewline:SnowbirdRepo.kt$net.opendasharchive.openarchive.db.SnowbirdRepo.kt + FinalNewline:SnowbirdRepoListAdapter.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoListAdapter.kt + FinalNewline:SnowbirdRepoListFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoListFragment.kt + FinalNewline:SnowbirdRepoRepository.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoRepository.kt + FinalNewline:SnowbirdRepoViewModel.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoViewModel.kt + FinalNewline:SnowbirdResult.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdResult.kt + FinalNewline:SnowbirdService.kt$net.opendasharchive.openarchive.services.snowbird.service.SnowbirdService.kt + FinalNewline:SnowbirdServiceStatus.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdServiceStatus.kt + FinalNewline:SnowbirdShareFragment.kt$net.opendasharchive.openarchive.services.snowbird.SnowbirdShareFragment.kt + FinalNewline:Space.kt$net.opendasharchive.openarchive.db.Space.kt + FinalNewline:SpaceAdapter.kt$net.opendasharchive.openarchive.SpaceAdapter.kt + FinalNewline:SpaceDrawerAdapter.kt$net.opendasharchive.openarchive.features.main.adapters.SpaceDrawerAdapter.kt + FinalNewline:SpaceListFragment.kt$net.opendasharchive.openarchive.features.spaces.SpaceListFragment.kt + FinalNewline:SpaceListScreen.kt$net.opendasharchive.openarchive.features.spaces.SpaceListScreen.kt + FinalNewline:SpaceSetupFragment.kt$net.opendasharchive.openarchive.features.settings.SpaceSetupFragment.kt + FinalNewline:SpaceSetupSuccessFragment.kt$net.opendasharchive.openarchive.features.settings.SpaceSetupSuccessFragment.kt + FinalNewline:SpacingItemDecoration.kt$net.opendasharchive.openarchive.util.SpacingItemDecoration.kt + FinalNewline:Stateful.kt$net.opendasharchive.openarchive.core.state.Stateful.kt + FinalNewline:Store.kt$net.opendasharchive.openarchive.core.state.Store.kt + FinalNewline:StringExtensions.kt$net.opendasharchive.openarchive.extensions.StringExtensions.kt + FinalNewline:SuspendableExtensions.kt$net.opendasharchive.openarchive.extensions.SuspendableExtensions.kt + FinalNewline:SwipeToDeleteCallback.kt$net.opendasharchive.openarchive.upload.SwipeToDeleteCallback.kt + FinalNewline:TextView.kt$net.opendasharchive.openarchive.util.extensions.TextView.kt + FinalNewline:ThrowableExceptions.kt$net.opendasharchive.openarchive.extensions.ThrowableExceptions.kt + FinalNewline:ToolbarConfigurable.kt$net.opendasharchive.openarchive.features.core.ToolbarConfigurable.kt + FinalNewline:TorStatusContentProvider.kt$net.opendasharchive.openarchive.provider.TorStatusContentProvider.kt + FinalNewline:TorStatusDatabase.kt$net.opendasharchive.openarchive.provider.TorStatusDatabase.kt + FinalNewline:TwoLetterDrawable.kt$net.opendasharchive.openarchive.util.TwoLetterDrawable.kt + FinalNewline:UiImage.kt$net.opendasharchive.openarchive.features.core.UiImage.kt + FinalNewline:UiText.kt$net.opendasharchive.openarchive.features.core.UiText.kt + FinalNewline:UnitTests.kt$net.opendasharchive.openarchive.UnitTests.kt + FinalNewline:UnixSocketAPI.kt$net.opendasharchive.openarchive.services.snowbird.service.UnixSocketAPI.kt + FinalNewline:UnixSocketClient.kt$net.opendasharchive.openarchive.features.main.UnixSocketClient.kt + FinalNewline:UnixSocketClientFileExtensions.kt$net.opendasharchive.openarchive.features.main.UnixSocketClientFileExtensions.kt + FinalNewline:UnixSocketClientUtilityExtensions.kt$net.opendasharchive.openarchive.features.main.UnixSocketClientUtilityExtensions.kt + FinalNewline:UnixSocketModule.kt$net.opendasharchive.openarchive.core.di.UnixSocketModule.kt + FinalNewline:UploadManagerActivity.kt$net.opendasharchive.openarchive.upload.UploadManagerActivity.kt + FinalNewline:UploadManagerFragment.kt$net.opendasharchive.openarchive.upload.UploadManagerFragment.kt + FinalNewline:UploadService.kt$net.opendasharchive.openarchive.upload.UploadService.kt + FinalNewline:UriExtensions.kt$net.opendasharchive.openarchive.extensions.UriExtensions.kt + FinalNewline:Util.kt$net.opendasharchive.openarchive.services.internetarchive.Util.kt + FinalNewline:Utility.kt$net.opendasharchive.openarchive.util.Utility.kt + FinalNewline:VideoRequestHandler.kt$net.opendasharchive.openarchive.fragments.VideoRequestHandler.kt + FinalNewline:ViewExtension.kt$net.opendasharchive.openarchive.extensions.ViewExtension.kt + FinalNewline:WebDAVModel.kt$net.opendasharchive.openarchive.db.WebDAVModel.kt + FinalNewline:WebDavActivity.kt$net.opendasharchive.openarchive.services.webdav.WebDavActivity.kt + FinalNewline:WebDavConduit.kt$net.opendasharchive.openarchive.services.webdav.WebDavConduit.kt + FinalNewline:WebDavFragment.kt$net.opendasharchive.openarchive.services.webdav.WebDavFragment.kt + FinalNewline:WebDavSetupLicenseFragment.kt$net.opendasharchive.openarchive.services.webdav.WebDavSetupLicenseFragment.kt + ForbiddenComment:FeaturesModule.kt$// TODO: have some registry of feature modules + ForbiddenComment:FullscreenDimmingOverlay.kt$FullScreenCreateGroupDimmingOverlay$// TODO: Cancel the offending event + ForbiddenComment:FullscreenDimmingOverlay.kt$FullScreenDimmingOverlay$// TODO: Cancel the offending event + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Display a dialog or Snackbar explaining why notifications are needed. + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Extract path, query parameters, etc. + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Launch your preview activity or update the UI as needed. + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Refresh projects in MainViewModel + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Return your current project from a ViewModel or other state. + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Update your UI state, refresh fragment content, etc. + ForbiddenComment:HomeActivity.kt$HomeActivity$// TODO: Update your navigation or fragment state to display the selected folder. + ForbiddenComment:InternetArchiveLocalSource.kt$InternetArchiveLocalSource$// TODO: just use a memory cache for demo, will need to store in DB + ForbiddenComment:InternetArchiveLoginUseCase.kt$InternetArchiveLoginUseCase$// TODO: use local data source for database + ForbiddenComment:UploadManagerActivity.kt$UploadManagerActivity.<no name provided>$// // TODO: Record metadata. See iOS implementation. + ForbiddenPublicDataClass:ApiError.kt$ApiError$ClientError : ApiError + ForbiddenPublicDataClass:ApiError.kt$ApiError$HttpError : ApiError + ForbiddenPublicDataClass:ApiError.kt$ApiError$NetworkError : ApiError + ForbiddenPublicDataClass:ApiError.kt$ApiError$ServerError : ApiError + ForbiddenPublicDataClass:ApiError.kt$ApiError$UnexpectedError : ApiError + ForbiddenPublicDataClass:ApiResponse.kt$ApiResponse$ErrorResponse : ApiResponse + ForbiddenPublicDataClass:ApiResponse.kt$ApiResponse$ListResponse<T> : ApiResponse + ForbiddenPublicDataClass:ApiResponse.kt$ApiResponse$SingleResponse<T> : ApiResponse + ForbiddenPublicDataClass:AppConfig.kt$AppConfig + ForbiddenPublicDataClass:BackoffStrategy.kt$BackoffStrategy$Exponential : BackoffStrategy + ForbiddenPublicDataClass:BackoffStrategy.kt$BackoffStrategy$Linear : BackoffStrategy + ForbiddenPublicDataClass:BrowseFoldersViewModel.kt$Folder + ForbiddenPublicDataClass:Collection.kt$Collection : SugarRecord + ForbiddenPublicDataClass:Colors.kt$ColorTheme + ForbiddenPublicDataClass:DialogConfigBuilder.kt$ButtonData + ForbiddenPublicDataClass:DialogConfigBuilder.kt$DialogConfig + ForbiddenPublicDataClass:Dimensions.kt$DimensionsTheme + ForbiddenPublicDataClass:Dimensions.kt$Elevations + ForbiddenPublicDataClass:Dimensions.kt$Icons + ForbiddenPublicDataClass:Dimensions.kt$Spacing + ForbiddenPublicDataClass:FileUploadResult.kt$FileUploadResult : SerializableMarker + ForbiddenPublicDataClass:Hbks.kt$Hbks.Availability$Available : Availability + ForbiddenPublicDataClass:Hbks.kt$Hbks.Availability$Enroll : Availability + ForbiddenPublicDataClass:HomeScreen.kt$HomeScreenAction$AddMediaClicked : HomeScreenAction + ForbiddenPublicDataClass:HomeScreen.kt$HomeScreenAction$UpdateSelectedProject : HomeScreenAction + ForbiddenPublicDataClass:HomeScreen.kt$HomeScreenState + ForbiddenPublicDataClass:InternetArchive.kt$InternetArchive + ForbiddenPublicDataClass:InternetArchive.kt$InternetArchive$Auth + ForbiddenPublicDataClass:InternetArchive.kt$InternetArchive$MetaData + ForbiddenPublicDataClass:InternetArchiveDetailsState.kt$InternetArchiveDetailsState + ForbiddenPublicDataClass:InternetArchiveDetailsViewModel.kt$InternetArchiveDetailsViewModel.Action$Load : Action + ForbiddenPublicDataClass:InternetArchiveDetailsViewModel.kt$InternetArchiveDetailsViewModel.Action$Loaded : Action + ForbiddenPublicDataClass:InternetArchiveLoginRequest.kt$InternetArchiveLoginRequest + ForbiddenPublicDataClass:InternetArchiveLoginResponse.kt$InternetArchiveLoginResponse + ForbiddenPublicDataClass:InternetArchiveLoginResponse.kt$InternetArchiveLoginResponse$S3 + ForbiddenPublicDataClass:InternetArchiveLoginResponse.kt$InternetArchiveLoginResponse$Values + ForbiddenPublicDataClass:InternetArchiveLoginState.kt$InternetArchiveLoginAction$LoginError : InternetArchiveLoginAction + ForbiddenPublicDataClass:InternetArchiveLoginState.kt$InternetArchiveLoginAction$LoginSuccess : InternetArchiveLoginAction + ForbiddenPublicDataClass:InternetArchiveLoginState.kt$InternetArchiveLoginAction$UpdatePassword : InternetArchiveLoginAction + ForbiddenPublicDataClass:InternetArchiveLoginState.kt$InternetArchiveLoginAction$UpdateUsername : InternetArchiveLoginAction + ForbiddenPublicDataClass:InternetArchiveLoginState.kt$InternetArchiveLoginState + ForbiddenPublicDataClass:JoinGroupResponse.kt$JoinGroupResponse : SerializableMarker + ForbiddenPublicDataClass:MainMediaScreen.kt$CollectionSection + ForbiddenPublicDataClass:MainViewModel.kt$MainUiState + ForbiddenPublicDataClass:Media.kt$Media : SugarRecord + ForbiddenPublicDataClass:MediaCacheScreen.kt$MediaFile + ForbiddenPublicDataClass:MediaLaunchers.kt$MediaLaunchers + ForbiddenPublicDataClass:PasscodeEntryViewModel.kt$PasscodeEntryScreenAction$OnNumberClick : PasscodeEntryScreenAction + ForbiddenPublicDataClass:PasscodeEntryViewModel.kt$PasscodeEntryScreenState + ForbiddenPublicDataClass:PasscodeEntryViewModel.kt$PasscodeEntryUiEvent$IncorrectPasscode : PasscodeEntryUiEvent + ForbiddenPublicDataClass:PasscodeSetupViewModel.kt$PasscodeSetupUiAction$OnNumberClick : PasscodeSetupUiAction + ForbiddenPublicDataClass:PasscodeSetupViewModel.kt$PasscodeSetupUiState + ForbiddenPublicDataClass:Project.kt$Project : SugarRecord + ForbiddenPublicDataClass:RequestNameDTO.kt$MembershipRequest : SerializableMarker + ForbiddenPublicDataClass:RequestNameDTO.kt$RequestName : SerializableMarker + ForbiddenPublicDataClass:RetryConfig.kt$RetryConfig + ForbiddenPublicDataClass:SectionViewHolder.kt$SectionViewHolder + ForbiddenPublicDataClass:SnowbirdError.kt$SnowbirdError$GeneralError : SnowbirdError + ForbiddenPublicDataClass:SnowbirdError.kt$SnowbirdError$NetworkError : SnowbirdError + ForbiddenPublicDataClass:SnowbirdFileItem.kt$SnowbirdFileItem : SugarRecordSerializableMarker + ForbiddenPublicDataClass:SnowbirdFileItem.kt$SnowbirdFileList : SerializableMarker + ForbiddenPublicDataClass:SnowbirdFileViewModel.kt$SnowbirdFileViewModel.State$DownloadSuccess : State + ForbiddenPublicDataClass:SnowbirdFileViewModel.kt$SnowbirdFileViewModel.State$Error : State + ForbiddenPublicDataClass:SnowbirdFileViewModel.kt$SnowbirdFileViewModel.State$FetchSuccess : State + ForbiddenPublicDataClass:SnowbirdFileViewModel.kt$SnowbirdFileViewModel.State$UploadSuccess : State + ForbiddenPublicDataClass:SnowbirdGroup.kt$SnowbirdGroup : SugarRecordSerializableMarker + ForbiddenPublicDataClass:SnowbirdGroup.kt$SnowbirdGroupList : SerializableMarker + ForbiddenPublicDataClass:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel.GroupState$Error : GroupState + ForbiddenPublicDataClass:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel.GroupState$JoinGroupSuccess : GroupState + ForbiddenPublicDataClass:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel.GroupState$MultiGroupSuccess : GroupState + ForbiddenPublicDataClass:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel.GroupState$SingleGroupSuccess : GroupState + ForbiddenPublicDataClass:SnowbirdRepo.kt$SnowbirdRepo : SugarRecordSerializableMarker + ForbiddenPublicDataClass:SnowbirdRepo.kt$SnowbirdRepoList : SerializableMarker + ForbiddenPublicDataClass:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel.RepoState$Error : RepoState + ForbiddenPublicDataClass:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel.RepoState$MultiRepoSuccess : RepoState + ForbiddenPublicDataClass:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel.RepoState$RepoFetchSuccess : RepoState + ForbiddenPublicDataClass:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel.RepoState$SingleRepoSuccess : RepoState + ForbiddenPublicDataClass:SnowbirdResult.kt$SnowbirdResult$Error : SnowbirdResult + ForbiddenPublicDataClass:SnowbirdResult.kt$SnowbirdResult$Success<out T> : SnowbirdResult + ForbiddenPublicDataClass:SnowbirdService.kt$ServiceStatus$Failed : ServiceStatus + ForbiddenPublicDataClass:SnowbirdServiceStatus.kt$SnowbirdServiceStatus$Error : SnowbirdServiceStatus + ForbiddenPublicDataClass:Space.kt$Space : SugarRecord + ForbiddenPublicDataClass:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.SpaceItem$SpaceItemData : SpaceItem + ForbiddenPublicDataClass:SuspendableExtensions.kt$RetryAttempt$Failure : RetryAttempt + ForbiddenPublicDataClass:SuspendableExtensions.kt$RetryAttempt$Retry : RetryAttempt + ForbiddenPublicDataClass:SuspendableExtensions.kt$RetryAttempt$Success<T> : RetryAttemptRetryResult + ForbiddenPublicDataClass:UiImage.kt$UiImage$DrawableResource : UiImage + ForbiddenPublicDataClass:UiImage.kt$UiImage$DynamicVector : UiImage + ForbiddenPublicDataClass:UiText.kt$UiText$DynamicString : UiText + ForbiddenPublicDataClass:UiText.kt$UiText$StringResource : UiText + ForbiddenPublicDataClass:WebDAVModel.kt$BackendCapabilities + ForbiddenPublicDataClass:WebDAVModel.kt$Data + ForbiddenPublicDataClass:WebDAVModel.kt$Meta + ForbiddenPublicDataClass:WebDAVModel.kt$Ocs + ForbiddenPublicDataClass:WebDAVModel.kt$Quota + ForbiddenPublicDataClass:WebDAVModel.kt$WebDAVModel + FunctionNaming:Accordion.kt$@Composable fun Accordion( modifier: Modifier = Modifier, headerModifier: Modifier = Modifier, state: AccordionState = rememberAccordionState(), animate: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, headerContent: @Composable () -> Unit, bodyContent: @Composable () -> Unit, ) + FunctionNaming:AddFolderScreen.kt$@Composable fun AddFolderScreen() + FunctionNaming:AddFolderScreen.kt$@Composable fun AddFolderScreenContent( onCreateFolder: () -> Unit, onBrowseFolders: () -> Unit ) + FunctionNaming:AddFolderScreen.kt$@Composable fun FolderOption(iconRes: Int, text: String, onClick: () -> Unit) + FunctionNaming:AddFolderScreen.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun AddFolderScreenPreview() + FunctionNaming:BaseButton.kt$@Composable fun BaseButton( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, backgroundColor: Color = MaterialTheme.colorScheme.primary, textColor: Color = MaterialTheme.colorScheme.onPrimary, cornerRadius: Dp = 12.dp, ) + FunctionNaming:BaseButton.kt$@Composable fun BaseDestructiveButton( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, borderColor: Color = MaterialTheme.colorScheme.error, textColor: Color = MaterialTheme.colorScheme.error, cornerRadius: Dp = 12.dp, ) + FunctionNaming:BaseButton.kt$@Composable fun BaseNeutralButton( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, textColor: Color = MaterialTheme.colorScheme.onPrimary, ) + FunctionNaming:BaseButton.kt$@Composable fun ButtonText( text: String, modifier: Modifier = Modifier, fontSize: TextUnit = 16.sp, fontWeight: FontWeight = FontWeight.SemiBold, color: Color = MaterialTheme.colorScheme.onPrimary ) + FunctionNaming:BaseButton.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CustomButtonPreview() + FunctionNaming:BaseButton.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CustomDestructiveButtonPreview() + FunctionNaming:BaseButton.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CustomNeutralButtonPreview() + FunctionNaming:BaseDialog.kt$@Composable fun BaseDialog( onDismiss: () -> Unit, icon: UiImage? = null, iconColor: Color? = null, title: String, message: String, hasCheckbox: Boolean = false, onCheckBoxStateChanged: (Boolean) -> Unit = {}, checkBoxHint: String = "Do not show me this again", positiveButton: ButtonData? = null, neutralButton: ButtonData? = null, destructiveButton: ButtonData? = null, backgroundColor: Color = MaterialTheme.colorScheme.surface ) + FunctionNaming:BaseDialog.kt$@Composable fun BaseDialogMessage( text: String, modifier: Modifier = Modifier ) + FunctionNaming:BaseDialog.kt$@Composable fun BaseDialogTitle( text: String, modifier: Modifier = Modifier ) + FunctionNaming:BaseDialog.kt$@Composable fun DialogHost(dialogStateManager: DialogStateManager) + FunctionNaming:BaseDialog.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun BaseDialogPreview() + FunctionNaming:BaseDialog.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun ErrorDialogPreview() + FunctionNaming:BaseDialog.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun WarningDialogPreview() + FunctionNaming:BrowseFolderScreen.kt$@Composable fun BrowseFolderItem( folder: Folder, onClick: () -> Unit ) + FunctionNaming:BrowseFolderScreen.kt$@Composable fun BrowseFolderScreen( viewModel: BrowseFoldersViewModel = koinViewModel() ) + FunctionNaming:BrowseFolderScreen.kt$@Composable fun BrowseFolderScreenContent( folders: List<Folder> ) + FunctionNaming:BrowseFolderScreen.kt$@Preview @Composable private fun BrowseFolderScreenPreview() + FunctionNaming:DefaultScaffold.kt$@Composable fun DefaultScaffold( modifier: Modifier = Modifier, topAppBar: (@Composable () -> Unit)? = null, content: @Composable () -> Unit ) + FunctionNaming:ExpandableSpaceList.kt$@Composable fun DrawerSpaceListItem( space: Space, ) + FunctionNaming:ExpandableSpaceList.kt$@Composable fun ExpandableSpaceList( serverAccordionState: AccordionState, selectedSpace: Space? = null, spaceList: List<Space> ) + FunctionNaming:ExpandableSpaceList.kt$@Composable fun SpaceIcon( type: Space.Type, modifier: Modifier = Modifier, tint: Color? = null ) + FunctionNaming:ExpandableSpaceList.kt$@Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun ExpandableSpaceListPreview() + FunctionNaming:FolderOptionsPopup.kt$@Composable fun FolderOptionsPopup( expanded: Boolean = false, onDismissRequest: () -> Unit, onRenameFolder: () -> Unit, onSelectMedia: () -> Unit, onRemoveFolder: () -> Unit ) + FunctionNaming:FolderOptionsPopup.kt$@Preview @Composable private fun FolderOptionsPopupPreview() + FunctionNaming:HomeAppBar.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeAppBar( openDrawer: () -> Unit, onExit: () -> Unit ) + FunctionNaming:HomeScreen.kt$@Composable fun HomeScreen( viewModel: HomeViewModel = koinViewModel(), onExit: () -> Unit, onNewFolder: () -> Unit, onFolderSelected: (Long) -> Unit, onAddMedia: (AddMediaType) -> Unit, onNavigateToCache: () -> Unit ) + FunctionNaming:HomeScreen.kt$@Composable fun HomeScreenContent( onExit: () -> Unit, state: HomeScreenState, onAction: (HomeScreenAction) -> Unit, onNavigateToCache: () -> Unit = {} ) + FunctionNaming:HomeScreen.kt$@Composable fun SaveNavGraph( context: Context, viewModel: HomeViewModel = koinViewModel(), onExit: () -> Unit, onNewFolder: () -> Unit, onFolderSelected: (Long) -> Unit, onAddMedia: (AddMediaType) -> Unit ) + FunctionNaming:HomeScreen.kt$@Preview @Composable private fun MainContentPreview() + FunctionNaming:InternetArchiveDetailsScreen.kt$@Composable @Preview(showBackground = true) @Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveScreenPreview() + FunctionNaming:InternetArchiveDetailsScreen.kt$@Composable fun InternetArchiveDetailsScreen(space: Space, onResult: (IAResult) -> Unit) + FunctionNaming:InternetArchiveDetailsScreen.kt$@Composable private fun InternetArchiveDetailsContent( state: InternetArchiveDetailsState, dispatch: Dispatch<Action>, dialogManager: DialogStateManager = koinViewModel() ) + FunctionNaming:InternetArchiveHeader.kt$@Composable @Preview(showBackground = true) @Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveHeaderPreview() + FunctionNaming:InternetArchiveHeader.kt$@Composable fun InternetArchiveHeader(modifier: Modifier = Modifier, titleSize: TextUnit = 18.sp) + FunctionNaming:InternetArchiveLoginScreen.kt$@Composable @Preview @Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveLoginPreview() + FunctionNaming:InternetArchiveLoginScreen.kt$@Composable fun CustomSecureField( modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: String, placeholder: String, isError: Boolean = false, isLoading: Boolean = false, keyboardType: KeyboardType, imeAction: ImeAction, ) + FunctionNaming:InternetArchiveLoginScreen.kt$@Composable fun CustomTextField( modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: String, enabled: Boolean = true, placeholder: String? = null, isError: Boolean = false, isLoading: Boolean = false, keyboardType: KeyboardType = KeyboardType.Text, imeAction: ImeAction = ImeAction.Next, ) + FunctionNaming:InternetArchiveLoginScreen.kt$@Composable fun InternetArchiveLoginScreen(space: Space, onResult: (IAResult) -> Unit) + FunctionNaming:InternetArchiveLoginScreen.kt$@Composable private fun InternetArchiveLoginContent( state: InternetArchiveLoginState, dispatch: Dispatch<Action> ) + FunctionNaming:InternetArchiveLoginScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ComposeAppBar( title: String = "Save App", onNavigationAction: () -> Unit = {} ) + FunctionNaming:InternetArchiveScreen.kt$@Composable fun InternetArchiveScreen(space: Space, isNewSpace: Boolean, onFinish: (IAResult) -> Unit) + FunctionNaming:MainBottomBar.kt$@Composable fun MainBottomBar( isSettings: Boolean, onMyMediaClick: () -> Unit, onSettingsClick: () -> Unit, onAddMediaClick: () -> Unit ) + FunctionNaming:MainBottomBar.kt$@Composable fun RowScope.BottomNavMenuItem( selectedIcon: ImageVector, unSelectedIcon: ImageVector, isSelected: Boolean, text: String, onClick: () -> Unit ) + FunctionNaming:MainDrawerContent.kt$@Composable fun MainDrawerContent( selectedSpace: Space? = null, spaceList: List<Space> = emptyList() ) + FunctionNaming:MainDrawerContent.kt$@Composable fun MainDrawerFolderListItem( project: Project, isSelected: Boolean = false, onSelected: () -> Unit ) + FunctionNaming:MainDrawerContent.kt$@Preview @Composable private fun MainDrawerContentPreview() + FunctionNaming:MainMediaScreen.kt$@Composable fun CollectionHeaderView(section: CollectionSection) + FunctionNaming:MainMediaScreen.kt$@Composable fun CollectionSectionView( section: CollectionSection, onMediaClick: (Media) -> Unit, onMediaLongPress: (Media) -> Unit ) + FunctionNaming:MainMediaScreen.kt$@Composable fun ErrorIndicator() + FunctionNaming:MainMediaScreen.kt$@Composable fun MainMediaScreen( projectId: Long, ) + FunctionNaming:MainMediaScreen.kt$@Composable fun MediaItemView( media: Media, isSelected: Boolean, onClick: () -> Unit, onLongClick: () -> Unit, modifier: Modifier = Modifier ) + FunctionNaming:MainMediaScreen.kt$@Composable fun UploadProgress(progress: Int) + FunctionNaming:MainMediaScreen.kt$@Composable fun WelcomeMessage() + FunctionNaming:MediaCacheScreen.kt$@Composable fun CacheFileItem(file: MediaFile) + FunctionNaming:MediaCacheScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun MediaCacheScreen(context: Context, onNavigateBack: () -> Unit) + FunctionNaming:NumericKeypad.kt$@Composable fun NumericKeypad( isEnabled: Boolean = true, onNumberClick: (String) -> Unit, onDeleteClick: () -> Unit, onSubmitClick: () -> Unit ) + FunctionNaming:NumericKeypad.kt$@Composable private fun NumberButton( label: String, enabled: Boolean = true, onClick: () -> Unit, hapticManager: HapticManager = koinInject() ) + FunctionNaming:NumericKeypad.kt$@Preview @Composable private fun NumericKeypadPreview() + FunctionNaming:PasscodeDots.kt$@Composable fun PasscodeDots( passcodeLength: Int, currentPasscodeLength: Int, shouldShake: Boolean = false ) + FunctionNaming:PasscodeDots.kt$@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview @Composable private fun PasswordDotsPreview() + FunctionNaming:PasscodeEntryScreen.kt$@Composable fun PasscodeEntryScreen( onPasscodeSuccess: () -> Unit, onExit: () -> Unit, viewModel: PasscodeEntryViewModel = koinViewModel(), hapticManager: HapticManager = koinInject() ) + FunctionNaming:PasscodeEntryScreen.kt$@Composable fun PasscodeEntryScreenContent( state: PasscodeEntryScreenState, onAction: (PasscodeEntryScreenAction) -> Unit, onExit: () -> Unit, ) + FunctionNaming:PasscodeEntryScreen.kt$@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview @Composable private fun PasscodeEntryScreenPreview() + FunctionNaming:PasscodeSetupScreen.kt$@Composable fun PasscodeSetupScreen( onPasscodeSet: () -> Unit, onCancel: () -> Unit, viewModel: PasscodeSetupViewModel = koinViewModel(), hapticManager: HapticManager = koinInject() ) + FunctionNaming:PasscodeSetupScreen.kt$@Composable private fun PasscodeSetupScreenContent( state: PasscodeSetupUiState, onAction: (PasscodeSetupUiAction) -> Unit ) + FunctionNaming:PasscodeSetupScreen.kt$@Preview(uiMode = UI_MODE_NIGHT_YES) @Preview @Composable private fun PasscodeSetupScreenPreview() + FunctionNaming:Preview.kt$@Composable fun DefaultBoxPreview( content: @Composable () -> Unit ) + FunctionNaming:Preview.kt$@Composable fun DefaultEmptyScaffoldPreview( content: @Composable () -> Unit ) + FunctionNaming:Preview.kt$@Composable fun DefaultScaffoldPreview( content: @Composable () -> Unit ) + FunctionNaming:PrimaryButton.kt$@Composable fun PrimaryButton( modifier: Modifier = Modifier, icon: ImageVector? = null, text: String, onClick: () -> Unit ) + FunctionNaming:PrimaryButton.kt$@Preview @Composable private fun PrimaryButtonPreview() + FunctionNaming:ProofModeScreen.kt$@Composable fun ProofModeScreen( onNavigateBack: () -> Unit ) + FunctionNaming:ProofModeScreen.kt$@Composable fun ProofModeScreenContent() + FunctionNaming:ProofModeScreen.kt$@Preview @Composable private fun ProofModeScreenPreview() + FunctionNaming:ServerOptionItem.kt$@Composable fun ServerOptionItem( @DrawableRes iconRes: Int, title: String, subtitle: String, onClick: () -> Unit ) + FunctionNaming:ServerOptionItem.kt$@Preview @Composable private fun ServerOptionItemPreview() + FunctionNaming:SettingsScreen.kt$@Composable fun SettingsScreen( onNavigateToCache: () -> Unit = {} ) + FunctionNaming:SettingsScreen.kt$@Preview @Composable private fun SettingsScreenPreview() + FunctionNaming:SpaceListScreen.kt$@Composable fun SpaceListItem( space: Space, onClick: () -> Unit ) + FunctionNaming:SpaceListScreen.kt$@Composable fun SpaceListScreen( onSpaceClicked: (Space) -> Unit, ) + FunctionNaming:SpaceListScreen.kt$@Composable fun SpaceListScreenContent( onSpaceClicked: (Space) -> Unit, spaceList: List<Space> = emptyList() ) + FunctionNaming:SpaceListScreen.kt$@Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun SpaceListScreenPreview() + FunctionNaming:SpaceSetupScreen.kt$@Composable fun SpaceSetupScreen( onWebDavClick: () -> Unit, isInternetArchiveAllowed: Boolean, onInternetArchiveClick: () -> Unit, isDwebEnabled: Boolean, onDwebClicked: () -> Unit ) + FunctionNaming:SpaceSetupScreen.kt$@Preview @Composable private fun SpaceSetupScreenPreview() + FunctionNaming:Theme.kt$@Composable fun SaveAppTheme( content: @Composable () -> Unit ) + FunctionNaming:TwoLetterDrawable.kt$TwoLetterDrawable.Companion$fun ReadOnly(context: Context) + FunctionNaming:TwoLetterDrawable.kt$TwoLetterDrawable.Companion$fun ReadWrite(context: Context) + FunctionOnlyReturningConstant:HomeActivity.kt$HomeActivity$private fun getCurrentProject(): Project? + FunctionStartOfBodySpacing:InternetArchiveLocalSource.kt$InternetArchiveLocalSource$fun set(value: InternetArchive) + ImportOrdering:ApplicationExtensions.kt$import android.app.Application import androidx.activity.ComponentActivity import androidx.fragment.app.Fragment import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.ViewModel import org.koin.android.ext.android.getKoin import org.koin.core.parameter.parametersOf import org.koin.androidx.viewmodel.ext.android.viewModel + ImportOrdering:FeaturesModule.kt$import android.app.Application import android.content.Context import net.opendasharchive.openarchive.features.internetarchive.internetArchiveModule import net.opendasharchive.openarchive.features.settings.passcode.AppConfig import net.opendasharchive.openarchive.features.settings.passcode.HapticManager import net.opendasharchive.openarchive.features.settings.passcode.HashingStrategy import net.opendasharchive.openarchive.features.settings.passcode.PBKDF2HashingStrategy import net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryViewModel import net.opendasharchive.openarchive.features.settings.passcode.PasscodeRepository import net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupViewModel import net.opendasharchive.openarchive.services.snowbird.ISnowbirdFileRepository import net.opendasharchive.openarchive.services.snowbird.ISnowbirdGroupRepository import net.opendasharchive.openarchive.services.snowbird.ISnowbirdRepoRepository import net.opendasharchive.openarchive.services.snowbird.SnowbirdFileRepository import net.opendasharchive.openarchive.services.snowbird.SnowbirdFileViewModel import net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupRepository import net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupViewModel import net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoRepository import net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoViewModel import org.koin.core.module.dsl.viewModel import org.koin.core.qualifier.named import org.koin.dsl.module + ImportOrdering:InternetArchiveDetailsScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.core.presentation.theme.ThemeColors import net.opendasharchive.openarchive.core.presentation.theme.ThemeDimensions import net.opendasharchive.openarchive.core.state.Dispatch import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.internetarchive.presentation.components.IAResult import net.opendasharchive.openarchive.features.internetarchive.presentation.components.InternetArchiveHeader import net.opendasharchive.openarchive.features.internetarchive.presentation.details.InternetArchiveDetailsViewModel.Action import net.opendasharchive.openarchive.features.internetarchive.presentation.login.CustomTextField import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview import net.opendasharchive.openarchive.features.core.UiImage import net.opendasharchive.openarchive.features.core.UiText import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager import net.opendasharchive.openarchive.features.core.dialog.showDialog import net.opendasharchive.openarchive.features.core.dialog.showSuccessDialog import net.opendasharchive.openarchive.features.core.dialog.showWarningDialog import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf + ImportOrdering:InternetArchiveFragment.kt$import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView import androidx.core.os.bundleOf import androidx.fragment.app.setFragmentResult import androidx.navigation.fragment.findNavController import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.internetarchive.presentation.components.IAResult import net.opendasharchive.openarchive.features.internetarchive.presentation.components.bundleWithNewSpace import net.opendasharchive.openarchive.features.internetarchive.presentation.components.bundleWithSpaceId import net.opendasharchive.openarchive.features.internetarchive.presentation.components.getSpace import net.opendasharchive.openarchive.features.core.BaseFragment import net.opendasharchive.openarchive.features.core.ToolbarConfigurable + ImportOrdering:SnowbirdFragment.kt$import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts import androidx.core.os.bundleOf import androidx.fragment.app.setFragmentResult import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import com.google.zxing.integration.android.IntentIntegrator import kotlinx.coroutines.launch import net.opendasharchive.openarchive.databinding.FragmentSnowbirdBinding import net.opendasharchive.openarchive.db.SnowbirdGroup import net.opendasharchive.openarchive.extensions.getQueryParameter import net.opendasharchive.openarchive.features.main.QRScannerActivity import net.opendasharchive.openarchive.features.core.BaseFragment import net.opendasharchive.openarchive.util.Utility import timber.log.Timber + ImportOrdering:StatefulViewModel.kt$import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import net.opendasharchive.openarchive.core.state.StateDispatcher import net.opendasharchive.openarchive.core.state.StoreObserver import net.opendasharchive.openarchive.core.state.Stateful import net.opendasharchive.openarchive.core.state.Store + ImportOrdering:VideoRequestHandler.kt$import android.content.Context import android.graphics.Bitmap import com.squareup.picasso.Picasso import android.media.MediaMetadataRetriever import android.net.Uri import com.squareup.picasso.Request import com.squareup.picasso.RequestHandler import java.io.IOException import java.lang.Exception import androidx.core.net.toUri + Indentation:Accordion.kt$ + Indentation:BaseButton.kt$ + Indentation:BaseDialog.kt$ + Indentation:BrowseFoldersFragment.kt$BrowseFoldersFragment$ + Indentation:CleanInsightsManager.kt$CleanInsightsManager.<no name provided>$ + Indentation:EditFolderActivity.kt$EditFolderActivity$ + Indentation:FileUtils.kt$FileUtils$ + Indentation:GDriveActivity.kt$GDriveActivity$ + Indentation:GDriveFragment.kt$GDriveFragment$ + Indentation:Hbks.kt$Hbks.<no name provided>$ + Indentation:HomeScreen.kt$ + Indentation:InternetArchiveActivity.kt$InternetArchiveActivity$ + Indentation:InternetArchiveDetailsViewModel.kt$InternetArchiveDetailsViewModel$ + Indentation:InternetArchiveHeader.kt$ + Indentation:MainMediaAdapter.kt$MediaDiffCallback$ + Indentation:Media.kt$Media$ + Indentation:MediaAdapter.kt$MediaAdapter$ + Indentation:MediaAdapter.kt$MediaDiffCallback$ + Indentation:MediaCacheScreen.kt$ + Indentation:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity.<no name provided>$ + Indentation:PasscodeManager.kt$PasscodeManager$ + Indentation:PasscodeSetupActivity.kt$PasscodeSetupActivity$ + Indentation:Picker.kt$Picker$ + Indentation:PreviewAdapter.kt$PreviewAdapter.Companion.<no name provided>$ + Indentation:Project.kt$Project$ + Indentation:ProofModeScreen.kt$ + Indentation:RequestBodyUtil.kt$RequestBodyUtil$ + Indentation:RequestBodyUtil.kt$RequestBodyUtil.<no name provided>$ + Indentation:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$ + Indentation:SnowbirdFileListFragment.kt$SnowbirdFileListFragment.<no name provided>$ + Indentation:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment.<no name provided>$ + Indentation:SnowbirdJoinGroupFragment.kt$SnowbirdJoinGroupFragment$ + Indentation:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment.<no name provided>$ + Indentation:SpaceAdapter.kt$SpaceAdapter$ + Indentation:SpaceListScreen.kt$ + Indentation:TextView.kt$ + Indentation:UnixSocketAPI.kt$UnixSocketAPI$ + Indentation:UriExtensions.kt$ + Indentation:ValidateLoginCredentialsUseCase.kt$ValidateLoginCredentialsUseCase$ + Indentation:WebDavFragment.kt$WebDavFragment$ + LambdaParameterEventTrailing:PrimaryButton.kt$onClick + LambdaParameterInRestartableEffect:HomeScreen.kt$onAction + LambdaParameterInRestartableEffect:InternetArchiveDetailsScreen.kt$onResult + LambdaParameterInRestartableEffect:InternetArchiveLoginScreen.kt$onResult + LambdaParameterInRestartableEffect:PasscodeEntryScreen.kt$onExit + LambdaParameterInRestartableEffect:PasscodeEntryScreen.kt$onPasscodeSuccess + LambdaParameterInRestartableEffect:PasscodeSetupScreen.kt$onCancel + LambdaParameterInRestartableEffect:PasscodeSetupScreen.kt$onPasscodeSet + LibraryEntitiesShouldNotBePublic:Accordion.kt$@Composable fun Accordion( modifier: Modifier = Modifier, headerModifier: Modifier = Modifier, state: AccordionState = rememberAccordionState(), animate: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, headerContent: @Composable () -> Unit, bodyContent: @Composable () -> Unit, ) + LibraryEntitiesShouldNotBePublic:Accordion.kt$@Composable fun rememberAccordionGroupState( count: Int, allowMultipleOpen: Boolean = false, ): AccordionGroupState + LibraryEntitiesShouldNotBePublic:Accordion.kt$@Composable fun rememberAccordionState( expanded: Boolean = false, enabled: Boolean = true, clickable: Boolean = true, onExpandedChange: ((Boolean) -> Unit)? = null, ) + LibraryEntitiesShouldNotBePublic:Accordion.kt$AccordionGroupState + LibraryEntitiesShouldNotBePublic:Accordion.kt$AccordionState + LibraryEntitiesShouldNotBePublic:ActivityExtension.kt$fun Activity.onBackButtonPressed(callback: () -> Boolean) + LibraryEntitiesShouldNotBePublic:AddFolderActivity.kt$AddFolderActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:AddFolderScreen.kt$@Composable fun AddFolderScreen() + LibraryEntitiesShouldNotBePublic:AddFolderScreen.kt$@Composable fun AddFolderScreenContent( onCreateFolder: () -> Unit, onBrowseFolders: () -> Unit ) + LibraryEntitiesShouldNotBePublic:AddFolderScreen.kt$@Composable fun FolderOption(iconRes: Int, text: String, onClick: () -> Unit) + LibraryEntitiesShouldNotBePublic:AddMediaDialogFragment.kt$AddMediaDialogFragment : DialogFragment + LibraryEntitiesShouldNotBePublic:AddMediaType.kt$AddMediaType + LibraryEntitiesShouldNotBePublic:AlertHelper.kt$AlertHelper + LibraryEntitiesShouldNotBePublic:ApiError.kt$ApiError : SerializableMarker + LibraryEntitiesShouldNotBePublic:ApiResponse.kt$ApiResponse<out T> + LibraryEntitiesShouldNotBePublic:AppConfig.kt$AppConfig + LibraryEntitiesShouldNotBePublic:ApplicationExtensions.kt$inline fun <reified T : AndroidViewModel> ComponentActivity.androidViewModel(): Lazy<T> + LibraryEntitiesShouldNotBePublic:ApplicationExtensions.kt$inline fun <reified T : AndroidViewModel> Fragment.androidViewModel(): Lazy<T> + LibraryEntitiesShouldNotBePublic:ApplicationExtensions.kt$inline fun <reified T : ViewModel> Application.getViewModel(vararg parameters: Any): T + LibraryEntitiesShouldNotBePublic:BackoffStrategy.kt$BackoffStrategy + LibraryEntitiesShouldNotBePublic:BadgeDrawable.kt$BadgeDrawable : Drawable + LibraryEntitiesShouldNotBePublic:BaseActivity.kt$BaseActivity : AppCompatActivity + LibraryEntitiesShouldNotBePublic:BaseButton.kt$@Composable fun BaseButton( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, backgroundColor: Color = MaterialTheme.colorScheme.primary, textColor: Color = MaterialTheme.colorScheme.onPrimary, cornerRadius: Dp = 12.dp, ) + LibraryEntitiesShouldNotBePublic:BaseButton.kt$@Composable fun BaseDestructiveButton( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, borderColor: Color = MaterialTheme.colorScheme.error, textColor: Color = MaterialTheme.colorScheme.error, cornerRadius: Dp = 12.dp, ) + LibraryEntitiesShouldNotBePublic:BaseButton.kt$@Composable fun BaseNeutralButton( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, textColor: Color = MaterialTheme.colorScheme.onPrimary, ) + LibraryEntitiesShouldNotBePublic:BaseButton.kt$@Composable fun ButtonText( text: String, modifier: Modifier = Modifier, fontSize: TextUnit = 16.sp, fontWeight: FontWeight = FontWeight.SemiBold, color: Color = MaterialTheme.colorScheme.onPrimary ) + LibraryEntitiesShouldNotBePublic:BaseComposeActivity.kt$BaseComposeActivity : AppCompatActivity + LibraryEntitiesShouldNotBePublic:BaseDialog.kt$@Composable fun BaseDialog( onDismiss: () -> Unit, icon: UiImage? = null, iconColor: Color? = null, title: String, message: String, hasCheckbox: Boolean = false, onCheckBoxStateChanged: (Boolean) -> Unit = {}, checkBoxHint: String = "Do not show me this again", positiveButton: ButtonData? = null, neutralButton: ButtonData? = null, destructiveButton: ButtonData? = null, backgroundColor: Color = MaterialTheme.colorScheme.surface ) + LibraryEntitiesShouldNotBePublic:BaseDialog.kt$@Composable fun BaseDialogMessage( text: String, modifier: Modifier = Modifier ) + LibraryEntitiesShouldNotBePublic:BaseDialog.kt$@Composable fun BaseDialogTitle( text: String, modifier: Modifier = Modifier ) + LibraryEntitiesShouldNotBePublic:BaseDialog.kt$@Composable fun DialogHost(dialogStateManager: DialogStateManager) + LibraryEntitiesShouldNotBePublic:BaseDialog.kt$DialogStateManager : ViewModel + LibraryEntitiesShouldNotBePublic:BaseFragment.kt$BaseFragment : FragmentToolbarConfigurable + LibraryEntitiesShouldNotBePublic:BaseSnowbirdFragment.kt$BaseSnowbirdFragment : Fragment + LibraryEntitiesShouldNotBePublic:BaseViewModel.kt$BaseViewModel : AndroidViewModel + LibraryEntitiesShouldNotBePublic:BasicAuthInterceptor.kt$BasicAuthInterceptor : Interceptor + LibraryEntitiesShouldNotBePublic:BiometricAuthenticator.kt$BiometricAuthenticator + LibraryEntitiesShouldNotBePublic:BottomSheetExtensions.kt$fun Fragment.showBottomSheetDialog( @LayoutRes layout: Int, @IdRes textViewToSet: Int? = null, textToSet: String? = null, fullScreen: Boolean = true, expand: Boolean = true ) + LibraryEntitiesShouldNotBePublic:BroadcastManager.kt$BroadcastManager$Action + LibraryEntitiesShouldNotBePublic:BrowseFolderScreen.kt$@Composable fun BrowseFolderItem( folder: Folder, onClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:BrowseFolderScreen.kt$@Composable fun BrowseFolderScreen( viewModel: BrowseFoldersViewModel = koinViewModel() ) + LibraryEntitiesShouldNotBePublic:BrowseFolderScreen.kt$@Composable fun BrowseFolderScreenContent( folders: List<Folder> ) + LibraryEntitiesShouldNotBePublic:BrowseFoldersAdapter.kt$BrowseFoldersAdapter : Adapter + LibraryEntitiesShouldNotBePublic:BrowseFoldersFragment.kt$BrowseFoldersFragment : BaseFragmentMenuProvider + LibraryEntitiesShouldNotBePublic:BrowseFoldersViewModel.kt$BrowseFoldersViewModel : ViewModel + LibraryEntitiesShouldNotBePublic:BrowseFoldersViewModel.kt$Folder + LibraryEntitiesShouldNotBePublic:BundleExt.kt$@Deprecated("only for use with fragments and activities") fun Bundle?.getSpace(type: Space.Type): Pair<Space, Boolean> + LibraryEntitiesShouldNotBePublic:BundleExt.kt$@Deprecated("only for use with fragments and activities") fun bundleWithNewSpace() + LibraryEntitiesShouldNotBePublic:BundleExt.kt$@Deprecated("only for use with fragments and activities") fun bundleWithSpaceId(spaceId: Long) + LibraryEntitiesShouldNotBePublic:BundleExt.kt$IAResult + LibraryEntitiesShouldNotBePublic:ClientResult.kt$suspend fun <T> OkHttpClient.enqueueResult( request: Request, onResume: (Response) -> T ) + LibraryEntitiesShouldNotBePublic:Collection.kt$Collection : SugarRecord + LibraryEntitiesShouldNotBePublic:Colors.kt$ColorTheme + LibraryEntitiesShouldNotBePublic:Conduit.kt$Conduit + LibraryEntitiesShouldNotBePublic:ConsentActivity.kt$ConsentActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:ContentPickerFragment.kt$ContentPickerFragment : BottomSheetDialogFragment + LibraryEntitiesShouldNotBePublic:Context.kt$fun Context.openBrowser(link: String) + LibraryEntitiesShouldNotBePublic:CreateNewFolderFragment.kt$CreateNewFolderFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:CustomBottomNavBar.kt$CustomBottomNavBar : LinearLayout + LibraryEntitiesShouldNotBePublic:CustomButton.kt$CustomButton : FrameLayout + LibraryEntitiesShouldNotBePublic:DefaultScaffold.kt$@Composable fun DefaultScaffold( modifier: Modifier = Modifier, topAppBar: (@Composable () -> Unit)? = null, content: @Composable () -> Unit ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$@Composable fun DialogStateManager.showDialog(block: DialogBuilder.() -> Unit) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$@Composable fun DialogStateManager.showSuccessDialog( message: String, title: String = "", // if empty, default title is used onPositive: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$ButtonBuilder + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$ButtonData + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$DefaultResourceProvider : ResourceProvider + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$DialogBuilder + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$DialogConfig + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$DialogDsl + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$DialogType + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$ResourceProvider + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$fun DialogStateManager.showDestructiveDialog( title: UiText?, message: UiText, icon: UiImage? = null, positiveButtonText: UiText? = null, onDone: () -> Unit = {}, onCancel: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$fun DialogStateManager.showDialog( resourceProvider: ResourceProvider = this.requireResourceProvider(), block: DialogBuilder.() -> Unit ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$fun DialogStateManager.showErrorDialog( message: String, title: String = "", onRetry: () -> Unit = {}, onCancel: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$fun DialogStateManager.showInfoDialog( message: UiText, title: UiText?, icon: UiImage? = null, onDone: () -> Unit = {}, ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$fun DialogStateManager.showSuccessDialog( @StringRes title: Int?, @StringRes message: Int, @StringRes positiveButtonText: Int? = null, icon: UiImage? = null, onDone: () -> Unit = {}, ) + LibraryEntitiesShouldNotBePublic:DialogConfigBuilder.kt$fun DialogStateManager.showWarningDialog( title: UiText?, message: UiText, icon: UiImage? = null, positiveButtonText: UiText? = null, onDone: () -> Unit = {}, onCancel: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:Dimensions.kt$DimensionsTheme + LibraryEntitiesShouldNotBePublic:Dimensions.kt$Elevations + LibraryEntitiesShouldNotBePublic:Dimensions.kt$Icons + LibraryEntitiesShouldNotBePublic:Dimensions.kt$Spacing + LibraryEntitiesShouldNotBePublic:Dimensions.kt$fun getThemeDimensions(isDarkTheme: Boolean) + LibraryEntitiesShouldNotBePublic:Dispatcher.kt$Dispatcher<Action> + LibraryEntitiesShouldNotBePublic:Dispatcher.kt$typealias Dispatch<A> = (A) -> Unit + LibraryEntitiesShouldNotBePublic:Drawable.kt$fun Drawable.clone(): Drawable? + LibraryEntitiesShouldNotBePublic:Drawable.kt$fun Drawable.scaled(biggerSideDipLength: Int, context: Context): Drawable + LibraryEntitiesShouldNotBePublic:Drawable.kt$fun Drawable.scaled(factor: Double, context: Context): Drawable + LibraryEntitiesShouldNotBePublic:Drawable.kt$fun Drawable.scaled(width: Int, height: Int, context: Context): Drawable + LibraryEntitiesShouldNotBePublic:Drawable.kt$fun Drawable.tint(color: Int): Drawable + LibraryEntitiesShouldNotBePublic:DrawableExtensions.kt$fun Drawable.clone(): Drawable? + LibraryEntitiesShouldNotBePublic:DrawableExtensions.kt$fun Drawable.scaled(biggerSideDipLength: Int, context: Context): Drawable + LibraryEntitiesShouldNotBePublic:DrawableExtensions.kt$fun Drawable.scaled(factor: Double, context: Context): Drawable + LibraryEntitiesShouldNotBePublic:DrawableExtensions.kt$fun Drawable.scaled(width: Int, height: Int, context: Context): Drawable + LibraryEntitiesShouldNotBePublic:DrawableExtensions.kt$fun Drawable.tint(color: Int): Drawable + LibraryEntitiesShouldNotBePublic:DurationExtensions.kt$fun Duration.formatToDecimalPlaces(decimals: Int = 1): String + LibraryEntitiesShouldNotBePublic:EditFolderActivity.kt$EditFolderActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:Effects.kt$typealias Effects<T, A> = suspend (T, A) -> Unit + LibraryEntitiesShouldNotBePublic:EmptyableRecyclerView.kt$EmptyableRecyclerView : RecyclerView + LibraryEntitiesShouldNotBePublic:ExpandableSpaceList.kt$@Composable fun DrawerSpaceListItem( space: Space, ) + LibraryEntitiesShouldNotBePublic:ExpandableSpaceList.kt$@Composable fun ExpandableSpaceList( serverAccordionState: AccordionState, selectedSpace: Space? = null, spaceList: List<Space> ) + LibraryEntitiesShouldNotBePublic:ExpandableSpaceList.kt$@Composable fun SpaceIcon( type: Space.Type, modifier: Modifier = Modifier, tint: Color? = null ) + LibraryEntitiesShouldNotBePublic:FileUploadResult.kt$FileUploadResult : SerializableMarker + LibraryEntitiesShouldNotBePublic:FolderAdapter.kt$FolderAdapter : ListAdapterFolderAdapterListener + LibraryEntitiesShouldNotBePublic:FolderAdapter.kt$FolderAdapterListener + LibraryEntitiesShouldNotBePublic:FolderDrawerAdapter.kt$FolderDrawerAdapter : ListAdapter + LibraryEntitiesShouldNotBePublic:FolderDrawerAdapter.kt$FolderDrawerAdapterListener + LibraryEntitiesShouldNotBePublic:FolderOptionsPopup.kt$@Composable fun FolderOptionsPopup( expanded: Boolean = false, onDismissRequest: () -> Unit, onRenameFolder: () -> Unit, onSelectMedia: () -> Unit, onRemoveFolder: () -> Unit ) + LibraryEntitiesShouldNotBePublic:FoldersActivity.kt$FoldersActivity : BaseActivityFolderAdapterListener + LibraryEntitiesShouldNotBePublic:FullscreenDimmingOverlay.kt$FullScreenCreateGroupDimmingOverlay : FrameLayout + LibraryEntitiesShouldNotBePublic:FullscreenDimmingOverlay.kt$FullScreenDimmingOverlay : FrameLayout + LibraryEntitiesShouldNotBePublic:GDriveActivity.kt$GDriveActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:GDriveConduit.kt$GDriveConduit : Conduit + LibraryEntitiesShouldNotBePublic:GDriveFragment.kt$GDriveFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:GeneralSettingsActivity.kt$GeneralSettingsActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:HapticManager.kt$AppHapticFeedbackType + LibraryEntitiesShouldNotBePublic:HapticManager.kt$HapticManager + LibraryEntitiesShouldNotBePublic:HashingStrategy.kt$HashingStrategy + LibraryEntitiesShouldNotBePublic:Hbks.kt$Hbks$Availability + LibraryEntitiesShouldNotBePublic:Hbks.kt$Hbks$BiometryType + LibraryEntitiesShouldNotBePublic:HomeActivity.kt$HomeActivity : FragmentActivity + LibraryEntitiesShouldNotBePublic:HomeAppBar.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeAppBar( openDrawer: () -> Unit, onExit: () -> Unit ) + LibraryEntitiesShouldNotBePublic:HomeScreen.kt$@Composable fun HomeScreen( viewModel: HomeViewModel = koinViewModel(), onExit: () -> Unit, onNewFolder: () -> Unit, onFolderSelected: (Long) -> Unit, onAddMedia: (AddMediaType) -> Unit, onNavigateToCache: () -> Unit ) + LibraryEntitiesShouldNotBePublic:HomeScreen.kt$@Composable fun HomeScreenContent( onExit: () -> Unit, state: HomeScreenState, onAction: (HomeScreenAction) -> Unit, onNavigateToCache: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:HomeScreen.kt$@Composable fun SaveNavGraph( context: Context, viewModel: HomeViewModel = koinViewModel(), onExit: () -> Unit, onNewFolder: () -> Unit, onFolderSelected: (Long) -> Unit, onAddMedia: (AddMediaType) -> Unit ) + LibraryEntitiesShouldNotBePublic:HomeScreen.kt$HomeScreenAction + LibraryEntitiesShouldNotBePublic:HomeScreen.kt$HomeScreenState + LibraryEntitiesShouldNotBePublic:HomeScreen.kt$HomeViewModel : ViewModel + LibraryEntitiesShouldNotBePublic:HttpLikeException.kt$HttpLikeException : Exception + LibraryEntitiesShouldNotBePublic:ISnowbirdAPI.kt$ISnowbirdAPI + LibraryEntitiesShouldNotBePublic:IaConduit.kt$IaConduit : Conduit + LibraryEntitiesShouldNotBePublic:InternetArchive.kt$InternetArchive + LibraryEntitiesShouldNotBePublic:InternetArchiveActivity.kt$InternetArchiveActivity : AppCompatActivity + LibraryEntitiesShouldNotBePublic:InternetArchiveDetailsScreen.kt$@Composable fun InternetArchiveDetailsScreen(space: Space, onResult: (IAResult) -> Unit) + LibraryEntitiesShouldNotBePublic:InternetArchiveDetailsState.kt$InternetArchiveDetailsState + LibraryEntitiesShouldNotBePublic:InternetArchiveDetailsViewModel.kt$InternetArchiveDetailsViewModel : StatefulViewModel + LibraryEntitiesShouldNotBePublic:InternetArchiveFragment.kt$InternetArchiveFragment : BaseFragmentToolbarConfigurable + LibraryEntitiesShouldNotBePublic:InternetArchiveHeader.kt$@Composable fun InternetArchiveHeader(modifier: Modifier = Modifier, titleSize: TextUnit = 18.sp) + LibraryEntitiesShouldNotBePublic:InternetArchiveLocalSource.kt$InternetArchiveLocalSource + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginRequest.kt$InternetArchiveLoginRequest + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginResponse.kt$InternetArchiveLoginResponse + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginScreen.kt$@Composable fun CustomSecureField( modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: String, placeholder: String, isError: Boolean = false, isLoading: Boolean = false, keyboardType: KeyboardType, imeAction: ImeAction, ) + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginScreen.kt$@Composable fun CustomTextField( modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: String, enabled: Boolean = true, placeholder: String? = null, isError: Boolean = false, isLoading: Boolean = false, keyboardType: KeyboardType = KeyboardType.Text, imeAction: ImeAction = ImeAction.Next, ) + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginScreen.kt$@Composable fun InternetArchiveLoginScreen(space: Space, onResult: (IAResult) -> Unit) + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun ComposeAppBar( title: String = "Save App", onNavigationAction: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginState.kt$InternetArchiveLoginAction + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginState.kt$InternetArchiveLoginState + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginUseCase.kt$InternetArchiveLoginUseCase + LibraryEntitiesShouldNotBePublic:InternetArchiveLoginViewModel.kt$InternetArchiveLoginViewModel : StatefulViewModelKoinComponent + LibraryEntitiesShouldNotBePublic:InternetArchiveMapper.kt$InternetArchiveMapper + LibraryEntitiesShouldNotBePublic:InternetArchiveRemoteSource.kt$InternetArchiveRemoteSource + LibraryEntitiesShouldNotBePublic:InternetArchiveRepository.kt$InternetArchiveRepository + LibraryEntitiesShouldNotBePublic:InternetArchiveScreen.kt$@Composable fun InternetArchiveScreen(space: Space, isNewSpace: Boolean, onFinish: (IAResult) -> Unit) + LibraryEntitiesShouldNotBePublic:JoinGroupResponse.kt$JoinGroupResponse : SerializableMarker + LibraryEntitiesShouldNotBePublic:Listener.kt$Listener<Action> + LibraryEntitiesShouldNotBePublic:MainActivity.kt$MainActivity : BaseActivitySpaceDrawerAdapterListenerFolderDrawerAdapterListener + LibraryEntitiesShouldNotBePublic:MainBottomBar.kt$@Composable fun MainBottomBar( isSettings: Boolean, onMyMediaClick: () -> Unit, onSettingsClick: () -> Unit, onAddMediaClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:MainBottomBar.kt$@Composable fun RowScope.BottomNavMenuItem( selectedIcon: ImageVector, unSelectedIcon: ImageVector, isSelected: Boolean, text: String, onClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:MainDrawerContent.kt$@Composable fun MainDrawerContent( selectedSpace: Space? = null, spaceList: List<Space> = emptyList() ) + LibraryEntitiesShouldNotBePublic:MainDrawerContent.kt$@Composable fun MainDrawerFolderListItem( project: Project, isSelected: Boolean = false, onSelected: () -> Unit ) + LibraryEntitiesShouldNotBePublic:MainMediaAdapter.kt$MainMediaAdapter : Adapter + LibraryEntitiesShouldNotBePublic:MainMediaAdapterTest.kt$MainMediaAdapterTest + LibraryEntitiesShouldNotBePublic:MainMediaAdapterTest.kt$fun createTestMedia( id: Long, uri: String, status: Media.Status, progress: Int? = 0, selected: Boolean = false, title: String = "Test Media" ): Media + LibraryEntitiesShouldNotBePublic:MainMediaFragment.kt$MainMediaFragment : Fragment + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun CollectionHeaderView(section: CollectionSection) + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun CollectionSectionView( section: CollectionSection, onMediaClick: (Media) -> Unit, onMediaLongPress: (Media) -> Unit ) + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun ErrorIndicator() + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun MainMediaScreen( projectId: Long, ) + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun MediaItemView( media: Media, isSelected: Boolean, onClick: () -> Unit, onLongClick: () -> Unit, modifier: Modifier = Modifier ) + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun UploadProgress(progress: Int) + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$@Composable fun WelcomeMessage() + LibraryEntitiesShouldNotBePublic:MainMediaScreen.kt$CollectionSection + LibraryEntitiesShouldNotBePublic:MainMediaViewHolder.kt$MainMediaViewHolder : ViewHolder + LibraryEntitiesShouldNotBePublic:MainMediaViewModel.kt$MainMediaViewModel : ViewModel + LibraryEntitiesShouldNotBePublic:MainViewModel.kt$MainUiState + LibraryEntitiesShouldNotBePublic:MainViewModel.kt$MainViewModel : ViewModel + LibraryEntitiesShouldNotBePublic:Media.kt$Media : SugarRecord + LibraryEntitiesShouldNotBePublic:MediaAdapter.kt$MediaAdapter : Adapter + LibraryEntitiesShouldNotBePublic:MediaAdapter.kt$MediaDiffCallback : Callback + LibraryEntitiesShouldNotBePublic:MediaCacheScreen.kt$@Composable fun CacheFileItem(file: MediaFile) + LibraryEntitiesShouldNotBePublic:MediaCacheScreen.kt$@OptIn(ExperimentalMaterial3Api::class) @Composable fun MediaCacheScreen(context: Context, onNavigateBack: () -> Unit) + LibraryEntitiesShouldNotBePublic:MediaCacheScreen.kt$FileType + LibraryEntitiesShouldNotBePublic:MediaCacheScreen.kt$MediaFile + LibraryEntitiesShouldNotBePublic:MediaCacheScreen.kt$fun File.toMediaFile(): MediaFile + LibraryEntitiesShouldNotBePublic:MediaLaunchers.kt$MediaLaunchers + LibraryEntitiesShouldNotBePublic:MediaViewHolder.kt$MediaViewHolder : ViewHolder + LibraryEntitiesShouldNotBePublic:Module.kt$typealias InternetArchiveGson = Gson + LibraryEntitiesShouldNotBePublic:Notifier.kt$Notifier<Action> + LibraryEntitiesShouldNotBePublic:Notifier.kt$typealias Notify<A> = suspend (A) -> Unit + LibraryEntitiesShouldNotBePublic:NumericKeypad.kt$@Composable fun NumericKeypad( isEnabled: Boolean = true, onNumberClick: (String) -> Unit, onDeleteClick: () -> Unit, onSubmitClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:Onboarding23Activity.kt$Onboarding23Activity : BaseActivity + LibraryEntitiesShouldNotBePublic:Onboarding23FragmentStateAdapter.kt$Onboarding23FragmentStateAdapter : FragmentStateAdapter + LibraryEntitiesShouldNotBePublic:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:Onboarding23SlideFragment.kt$Onboarding23SlideFragment : Fragment + LibraryEntitiesShouldNotBePublic:PBKDF2HashingStrategy.kt$PBKDF2HashingStrategy : HashingStrategy + LibraryEntitiesShouldNotBePublic:PackageManager.kt$fun PackageManager.getVersionName(packageName: String): String + LibraryEntitiesShouldNotBePublic:PasscodeDots.kt$@Composable fun PasscodeDots( passcodeLength: Int, currentPasscodeLength: Int, shouldShake: Boolean = false ) + LibraryEntitiesShouldNotBePublic:PasscodeEntryActivity.kt$PasscodeEntryActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:PasscodeEntryScreen.kt$@Composable fun PasscodeEntryScreen( onPasscodeSuccess: () -> Unit, onExit: () -> Unit, viewModel: PasscodeEntryViewModel = koinViewModel(), hapticManager: HapticManager = koinInject() ) + LibraryEntitiesShouldNotBePublic:PasscodeEntryScreen.kt$@Composable fun PasscodeEntryScreenContent( state: PasscodeEntryScreenState, onAction: (PasscodeEntryScreenAction) -> Unit, onExit: () -> Unit, ) + LibraryEntitiesShouldNotBePublic:PasscodeEntryViewModel.kt$PasscodeEntryScreenAction + LibraryEntitiesShouldNotBePublic:PasscodeEntryViewModel.kt$PasscodeEntryScreenState + LibraryEntitiesShouldNotBePublic:PasscodeEntryViewModel.kt$PasscodeEntryUiEvent + LibraryEntitiesShouldNotBePublic:PasscodeEntryViewModel.kt$PasscodeEntryViewModel : ViewModel + LibraryEntitiesShouldNotBePublic:PasscodeManager.kt$PasscodeManager : ActivityLifecycleCallbacks + LibraryEntitiesShouldNotBePublic:PasscodeRepository.kt$PasscodeRepository + LibraryEntitiesShouldNotBePublic:PasscodeSetupActivity.kt$PasscodeSetupActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:PasscodeSetupScreen.kt$@Composable fun PasscodeSetupScreen( onPasscodeSet: () -> Unit, onCancel: () -> Unit, viewModel: PasscodeSetupViewModel = koinViewModel(), hapticManager: HapticManager = koinInject() ) + LibraryEntitiesShouldNotBePublic:PasscodeSetupViewModel.kt$PasscodeSetupUiAction + LibraryEntitiesShouldNotBePublic:PasscodeSetupViewModel.kt$PasscodeSetupUiEvent + LibraryEntitiesShouldNotBePublic:PasscodeSetupViewModel.kt$PasscodeSetupUiState + LibraryEntitiesShouldNotBePublic:PasscodeSetupViewModel.kt$PasscodeSetupViewModel : ViewModel + LibraryEntitiesShouldNotBePublic:Preview.kt$@Composable fun DefaultBoxPreview( content: @Composable () -> Unit ) + LibraryEntitiesShouldNotBePublic:Preview.kt$@Composable fun DefaultEmptyScaffoldPreview( content: @Composable () -> Unit ) + LibraryEntitiesShouldNotBePublic:Preview.kt$@Composable fun DefaultScaffoldPreview( content: @Composable () -> Unit ) + LibraryEntitiesShouldNotBePublic:PreviewActivity.kt$PreviewActivity : BaseActivityOnClickListenerListener + LibraryEntitiesShouldNotBePublic:PreviewAdapter.kt$PreviewAdapter : ListAdapter + LibraryEntitiesShouldNotBePublic:PreviewViewHolder.kt$PreviewViewHolder : ViewHolder + LibraryEntitiesShouldNotBePublic:PrimaryButton.kt$@Composable fun PrimaryButton( modifier: Modifier = Modifier, icon: ImageVector? = null, text: String, onClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:ProcessingTracker.kt$ProcessingTracker + LibraryEntitiesShouldNotBePublic:ProcessingTracker.kt$suspend fun <T> ProcessingTracker.trackProcessing( taskName: String = "Unnamed task", block: suspend () -> T ): T + LibraryEntitiesShouldNotBePublic:ProcessingTracker.kt$suspend fun <T> ProcessingTracker.trackProcessingWithTimeout( timeoutMs: Long, taskName: String = "Unnamed task", block: suspend () -> T ): T + LibraryEntitiesShouldNotBePublic:Project.kt$Project : SugarRecord + LibraryEntitiesShouldNotBePublic:ProjectAdapter.kt$ProjectAdapter : FragmentStateAdapter + LibraryEntitiesShouldNotBePublic:ProofModeScreen.kt$@Composable fun ProofModeScreen( onNavigateBack: () -> Unit ) + LibraryEntitiesShouldNotBePublic:ProofModeScreen.kt$@Composable fun ProofModeScreenContent() + LibraryEntitiesShouldNotBePublic:ProofModeSettingsActivity.kt$ProofModeSettingsActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:QRScannerActivity.kt$QRScannerActivity : CaptureActivity + LibraryEntitiesShouldNotBePublic:Reducer.kt$fun <T, A> MutableStateFlow<T>.apply(action: A, reducer: Reducer<T, A>) + LibraryEntitiesShouldNotBePublic:Reducer.kt$typealias Reducer<T, A> = (T, A) -> T + LibraryEntitiesShouldNotBePublic:RequestBodyUtil.kt$fun createListener( cancellable: () -> Boolean, onProgress: (Long) -> Unit = { }, onComplete: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:RequestListener.kt$RequestListener + LibraryEntitiesShouldNotBePublic:RequestNameDTO.kt$MembershipRequest : SerializableMarker + LibraryEntitiesShouldNotBePublic:RequestNameDTO.kt$RequestName : SerializableMarker + LibraryEntitiesShouldNotBePublic:RestEndpointTask.kt$RestEndpointTask : Runnable + LibraryEntitiesShouldNotBePublic:RetrofitAPI.kt$RetrofitAPI : ISnowbirdAPI + LibraryEntitiesShouldNotBePublic:RetrofitClient.kt$RetrofitClient + LibraryEntitiesShouldNotBePublic:RetryConfig.kt$RetryConfig + LibraryEntitiesShouldNotBePublic:ReviewActivity.kt$ReviewActivity : BaseActivityOnClickListener + LibraryEntitiesShouldNotBePublic:SaveApp.kt$SaveApp : SugarAppFactory + LibraryEntitiesShouldNotBePublic:SaveClient.kt$SaveClient : StrongBuilderBase + LibraryEntitiesShouldNotBePublic:ScryptHashingStrategy.kt$ScryptHashingStrategy : HashingStrategy + LibraryEntitiesShouldNotBePublic:SectionViewHolder.kt$SectionViewHolder + LibraryEntitiesShouldNotBePublic:SerializableMarker.kt$SerializableMarker + LibraryEntitiesShouldNotBePublic:ServerOptionItem.kt$@Composable fun ServerOptionItem( @DrawableRes iconRes: Int, title: String, subtitle: String, onClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:SettingsFragment.kt$SettingsFragment : PreferenceFragmentCompat + LibraryEntitiesShouldNotBePublic:SettingsScreen.kt$@Composable fun SettingsScreen( onNavigateToCache: () -> Unit = {} ) + LibraryEntitiesShouldNotBePublic:SmartFragmentStatePagerAdapter.kt$SmartFragmentStatePagerAdapter : FragmentStatePagerAdapter + LibraryEntitiesShouldNotBePublic:SnowbirdBridge.kt$SnowbirdBridge + LibraryEntitiesShouldNotBePublic:SnowbirdConduit.kt$SnowbirdConduit : Conduit + LibraryEntitiesShouldNotBePublic:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdError.kt$SnowbirdError : SerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdFileItem.kt$SnowbirdFileItem : SugarRecordSerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdFileItem.kt$SnowbirdFileList : SerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdFileListAdapter.kt$SnowbirdFileDiffCallback : ItemCallback + LibraryEntitiesShouldNotBePublic:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter : ListAdapter + LibraryEntitiesShouldNotBePublic:SnowbirdFileListAdapter.kt$SnowbirdFileViewHolder : ViewHolder + LibraryEntitiesShouldNotBePublic:SnowbirdFileListFragment.kt$SnowbirdFileListFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdFileRepository.kt$ISnowbirdFileRepository + LibraryEntitiesShouldNotBePublic:SnowbirdFileRepository.kt$SnowbirdFileRepository : ISnowbirdFileRepository + LibraryEntitiesShouldNotBePublic:SnowbirdFileViewModel.kt$SnowbirdFileViewModel : BaseViewModel + LibraryEntitiesShouldNotBePublic:SnowbirdFragment.kt$SnowbirdFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdGroup.kt$SnowbirdGroup : SugarRecordSerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdGroup.kt$SnowbirdGroupList : SerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdGroup.kt$fun SnowbirdGroup.shortHash(): String + LibraryEntitiesShouldNotBePublic:SnowbirdGroupListAdapter.kt$SnowbirdGroupsAdapter : ListAdapter + LibraryEntitiesShouldNotBePublic:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdGroupOverviewFragment.kt$SnowbirdGroupOverviewFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdGroupRepository.kt$ISnowbirdGroupRepository + LibraryEntitiesShouldNotBePublic:SnowbirdGroupRepository.kt$SnowbirdGroupRepository : ISnowbirdGroupRepository + LibraryEntitiesShouldNotBePublic:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel : BaseViewModel + LibraryEntitiesShouldNotBePublic:SnowbirdJoinGroupFragment.kt$SnowbirdJoinGroupFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdRepo.kt$SnowbirdRepo : SugarRecordSerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdRepo.kt$SnowbirdRepoList : SerializableMarker + LibraryEntitiesShouldNotBePublic:SnowbirdRepo.kt$fun SnowbirdRepo.shortHash(): String + LibraryEntitiesShouldNotBePublic:SnowbirdRepoListAdapter.kt$SnowbirdRepoListAdapter : ListAdapter + LibraryEntitiesShouldNotBePublic:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SnowbirdRepoRepository.kt$ISnowbirdRepoRepository + LibraryEntitiesShouldNotBePublic:SnowbirdRepoRepository.kt$SnowbirdRepoRepository : ISnowbirdRepoRepository + LibraryEntitiesShouldNotBePublic:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel : BaseViewModel + LibraryEntitiesShouldNotBePublic:SnowbirdResult.kt$SnowbirdResult<out T> + LibraryEntitiesShouldNotBePublic:SnowbirdService.kt$ServiceStatus + LibraryEntitiesShouldNotBePublic:SnowbirdService.kt$SnowbirdService : Service + LibraryEntitiesShouldNotBePublic:SnowbirdServiceStatus.kt$SnowbirdServiceStatus + LibraryEntitiesShouldNotBePublic:SnowbirdShareFragment.kt$SnowbirdShareFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:Space.kt$Space : SugarRecord + LibraryEntitiesShouldNotBePublic:SpaceAdapter.kt$SpaceAdapter : ListAdapterSpaceAdapterListener + LibraryEntitiesShouldNotBePublic:SpaceAdapter.kt$SpaceAdapterListener + LibraryEntitiesShouldNotBePublic:SpaceAdapter.kt$SpaceItemDecoration : ItemDecoration + LibraryEntitiesShouldNotBePublic:SpaceDrawerAdapter.kt$SpaceDrawerAdapter : ListAdapter + LibraryEntitiesShouldNotBePublic:SpaceDrawerAdapter.kt$SpaceDrawerAdapterListener + LibraryEntitiesShouldNotBePublic:SpaceListFragment.kt$SpaceListFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SpaceListScreen.kt$@Composable fun SpaceListItem( space: Space, onClick: () -> Unit ) + LibraryEntitiesShouldNotBePublic:SpaceListScreen.kt$@Composable fun SpaceListScreen( onSpaceClicked: (Space) -> Unit, ) + LibraryEntitiesShouldNotBePublic:SpaceListScreen.kt$@Composable fun SpaceListScreenContent( onSpaceClicked: (Space) -> Unit, spaceList: List<Space> = emptyList() ) + LibraryEntitiesShouldNotBePublic:SpaceSetupActivity.kt$SpaceSetupActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:SpaceSetupActivity.kt$StartDestination + LibraryEntitiesShouldNotBePublic:SpaceSetupFragment.kt$SpaceSetupFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SpaceSetupScreen.kt$@Composable fun SpaceSetupScreen( onWebDavClick: () -> Unit, isInternetArchiveAllowed: Boolean, onInternetArchiveClick: () -> Unit, isDwebEnabled: Boolean, onDwebClicked: () -> Unit ) + LibraryEntitiesShouldNotBePublic:SpaceSetupSuccessFragment.kt$SpaceSetupSuccessFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:SpacingItemDecoration.kt$SpacingItemDecoration : ItemDecoration + LibraryEntitiesShouldNotBePublic:StateDispatcher.kt$StateDispatcher<T, A> : DispatcherStateful + LibraryEntitiesShouldNotBePublic:Stateful.kt$Stateful<T> + LibraryEntitiesShouldNotBePublic:StatefulViewModel.kt$StatefulViewModel<State, Action> : ViewModelStoreStateful + LibraryEntitiesShouldNotBePublic:Store.kt$Store<Action> : DispatcherListenerNotifier + LibraryEntitiesShouldNotBePublic:StoreObserver.kt$StoreObserver<T> : NotifierListener + LibraryEntitiesShouldNotBePublic:StringExtensions.kt$fun String.asQRCode(size: Int = 512, quietZone: Int = 4): Bitmap + LibraryEntitiesShouldNotBePublic:StringExtensions.kt$fun String.createInputStream(): InputStream? + LibraryEntitiesShouldNotBePublic:StringExtensions.kt$fun String.getQueryParameter(paramName: String): String? + LibraryEntitiesShouldNotBePublic:StringExtensions.kt$fun String.isValidUrl() + LibraryEntitiesShouldNotBePublic:StringExtensions.kt$fun String.uriToPath(): String + LibraryEntitiesShouldNotBePublic:StringExtensions.kt$fun String.urlEncode(): String + LibraryEntitiesShouldNotBePublic:SuspendableExtensions.kt$RetryAttempt<out T> + LibraryEntitiesShouldNotBePublic:SuspendableExtensions.kt$RetryResult<out T> + LibraryEntitiesShouldNotBePublic:SuspendableExtensions.kt$fun <T> (suspend () -> T).retryWithScope( scope: CoroutineScope, config: RetryConfig, shouldRetry: (Throwable) -> Boolean = { true }, onEach: (RetryAttempt<T>) -> Unit ): Job + LibraryEntitiesShouldNotBePublic:SuspendableExtensions.kt$fun <T> (suspend () -> T).withRetry( config: RetryConfig, shouldRetry: (Throwable) -> Boolean = { true } ): Flow<RetryAttempt<T>> + LibraryEntitiesShouldNotBePublic:SuspendableExtensions.kt$fun <T> suspendToRetry(block: suspend () -> T): suspend () -> T + LibraryEntitiesShouldNotBePublic:SwipeToDeleteCallback.kt$SwipeToDeleteCallback : Callback + LibraryEntitiesShouldNotBePublic:TextView.kt$Position + LibraryEntitiesShouldNotBePublic:TextView.kt$fun TextView.scaleAndTintDrawable(position: Position, scale: Double = 1.0, tint: Boolean = true) + LibraryEntitiesShouldNotBePublic:TextView.kt$fun TextView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawables: List<Drawable?>) + LibraryEntitiesShouldNotBePublic:TextView.kt$fun TextView.setDrawable(drawable: Drawable?, position: Position, scale: Double = 1.0, tint: Boolean = true) + LibraryEntitiesShouldNotBePublic:TextView.kt$fun TextView.setDrawable(id: Int, position: Position, scale: Double = 1.0, tint: Boolean = true) + LibraryEntitiesShouldNotBePublic:TextView.kt$fun TextView.styleAsLink() + LibraryEntitiesShouldNotBePublic:Theme.kt$@Composable fun SaveAppTheme( content: @Composable () -> Unit ) + LibraryEntitiesShouldNotBePublic:Theme.kt$Theme + LibraryEntitiesShouldNotBePublic:ThrowableExceptions.kt$fun Throwable.toSnowbirdError(): SnowbirdError + LibraryEntitiesShouldNotBePublic:ToolbarConfigurable.kt$ToolbarConfigurable + LibraryEntitiesShouldNotBePublic:TorStatusContentProvider.kt$TorStatusContentProvider : ContentProvider + LibraryEntitiesShouldNotBePublic:TorStatusDatabase.kt$TorStatusDatabase : SQLiteOpenHelper + LibraryEntitiesShouldNotBePublic:TwoLetterDrawable.kt$TwoLetterDrawable : Drawable + LibraryEntitiesShouldNotBePublic:UiImage.kt$UiImage + LibraryEntitiesShouldNotBePublic:UiImage.kt$fun @receiver:DrawableRes Int.asUiImage(): UiImage.DrawableResource + LibraryEntitiesShouldNotBePublic:UiImage.kt$fun ImageVector.asUiImage(): UiImage + LibraryEntitiesShouldNotBePublic:UiText.kt$UiText + LibraryEntitiesShouldNotBePublic:UiText.kt$fun @receiver:StringRes Int.asUiText(): UiText + LibraryEntitiesShouldNotBePublic:UiText.kt$fun String.asUiText(): UiText + LibraryEntitiesShouldNotBePublic:UnauthenticatedException.kt$UnauthenticatedException : RuntimeException + LibraryEntitiesShouldNotBePublic:UnitTests.kt$UnitTests + LibraryEntitiesShouldNotBePublic:UnixSocketAPI.kt$UnixSocketAPI : ISnowbirdAPI + LibraryEntitiesShouldNotBePublic:UnixSocketClient.kt$HttpMethod + LibraryEntitiesShouldNotBePublic:UnixSocketClient.kt$UnixSocketClient + LibraryEntitiesShouldNotBePublic:UnixSocketClientFileExtensions.kt$suspend fun UnixSocketClient.downloadFile(endpoint: String): ByteArray + LibraryEntitiesShouldNotBePublic:UnixSocketClientFileExtensions.kt$suspend inline fun <reified RESPONSE : SerializableMarker> UnixSocketClient.uploadFile( endpoint: String, imageData: ByteArray ): RESPONSE + LibraryEntitiesShouldNotBePublic:UnixSocketClientFileExtensions.kt$suspend inline fun <reified RESPONSE : SerializableMarker> UnixSocketClient.uploadFile( endpoint: String, inputStream: InputStream, ): RESPONSE + LibraryEntitiesShouldNotBePublic:UnixSocketClientUtilityExtensions.kt$suspend fun UnixSocketClient.readBinaryResponseWithCancellation( inputStream: InputStream, onProgress: ((Long) -> Unit)? = null ): Triple<Int, Map<String, String>, ByteArray> + LibraryEntitiesShouldNotBePublic:UploadManagerActivity.kt$UploadManagerActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:UploadManagerFragment.kt$UploadManagerFragment : BottomSheetDialogFragment + LibraryEntitiesShouldNotBePublic:UploadService.kt$UploadService : JobService + LibraryEntitiesShouldNotBePublic:UriExtensions.kt$fun Uri.createInputStream(applicationContext: Context): InputStream? + LibraryEntitiesShouldNotBePublic:UriExtensions.kt$fun Uri.getFilename(applicationContext: Context): String? + LibraryEntitiesShouldNotBePublic:Util.kt$Util$RandomString + LibraryEntitiesShouldNotBePublic:ValidateLoginCredentialsUseCase.kt$ValidateLoginCredentialsUseCase + LibraryEntitiesShouldNotBePublic:VideoRequestHandler.kt$VideoRequestHandler : RequestHandler + LibraryEntitiesShouldNotBePublic:View.kt$fun View.cloak(animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:View.kt$fun View.disableAnimation(around: () -> Unit) + LibraryEntitiesShouldNotBePublic:View.kt$fun View.hide(animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:View.kt$fun View.makeSnackBar(message: CharSequence, duration: Int = Snackbar.LENGTH_INDEFINITE): Snackbar + LibraryEntitiesShouldNotBePublic:View.kt$fun View.show(animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:View.kt$fun View.toggle(state: Boolean? = null, animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.cloak(animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.disableAnimation(around: () -> Unit) + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.getMeasurments(): Pair<Int, Int> + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.hide(animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.makeSnackBar(message: CharSequence, duration: Int = Snackbar.LENGTH_INDEFINITE): Snackbar + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.propagateClickToParent() + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.show(animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.showKeyboard() + LibraryEntitiesShouldNotBePublic:ViewExtension.kt$fun View.toggle(state: Boolean? = null, animate: Boolean = false) + LibraryEntitiesShouldNotBePublic:WebDAVModel.kt$BackendCapabilities + LibraryEntitiesShouldNotBePublic:WebDAVModel.kt$Data + LibraryEntitiesShouldNotBePublic:WebDAVModel.kt$Meta + LibraryEntitiesShouldNotBePublic:WebDAVModel.kt$Ocs + LibraryEntitiesShouldNotBePublic:WebDAVModel.kt$Quota + LibraryEntitiesShouldNotBePublic:WebDAVModel.kt$WebDAVModel + LibraryEntitiesShouldNotBePublic:WebDavActivity.kt$WebDavActivity : BaseActivity + LibraryEntitiesShouldNotBePublic:WebDavConduit.kt$WebDavConduit : Conduit + LibraryEntitiesShouldNotBePublic:WebDavFragment.kt$WebDavFragment : BaseFragment + LibraryEntitiesShouldNotBePublic:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment : BaseFragment + LongMethod:BaseDialog.kt$@Composable fun BaseDialog( onDismiss: () -> Unit, icon: UiImage? = null, iconColor: Color? = null, title: String, message: String, hasCheckbox: Boolean = false, onCheckBoxStateChanged: (Boolean) -> Unit = {}, checkBoxHint: String = "Do not show me this again", positiveButton: ButtonData? = null, neutralButton: ButtonData? = null, destructiveButton: ButtonData? = null, backgroundColor: Color = MaterialTheme.colorScheme.surface ) + LongMethod:FileUtils.kt$FileUtils$@SuppressLint("NewAPI", "LogNotTimber") fun getPath(context: Context, uri: Uri): String? + LongMethod:HomeScreen.kt$@Composable fun HomeScreenContent( onExit: () -> Unit, state: HomeScreenState, onAction: (HomeScreenAction) -> Unit, onNavigateToCache: () -> Unit = {} ) + LongMethod:InternetArchiveDetailsScreen.kt$@Composable private fun InternetArchiveDetailsContent( state: InternetArchiveDetailsState, dispatch: Dispatch<Action>, dialogManager: DialogStateManager = koinViewModel() ) + LongMethod:InternetArchiveLoginScreen.kt$@Composable private fun InternetArchiveLoginContent( state: InternetArchiveLoginState, dispatch: Dispatch<Action> ) + LongMethod:MainDrawerContent.kt$@Composable fun MainDrawerContent( selectedSpace: Space? = null, spaceList: List<Space> = emptyList() ) + LongMethod:MainMediaViewHolder.kt$MainMediaViewHolder$fun bind(media: Media? = null, isInSelectionMode: Boolean = false, doImageFade: Boolean = true) + LongMethod:MediaAdapter.kt$MediaAdapter$override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaViewHolder + LongMethod:MediaViewHolder.kt$MediaViewHolder$@SuppressLint("SetTextI18n") fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) + LongMethod:NumericKeypad.kt$@Composable private fun NumberButton( label: String, enabled: Boolean = true, onClick: () -> Unit, hapticManager: HapticManager = koinInject() ) + LongMethod:PasscodeSetupScreen.kt$@Composable private fun PasscodeSetupScreenContent( state: PasscodeSetupUiState, onAction: (PasscodeSetupUiAction) -> Unit ) + LongMethod:PreviewViewHolder.kt$PreviewViewHolder$@SuppressLint("SetTextI18n") fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) + LongMethod:ProofModeScreen.kt$@Composable fun ProofModeScreenContent() + LongMethod:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) + LongMethod:SettingsFragment.kt$SettingsFragment$override fun onCreatePreferences( savedInstanceState: Bundle?, rootKey: String? ) + LongMethod:SettingsScreen.kt$@Composable fun SettingsScreen( onNavigateToCache: () -> Unit = {} ) + LongMethod:UnixSocketClientUtilityExtensions.kt$suspend fun UnixSocketClient.readBinaryResponseWithCancellation( inputStream: InputStream, onProgress: ((Long) -> Unit)? = null ): Triple<Int, Map<String, String>, ByteArray> + LongMethod:WebDavConduit.kt$WebDavConduit$@Throws(IOException::class) private suspend fun uploadChunked(base: HttpUrl, path: List<String>, fileName: String): Boolean + LongMethod:WebDavFragment.kt$WebDavFragment$override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View + LongParameterList:Accordion.kt$( modifier: Modifier = Modifier, headerModifier: Modifier = Modifier, state: AccordionState = rememberAccordionState(), animate: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, headerContent: @Composable () -> Unit, bodyContent: @Composable () -> Unit, ) + LongParameterList:BaseButton.kt$( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, backgroundColor: Color = MaterialTheme.colorScheme.primary, textColor: Color = MaterialTheme.colorScheme.onPrimary, cornerRadius: Dp = 12.dp, ) + LongParameterList:BaseButton.kt$( text: String, onClick: () -> Unit, modifier: Modifier = Modifier, borderColor: Color = MaterialTheme.colorScheme.error, textColor: Color = MaterialTheme.colorScheme.error, cornerRadius: Dp = 12.dp, ) + LongParameterList:BaseDialog.kt$( onDismiss: () -> Unit, icon: UiImage? = null, iconColor: Color? = null, title: String, message: String, hasCheckbox: Boolean = false, onCheckBoxStateChanged: (Boolean) -> Unit = {}, checkBoxHint: String = "Do not show me this again", positiveButton: ButtonData? = null, neutralButton: ButtonData? = null, destructiveButton: ButtonData? = null, backgroundColor: Color = MaterialTheme.colorScheme.surface ) + LongParameterList:DialogConfigBuilder.kt$( title: UiText?, message: UiText, icon: UiImage? = null, positiveButtonText: UiText? = null, onDone: () -> Unit = {}, onCancel: () -> Unit = {} ) + LongParameterList:HomeScreen.kt$( context: Context, viewModel: HomeViewModel = koinViewModel(), onExit: () -> Unit, onNewFolder: () -> Unit, onFolderSelected: (Long) -> Unit, onAddMedia: (AddMediaType) -> Unit ) + LongParameterList:HomeScreen.kt$( viewModel: HomeViewModel = koinViewModel(), onExit: () -> Unit, onNewFolder: () -> Unit, onFolderSelected: (Long) -> Unit, onAddMedia: (AddMediaType) -> Unit, onNavigateToCache: () -> Unit ) + LongParameterList:InternetArchiveLoginScreen.kt$( modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: String, enabled: Boolean = true, placeholder: String? = null, isError: Boolean = false, isLoading: Boolean = false, keyboardType: KeyboardType = KeyboardType.Text, imeAction: ImeAction = ImeAction.Next, ) + LongParameterList:InternetArchiveLoginScreen.kt$( modifier: Modifier = Modifier, value: String, onValueChange: (String) -> Unit, label: String, placeholder: String, isError: Boolean = false, isLoading: Boolean = false, keyboardType: KeyboardType, imeAction: ImeAction, ) + LongParameterList:MainMediaAdapterTest.kt$( id: Long, uri: String, status: Media.Status, progress: Int? = 0, selected: Boolean = false, title: String = "Test Media" ) + LongParameterList:Utility.kt$Utility$( context: Context, title: String, message: String? = null, positiveButtonText: String, negativeButtonText: String, completion: (Boolean) -> Unit ) + LoopWithTooManyJumpStatements:SuspendableExtensions.kt$while + LoopWithTooManyJumpStatements:UnixSocketClientUtilityExtensions.kt$while + MagicNumber:BadgeDrawable.kt$BadgeDrawable$4 + MagicNumber:BadgeDrawable.kt$BadgeDrawable$5f + MagicNumber:Colors.kt$0xff000A0A + MagicNumber:Colors.kt$0xff001b19 + MagicNumber:Colors.kt$0xff003530 + MagicNumber:Colors.kt$0xff004e48 + MagicNumber:Colors.kt$0xff00685f + MagicNumber:Colors.kt$0xff008177 + MagicNumber:Colors.kt$0xff009b8f + MagicNumber:Colors.kt$0xff00b4a6 + MagicNumber:Colors.kt$0xff00cebe + MagicNumber:Colors.kt$0xff00e7d5 + MagicNumber:Colors.kt$0xff00ffeb + MagicNumber:Colors.kt$0xff101010 + MagicNumber:Colors.kt$0xff212021 + MagicNumber:Colors.kt$0xff333333 + MagicNumber:Colors.kt$0xff434343 + MagicNumber:Colors.kt$0xff696666 + MagicNumber:Colors.kt$0xff777979 + MagicNumber:Colors.kt$0xff9f9f9f + MagicNumber:Colors.kt$0xffaae6e1 + MagicNumber:Colors.kt$0xffe3e3e4 + MagicNumber:Colors.kt$0xfffffbf0 + MagicNumber:Conduit.kt$Conduit$100 + MagicNumber:DrawableUtil.kt$DrawableUtil$100 + MagicNumber:DrawableUtil.kt$DrawableUtil$40f + MagicNumber:DurationExtensions.kt$1e9 + MagicNumber:EditFolderActivity.kt$EditFolderActivity$0.5 + MagicNumber:ExpandableSpaceList.kt$180 + MagicNumber:FullscreenDimmingOverlay.kt$FullScreenCreateGroupDimmingOverlay$200 + MagicNumber:FullscreenDimmingOverlay.kt$FullScreenDimmingOverlay$200 + MagicNumber:GDriveConduit.kt$GDriveConduit$262144 + MagicNumber:GDriveConduit.kt$GDriveConduit.Companion$1000 + MagicNumber:GDriveConduit.kt$GDriveConduit.Companion$20 + MagicNumber:GDriveConduit.kt$GDriveConduit.Companion$200 + MagicNumber:GDriveConduit.kt$GDriveConduit.Companion$443 + MagicNumber:GDriveConduit.kt$GDriveConduit.Companion$80 + MagicNumber:GDriveConduit.kt$GDriveConduit.Companion$8192 + MagicNumber:Hbks.kt$Hbks$12 + MagicNumber:Hbks.kt$Hbks$128 + MagicNumber:Hbks.kt$Hbks$60 + MagicNumber:IaConduit.kt$IaConduit$4 + MagicNumber:InternetArchiveLoginScreen.kt$3000 + MagicNumber:MainActivity.kt$MainActivity$0.3f + MagicNumber:MainActivity.kt$MainActivity$0.75 + MagicNumber:MainActivity.kt$MainActivity$200 + MagicNumber:MainActivity.kt$MainActivity$60 + MagicNumber:MainActivity.kt$MainActivity$8f + MagicNumber:MainDrawerContent.kt$0.65f + MagicNumber:MainDrawerContent.kt$0.7f + MagicNumber:MainDrawerContent.kt$8f + MagicNumber:MainMediaScreen.kt$4 + MagicNumber:MainMediaViewHolder.kt$MainMediaViewHolder$0.5f + MagicNumber:MainMediaViewHolder.kt$MainMediaViewHolder$1000 + MagicNumber:MainMediaViewHolder.kt$MainMediaViewHolder$300 + MagicNumber:MainMediaViewHolder.kt$MainMediaViewHolder$30f + MagicNumber:MainMediaViewHolder.kt$MainMediaViewHolder$5f + MagicNumber:Media.kt$Media.Status.DeleteRemote$7 + MagicNumber:Media.kt$Media.Status.Error$9 + MagicNumber:Media.kt$Media.Status.Published$3 + MagicNumber:Media.kt$Media.Status.Uploaded$5 + MagicNumber:Media.kt$Media.Status.Uploading$4 + MagicNumber:MediaViewHolder.kt$MediaViewHolder$0.5f + MagicNumber:MediaViewHolder.kt$MediaViewHolder$30f + MagicNumber:MediaViewHolder.kt$MediaViewHolder$5f + MagicNumber:NumericKeypad.kt$3 + MagicNumber:Onboarding23Activity.kt$Onboarding23Activity$0xffffff + MagicNumber:Onboarding23Activity.kt$Onboarding23Activity$2000 + MagicNumber:Onboarding23Activity.kt$Onboarding23Activity$25F + MagicNumber:Onboarding23Activity.kt$Onboarding23Activity$3000 + MagicNumber:Onboarding23Activity.kt$Onboarding23Activity$999999 + MagicNumber:Onboarding23FragmentStateAdapter.kt$Onboarding23FragmentStateAdapter$3 + MagicNumber:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity$200L + MagicNumber:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity$3 + MagicNumber:PasscodeDots.kt$10f + MagicNumber:PasscodeDots.kt$15f + MagicNumber:PasscodeDots.kt$25f + MagicNumber:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$200 + MagicNumber:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$500 + MagicNumber:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$100 + MagicNumber:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$500 + MagicNumber:Picker.kt$Picker$99 + MagicNumber:PreviewViewHolder.kt$PreviewViewHolder$0.5f + MagicNumber:PreviewViewHolder.kt$PreviewViewHolder$30f + MagicNumber:PreviewViewHolder.kt$PreviewViewHolder$5f + MagicNumber:PrimaryButton.kt$8f + MagicNumber:ProcessingTracker.kt$ProcessingTracker$3 + MagicNumber:RestEndpointTask.kt$RestEndpointTask$9050 + MagicNumber:RetrofitModule.kt$60 + MagicNumber:SaveClient.kt$SaveClient$40L + MagicNumber:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$40 + MagicNumber:SnowbirdFileViewModel.kt$SnowbirdFileViewModel$30_000 + MagicNumber:SnowbirdFileViewModel.kt$SnowbirdFileViewModel$60_000 + MagicNumber:SnowbirdGroup.kt$10 + MagicNumber:SnowbirdGroupListAdapter.kt$SnowbirdGroupsAdapter.ViewHolder$40 + MagicNumber:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$1000 + MagicNumber:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$5 + MagicNumber:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$60 + MagicNumber:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel$30_000 + MagicNumber:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel$60_000 + MagicNumber:SnowbirdRepo.kt$10 + MagicNumber:SnowbirdRepoListAdapter.kt$SnowbirdRepoListAdapter.SnowbirdRepoListViewHolder$40 + MagicNumber:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel$30_000 + MagicNumber:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel$60_000 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus$3 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus$4 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus$5 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus$6 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus.Companion$3 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus.Companion$4 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus.Companion$5 + MagicNumber:SnowbirdServiceStatus.kt$SnowbirdServiceStatus.Companion$6 + MagicNumber:Space.kt$Space.Type.GDRIVE$4 + MagicNumber:Space.kt$Space.Type.RAVEN$5 + MagicNumber:SpaceAdapter.kt$SpaceAdapter.ViewHolder$32 + MagicNumber:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.SpaceViewHolder$21 + MagicNumber:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$0.75 + MagicNumber:TwoLetterDrawable.kt$TwoLetterDrawable$0.5f + MagicNumber:TwoLetterDrawable.kt$TwoLetterDrawable$0.8f + MagicNumber:UnixSocketClient.kt$UnixSocketClient$200 + MagicNumber:UnixSocketClient.kt$UnixSocketClient$299 + MagicNumber:UnixSocketClientFileExtensions.kt$200 + MagicNumber:UnixSocketClientFileExtensions.kt$299 + MagicNumber:UnixSocketClientUtilityExtensions.kt$16 + MagicNumber:UnixSocketClientUtilityExtensions.kt$8192 + MagicNumber:UploadService.kt$UploadService$7918 + MagicNumber:Utility.kt$Utility$1024 + MagicNumber:Utility.kt$Utility$4 + MagicNumber:VideoRequestHandler.kt$VideoRequestHandler$6 + MagicNumber:WebDavFragment.kt$WebDavFragment.<no name provided>$200 + MagicNumber:WebDavFragment.kt$WebDavFragment.<no name provided>$204 + MatchingDeclarationName:DefaultScaffold.kt$MessageManager + MatchingDeclarationName:MainMediaScreen.kt$CollectionSection + MatchingDeclarationName:SnowbirdGroupListAdapter.kt$SnowbirdGroupsAdapter : ListAdapter + MatchingDeclarationName:TextView.kt$Position + MaxLineLength:BiometricAuthenticator.kt$BiometricAuthenticator$return config.biometricAuthEnabled && biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS + MaxLineLength:BottomSheetExtensions.kt$val bottomSheet: FrameLayout = dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet) ?: return@setOnShowListener + MaxLineLength:BrowseFoldersAdapter.kt$BrowseFoldersAdapter.FolderViewHolder$inner + MaxLineLength:ConsentActivity.kt$ConsentActivity$R.string.by_allowing_health_checks_you_give_permission_for_the_app_to_securely_send_health_check_data_to_the_s_team + MaxLineLength:CreativeCommonsLicenseManager.kt$CreativeCommonsLicenseManager$swRequireShareAlike.isChecked = isActive && binding.swAllowRemix.isChecked && currentLicense?.contains("-sa", true) ?: false + MaxLineLength:DriveServiceHelper.kt$DriveServiceHelper$suspend + MaxLineLength:DurationExtensions.kt$* + MaxLineLength:GDriveConduit.kt$GDriveConduit.Companion$"mimeType='application/vnd.google-apps.folder' and 'root' in parents and trashed = false" + MaxLineLength:GDriveConduit.kt$GDriveConduit.Companion$"mimeType='application/vnd.google-apps.folder' and name = '$folderName' and trashed = false and '$parentId' in parents" + MaxLineLength:Hbks.kt$Hbks$} + MaxLineLength:IaConduit.kt$IaConduit$// TODO this should make sure we aren't accidentally using one of archive.org's metadata fields by accident + MaxLineLength:InternetArchiveDetailsScreen.kt$message = UiText.StringResource(R.string.are_you_sure_you_want_to_remove_this_server_from_the_app) + MaxLineLength:InternetArchiveFragment.kt$InternetArchiveFragment$val + MaxLineLength:MediaAdapter.kt$MediaAdapter$// CleanInsightsManager.measureEvent("backend", "upload-error", media[pos].space?.friendlyName) + MaxLineLength:PasscodeSetupScreen.kt$text = "Make sure you remember this pin. If you forget it, you will need to reset the app, and all data will be erased." + MaxLineLength:Prefs.kt$Prefs$get() = prefs?.getString(ProofModeConstants.PREFS_KEY_PASSPHRASE, null) ?: ProofModeConstants.PREFS_KEY_PASSPHRASE_DEFAULT + MaxLineLength:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$if + MaxLineLength:ReviewActivity.kt$ReviewActivity.Companion$fun + MaxLineLength:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment$SnowbirdCreateGroupFragmentDirections + MaxLineLength:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$// viewBinding.snowbirdMediaRecyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) + MaxLineLength:SnowbirdFileRepository.kt$SnowbirdFileRepository$private suspend + MaxLineLength:SnowbirdFragment.kt$SnowbirdFragment$"save+dweb::?dht=82fd345d484393a96b6e0c5d5e17a85a61c9184cc5a3311ab069d6efa0bf1410&enc=6fa27396fe298f92c91013ac54d8f316c2d45dc3bed0edec73078040aa10feed&pk=f4b404d294817cf11ea7f8ef7231626e03b74f6fafe3271b53918608afa82d12&sk=5482a8f490081be684fbadb8bde7f0a99bab8acdcf1ec094826f0f18e327e399" + MaxLineLength:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$// findNavController().navigate(SnowbirdGroupListFragmentDirections.navigateToSnowbirdShareScreen(groupKey)) + MaxLineLength:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$val + MaxLineLength:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment.<no name provided>$SnowbirdGroupListFragmentDirections.actionFragmentSnowbirdGroupListToFragmentSnowbirdCreateGroup() + MaxLineLength:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$// findNavController().navigate(SnowbirdRepoListFragmentDirections.navigateToSnowbirdListFilesScreen(groupKey, repoKey)) + MaxLineLength:SpaceAdapter.kt$SpaceAdapter$class + MaxLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$class + MaxLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$val previousIndex = currentList.indexOfFirst { it is SpaceItem.SpaceItemData && it.space.id == selectedSpace?.id } + MaxLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.Companion.<no name provided>$oldItem is SpaceItem.SpaceItemData && newItem is SpaceItem.SpaceItemData -> oldItem.space.friendlyName == newItem.space.friendlyName + MaxLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.Companion.<no name provided>$oldItem is SpaceItem.SpaceItemData && newItem is SpaceItem.SpaceItemData -> oldItem.space.id == newItem.space.id + MaxLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.SpaceViewHolder$val previousIndex = currentList.indexOfFirst { it is SpaceItem.SpaceItemData && it.space.id == selectedSpace?.id } + MaxLineLength:Utility.kt$Utility$fun + MaxLineLength:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$val + MaximumLineLength:BiometricAuthenticator.kt$BiometricAuthenticator$ + MaximumLineLength:BottomSheetExtensions.kt$ + MaximumLineLength:BrowseFoldersAdapter.kt$BrowseFoldersAdapter$ + MaximumLineLength:ConsentActivity.kt$ConsentActivity$ + MaximumLineLength:CreativeCommonsLicenseManager.kt$CreativeCommonsLicenseManager$ + MaximumLineLength:DriveServiceHelper.kt$DriveServiceHelper$ + MaximumLineLength:GDriveConduit.kt$GDriveConduit.Companion$ + MaximumLineLength:Hbks.kt$Hbks$ + MaximumLineLength:InternetArchiveDetailsScreen.kt$ + MaximumLineLength:InternetArchiveFragment.kt$InternetArchiveFragment$ + MaximumLineLength:PasscodeSetupScreen.kt$ + MaximumLineLength:Prefs.kt$Prefs$ + MaximumLineLength:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$ + MaximumLineLength:ReviewActivity.kt$ReviewActivity.Companion$ + MaximumLineLength:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment$ + MaximumLineLength:SnowbirdFileRepository.kt$SnowbirdFileRepository$ + MaximumLineLength:SnowbirdFragment.kt$SnowbirdFragment$ + MaximumLineLength:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$ + MaximumLineLength:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment.<no name provided>$ + MaximumLineLength:SpaceAdapter.kt$SpaceAdapter$class + MaximumLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$ + MaximumLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$class + MaximumLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.Companion.<no name provided>$ + MaximumLineLength:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.SpaceViewHolder$ + MaximumLineLength:Utility.kt$Utility$ + MaximumLineLength:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$ + MemberNameEqualsClassName:Prefs.kt$Prefs$private var prefs: SharedPreferences? = null + ModifierClickableOrder:NumericKeypad.kt$clickable( interactionSource = interactionSource, indication = null, enabled = enabled, onClick = { hapticManager.performHapticFeedback(AppHapticFeedbackType.KeyPress) onClick() } ) + ModifierMissing:AddFolderScreen.kt$AddFolderScreenContent + ModifierMissing:AddFolderScreen.kt$FolderOption + ModifierMissing:BrowseFolderScreen.kt$BrowseFolderItem + ModifierMissing:BrowseFolderScreen.kt$BrowseFolderScreenContent + ModifierMissing:ExpandableSpaceList.kt$DrawerSpaceListItem + ModifierMissing:ExpandableSpaceList.kt$ExpandableSpaceList + ModifierMissing:FolderOptionsPopup.kt$FolderOptionsPopup + ModifierMissing:HomeAppBar.kt$HomeAppBar + ModifierMissing:HomeScreen.kt$HomeScreenContent + ModifierMissing:InternetArchiveLoginScreen.kt$ComposeAppBar + ModifierMissing:MainBottomBar.kt$BottomNavMenuItem + ModifierMissing:MainBottomBar.kt$MainBottomBar + ModifierMissing:MainDrawerContent.kt$MainDrawerContent + ModifierMissing:MainDrawerContent.kt$MainDrawerFolderListItem + ModifierMissing:MainMediaScreen.kt$CollectionHeaderView + ModifierMissing:MainMediaScreen.kt$CollectionSectionView + ModifierMissing:MainMediaScreen.kt$ErrorIndicator + ModifierMissing:MainMediaScreen.kt$MainMediaScreen + ModifierMissing:MainMediaScreen.kt$UploadProgress + ModifierMissing:MainMediaScreen.kt$WelcomeMessage + ModifierMissing:MediaCacheScreen.kt$CacheFileItem + ModifierMissing:MediaCacheScreen.kt$MediaCacheScreen + ModifierMissing:NumericKeypad.kt$NumericKeypad + ModifierMissing:PasscodeDots.kt$PasscodeDots + ModifierMissing:PasscodeEntryScreen.kt$PasscodeEntryScreenContent + ModifierMissing:Preview.kt$DefaultBoxPreview + ModifierMissing:Preview.kt$DefaultEmptyScaffoldPreview + ModifierMissing:Preview.kt$DefaultScaffoldPreview + ModifierMissing:ProofModeScreen.kt$ProofModeScreenContent + ModifierMissing:ServerOptionItem.kt$ServerOptionItem + ModifierMissing:SettingsScreen.kt$SettingsScreen + ModifierMissing:SpaceListScreen.kt$SpaceListItem + ModifierMissing:SpaceListScreen.kt$SpaceListScreen + ModifierMissing:SpaceListScreen.kt$SpaceListScreenContent + ModifierMissing:SpaceSetupScreen.kt$SpaceSetupScreen + MultiLineIfElse:EditFolderActivity.kt$EditFolderActivity$R.string.action_archive_project + MultiLineIfElse:EditFolderActivity.kt$EditFolderActivity$R.string.action_unarchive_project + MultiLineIfElse:FileUtils.kt$FileUtils$Log.d( "$TAG File -", "Authority: " + uri.authority + ", Fragment: " + uri.fragment + ", Port: " + uri.port + ", Query: " + uri.query + ", Scheme: " + uri.scheme + ", Host: " + uri.host + ", Segments: " + uri.pathSegments.toString() ) + MultiLineIfElse:MainActivity.kt$MainActivity$false + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_edit_selected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_edit_unselected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_flag_selected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_flag_unselected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_location_selected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_location_unselected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_tag_selected + MultiLineIfElse:MediaViewHolder.kt$MediaViewHolder$R.drawable.ic_tag_unselected + MultiLineIfElse:PasscodeDots.kt$MaterialTheme.colorScheme.onBackground + MultiLineIfElse:PasscodeDots.kt$MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f) + MultiLineIfElse:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$null + MultiLineIfElse:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$state + MultiLineIfElse:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$state.copy(passcode = state.passcode + number) + MultiLineIfElse:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$state.copy(passcode = state.passcode.dropLast(1)) + MultiLineIfElse:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$state + MultiLineIfElse:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$state.copy(passcode = state.passcode + number) + MultiLineIfElse:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$state.copy(passcode = state.passcode.dropLast(1)) + MultiLineIfElse:RequestBodyUtil.kt$RequestBodyUtil.<no name provided>$FileInputStream( uri.path?.let { File(it) } ) + MultiLineIfElse:RequestBodyUtil.kt$RequestBodyUtil.<no name provided>$cr.openInputStream(uri) + MultiLineIfElse:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$0 + MultiLineIfElse:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$ColorDrawable(ContextCompat.getColor(context, R.color.colorDanger)) + MultiLineIfElse:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$ContextCompat.getColor(context, R.color.colorOnBackground) + MultiLineIfElse:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$ContextCompat.getDrawable(context, R.drawable.ic_delete) + MultiLineIfElse:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$null + NestedBlockDepth:MediaViewHolder.kt$MediaViewHolder$@SuppressLint("SetTextI18n") fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) + NestedBlockDepth:UriExtensions.kt$fun Uri.getFilename(applicationContext: Context): String? + NestedBlockDepth:WebDavConduit.kt$WebDavConduit$@Throws(IOException::class) private suspend fun uploadChunked(base: HttpUrl, path: List<String>, fileName: String): Boolean + NoBlankLineBeforeRbrace:AddFolderScreen.kt$ + NoBlankLineBeforeRbrace:BaseDialog.kt$ + NoBlankLineBeforeRbrace:BrowseFolderScreen.kt$ + NoBlankLineBeforeRbrace:CreateNewFolderFragment.kt$CreateNewFolderFragment$ + NoBlankLineBeforeRbrace:ExpandableSpaceList.kt$ + NoBlankLineBeforeRbrace:FileUtils.kt$FileUtils$ + NoBlankLineBeforeRbrace:FolderAdapter.kt$FolderAdapter.ViewHolder$ + NoBlankLineBeforeRbrace:FolderOptionsPopup.kt$ + NoBlankLineBeforeRbrace:HomeActivity.kt$HomeActivity$ + NoBlankLineBeforeRbrace:HomeAppBar.kt$ + NoBlankLineBeforeRbrace:HomeScreen.kt$ + NoBlankLineBeforeRbrace:HomeScreen.kt$HomeViewModel$ + NoBlankLineBeforeRbrace:IaConduit.kt$IaConduit.<no name provided>$ + NoBlankLineBeforeRbrace:InternetArchiveActivity.kt$InternetArchiveActivity$ + NoBlankLineBeforeRbrace:InternetArchiveDetailsScreen.kt$ + NoBlankLineBeforeRbrace:InternetArchiveLoginUseCase.kt$InternetArchiveLoginUseCase$ + NoBlankLineBeforeRbrace:InternetArchiveLoginViewModel.kt$InternetArchiveLoginViewModel$ + NoBlankLineBeforeRbrace:MainActivity.kt$MainActivity$ + NoBlankLineBeforeRbrace:MainBottomBar.kt$ + NoBlankLineBeforeRbrace:MainDrawerContent.kt$ + NoBlankLineBeforeRbrace:MainMediaViewHolder.kt$MainMediaViewHolder$ + NoBlankLineBeforeRbrace:MainMediaViewModel.kt$MainMediaViewModel$ + NoBlankLineBeforeRbrace:MediaCacheScreen.kt$ + NoBlankLineBeforeRbrace:NumericKeypad.kt$ + NoBlankLineBeforeRbrace:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity.<no name provided>$ + NoBlankLineBeforeRbrace:PackageManager.kt$ + NoBlankLineBeforeRbrace:PasscodeEntryScreen.kt$ + NoBlankLineBeforeRbrace:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$ + NoBlankLineBeforeRbrace:Preview.kt$ + NoBlankLineBeforeRbrace:PreviewActivity.kt$PreviewActivity$ + NoBlankLineBeforeRbrace:PreviewViewHolder.kt$PreviewViewHolder$ + NoBlankLineBeforeRbrace:Project.kt$Project$ + NoBlankLineBeforeRbrace:ProofModeSettingsActivity.kt$ProofModeSettingsActivity$ + NoBlankLineBeforeRbrace:RetrofitAPI.kt$RetrofitAPI$ + NoBlankLineBeforeRbrace:SectionViewHolder.kt$SectionViewHolder.Companion$ + NoBlankLineBeforeRbrace:ServerOptionItem.kt$ + NoBlankLineBeforeRbrace:SmartFragmentStatePagerAdapter.kt$SmartFragmentStatePagerAdapter$ + NoBlankLineBeforeRbrace:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment$ + NoBlankLineBeforeRbrace:SnowbirdFileRepository.kt$SnowbirdFileRepository$ + NoBlankLineBeforeRbrace:Space.kt$Space$ + NoBlankLineBeforeRbrace:SpaceAdapter.kt$SpaceAdapter.Companion$ + NoBlankLineBeforeRbrace:SpaceListFragment.kt$SpaceListFragment$ + NoBlankLineBeforeRbrace:SpaceListScreen.kt$ + NoBlankLineBeforeRbrace:SpaceSetupActivity.kt$SpaceSetupActivity$ + NoBlankLineBeforeRbrace:SpaceSetupFragment.kt$SpaceSetupFragment$ + NoBlankLineBeforeRbrace:TorStatusContentProvider.kt$TorStatusContentProvider$ + NoBlankLineBeforeRbrace:UiImage.kt$UiImage$ + NoBlankLineBeforeRbrace:WebDavFragment.kt$WebDavFragment$ + NoConsecutiveBlankLines:AddFolderActivity.kt$AddFolderActivity$ + NoConsecutiveBlankLines:AddFolderScreen.kt$ + NoConsecutiveBlankLines:AppLogger.kt$ + NoConsecutiveBlankLines:BadgeDrawable.kt$BadgeDrawable$ + NoConsecutiveBlankLines:BaseButton.kt$ + NoConsecutiveBlankLines:BaseComposeActivity.kt$BaseComposeActivity$ + NoConsecutiveBlankLines:BaseDialog.kt$ + NoConsecutiveBlankLines:BrowseFolderScreen.kt$ + NoConsecutiveBlankLines:BrowseFoldersAdapter.kt$BrowseFoldersAdapter.FolderViewHolder$ + NoConsecutiveBlankLines:BrowseFoldersFragment.kt$ + NoConsecutiveBlankLines:BrowseFoldersFragment.kt$BrowseFoldersFragment$ + NoConsecutiveBlankLines:BrowseFoldersViewModel.kt$ + NoConsecutiveBlankLines:Collection.kt$Collection$ + NoConsecutiveBlankLines:ContentPickerFragment.kt$ContentPickerFragment$ + NoConsecutiveBlankLines:CoreModule.kt$ + NoConsecutiveBlankLines:CustomBottomNavBar.kt$CustomBottomNavBar$ + NoConsecutiveBlankLines:DialogConfigBuilder.kt$ + NoConsecutiveBlankLines:EditFolderActivity.kt$EditFolderActivity$ + NoConsecutiveBlankLines:Effects.kt$ + NoConsecutiveBlankLines:FeaturesModule.kt$ + NoConsecutiveBlankLines:FileUtils.kt$FileUtils$ + NoConsecutiveBlankLines:FolderAdapter.kt$FolderAdapter.ViewHolder$ + NoConsecutiveBlankLines:FolderDrawerAdapter.kt$ + NoConsecutiveBlankLines:FolderDrawerAdapter.kt$FolderDrawerAdapter$ + NoConsecutiveBlankLines:FoldersActivity.kt$FoldersActivity$ + NoConsecutiveBlankLines:GeneralSettingsActivity.kt$ + NoConsecutiveBlankLines:GeneralSettingsActivity.kt$GeneralSettingsActivity$ + NoConsecutiveBlankLines:GeneralSettingsActivity.kt$GeneralSettingsActivity.Fragment$ + NoConsecutiveBlankLines:Hbks.kt$Hbks$ + NoConsecutiveBlankLines:HomeScreen.kt$ + NoConsecutiveBlankLines:IaConduit.kt$IaConduit$ + NoConsecutiveBlankLines:InternetArchive.kt$InternetArchive$ + NoConsecutiveBlankLines:InternetArchiveActivity.kt$InternetArchiveActivity$ + NoConsecutiveBlankLines:InternetArchiveDetailsScreen.kt$ + NoConsecutiveBlankLines:InternetArchiveDetailsState.kt$ + NoConsecutiveBlankLines:MainActivity.kt$ + NoConsecutiveBlankLines:MainActivity.kt$MainActivity$ + NoConsecutiveBlankLines:MainDrawerContent.kt$ + NoConsecutiveBlankLines:MainMediaAdapter.kt$MainMediaAdapter$ + NoConsecutiveBlankLines:MainMediaAdapterTest.kt$ + NoConsecutiveBlankLines:MainMediaAdapterTest.kt$MainMediaAdapterTest$ + NoConsecutiveBlankLines:MainMediaFragment.kt$MainMediaFragment$ + NoConsecutiveBlankLines:MainMediaScreen.kt$ + NoConsecutiveBlankLines:MainMediaViewHolder.kt$MainMediaViewHolder$ + NoConsecutiveBlankLines:MainMediaViewModel.kt$ + NoConsecutiveBlankLines:MainViewModel.kt$MainViewModel$ + NoConsecutiveBlankLines:Media.kt$Media$ + NoConsecutiveBlankLines:Media.kt$Media.Companion$ + NoConsecutiveBlankLines:MediaAdapter.kt$MediaAdapter$ + NoConsecutiveBlankLines:MediaCacheScreen.kt$ + NoConsecutiveBlankLines:MediaViewHolder.kt$MediaViewHolder$ + NoConsecutiveBlankLines:Notifier.kt$ + NoConsecutiveBlankLines:NumericKeypad.kt$ + NoConsecutiveBlankLines:Onboarding23SlideFragment.kt$Onboarding23SlideFragment$ + NoConsecutiveBlankLines:PasscodeEntryActivity.kt$PasscodeEntryActivity$ + NoConsecutiveBlankLines:PasscodeEntryScreen.kt$ + NoConsecutiveBlankLines:PasscodeSetupActivity.kt$PasscodeSetupActivity$ + NoConsecutiveBlankLines:PasscodeSetupScreen.kt$ + NoConsecutiveBlankLines:PreviewActivity.kt$PreviewActivity$ + NoConsecutiveBlankLines:PreviewViewHolder.kt$PreviewViewHolder$ + NoConsecutiveBlankLines:ProofModeScreen.kt$ + NoConsecutiveBlankLines:ProofModeSettingsActivity.kt$ + NoConsecutiveBlankLines:ProofModeSettingsActivity.kt$ProofModeSettingsActivity$ + NoConsecutiveBlankLines:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$ + NoConsecutiveBlankLines:ReviewActivity.kt$ReviewActivity$ + NoConsecutiveBlankLines:SettingsFragment.kt$SettingsFragment$ + NoConsecutiveBlankLines:SettingsScreen.kt$ + NoConsecutiveBlankLines:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment$ + NoConsecutiveBlankLines:SnowbirdFileItem.kt$ + NoConsecutiveBlankLines:SnowbirdJoinGroupFragment.kt$SnowbirdJoinGroupFragment.Companion$ + NoConsecutiveBlankLines:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$ + NoConsecutiveBlankLines:SpaceAdapter.kt$SpaceAdapter.ViewHolder$ + NoConsecutiveBlankLines:SpaceDrawerAdapter.kt$SpaceDrawerAdapter$ + NoConsecutiveBlankLines:SpaceListFragment.kt$SpaceListFragment$ + NoConsecutiveBlankLines:SpaceListScreen.kt$ + NoConsecutiveBlankLines:SpaceSetupActivity.kt$SpaceSetupActivity$ + NoConsecutiveBlankLines:SpaceSetupScreen.kt$ + NoConsecutiveBlankLines:Theme.kt$ + NoConsecutiveBlankLines:UiImage.kt$ + NoConsecutiveBlankLines:UiImage.kt$UiImage$ + NoConsecutiveBlankLines:View.kt$ + NoConsecutiveBlankLines:ViewExtension.kt$ + NoConsecutiveBlankLines:WebDavConduit.kt$ + NoConsecutiveBlankLines:WebDavFragment.kt$WebDavFragment$ + NoConsecutiveBlankLines:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$ + NoEmptyClassBody:MainMediaViewModel.kt$MainMediaViewModel${ } + NoEmptyFirstLineInMethodBlock:AddFolderActivity.kt$AddFolderActivity$ + NoEmptyFirstLineInMethodBlock:AddFolderScreen.kt$ + NoEmptyFirstLineInMethodBlock:AppLogger.kt$AppLogger$ + NoEmptyFirstLineInMethodBlock:BaseButton.kt$ + NoEmptyFirstLineInMethodBlock:BaseDialog.kt$ + NoEmptyFirstLineInMethodBlock:BrowseFolderScreen.kt$ + NoEmptyFirstLineInMethodBlock:BrowseFoldersAdapter.kt$BrowseFoldersAdapter.FolderViewHolder$ + NoEmptyFirstLineInMethodBlock:CreateNewFolderFragment.kt$CreateNewFolderFragment$ + NoEmptyFirstLineInMethodBlock:DefaultScaffold.kt$ + NoEmptyFirstLineInMethodBlock:DialogConfigBuilder.kt$DialogBuilder$ + NoEmptyFirstLineInMethodBlock:ExpandableSpaceList.kt$ + NoEmptyFirstLineInMethodBlock:FileUtils.kt$FileUtils$ + NoEmptyFirstLineInMethodBlock:FolderAdapter.kt$FolderAdapter.ViewHolder$ + NoEmptyFirstLineInMethodBlock:FolderDrawerAdapter.kt$FolderDrawerAdapter.FolderViewHolder$ + NoEmptyFirstLineInMethodBlock:FolderOptionsPopup.kt$ + NoEmptyFirstLineInMethodBlock:FoldersActivity.kt$FoldersActivity$ + NoEmptyFirstLineInMethodBlock:HomeAppBar.kt$ + NoEmptyFirstLineInMethodBlock:HomeScreen.kt$ + NoEmptyFirstLineInMethodBlock:InternetArchiveActivity.kt$InternetArchiveActivity$ + NoEmptyFirstLineInMethodBlock:InternetArchiveDetailsScreen.kt$ + NoEmptyFirstLineInMethodBlock:InternetArchiveFragment.kt$InternetArchiveFragment$ + NoEmptyFirstLineInMethodBlock:InternetArchiveLoginScreen.kt$ + NoEmptyFirstLineInMethodBlock:MainActivity.kt$MainActivity$ + NoEmptyFirstLineInMethodBlock:MainBottomBar.kt$ + NoEmptyFirstLineInMethodBlock:MainDrawerContent.kt$ + NoEmptyFirstLineInMethodBlock:MainMediaViewHolder.kt$MainMediaViewHolder$ + NoEmptyFirstLineInMethodBlock:NumericKeypad.kt$ + NoEmptyFirstLineInMethodBlock:PasscodeDots.kt$ + NoEmptyFirstLineInMethodBlock:PasscodeEntryScreen.kt$ + NoEmptyFirstLineInMethodBlock:PasscodeEntryViewModel.kt$PasscodeEntryViewModel$ + NoEmptyFirstLineInMethodBlock:PasscodeSetupScreen.kt$ + NoEmptyFirstLineInMethodBlock:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$ + NoEmptyFirstLineInMethodBlock:Picker.kt$Picker$ + NoEmptyFirstLineInMethodBlock:Preview.kt$ + NoEmptyFirstLineInMethodBlock:PreviewActivity.kt$PreviewActivity$ + NoEmptyFirstLineInMethodBlock:PreviewViewHolder.kt$PreviewViewHolder$ + NoEmptyFirstLineInMethodBlock:PrimaryButton.kt$ + NoEmptyFirstLineInMethodBlock:ProofModeScreen.kt$ + NoEmptyFirstLineInMethodBlock:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$ + NoEmptyFirstLineInMethodBlock:SaveClient.kt$SaveClient.Companion$ + NoEmptyFirstLineInMethodBlock:ServerOptionItem.kt$ + NoEmptyFirstLineInMethodBlock:SettingsScreen.kt$ + NoEmptyFirstLineInMethodBlock:SnowbirdFragment.kt$SnowbirdFragment$ + NoEmptyFirstLineInMethodBlock:SnowbirdGroupListAdapter.kt$SnowbirdGroupsAdapter.ViewHolder$ + NoEmptyFirstLineInMethodBlock:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$ + NoEmptyFirstLineInMethodBlock:Space.kt$Space$ + NoEmptyFirstLineInMethodBlock:SpaceAdapter.kt$SpaceAdapter.ViewHolder$ + NoEmptyFirstLineInMethodBlock:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.SpaceViewHolder$ + NoEmptyFirstLineInMethodBlock:SpaceListFragment.kt$SpaceListFragment$ + NoEmptyFirstLineInMethodBlock:SpaceListScreen.kt$ + NoEmptyFirstLineInMethodBlock:SpaceSetupFragment.kt$SpaceSetupFragment$ + NoEmptyFirstLineInMethodBlock:UploadService.kt$UploadService$ + NoEmptyFirstLineInMethodBlock:WebDavFragment.kt$WebDavFragment$ + NoEmptyFirstLineInMethodBlock:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$ + NoMultipleSpaces:CleanInsightsManager.kt$CleanInsightsManager$ + NoMultipleSpaces:DialogConfigBuilder.kt$ + NoMultipleSpaces:GDriveConduit.kt$GDriveConduit$ + NoMultipleSpaces:Media.kt$Media$ + NoMultipleSpaces:NumericKeypad.kt$ + NoMultipleSpaces:PreviewAdapter.kt$PreviewAdapter$ + NoMultipleSpaces:RequestBodyUtil.kt$<no name provided>$ + NoMultipleSpaces:ScryptHashingStrategy.kt$ScryptHashingStrategy.Companion$ + NoMultipleSpaces:SnowbirdFragment.kt$SnowbirdFragment$ + NoMultipleSpaces:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$ + NoUnusedImports:AddFolderScreen.kt$net.opendasharchive.openarchive.features.folders.AddFolderScreen.kt + NoUnusedImports:AppLogger.kt$net.opendasharchive.openarchive.core.logger.AppLogger.kt + NoUnusedImports:BaseComposeActivity.kt$net.opendasharchive.openarchive.features.core.BaseComposeActivity.kt + NoUnusedImports:BaseDialog.kt$net.opendasharchive.openarchive.features.core.dialog.BaseDialog.kt + NoUnusedImports:BottomSheetExtensions.kt$net.opendasharchive.openarchive.extensions.BottomSheetExtensions.kt + NoUnusedImports:BrowseFolderScreen.kt$net.opendasharchive.openarchive.features.folders.BrowseFolderScreen.kt + NoUnusedImports:BrowseFoldersFragment.kt$net.opendasharchive.openarchive.features.folders.BrowseFoldersFragment.kt + NoUnusedImports:CoreModule.kt$net.opendasharchive.openarchive.core.di.CoreModule.kt + NoUnusedImports:CreateNewFolderFragment.kt$net.opendasharchive.openarchive.features.folders.CreateNewFolderFragment.kt + NoUnusedImports:CustomButton.kt$net.opendasharchive.openarchive.features.main.ui.CustomButton.kt + NoUnusedImports:DialogConfigBuilder.kt$net.opendasharchive.openarchive.features.core.dialog.DialogConfigBuilder.kt + NoUnusedImports:ExpandableSpaceList.kt$net.opendasharchive.openarchive.features.main.ui.components.ExpandableSpaceList.kt + NoUnusedImports:FeaturesModule.kt$net.opendasharchive.openarchive.core.di.FeaturesModule.kt + NoUnusedImports:FullscreenDimmingOverlay.kt$net.opendasharchive.openarchive.util.FullscreenDimmingOverlay.kt + NoUnusedImports:HomeActivity.kt$net.opendasharchive.openarchive.features.main.HomeActivity.kt + NoUnusedImports:InternetArchiveDetailsScreen.kt$net.opendasharchive.openarchive.features.internetarchive.presentation.details.InternetArchiveDetailsScreen.kt + NoUnusedImports:InternetArchiveLocalSource.kt$net.opendasharchive.openarchive.features.internetarchive.infrastructure.datasource.InternetArchiveLocalSource.kt + NoUnusedImports:InternetArchiveLoginScreen.kt$net.opendasharchive.openarchive.features.internetarchive.presentation.login.InternetArchiveLoginScreen.kt + NoUnusedImports:MainActivity.kt$net.opendasharchive.openarchive.features.main.MainActivity.kt + NoUnusedImports:MainMediaScreen.kt$net.opendasharchive.openarchive.features.main.ui.MainMediaScreen.kt + NoUnusedImports:MainMediaViewHolder.kt$net.opendasharchive.openarchive.features.main.adapters.MainMediaViewHolder.kt + NoUnusedImports:MediaCacheScreen.kt$net.opendasharchive.openarchive.features.main.ui.MediaCacheScreen.kt + NoUnusedImports:MediaViewHolder.kt$net.opendasharchive.openarchive.db.MediaViewHolder.kt + NoUnusedImports:NumericKeypad.kt$net.opendasharchive.openarchive.features.settings.passcode.components.NumericKeypad.kt + NoUnusedImports:PasscodeEntryScreen.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryScreen.kt + NoUnusedImports:PasscodeSetupActivity.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupActivity.kt + NoUnusedImports:PasscodeSetupScreen.kt$net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupScreen.kt + NoUnusedImports:ProofModeSettingsActivity.kt$net.opendasharchive.openarchive.features.settings.ProofModeSettingsActivity.kt + NoUnusedImports:RequestBodyUtil.kt$net.opendasharchive.openarchive.services.internetarchive.RequestBodyUtil.kt + NoUnusedImports:RestEndpointTask.kt$net.opendasharchive.openarchive.features.main.RestEndpointTask.kt + NoUnusedImports:ReviewActivity.kt$net.opendasharchive.openarchive.features.media.ReviewActivity.kt + NoUnusedImports:SaveApp.kt$net.opendasharchive.openarchive.SaveApp.kt + NoUnusedImports:ServerOptionItem.kt$net.opendasharchive.openarchive.features.spaces.ServerOptionItem.kt + NoUnusedImports:SettingsFragment.kt$net.opendasharchive.openarchive.features.settings.SettingsFragment.kt + NoUnusedImports:SettingsScreen.kt$net.opendasharchive.openarchive.features.settings.SettingsScreen.kt + NoUnusedImports:SpaceListFragment.kt$net.opendasharchive.openarchive.features.spaces.SpaceListFragment.kt + NoUnusedImports:SpaceListScreen.kt$net.opendasharchive.openarchive.features.spaces.SpaceListScreen.kt + NoUnusedImports:SpaceSetupActivity.kt$net.opendasharchive.openarchive.features.onboarding.SpaceSetupActivity.kt + NoUnusedImports:SpaceSetupFragment.kt$net.opendasharchive.openarchive.features.settings.SpaceSetupFragment.kt + NoUnusedImports:UnixSocketClient.kt$net.opendasharchive.openarchive.features.main.UnixSocketClient.kt + NoUnusedImports:UploadManagerActivity.kt$net.opendasharchive.openarchive.upload.UploadManagerActivity.kt + NoUnusedImports:UploadManagerFragment.kt$net.opendasharchive.openarchive.upload.UploadManagerFragment.kt + NoWildcardImports:BadgeDrawable.kt$import android.graphics.* + NoWildcardImports:CleanInsightsManager.kt$import org.cleaninsights.sdk.* + NoWildcardImports:Hbks.kt$import java.security.* + NoWildcardImports:Hbks.kt$import javax.crypto.* + NoWildcardImports:IaConduit.kt$import okhttp3.* + NoWildcardImports:MediaCacheScreen.kt$import androidx.compose.foundation.layout.* + NoWildcardImports:RequestBodyUtil.kt$import java.io.* + NoWildcardImports:UploadService.kt$import android.app.* + PackageName:PasscodeEntryActivity.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_entry + PackageName:PasscodeEntryScreen.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_entry + PackageName:PasscodeEntryViewModel.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_entry + PackageName:PasscodeSetupActivity.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_setup + PackageName:PasscodeSetupScreen.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_setup + PackageName:PasscodeSetupViewModel.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_setup + PackageNaming:PasscodeEntryActivity.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_entry + PackageNaming:PasscodeEntryScreen.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_entry + PackageNaming:PasscodeEntryViewModel.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_entry + PackageNaming:PasscodeSetupActivity.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_setup + PackageNaming:PasscodeSetupScreen.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_setup + PackageNaming:PasscodeSetupViewModel.kt$package net.opendasharchive.openarchive.features.settings.passcode.passcode_setup + ParameterListWrapping:AddMediaDialogFragment.kt$AddMediaDialogFragment$( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) + ParameterListWrapping:AlertHelper.kt$AlertHelper.Companion$( context: Context, message: Int?, title: Int? = R.string.error, icon: Int? = null, buttons: List<Button>? = listOf(Button()) ) + ParameterListWrapping:AlertHelper.kt$AlertHelper.Companion$( context: Context, message: String? = null, title: Int? = R.string.error, icon: Int? = null, buttons: List<Button>? = listOf(Button()) ) + ParameterListWrapping:BiometricAuthenticator.kt$BiometricAuthenticator$( private val activity: BaseActivity, private val config: AppConfig ) + ParameterListWrapping:DialogConfigBuilder.kt$( resourceProvider: ResourceProvider = this.requireResourceProvider(), block: DialogBuilder.() -> Unit) + ParameterListWrapping:DialogConfigBuilder.kt$(resourceProvider: ResourceProvider = this.requireResourceProvider(), block: DialogBuilder.() -> Unit) + ParameterListWrapping:FileUtils.kt$FileUtils$( context: Context, uri: Uri, selection: String?, selectionArgs: Array<String>?) + ParameterListWrapping:FileUtils.kt$FileUtils$(context: Context, uri: Uri, selection: String?, selectionArgs: Array<String>?) + ParameterListWrapping:GDriveFragment.kt$GDriveFragment$( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) + ParameterListWrapping:Hbks.kt$Hbks$( ciphertext: ByteArray?, key: SecretKey?, activity: FragmentActivity? = null, completed: (plaintext: String?, exception: Exception?) -> Unit) + ParameterListWrapping:Hbks.kt$Hbks$( plaintext: String?, key: SecretKey?, activity: FragmentActivity? = null, completed: (ciphertext: ByteArray?, exception: Exception?) -> Unit) + ParameterListWrapping:Hbks.kt$Hbks$(ciphertext: ByteArray?, key: SecretKey?, activity: FragmentActivity? = null, completed: (plaintext: String?, exception: Exception?) -> Unit) + ParameterListWrapping:Hbks.kt$Hbks$(plaintext: String?, key: SecretKey?, activity: FragmentActivity? = null, completed: (ciphertext: ByteArray?, exception: Exception?) -> Unit) + ParameterListWrapping:InternetArchiveLoginScreen.kt$( state: InternetArchiveLoginState, dispatch: Dispatch<Action> ) + ParameterListWrapping:Onboarding23SlideFragment.kt$Onboarding23SlideFragment$( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) + ParameterListWrapping:RequestBodyUtil.kt$( cancellable: () -> Boolean, onProgress: (Long) -> Unit = { }, onComplete: () -> Unit = {}) + ParameterListWrapping:RequestBodyUtil.kt$(cancellable: () -> Boolean, onProgress: (Long) -> Unit = { }, onComplete: () -> Unit = {}) + ParameterListWrapping:RequestBodyUtil.kt$RequestBodyUtil$( mediaType: MediaType?, inputStream: InputStream, contentLength: Long? = null, listener: RequestListener? ) + ParameterListWrapping:SnowbirdFileRepository.kt$ISnowbirdFileRepository$( groupKey: String, repoKey: String, forceRefresh: Boolean = false) + ParameterListWrapping:SnowbirdFileRepository.kt$ISnowbirdFileRepository$(groupKey: String, repoKey: String, forceRefresh: Boolean = false) + ParameterListWrapping:SnowbirdFileRepository.kt$SnowbirdFileRepository$( groupKey: String, repoKey: String, forceRefresh: Boolean) + ParameterListWrapping:SnowbirdFileRepository.kt$SnowbirdFileRepository$(groupKey: String, repoKey: String, forceRefresh: Boolean) + ParameterListWrapping:SpaceSetupSuccessFragment.kt$SpaceSetupSuccessFragment$( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) + ParameterListWrapping:WebDavFragment.kt$WebDavFragment$( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ) + ParameterNaming:BaseDialog.kt$onCheckBoxStateChanged + ParameterNaming:HomeScreen.kt$onFolderSelected + ParameterNaming:MainDrawerContent.kt$onSelected + ParameterNaming:SpaceListScreen.kt$onSpaceClicked + ParameterNaming:SpaceSetupScreen.kt$onDwebClicked + PrintStackTrace:SnowbirdFileRepository.kt$SnowbirdFileRepository$e + PrintStackTrace:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$e + PrintStackTrace:SnowbirdService.kt$SnowbirdService$e + PrintStackTrace:UnixSocketClient.kt$UnixSocketClient$e + PrintStackTrace:VideoRequestHandler.kt$VideoRequestHandler$throwable + RethrowCaughtException:UnixSocketClientUtilityExtensions.kt$throw e + ReturnCount:BrowseFoldersFragment.kt$BrowseFoldersFragment$private fun addFolder(folder: Folder?) + ReturnCount:Conduit.kt$Conduit$fun getProof(): Array<out File> + ReturnCount:CreateNewFolderFragment.kt$CreateNewFolderFragment$private fun store() + ReturnCount:EmptyableRecyclerView.kt$EmptyableRecyclerView$private fun findSuitableParent(): ViewGroup? + ReturnCount:FileUtils.kt$FileUtils$@SuppressLint("NewAPI", "LogNotTimber") fun getPath(context: Context, uri: Uri): String? + ReturnCount:FolderAdapter.kt$FolderAdapter.Companion$fun getColorOld(context: Context, highlight: Boolean): Int + ReturnCount:GDriveConduit.kt$GDriveConduit$override suspend fun upload(): Boolean + ReturnCount:Hbks.kt$Hbks$@RequiresApi(Build.VERSION_CODES.M) fun decrypt( ciphertext: ByteArray?, key: SecretKey?, activity: FragmentActivity? = null, completed: (plaintext: String?, exception: Exception?) -> Unit ) + ReturnCount:Hbks.kt$Hbks$@RequiresApi(Build.VERSION_CODES.M) fun encrypt( plaintext: String?, key: SecretKey?, activity: FragmentActivity? = null, completed: (ciphertext: ByteArray?, exception: Exception?) -> Unit ) + ReturnCount:Hbks.kt$Hbks$fun biometryType(context: Context): BiometryType + ReturnCount:Hbks.kt$Hbks$fun deviceAvailablity(context: Context): Availability + ReturnCount:MainActivity.kt$MainActivity$private fun importSharedMedia(imageIntent: Intent?) + ReturnCount:Onboarding23FragmentStateAdapter.kt$Onboarding23FragmentStateAdapter$override fun createFragment(position: Int): Fragment + ReturnCount:PasscodeRepository.kt$PasscodeRepository$fun isLockedOut(): Boolean + ReturnCount:Picker.kt$Picker$fun import(context: Context, project: Project?, uri: Uri): Media? + ReturnCount:UploadManagerActivity.kt$UploadManagerActivity$override fun onOptionsItemSelected(item: MenuItem): Boolean + ReturnCount:UploadService.kt$UploadService$private fun isNetworkAvailable(requireUnmetered: Boolean): Boolean + ReturnCount:Utility.kt$Utility$fun writeStreamToFile(input: InputStream?, file: File?): Boolean + ReturnCount:WebDavConduit.kt$WebDavConduit$@Throws(IOException::class) private suspend fun uploadChunked(base: HttpUrl, path: List<String>, fileName: String): Boolean + ReturnCount:WebDavConduit.kt$WebDavConduit$override suspend fun upload(): Boolean + SpacingAroundColon:ApiError.kt$ApiError$: + SpacingAroundColon:ConsentActivity.kt$ConsentActivity$: + SpacingAroundColon:ContentPickerFragment.kt$ContentPickerFragment$: + SpacingAroundColon:GeneralSettingsActivity.kt$GeneralSettingsActivity$: + SpacingAroundColon:GeneralSettingsActivity.kt$GeneralSettingsActivity.Fragment$: + SpacingAroundColon:Hbks.kt$Hbks.Availability.Enroll$: + SpacingAroundColon:HomeActivity.kt$HomeActivity$: + SpacingAroundColon:HomeScreen.kt$HomeScreenAction.AddMediaClicked$: + SpacingAroundColon:JoinGroupResponse.kt$JoinGroupResponse$: + SpacingAroundColon:PasscodeEntryViewModel.kt$PasscodeEntryScreenAction.OnSubmit$: + SpacingAroundColon:PasscodeManager.kt$PasscodeManager$: + SpacingAroundColon:PasscodeSetupViewModel.kt$PasscodeSetupUiAction.OnSubmit$: + SpacingAroundColon:PreviewAdapter.kt$PreviewAdapter$: + SpacingAroundColon:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Fragment$: + SpacingAroundColon:RequestNameDTO.kt$MembershipRequest$: + SpacingAroundColon:RequestNameDTO.kt$RequestName$: + SpacingAroundColon:SaveClient.kt$SaveClient.OrbotException$: + SpacingAroundColon:SettingsFragment.kt$SettingsFragment$: + SpacingAroundColon:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment$: + SpacingAroundColon:SnowbirdError.kt$SnowbirdError$: + SpacingAroundColon:SnowbirdFileItem.kt$SnowbirdFileItem$: + SpacingAroundColon:SnowbirdGroupOverviewFragment.kt$SnowbirdGroupOverviewFragment$: + SpacingAroundColon:SnowbirdJoinGroupFragment.kt$SnowbirdJoinGroupFragment$: + SpacingAroundColon:SnowbirdRepoListAdapter.kt$SnowbirdRepoListAdapter$: + SpacingAroundColon:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$: + SpacingAroundColon:SnowbirdShareFragment.kt$SnowbirdShareFragment$: + SpacingAroundColon:SwipeToDeleteCallback.kt$SwipeToDeleteCallback$: + SpacingAroundColon:UnixSocketAPI.kt$UnixSocketAPI$: + SpacingAroundColon:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$: + SpacingAroundKeyword:BrowseFoldersViewModel.kt$BrowseFoldersViewModel$else + SpacingAroundKeyword:Context.kt$catch + SpacingAroundKeyword:Drawable.kt$else + SpacingAroundKeyword:DrawableExtensions.kt$else + SpacingAroundKeyword:GDriveFragment.kt$GDriveFragment$if + SpacingAroundKeyword:Hbks.kt$Hbks$catch + SpacingAroundKeyword:Hbks.kt$Hbks$else + SpacingAroundKeyword:InternetArchiveDetailsViewModel.kt$InternetArchiveDetailsViewModel$when + SpacingAroundKeyword:PackageManager.kt$else + SpacingAroundKeyword:Picker.kt$Picker$else + SpacingAroundKeyword:ProofModeHelper.kt$ProofModeHelper$catch + SpacingAroundKeyword:ProofModeHelper.kt$ProofModeHelper$else + SpacingAroundKeyword:ReviewActivity.kt$ReviewActivity$else + SpacingAroundKeyword:ReviewActivity.kt$ReviewActivity.<no name provided>$else + SpacingAroundKeyword:SaveClient.kt$SaveClient.Companion$else + SpacingAroundKeyword:SaveClient.kt$SaveClient.Companion.<no name provided>$else + SpacingAroundKeyword:SpaceAdapter.kt$SpaceAdapter$else + SpacingAroundKeyword:SpaceDrawerAdapter.kt$SpaceDrawerAdapter.SpaceViewHolder$if + SpacingAroundKeyword:UploadManagerActivity.kt$UploadManagerActivity$else + SpacingAroundKeyword:UploadManagerActivity.kt$UploadManagerActivity.<no name provided>$else + SpacingAroundKeyword:Util.kt$Util$else + SpacingAroundKeyword:Utility.kt$Utility$catch + SpacingAroundKeyword:Utility.kt$Utility$finally + SpacingAroundKeyword:View.kt$ViewHelper$else + SpacingAroundKeyword:View.kt$else + SpacingAroundKeyword:ViewExtension.kt$ViewHelper$else + SpacingAroundKeyword:ViewExtension.kt$else + SpacingAroundKeyword:WebDavConduit.kt$WebDavConduit$catch + SpacingAroundKeyword:WebDavFragment.kt$WebDavFragment.<no name provided>$if + SpacingAroundKeyword:WebDavSetupLicenseFragment.kt$WebDavSetupLicenseFragment$if + SpacingAroundOperators:MediaCacheScreen.kt$= + SpacingAroundOperators:PasscodeSetupViewModel.kt$PasscodeSetupViewModel$-> + SpacingAroundParens:FileUploadResult.kt$FileUploadResult$( + SpacingAroundParens:Picker.kt$Picker$( + SpacingAroundParens:ReviewActivity.kt$ReviewActivity$( + SpacingAroundParens:SnowbirdConduit.kt$SnowbirdConduit$( + SpacingAroundParens:SnowbirdFileListAdapter.kt$SnowbirdFileListAdapter$( + SpacingAroundParens:WebDAVModel.kt$BackendCapabilities$( + SpacingAroundParens:WebDAVModel.kt$Data$( + SpacingAroundParens:WebDAVModel.kt$Meta$( + SpacingAroundParens:WebDAVModel.kt$Ocs$( + SpacingAroundParens:WebDAVModel.kt$Quota$( + SpacingAroundParens:WebDAVModel.kt$WebDAVModel$( + SpacingBetweenDeclarationsWithAnnotations:BasicAuthInterceptor.kt$BasicAuthInterceptor$@Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response + SpacingBetweenDeclarationsWithAnnotations:Hbks.kt$Hbks.Availability$Enroll : Availability + SpacingBetweenDeclarationsWithAnnotations:Media.kt$Media.Status$DeleteRemote : Status + SpacingBetweenDeclarationsWithAnnotations:Media.kt$Media.Status$Published : Status + SpacingBetweenDeclarationsWithAnnotations:VideoRequestHandler.kt$VideoRequestHandler.Companion$@Throws(Throwable::class) fun retrieveVideoFrameFromVideo(context: Context?, videoPath: Uri?): Bitmap? + SpacingBetweenDeclarationsWithComments:Prefs.kt$Prefs$// private const val USE_NEXTCLOUD_CHUNKING = "upload_nextcloud_chunks" + SpacingBetweenDeclarationsWithComments:UnixSocketClient.kt$UnixSocketClient$// val socketPath: String = File(context.filesDir, "rust_server.sock").absolutePath + SpreadOperator:GDriveConduit.kt$GDriveConduit.Companion$( GoogleSignIn.getLastSignedInAccount(context), *SCOPES ) + SpreadOperator:GDriveFragment.kt$GDriveFragment$( requireActivity(), REQUEST_CODE_GOOGLE_AUTH, GoogleSignIn.getLastSignedInAccount(requireActivity()), *GDriveConduit.SCOPES ) + StringTemplate:Hbks.kt$Hbks$${algorithm} + StringTemplate:Hbks.kt$Hbks$${blockMode} + StringTemplate:Hbks.kt$Hbks$${padding} + StringTemplate:MainMediaViewHolder.kt$MainMediaViewHolder$${progressValue} + StringTemplate:MediaViewHolder.kt$MediaViewHolder$${progressValue} + StringTemplate:PreviewViewHolder.kt$PreviewViewHolder$${progressValue} + StringTemplate:Utility.kt$Utility$${appId} + SwallowedException:Context.kt$e: ActivityNotFoundException + SwallowedException:PackageManager.kt$e: PackageManager.NameNotFoundException + SwallowedException:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Companion$ioe: IOException + SwallowedException:RestEndpointTask.kt$RestEndpointTask$e: Exception + SwallowedException:SnowbirdFileItem.kt$SnowbirdFileItem.Companion$e: SQLiteException + SwallowedException:SnowbirdFileViewModel.kt$SnowbirdFileViewModel$e: TimeoutCancellationException + SwallowedException:SnowbirdGroup.kt$SnowbirdGroup.Companion$e: SQLiteException + SwallowedException:SnowbirdGroupViewModel.kt$SnowbirdGroupViewModel$e: TimeoutCancellationException + SwallowedException:SnowbirdRepoViewModel.kt$SnowbirdRepoViewModel$e: TimeoutCancellationException + SwallowedException:UnixSocketClient.kt$UnixSocketClient$e: Exception + SwallowedException:UnixSocketClientFileExtensions.kt$e: Exception + SwallowedException:VideoRequestHandler.kt$VideoRequestHandler.Companion$e: Exception + ThrowingExceptionsWithoutMessageOrCause:Hbks.kt$Hbks$NullPointerException() + ThrowingExceptionsWithoutMessageOrCause:Onboarding23FragmentStateAdapter.kt$Onboarding23FragmentStateAdapter$IndexOutOfBoundsException() + ThrowsCount:UnixSocketClient.kt$UnixSocketClient$fun <REQUEST : SerializableMarker, RESPONSE : Any> sendRequestInternal( endpoint: String, method: HttpMethod, body: REQUEST?, serialize: (REQUEST) -> String, deserialize: (String) -> RESPONSE ): RESPONSE + TooGenericExceptionCaught:BrowseFoldersViewModel.kt$BrowseFoldersViewModel$e: Throwable + TooGenericExceptionCaught:GDriveConduit.kt$GDriveConduit$e: Exception + TooGenericExceptionCaught:Hbks.kt$Hbks$e: Exception + TooGenericExceptionCaught:IaConduit.kt$IaConduit$e: Throwable + TooGenericExceptionCaught:MainMediaViewHolder.kt$MainMediaViewHolder$e: Throwable + TooGenericExceptionCaught:MediaViewHolder.kt$MediaViewHolder$e: Throwable + TooGenericExceptionCaught:Picker.kt$Picker$e: Exception + TooGenericExceptionCaught:PreviewViewHolder.kt$PreviewViewHolder$e: Throwable + TooGenericExceptionCaught:ProofModeHelper.kt$ProofModeHelper$e: Exception + TooGenericExceptionCaught:RestEndpointTask.kt$RestEndpointTask$e: Exception + TooGenericExceptionCaught:SnowbirdFileRepository.kt$SnowbirdFileRepository$e: Exception + TooGenericExceptionCaught:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$e: Exception + TooGenericExceptionCaught:SnowbirdRepoRepository.kt$SnowbirdRepoRepository$e: Exception + TooGenericExceptionCaught:SnowbirdService.kt$SnowbirdService$e: Exception + TooGenericExceptionCaught:StringExtensions.kt$e: Exception + TooGenericExceptionCaught:SuspendableExtensions.kt$e: Throwable + TooGenericExceptionCaught:UnixSocketClient.kt$UnixSocketClient$e: Exception + TooGenericExceptionCaught:UnixSocketClientFileExtensions.kt$e: Exception + TooGenericExceptionCaught:VideoRequestHandler.kt$VideoRequestHandler$throwable: Throwable + TooGenericExceptionCaught:VideoRequestHandler.kt$VideoRequestHandler.Companion$e: Exception + TooGenericExceptionCaught:WebDavConduit.kt$WebDavConduit$e: Throwable + TooGenericExceptionThrown:Conduit.kt$Conduit$throw Exception("Cancelled") + TooGenericExceptionThrown:GDriveConduit.kt$GDriveConduit$throw Exception("Cancelled") + TooGenericExceptionThrown:GDriveConduit.kt$GDriveConduit.Companion$throw Exception("could not create folders $destinationPath") + TooGenericExceptionThrown:IaConduit.kt$IaConduit$throw RuntimeException("${result.code}: ${result.message}") + TooGenericExceptionThrown:VideoRequestHandler.kt$VideoRequestHandler.Companion$throw Throwable("Exception in retrieveVideoFrameFromVideo(String videoPath)" + e.message) + TooGenericExceptionThrown:WebDavConduit.kt$WebDavConduit$throw Exception("Cancelled") + TooManyFunctions:AppLogger.kt$AppLogger + TooManyFunctions:Conduit.kt$Conduit + TooManyFunctions:FoldersActivity.kt$FoldersActivity : BaseActivityFolderAdapterListener + TooManyFunctions:HomeActivity.kt$HomeActivity : FragmentActivity + TooManyFunctions:MainActivity.kt$MainActivity : BaseActivitySpaceDrawerAdapterListenerFolderDrawerAdapterListener + TooManyFunctions:MainMediaAdapter.kt$MainMediaAdapter : Adapter + TooManyFunctions:MainMediaFragment.kt$MainMediaFragment : Fragment + TooManyFunctions:MainMediaScreen.kt$net.opendasharchive.openarchive.features.main.ui.MainMediaScreen.kt + TooManyFunctions:MediaAdapter.kt$MediaAdapter : Adapter + TooManyFunctions:PasscodeRepository.kt$PasscodeRepository + TooManyFunctions:PreviewActivity.kt$PreviewActivity : BaseActivityOnClickListenerListener + TooManyFunctions:SnowbirdCreateGroupFragment.kt$SnowbirdCreateGroupFragment : BaseFragment + TooManyFunctions:SnowbirdFileListFragment.kt$SnowbirdFileListFragment : BaseFragment + TooManyFunctions:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment : BaseFragment + TooManyFunctions:SnowbirdJoinGroupFragment.kt$SnowbirdJoinGroupFragment : BaseFragment + TooManyFunctions:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment : BaseFragment + TooManyFunctions:SnowbirdService.kt$SnowbirdService : Service + TooManyFunctions:WebDavFragment.kt$WebDavFragment : BaseFragment + UnusedParameter:AppLogger.kt$AppLogger$context: Context + UnusedParameter:AppLogger.kt$AppLogger$initDebugger: Boolean + UnusedParameter:BrowseFolderScreen.kt$onClick: () -> Unit + UnusedParameter:BrowseFoldersViewModel.kt$BrowseFoldersViewModel$space: Space + UnusedParameter:HomeActivity.kt$HomeActivity$folderId: Long + UnusedParameter:HomeScreen.kt$onAddMedia: (AddMediaType) -> Unit + UnusedParameter:HomeScreen.kt$onFolderSelected: (Long) -> Unit + UnusedParameter:HomeScreen.kt$onNewFolder: () -> Unit + UnusedParameter:InternetArchiveHeader.kt$titleSize: TextUnit = 18.sp + UnusedParameter:InternetArchiveLoginScreen.kt$enabled: Boolean = true + UnusedParameter:MainActivity.kt$MainActivity$count: Int + UnusedParameter:MainDrawerContent.kt$isSelected: Boolean = false + UnusedParameter:MainDrawerContent.kt$onSelected: () -> Unit + UnusedParameter:MainDrawerContent.kt$project: Project + UnusedParameter:MainMediaAdapterTest.kt$progress: Int? = 0 + UnusedParameter:PasscodeEntryScreen.kt$onExit: () -> Unit + UnusedParameter:SnowbirdBridge.kt$SnowbirdBridge.Companion$message: String + UnusedParameter:Space.kt$Space$style: IconStyle = IconStyle.SOLID + UnusedParameter:Utility.kt$Utility$appId: String + UnusedPrivateMember:AddFolderScreen.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun AddFolderScreenPreview() + UnusedPrivateMember:BaseButton.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CustomButtonPreview() + UnusedPrivateMember:BaseButton.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CustomDestructiveButtonPreview() + UnusedPrivateMember:BaseButton.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CustomNeutralButtonPreview() + UnusedPrivateMember:BaseDialog.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun BaseDialogPreview() + UnusedPrivateMember:BaseDialog.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun ErrorDialogPreview() + UnusedPrivateMember:BaseDialog.kt$@Preview @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun WarningDialogPreview() + UnusedPrivateMember:BrowseFolderScreen.kt$@Preview @Composable private fun BrowseFolderScreenPreview() + UnusedPrivateMember:ExpandableSpaceList.kt$@Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun ExpandableSpaceListPreview() + UnusedPrivateMember:FolderOptionsPopup.kt$@Preview @Composable private fun FolderOptionsPopupPreview() + UnusedPrivateMember:HomeScreen.kt$@Preview @Composable private fun MainContentPreview() + UnusedPrivateMember:IaConduit.kt$IaConduit$@Throws(IOException::class) private fun OkHttpClient.uploadProofFiles(uploadFile: File) + UnusedPrivateMember:InternetArchiveDetailsScreen.kt$@Composable @Preview(showBackground = true) @Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveScreenPreview() + UnusedPrivateMember:InternetArchiveHeader.kt$@Composable @Preview(showBackground = true) @Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveHeaderPreview() + UnusedPrivateMember:InternetArchiveLoginScreen.kt$@Composable @Preview @Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveLoginPreview() + UnusedPrivateMember:MainDrawerContent.kt$@Preview @Composable private fun MainDrawerContentPreview() + UnusedPrivateMember:MainMediaAdapter.kt$MainMediaAdapter$private fun selectView(view: View) + UnusedPrivateMember:MainMediaScreen.kt$private fun deleteMediaItem(sections: MutableList<CollectionSection>, media: Media) + UnusedPrivateMember:MainMediaScreen.kt$private fun deleteSelected(sections: MutableList<CollectionSection>, context: Context) + UnusedPrivateMember:NumericKeypad.kt$@Preview @Composable private fun NumericKeypadPreview() + UnusedPrivateMember:PasscodeDots.kt$@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview @Composable private fun PasswordDotsPreview() + UnusedPrivateMember:PasscodeEntryScreen.kt$@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview @Composable private fun PasscodeEntryScreenPreview() + UnusedPrivateMember:PasscodeSetupScreen.kt$@Preview(uiMode = UI_MODE_NIGHT_YES) @Preview @Composable private fun PasscodeSetupScreenPreview() + UnusedPrivateMember:PrimaryButton.kt$@Preview @Composable private fun PrimaryButtonPreview() + UnusedPrivateMember:ProofModeScreen.kt$@Preview @Composable private fun ProofModeScreenPreview() + UnusedPrivateMember:ProofModeSettingsActivity.kt$ProofModeSettingsActivity.Companion$private fun shareKey(activity: Activity) + UnusedPrivateMember:ServerOptionItem.kt$@Preview @Composable private fun ServerOptionItemPreview() + UnusedPrivateMember:SettingsScreen.kt$@Preview @Composable private fun SettingsScreenPreview() + UnusedPrivateMember:SpaceListScreen.kt$@Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun SpaceListScreenPreview() + UnusedPrivateMember:SpaceSetupScreen.kt$@Preview @Composable private fun SpaceSetupScreenPreview() + UnusedPrivateProperty:BrowseFolderScreen.kt$val navController = LocalView.current.findNavController() + UnusedPrivateProperty:Colors.kt$private val c23_grey_50 = Color(0xff777979) + UnusedPrivateProperty:Colors.kt$private val c23_nav_drawer_night = Color(0xff101010) + UnusedPrivateProperty:Colors.kt$private val c23_teal_10 = Color(0xff001b19) // v=10.6 --> + UnusedPrivateProperty:Colors.kt$private val c23_teal_100 = Color(0xff00ffeb) // h=175,3 s=100 v=100 --> + UnusedPrivateProperty:Colors.kt$private val c23_teal_30 = Color(0xff004e48) // v=30.6 --> + UnusedPrivateProperty:Colors.kt$private val c23_teal_50 = Color(0xff008177) // v=50.6 --> + UnusedPrivateProperty:Colors.kt$private val c23_teal_60 = Color(0xff009b8f) // v=60.6 --> + UnusedPrivateProperty:Colors.kt$private val c23_teal_80 = Color(0xff00cebe) // v=80.6 --> + UnusedPrivateProperty:Colors.kt$private val c23_teal_90 = Color(0xff00e7d5) // v=90.6 --> + UnusedPrivateProperty:Colors.kt$private val darkPrimary = Color(0xff000A0A) + UnusedPrivateProperty:GDriveConduit.kt$GDriveConduit$val response = request.execute() + UnusedPrivateProperty:HomeActivity.kt$HomeActivity$private val folderResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val selectedFolderId: Long? = result.data?.getLongExtra("SELECTED_FOLDER_ID", -1) if (selectedFolderId != null && selectedFolderId > -1) { navigateToFolder(selectedFolderId) } } } + UnusedPrivateProperty:HomeActivity.kt$HomeActivity$private val mNewFolderResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { // TODO: Refresh projects in MainViewModel } } + UnusedPrivateProperty:IaConduit.kt$IaConduit.Companion$private const val ARCHIVE_DETAILS_ENDPOINT = "https://archive.org/details/" + UnusedPrivateProperty:MainActivity.kt$MainActivity$private var currentSelectionCount = 0 + UnusedPrivateProperty:MainMediaAdapter.kt$MainMediaAdapter.Companion$private const val PAYLOAD_PROGRESS = "progress" + UnusedPrivateProperty:MainMediaAdapter.kt$MainMediaAdapter.Companion$private const val PAYLOAD_SELECTION = "selection" + UnusedPrivateProperty:MainMediaScreen.kt$var isSelecting by remember { mutableStateOf(false) } + UnusedPrivateProperty:MainMediaScreen.kt$var showDeleteDialog by remember { mutableStateOf(false) } + UnusedPrivateProperty:NumericKeypad.kt$val borderColor by animateColorAsState( targetValue = when { isPressed -> when (label) { "delete" -> colorResource(R.color.red_bg).copy(alpha = 0.7f) "submit" -> MaterialTheme.colorScheme.tertiary.copy(alpha = 0.7f) else -> MaterialTheme.colorScheme.primary.copy(alpha = 0.5f) } else -> when (label) { "delete" -> colorResource(R.color.red_bg).copy(alpha = 0.5f) "submit" -> MaterialTheme.colorScheme.tertiary.copy(alpha = 0.5f) else -> Color.Transparent } }, animationSpec = spring(), label = "" ) + UnusedPrivateProperty:ProofModeScreen.kt$val permissionLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.RequestPermission() ) { isGranted -> if (!isGranted) { Toast.makeText(context, "Please allow all permissions", Toast.LENGTH_LONG).show() val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val uri = Uri.fromParts("package", context.packageName, null) intent.data = uri context.startActivity(intent) } } + UnusedPrivateProperty:ProofModeScreen.kt$val uriHandler = LocalUriHandler.current + UnusedPrivateProperty:SectionViewHolder.kt$SectionViewHolder.Companion$private val mDf = DateFormat.getDateTimeInstance() + UnusedPrivateProperty:SnowbirdFragment.kt$SnowbirdFragment$private val CANNED_URI = "save+dweb::?dht=82fd345d484393a96b6e0c5d5e17a85a61c9184cc5a3311ab069d6efa0bf1410&enc=6fa27396fe298f92c91013ac54d8f316c2d45dc3bed0edec73078040aa10feed&pk=f4b404d294817cf11ea7f8ef7231626e03b74f6fafe3271b53918608afa82d12&sk=5482a8f490081be684fbadb8bde7f0a99bab8acdcf1ec094826f0f18e327e399" + UnusedPrivateProperty:SnowbirdFragment.kt$SnowbirdFragment$private var canNavigate = false + UnusedPrivateProperty:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$val shouldFetchFromNetwork = forceRefresh || currentTime - lastFetchTime > cacheValidityPeriod + UnusedPrivateProperty:UnixSocketClient.kt$UnixSocketClient$context: Context + VariableNaming:SnowbirdFragment.kt$SnowbirdFragment$private val CANNED_URI = "save+dweb::?dht=82fd345d484393a96b6e0c5d5e17a85a61c9184cc5a3311ab069d6efa0bf1410&enc=6fa27396fe298f92c91013ac54d8f316c2d45dc3bed0edec73078040aa10feed&pk=f4b404d294817cf11ea7f8ef7231626e03b74f6fafe3271b53918608afa82d12&sk=5482a8f490081be684fbadb8bde7f0a99bab8acdcf1ec094826f0f18e327e399" + ViewModelForwarding:HomeScreen.kt$HomeScreen( viewModel = viewModel, onExit = onExit, onNewFolder = onNewFolder, onFolderSelected = onFolderSelected, onAddMedia = onAddMedia, onNavigateToCache = { navController.navigate(MediaCacheRoute) } ) + WildcardImport:BadgeDrawable.kt$import android.graphics.* + WildcardImport:CleanInsightsManager.kt$import org.cleaninsights.sdk.* + WildcardImport:Hbks.kt$import java.security.* + WildcardImport:Hbks.kt$import javax.crypto.* + WildcardImport:IaConduit.kt$import okhttp3.* + WildcardImport:MediaCacheScreen.kt$import androidx.compose.foundation.layout.* + WildcardImport:RequestBodyUtil.kt$import java.io.* + WildcardImport:UploadService.kt$import android.app.* + Wrapping:BaseDialog.kt$( + Wrapping:BrowseFoldersFragment.kt$BrowseFoldersFragment$( + Wrapping:BrowseFoldersFragment.kt$BrowseFoldersFragment$(RESULT_OK, Intent().apply { putExtra(AddFolderActivity.EXTRA_FOLDER_ID, project.id) }) + Wrapping:CleanInsightsManager.kt$CleanInsightsManager$( + Wrapping:CleanInsightsManager.kt$CleanInsightsManager$(CI_CAMPAIGN, object : ConsentRequestUi { override fun show( campaignId: String, campaign: Campaign, complete: ConsentRequestUiComplete ) { mCompleted = completed context.startActivity(Intent(context, ConsentActivity::class.java)) } override fun show(feature: Feature, complete: ConsentRequestUiComplete) { complete(true) } }, completed) + Wrapping:ConsentActivity.kt$ConsentActivity$( + Wrapping:Drawable.kt$( + Wrapping:EditFolderActivity.kt$EditFolderActivity$( + Wrapping:EditFolderActivity.kt$EditFolderActivity$(this, R.string.action_remove_project, R.string.remove_from_app, buttons = listOf( AlertHelper.positiveButton(R.string.remove) { _, _ -> mProject.delete() finish() }, AlertHelper.negativeButton())) + Wrapping:FileUtils.kt$FileUtils$( + Wrapping:GDriveActivity.kt$GDriveActivity$( + Wrapping:GDriveActivity.kt$GDriveActivity$(this, R.string.are_you_sure_you_want_to_remove_this_server_from_the_app, R.string.remove_from_app, buttons = listOf( AlertHelper.positiveButton(R.string.remove) { _, _ -> // delete sign-in from database space.delete() // google logout val googleSignInClient = GoogleSignIn.getClient(applicationContext, GoogleSignInOptions.DEFAULT_SIGN_IN) googleSignInClient.revokeAccess().addOnCompleteListener { googleSignInClient.signOut() } // leave activity Space.navigate(this) }, AlertHelper.negativeButton() )) + Wrapping:GDriveFragment.kt$GDriveFragment$( getString( R.string.gdrive_disclaimer_1, getString(R.string.app_name), getString(R.string.google_name), getString(R.string.gdrive_sudp_name), ), HtmlCompat.FROM_HTML_MODE_COMPACT ) + Wrapping:Hbks.kt$Hbks$( + Wrapping:Hbks.kt$Hbks$(activity, object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationError( errorCode: Int, errString: CharSequence ) { super.onAuthenticationError(errorCode, errString) completed(false) } override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) completed(true) } override fun onAuthenticationFailed() { super.onAuthenticationFailed() completed(false) } }) + Wrapping:InternetArchiveActivity.kt$InternetArchiveActivity$( + Wrapping:MainMediaScreen.kt${ /* no op */ } + Wrapping:Media.kt$Media.Companion$( + Wrapping:MediaAdapter.kt$MediaAdapter$( it, it.getString(R.string.upload_unsuccessful_description), R.string.upload_unsuccessful, R.drawable.ic_error, listOf( AlertHelper.positiveButton(R.string.retry) { _, _ -> media[pos].apply { sStatus = Media.Status.Queued statusMessage = "" save() BroadcastManager.postChange(it, collectionId, id) } UploadService.startUploadService(it) }, AlertHelper.negativeButton(R.string.remove) { _, _ -> deleteItem(pos) }, AlertHelper.neutralButton() ) ) + Wrapping:MediaCacheScreen.kt$( + Wrapping:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity$( + Wrapping:Onboarding23InstructionsActivity.kt$Onboarding23InstructionsActivity$(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { if (isFirstPage()) { finish() } else { mBinding.viewPager.currentItem-- } } }) + Wrapping:PasscodeSetupActivity.kt$PasscodeSetupActivity$( + Wrapping:PasscodeSetupActivity.kt$PasscodeSetupActivity$(RESULT_OK, Intent().apply { putExtra(EXTRA_PASSCODE_ENABLED, true) }) + Wrapping:Picker.kt$Picker$( + Wrapping:Picker.kt$Picker$(activity, arrayOf( Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO )) + Wrapping:ProofModeHelper.kt$ProofModeHelper$( + Wrapping:RequestBodyUtil.kt$ + Wrapping:RequestBodyUtil.kt$RequestBodyUtil$( + Wrapping:SnowbirdFileItem.kt$SnowbirdFileItem.Companion$( + Wrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$( + Wrapping:SnowbirdFileListFragment.kt$SnowbirdFileListFragment$(object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_snowbird, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when (menuItem.itemId) { R.id.action_add -> { Timber.d("Adde!") openFilePicker() true } else -> false } } }, viewLifecycleOwner, Lifecycle.State.RESUMED) + Wrapping:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$( + Wrapping:SnowbirdGroupListFragment.kt$SnowbirdGroupListFragment$(object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_snowbird, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when (menuItem.itemId) { R.id.action_add -> { if (isJetpackNavigation) { val action = SnowbirdGroupListFragmentDirections.actionFragmentSnowbirdGroupListToFragmentSnowbirdCreateGroup() findNavController().navigate(action) } else { setFragmentResult( RESULT_REQUEST_KEY, bundleOf(RESULT_BUNDLE_NAVIGATION_KEY to RESULT_VAL_RAVEN_CREATE_GROUP_SCREEN) ) } true } else -> false } } }, viewLifecycleOwner, Lifecycle.State.RESUMED) + Wrapping:SnowbirdGroupRepository.kt$SnowbirdGroupRepository$( + Wrapping:SnowbirdRepo.kt$SnowbirdRepo.Companion$( + Wrapping:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$( + Wrapping:SnowbirdRepoListFragment.kt$SnowbirdRepoListFragment$(object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_snowbird, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return when (menuItem.itemId) { R.id.action_add -> { Utility.showMaterialWarning( context = requireContext(), message = "Feature not implemented yet.", positiveButtonText = "OK" ) true } else -> false } } }, viewLifecycleOwner, Lifecycle.State.RESUMED) + Wrapping:SpaceAdapter.kt$SpaceAdapter$( + Wrapping:TextView.kt$( + Wrapping:TextView.kt$(SpannableString(text).apply { setSpan(URLSpan(""), 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) }, TextView.BufferType.SPANNABLE) + Wrapping:TwoLetterDrawable.kt$TwoLetterDrawable$( + Wrapping:UnixSocketAPI.kt$UnixSocketAPI$( + Wrapping:Utility.kt$Utility$( + Wrapping:WebDavFragment.kt$WebDavFragment$( + + diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 12125fc7..a6e7fc29 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -2,7 +2,7 @@ # By default, the flags in this file are appended to flags specified # in /home/josh/android-sdks/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. +# directive in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4d250a93..773f72f4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,6 +19,7 @@ + @@ -52,31 +53,19 @@ android:networkSecurityConfig="@xml/network_security_config" android:requestLegacyExternalStorage="true" android:supportsRtl="true" - android:theme="@style/AppTheme.NoActionBar" + android:theme="@style/Theme.SaveApp.Starting" tools:ignore="UnusedAttribute,LockedOrientationActivity" tools:replace="android:icon,android:allowBackup"> - - - - - + android:screenOrientation="portrait" + android:windowSoftInputMode="adjustPan"> @@ -103,49 +92,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:taskAffinity="" + android:theme="@style/SaveAppTheme.NoActionBar" /> - + + android:label="@string/folders" + android:theme="@style/SaveAppTheme.NoActionBar" /> + android:taskAffinity="" + android:theme="@style/SaveAppTheme.NoActionBar" /> + android:taskAffinity="" + android:theme="@style/SaveAppTheme.NoActionBar" /> + android:taskAffinity="" + android:theme="@style/SaveAppTheme.NoActionBar" /> + + + + + + + android:taskAffinity="" + android:theme="@style/SaveAppTheme.NoActionBar.Onboarding" /> - - + android:theme="@style/SaveAppTheme.NoActionBar" /> + + + + + + + android:theme="@style/SaveAppTheme.NoActionBar" /> + android:theme="@style/SaveAppTheme.NoActionBar" /> + android:taskAffinity="" + android:theme="@style/SaveAppTheme.NoActionBar" /> + android:value="37" /> + + diff --git a/app/src/main/assets/filecoin.js b/app/src/main/assets/filecoin.js new file mode 100644 index 00000000..1bfeacf0 --- /dev/null +++ b/app/src/main/assets/filecoin.js @@ -0,0 +1,44 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("FilecoinJs",[],t):"object"==typeof exports?exports.FilecoinJs=t():e.FilecoinJs=t()}(window,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=188)}([function(e,t,r){"use strict";(function(e){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +var n=r(195),i=r(108),o=r(109);function a(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function p(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var r=e.length;if(0===r)return 0;for(var n=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return D(e).length;default:if(n)return F(e).length;t=(""+t).toLowerCase(),n=!0}}function m(e,t,r){var n=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,r);case"utf8":case"utf-8":return A(this,t,r);case"ascii":return x(this,t,r);case"latin1":case"binary":return I(this,t,r);case"base64":return E(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return O(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}function g(e,t,r){var n=e[t];e[t]=e[r],e[r]=n}function b(e,t,r,n,i){if(0===e.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=i?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(i)return-1;r=e.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof t&&(t=u.from(t,n)),u.isBuffer(t))return 0===t.length?-1:v(e,t,r,n,i);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):v(e,[t],r,n,i);throw new TypeError("val must be string, number or Buffer")}function v(e,t,r,n,i){var o,a=1,s=e.length,u=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,r/=2}function c(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(i){var h=-1;for(o=r;os&&(r=s-u),o=r;o>=0;o--){for(var f=!0,l=0;li&&(n=i):n=i;var o=t.length;if(o%2!=0)throw new TypeError("Invalid hex string");n>o/2&&(n=o/2);for(var a=0;a>8,i=r%256,o.push(i),o.push(n);return o}(t,e.length-r),e,r,n)}function E(e,t,r){return 0===t&&r===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,r))}function A(e,t,r){r=Math.min(e.length,r);for(var n=[],i=t;i239?4:c>223?3:c>191?2:1;if(i+f<=r)switch(f){case 1:c<128&&(h=c);break;case 2:128==(192&(o=e[i+1]))&&(u=(31&c)<<6|63&o)>127&&(h=u);break;case 3:o=e[i+1],a=e[i+2],128==(192&o)&&128==(192&a)&&(u=(15&c)<<12|(63&o)<<6|63&a)>2047&&(u<55296||u>57343)&&(h=u);break;case 4:o=e[i+1],a=e[i+2],s=e[i+3],128==(192&o)&&128==(192&a)&&128==(192&s)&&(u=(15&c)<<18|(63&o)<<12|(63&a)<<6|63&s)>65535&&u<1114112&&(h=u)}null===h?(h=65533,f=1):h>65535&&(h-=65536,n.push(h>>>10&1023|55296),h=56320|1023&h),n.push(h),i+=f}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var r="",n=0;for(;n0&&(e=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(e+=" ... ")),""},u.prototype.compare=function(e,t,r,n,i){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===n&&(n=0),void 0===i&&(i=this.length),t<0||r>e.length||n<0||i>this.length)throw new RangeError("out of range index");if(n>=i&&t>=r)return 0;if(n>=i)return-1;if(t>=r)return 1;if(this===e)return 0;for(var o=(i>>>=0)-(n>>>=0),a=(r>>>=0)-(t>>>=0),s=Math.min(o,a),c=this.slice(n,i),h=e.slice(t,r),f=0;fi)&&(r=i),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var o=!1;;)switch(n){case"hex":return y(this,e,t,r);case"utf8":case"utf-8":return w(this,e,t,r);case"ascii":return _(this,e,t,r);case"latin1":case"binary":return S(this,e,t,r);case"base64":return M(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return k(this,e,t,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function x(e,t,r){var n="";r=Math.min(e.length,r);for(var i=t;in)&&(r=n);for(var i="",o=t;or)throw new RangeError("Trying to access beyond buffer length")}function R(e,t,r,n,i,o){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function B(e,t,r,n){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-r,2);i>>8*(n?i:1-i)}function N(e,t,r,n){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-r,4);i>>8*(n?i:3-i)&255}function C(e,t,r,n,i,o){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function j(e,t,r,n,o){return o||C(e,0,r,4),i.write(e,t,r,n,23,4),r+4}function z(e,t,r,n,o){return o||C(e,0,r,8),i.write(e,t,r,n,52,8),r+8}u.prototype.slice=function(e,t){var r,n=this.length;if((e=~~e)<0?(e+=n)<0&&(e=0):e>n&&(e=n),(t=void 0===t?n:~~t)<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)n+=this[e+--t]*i;return n},u.prototype.readUInt8=function(e,t){return t||T(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||T(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||T(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||T(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||T(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,r){e|=0,t|=0,r||T(e,t,this.length);for(var n=this[e],i=1,o=0;++o=(i*=128)&&(n-=Math.pow(2,8*t)),n},u.prototype.readIntBE=function(e,t,r){e|=0,t|=0,r||T(e,t,this.length);for(var n=t,i=1,o=this[e+--n];n>0&&(i*=256);)o+=this[e+--n]*i;return o>=(i*=128)&&(o-=Math.pow(2,8*t)),o},u.prototype.readInt8=function(e,t){return t||T(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||T(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt16BE=function(e,t){t||T(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt32LE=function(e,t){return t||T(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||T(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||T(e,4,this.length),i.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||T(e,4,this.length),i.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||T(e,8,this.length),i.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||T(e,8,this.length),i.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,r,n){(e=+e,t|=0,r|=0,n)||R(this,e,t,r,Math.pow(2,8*r)-1,0);var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+r},u.prototype.writeUInt8=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):B(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):B(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,r,n){if(e=+e,t|=0,!n){var i=Math.pow(2,8*r-1);R(this,e,t,r,i-1,-i)}var o=0,a=1,s=0;for(this[t]=255&e;++o>0)-s&255;return t+r},u.prototype.writeIntBE=function(e,t,r,n){if(e=+e,t|=0,!n){var i=Math.pow(2,8*r-1);R(this,e,t,r,i-1,-i)}var o=r-1,a=1,s=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===s&&0!==this[t+o+1]&&(s=1),this[t+o]=(e/a>>0)-s&255;return t+r},u.prototype.writeInt8=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):B(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):B(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,r){return e=+e,t|=0,r||R(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,r){return j(this,e,t,!0,r)},u.prototype.writeFloatBE=function(e,t,r){return j(this,e,t,!1,r)},u.prototype.writeDoubleLE=function(e,t,r){return z(this,e,t,!0,r)},u.prototype.writeDoubleBE=function(e,t,r){return z(this,e,t,!1,r)},u.prototype.copy=function(e,t,r,n){if(r||(r=0),n||0===n||(n=this.length),t>=e.length&&(t=e.length),t||(t=0),n>0&&n=this.length)throw new RangeError("sourceStart out of bounds");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t=0;--i)e[i+t]=this[i+r];else if(o<1e3||!u.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(o=t;o55295&&r<57344){if(!i){if(r>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===n){(t-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(r<56320){(t-=3)>-1&&o.push(239,191,189),i=r;continue}r=65536+(i-55296<<10|r-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,r<128){if((t-=1)<0)break;o.push(r)}else if(r<2048){if((t-=2)<0)break;o.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return o}function D(e){return n.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(U,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function q(e,t,r,n){for(var i=0;i=t.length||i>=e.length);++i)t[i+r]=e[i];return i}}).call(this,r(8))},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}}},function(e,t,r){ +/*! safe-buffer. MIT License. Feross Aboukhadijeh */ +var n=r(0),i=n.Buffer;function o(e,t){for(var r in e)t[r]=e[r]}function a(e,t,r){return i(e,t,r)}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?e.exports=n:(o(n,t),t.Buffer=a),a.prototype=Object.create(i.prototype),o(i,a),a.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return i(e,t,r)},a.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var n=i(e);return void 0!==t?"string"==typeof r?n.fill(t,r):n.fill(t):n.fill(0),n},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return i(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n.SlowBuffer(e)}},function(e,t,r){(function(e,n){var i; +/** + * @license + * Lodash + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */(function(){var o="Expected a function",a="__lodash_placeholder__",s=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],u="[object Arguments]",c="[object Array]",h="[object Boolean]",f="[object Date]",l="[object Error]",d="[object Function]",p="[object GeneratorFunction]",m="[object Map]",g="[object Number]",b="[object Object]",v="[object RegExp]",y="[object Set]",w="[object String]",_="[object Symbol]",S="[object WeakMap]",M="[object ArrayBuffer]",k="[object DataView]",E="[object Float32Array]",A="[object Float64Array]",x="[object Int8Array]",I="[object Int16Array]",P="[object Int32Array]",O="[object Uint8Array]",T="[object Uint16Array]",R="[object Uint32Array]",B=/\b__p \+= '';/g,N=/\b(__p \+=) '' \+/g,C=/(__e\(.*?\)|\b__t\)) \+\n'';/g,j=/&(?:amp|lt|gt|quot|#39);/g,z=/[&<>"']/g,U=RegExp(j.source),L=RegExp(z.source),F=/<%-([\s\S]+?)%>/g,D=/<%([\s\S]+?)%>/g,q=/<%=([\s\S]+?)%>/g,K=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,H=/^\w*$/,V=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,G=/[\\^$.*+?()[\]{}|]/g,W=RegExp(G.source),Y=/^\s+|\s+$/g,Z=/^\s+/,J=/\s+$/,X=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,$=/\{\n\/\* \[wrapped with (.+)\] \*/,Q=/,? & /,ee=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,te=/\\(\\)?/g,re=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,ne=/\w*$/,ie=/^[-+]0x[0-9a-f]+$/i,oe=/^0b[01]+$/i,ae=/^\[object .+?Constructor\]$/,se=/^0o[0-7]+$/i,ue=/^(?:0|[1-9]\d*)$/,ce=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,he=/($^)/,fe=/['\n\r\u2028\u2029\\]/g,le="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",de="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pe="[\\ud800-\\udfff]",me="["+de+"]",ge="["+le+"]",be="\\d+",ve="[\\u2700-\\u27bf]",ye="[a-z\\xdf-\\xf6\\xf8-\\xff]",we="[^\\ud800-\\udfff"+de+be+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",_e="\\ud83c[\\udffb-\\udfff]",Se="[^\\ud800-\\udfff]",Me="(?:\\ud83c[\\udde6-\\uddff]){2}",ke="[\\ud800-\\udbff][\\udc00-\\udfff]",Ee="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Ae="(?:"+ye+"|"+we+")",xe="(?:"+Ee+"|"+we+")",Ie="(?:"+ge+"|"+_e+")"+"?",Pe="[\\ufe0e\\ufe0f]?"+Ie+("(?:\\u200d(?:"+[Se,Me,ke].join("|")+")[\\ufe0e\\ufe0f]?"+Ie+")*"),Oe="(?:"+[ve,Me,ke].join("|")+")"+Pe,Te="(?:"+[Se+ge+"?",ge,Me,ke,pe].join("|")+")",Re=RegExp("['’]","g"),Be=RegExp(ge,"g"),Ne=RegExp(_e+"(?="+_e+")|"+Te+Pe,"g"),Ce=RegExp([Ee+"?"+ye+"+(?:['’](?:d|ll|m|re|s|t|ve))?(?="+[me,Ee,"$"].join("|")+")",xe+"+(?:['’](?:D|LL|M|RE|S|T|VE))?(?="+[me,Ee+Ae,"$"].join("|")+")",Ee+"?"+Ae+"+(?:['’](?:d|ll|m|re|s|t|ve))?",Ee+"+(?:['’](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",be,Oe].join("|"),"g"),je=RegExp("[\\u200d\\ud800-\\udfff"+le+"\\ufe0e\\ufe0f]"),ze=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Ue=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Le=-1,Fe={};Fe[E]=Fe[A]=Fe[x]=Fe[I]=Fe[P]=Fe[O]=Fe["[object Uint8ClampedArray]"]=Fe[T]=Fe[R]=!0,Fe[u]=Fe[c]=Fe[M]=Fe[h]=Fe[k]=Fe[f]=Fe[l]=Fe[d]=Fe[m]=Fe[g]=Fe[b]=Fe[v]=Fe[y]=Fe[w]=Fe[S]=!1;var De={};De[u]=De[c]=De[M]=De[k]=De[h]=De[f]=De[E]=De[A]=De[x]=De[I]=De[P]=De[m]=De[g]=De[b]=De[v]=De[y]=De[w]=De[_]=De[O]=De["[object Uint8ClampedArray]"]=De[T]=De[R]=!0,De[l]=De[d]=De[S]=!1;var qe={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Ke=parseFloat,He=parseInt,Ve="object"==typeof e&&e&&e.Object===Object&&e,Ge="object"==typeof self&&self&&self.Object===Object&&self,We=Ve||Ge||Function("return this")(),Ye=t&&!t.nodeType&&t,Ze=Ye&&"object"==typeof n&&n&&!n.nodeType&&n,Je=Ze&&Ze.exports===Ye,Xe=Je&&Ve.process,$e=function(){try{var e=Ze&&Ze.require&&Ze.require("util").types;return e||Xe&&Xe.binding&&Xe.binding("util")}catch(e){}}(),Qe=$e&&$e.isArrayBuffer,et=$e&&$e.isDate,tt=$e&&$e.isMap,rt=$e&&$e.isRegExp,nt=$e&&$e.isSet,it=$e&&$e.isTypedArray;function ot(e,t,r){switch(r.length){case 0:return e.call(t);case 1:return e.call(t,r[0]);case 2:return e.call(t,r[0],r[1]);case 3:return e.call(t,r[0],r[1],r[2])}return e.apply(t,r)}function at(e,t,r,n){for(var i=-1,o=null==e?0:e.length;++i-1}function lt(e,t,r){for(var n=-1,i=null==e?0:e.length;++n-1;);return r}function Nt(e,t){for(var r=e.length;r--&&_t(t,e[r],0)>-1;);return r}function Ct(e,t){for(var r=e.length,n=0;r--;)e[r]===t&&++n;return n}var jt=At({"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"}),zt=At({"&":"&","<":"<",">":">",'"':""","'":"'"});function Ut(e){return"\\"+qe[e]}function Lt(e){return je.test(e)}function Ft(e){var t=-1,r=Array(e.size);return e.forEach((function(e,n){r[++t]=[n,e]})),r}function Dt(e,t){return function(r){return e(t(r))}}function qt(e,t){for(var r=-1,n=e.length,i=0,o=[];++r",""":'"',"'":"'"});var Yt=function e(t){var r,n=(t=null==t?We:Yt.defaults(We.Object(),t,Yt.pick(We,Ue))).Array,i=t.Date,le=t.Error,de=t.Function,pe=t.Math,me=t.Object,ge=t.RegExp,be=t.String,ve=t.TypeError,ye=n.prototype,we=de.prototype,_e=me.prototype,Se=t["__core-js_shared__"],Me=we.toString,ke=_e.hasOwnProperty,Ee=0,Ae=(r=/[^.]+$/.exec(Se&&Se.keys&&Se.keys.IE_PROTO||""))?"Symbol(src)_1."+r:"",xe=_e.toString,Ie=Me.call(me),Pe=We._,Oe=ge("^"+Me.call(ke).replace(G,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Te=Je?t.Buffer:void 0,Ne=t.Symbol,je=t.Uint8Array,qe=Te?Te.allocUnsafe:void 0,Ve=Dt(me.getPrototypeOf,me),Ge=me.create,Ye=_e.propertyIsEnumerable,Ze=ye.splice,Xe=Ne?Ne.isConcatSpreadable:void 0,$e=Ne?Ne.iterator:void 0,vt=Ne?Ne.toStringTag:void 0,At=function(){try{var e=Qi(me,"defineProperty");return e({},"",{}),e}catch(e){}}(),Zt=t.clearTimeout!==We.clearTimeout&&t.clearTimeout,Jt=i&&i.now!==We.Date.now&&i.now,Xt=t.setTimeout!==We.setTimeout&&t.setTimeout,$t=pe.ceil,Qt=pe.floor,er=me.getOwnPropertySymbols,tr=Te?Te.isBuffer:void 0,rr=t.isFinite,nr=ye.join,ir=Dt(me.keys,me),or=pe.max,ar=pe.min,sr=i.now,ur=t.parseInt,cr=pe.random,hr=ye.reverse,fr=Qi(t,"DataView"),lr=Qi(t,"Map"),dr=Qi(t,"Promise"),pr=Qi(t,"Set"),mr=Qi(t,"WeakMap"),gr=Qi(me,"create"),br=mr&&new mr,vr={},yr=xo(fr),wr=xo(lr),_r=xo(dr),Sr=xo(pr),Mr=xo(mr),kr=Ne?Ne.prototype:void 0,Er=kr?kr.valueOf:void 0,Ar=kr?kr.toString:void 0;function xr(e){if(Ha(e)&&!Ba(e)&&!(e instanceof Tr)){if(e instanceof Or)return e;if(ke.call(e,"__wrapped__"))return Io(e)}return new Or(e)}var Ir=function(){function e(){}return function(t){if(!Ka(t))return{};if(Ge)return Ge(t);e.prototype=t;var r=new e;return e.prototype=void 0,r}}();function Pr(){}function Or(e,t){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=void 0}function Tr(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Rr(e){var t=-1,r=null==e?0:e.length;for(this.clear();++t=t?e:t)),e}function Zr(e,t,r,n,i,o){var a,s=1&t,c=2&t,l=4&t;if(r&&(a=i?r(e,n,i,o):r(e)),void 0!==a)return a;if(!Ka(e))return e;var S=Ba(e);if(S){if(a=function(e){var t=e.length,r=new e.constructor(t);t&&"string"==typeof e[0]&&ke.call(e,"index")&&(r.index=e.index,r.input=e.input);return r}(e),!s)return bi(e,a)}else{var B=ro(e),N=B==d||B==p;if(za(e))return fi(e,s);if(B==b||B==u||N&&!i){if(a=c||N?{}:io(e),!s)return c?function(e,t){return vi(e,to(e),t)}(e,function(e,t){return e&&vi(t,_s(t),e)}(a,e)):function(e,t){return vi(e,eo(e),t)}(e,Vr(a,e))}else{if(!De[B])return i?e:{};a=function(e,t,r){var n=e.constructor;switch(t){case M:return li(e);case h:case f:return new n(+e);case k:return function(e,t){var r=t?li(e.buffer):e.buffer;return new e.constructor(r,e.byteOffset,e.byteLength)}(e,r);case E:case A:case x:case I:case P:case O:case"[object Uint8ClampedArray]":case T:case R:return di(e,r);case m:return new n;case g:case w:return new n(e);case v:return function(e){var t=new e.constructor(e.source,ne.exec(e));return t.lastIndex=e.lastIndex,t}(e);case y:return new n;case _:return i=e,Er?me(Er.call(i)):{}}var i}(e,B,s)}}o||(o=new jr);var C=o.get(e);if(C)return C;o.set(e,a),Za(e)?e.forEach((function(n){a.add(Zr(n,t,r,n,e,o))})):Va(e)&&e.forEach((function(n,i){a.set(i,Zr(n,t,r,i,e,o))}));var j=S?void 0:(l?c?Gi:Vi:c?_s:ws)(e);return st(j||e,(function(n,i){j&&(n=e[i=n]),qr(a,i,Zr(n,t,r,i,e,o))})),a}function Jr(e,t,r){var n=r.length;if(null==e)return!n;for(e=me(e);n--;){var i=r[n],o=t[i],a=e[i];if(void 0===a&&!(i in e)||!o(a))return!1}return!0}function Xr(e,t,r){if("function"!=typeof e)throw new ve(o);return wo((function(){e.apply(void 0,r)}),t)}function $r(e,t,r,n){var i=-1,o=ft,a=!0,s=e.length,u=[],c=t.length;if(!s)return u;r&&(t=dt(t,Ot(r))),n?(o=lt,a=!1):t.length>=200&&(o=Rt,a=!1,t=new Cr(t));e:for(;++i-1},Br.prototype.set=function(e,t){var r=this.__data__,n=Kr(r,e);return n<0?(++this.size,r.push([e,t])):r[n][1]=t,this},Nr.prototype.clear=function(){this.size=0,this.__data__={hash:new Rr,map:new(lr||Br),string:new Rr}},Nr.prototype.delete=function(e){var t=Xi(this,e).delete(e);return this.size-=t?1:0,t},Nr.prototype.get=function(e){return Xi(this,e).get(e)},Nr.prototype.has=function(e){return Xi(this,e).has(e)},Nr.prototype.set=function(e,t){var r=Xi(this,e),n=r.size;return r.set(e,t),this.size+=r.size==n?0:1,this},Cr.prototype.add=Cr.prototype.push=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this},Cr.prototype.has=function(e){return this.__data__.has(e)},jr.prototype.clear=function(){this.__data__=new Br,this.size=0},jr.prototype.delete=function(e){var t=this.__data__,r=t.delete(e);return this.size=t.size,r},jr.prototype.get=function(e){return this.__data__.get(e)},jr.prototype.has=function(e){return this.__data__.has(e)},jr.prototype.set=function(e,t){var r=this.__data__;if(r instanceof Br){var n=r.__data__;if(!lr||n.length<199)return n.push([e,t]),this.size=++r.size,this;r=this.__data__=new Nr(n)}return r.set(e,t),this.size=r.size,this};var Qr=_i(un),en=_i(cn,!0);function tn(e,t){var r=!0;return Qr(e,(function(e,n,i){return r=!!t(e,n,i)})),r}function rn(e,t,r){for(var n=-1,i=e.length;++n0&&r(s)?t>1?on(s,t-1,r,n,i):pt(i,s):n||(i[i.length]=s)}return i}var an=Si(),sn=Si(!0);function un(e,t){return e&&an(e,t,ws)}function cn(e,t){return e&&sn(e,t,ws)}function hn(e,t){return ht(t,(function(t){return Fa(e[t])}))}function fn(e,t){for(var r=0,n=(t=si(t,e)).length;null!=e&&rt}function mn(e,t){return null!=e&&ke.call(e,t)}function gn(e,t){return null!=e&&t in me(e)}function bn(e,t,r){for(var i=r?lt:ft,o=e[0].length,a=e.length,s=a,u=n(a),c=1/0,h=[];s--;){var f=e[s];s&&t&&(f=dt(f,Ot(t))),c=ar(f.length,c),u[s]=!r&&(t||o>=120&&f.length>=120)?new Cr(s&&f):void 0}f=e[0];var l=-1,d=u[0];e:for(;++l=s)return u;var c=r[n];return u*("desc"==c?-1:1)}}return e.index-t.index}(e,t,r)}))}function Bn(e,t,r){for(var n=-1,i=t.length,o={};++n-1;)s!==e&&Ze.call(s,u,1),Ze.call(e,u,1);return e}function Cn(e,t){for(var r=e?t.length:0,n=r-1;r--;){var i=t[r];if(r==n||i!==o){var o=i;ao(i)?Ze.call(e,i,1):Qn(e,i)}}return e}function jn(e,t){return e+Qt(cr()*(t-e+1))}function zn(e,t){var r="";if(!e||t<1||t>9007199254740991)return r;do{t%2&&(r+=e),(t=Qt(t/2))&&(e+=e)}while(t);return r}function Un(e,t){return _o(mo(e,t,Gs),e+"")}function Ln(e){return Ur(Ps(e))}function Fn(e,t){var r=Ps(e);return ko(r,Yr(t,0,r.length))}function Dn(e,t,r,n){if(!Ka(e))return e;for(var i=-1,o=(t=si(t,e)).length,a=o-1,s=e;null!=s&&++io?0:o+t),(r=r>o?o:r)<0&&(r+=o),o=t>r?0:r-t>>>0,t>>>=0;for(var a=n(o);++i>>1,a=e[o];null!==a&&!Xa(a)&&(r?a<=t:a=200){var c=t?null:zi(e);if(c)return Kt(c);a=!1,i=Rt,u=new Cr}else u=t?[]:s;e:for(;++n=n?e:Vn(e,t,r)}var hi=Zt||function(e){return We.clearTimeout(e)};function fi(e,t){if(t)return e.slice();var r=e.length,n=qe?qe(r):new e.constructor(r);return e.copy(n),n}function li(e){var t=new e.constructor(e.byteLength);return new je(t).set(new je(e)),t}function di(e,t){var r=t?li(e.buffer):e.buffer;return new e.constructor(r,e.byteOffset,e.length)}function pi(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=e==e,o=Xa(e),a=void 0!==t,s=null===t,u=t==t,c=Xa(t);if(!s&&!c&&!o&&e>t||o&&a&&u&&!s&&!c||n&&a&&u||!r&&u||!i)return 1;if(!n&&!o&&!c&&e1?r[i-1]:void 0,a=i>2?r[2]:void 0;for(o=e.length>3&&"function"==typeof o?(i--,o):void 0,a&&so(r[0],r[1],a)&&(o=i<3?void 0:o,i=1),t=me(t);++n-1?i[o?t[a]:a]:void 0}}function xi(e){return Hi((function(t){var r=t.length,n=r,i=Or.prototype.thru;for(e&&t.reverse();n--;){var a=t[n];if("function"!=typeof a)throw new ve(o);if(i&&!s&&"wrapper"==Yi(a))var s=new Or([],!0)}for(n=s?n:r;++n1&&y.reverse(),f&&cs))return!1;var c=o.get(e),h=o.get(t);if(c&&h)return c==t&&h==e;var f=-1,l=!0,d=2&r?new Cr:void 0;for(o.set(e,t),o.set(t,e);++f-1&&e%1==0&&e1?"& ":"")+t[n],t=t.join(r>2?", ":" "),e.replace(X,"{\n/* [wrapped with "+t+"] */\n")}(n,function(e,t){return st(s,(function(r){var n="_."+r[0];t&r[1]&&!ft(e,n)&&e.push(n)})),e.sort()}(function(e){var t=e.match($);return t?t[1].split(Q):[]}(n),r)))}function Mo(e){var t=0,r=0;return function(){var n=sr(),i=16-(n-r);if(r=n,i>0){if(++t>=800)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}function ko(e,t){var r=-1,n=e.length,i=n-1;for(t=void 0===t?n:t;++r1?e[t-1]:void 0;return r="function"==typeof r?(e.pop(),r):void 0,Yo(e,r)}));function ta(e){var t=xr(e);return t.__chain__=!0,t}function ra(e,t){return t(e)}var na=Hi((function(e){var t=e.length,r=t?e[0]:0,n=this.__wrapped__,i=function(t){return Wr(t,e)};return!(t>1||this.__actions__.length)&&n instanceof Tr&&ao(r)?((n=n.slice(r,+r+(t?1:0))).__actions__.push({func:ra,args:[i],thisArg:void 0}),new Or(n,this.__chain__).thru((function(e){return t&&!e.length&&e.push(void 0),e}))):this.thru(i)}));var ia=yi((function(e,t,r){ke.call(e,r)?++e[r]:Gr(e,r,1)}));var oa=Ai(Ro),aa=Ai(Bo);function sa(e,t){return(Ba(e)?st:Qr)(e,Ji(t,3))}function ua(e,t){return(Ba(e)?ut:en)(e,Ji(t,3))}var ca=yi((function(e,t,r){ke.call(e,r)?e[r].push(t):Gr(e,r,[t])}));var ha=Un((function(e,t,r){var i=-1,o="function"==typeof t,a=Ca(e)?n(e.length):[];return Qr(e,(function(e){a[++i]=o?ot(t,e,r):vn(e,t,r)})),a})),fa=yi((function(e,t,r){Gr(e,r,t)}));function la(e,t){return(Ba(e)?dt:xn)(e,Ji(t,3))}var da=yi((function(e,t,r){e[r?0:1].push(t)}),(function(){return[[],[]]}));var pa=Un((function(e,t){if(null==e)return[];var r=t.length;return r>1&&so(e,t[0],t[1])?t=[]:r>2&&so(t[0],t[1],t[2])&&(t=[t[0]]),Rn(e,on(t,1),[])})),ma=Jt||function(){return We.Date.now()};function ga(e,t,r){return t=r?void 0:t,Li(e,128,void 0,void 0,void 0,void 0,t=e&&null==t?e.length:t)}function ba(e,t){var r;if("function"!=typeof t)throw new ve(o);return e=ns(e),function(){return--e>0&&(r=t.apply(this,arguments)),e<=1&&(t=void 0),r}}var va=Un((function(e,t,r){var n=1;if(r.length){var i=qt(r,Zi(va));n|=32}return Li(e,n,t,r,i)})),ya=Un((function(e,t,r){var n=3;if(r.length){var i=qt(r,Zi(ya));n|=32}return Li(t,n,e,r,i)}));function wa(e,t,r){var n,i,a,s,u,c,h=0,f=!1,l=!1,d=!0;if("function"!=typeof e)throw new ve(o);function p(t){var r=n,o=i;return n=i=void 0,h=t,s=e.apply(o,r)}function m(e){return h=e,u=wo(b,t),f?p(e):s}function g(e){var r=e-c;return void 0===c||r>=t||r<0||l&&e-h>=a}function b(){var e=ma();if(g(e))return v(e);u=wo(b,function(e){var r=t-(e-c);return l?ar(r,a-(e-h)):r}(e))}function v(e){return u=void 0,d&&n?p(e):(n=i=void 0,s)}function y(){var e=ma(),r=g(e);if(n=arguments,i=this,c=e,r){if(void 0===u)return m(c);if(l)return hi(u),u=wo(b,t),p(c)}return void 0===u&&(u=wo(b,t)),s}return t=os(t)||0,Ka(r)&&(f=!!r.leading,a=(l="maxWait"in r)?or(os(r.maxWait)||0,t):a,d="trailing"in r?!!r.trailing:d),y.cancel=function(){void 0!==u&&hi(u),h=0,n=c=i=u=void 0},y.flush=function(){return void 0===u?s:v(ma())},y}var _a=Un((function(e,t){return Xr(e,1,t)})),Sa=Un((function(e,t,r){return Xr(e,os(t)||0,r)}));function Ma(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw new ve(o);var r=function(){var n=arguments,i=t?t.apply(this,n):n[0],o=r.cache;if(o.has(i))return o.get(i);var a=e.apply(this,n);return r.cache=o.set(i,a)||o,a};return r.cache=new(Ma.Cache||Nr),r}function ka(e){if("function"!=typeof e)throw new ve(o);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}Ma.Cache=Nr;var Ea=ui((function(e,t){var r=(t=1==t.length&&Ba(t[0])?dt(t[0],Ot(Ji())):dt(on(t,1),Ot(Ji()))).length;return Un((function(n){for(var i=-1,o=ar(n.length,r);++i=t})),Ra=yn(function(){return arguments}())?yn:function(e){return Ha(e)&&ke.call(e,"callee")&&!Ye.call(e,"callee")},Ba=n.isArray,Na=Qe?Ot(Qe):function(e){return Ha(e)&&dn(e)==M};function Ca(e){return null!=e&&qa(e.length)&&!Fa(e)}function ja(e){return Ha(e)&&Ca(e)}var za=tr||ou,Ua=et?Ot(et):function(e){return Ha(e)&&dn(e)==f};function La(e){if(!Ha(e))return!1;var t=dn(e);return t==l||"[object DOMException]"==t||"string"==typeof e.message&&"string"==typeof e.name&&!Wa(e)}function Fa(e){if(!Ka(e))return!1;var t=dn(e);return t==d||t==p||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Da(e){return"number"==typeof e&&e==ns(e)}function qa(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991}function Ka(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}function Ha(e){return null!=e&&"object"==typeof e}var Va=tt?Ot(tt):function(e){return Ha(e)&&ro(e)==m};function Ga(e){return"number"==typeof e||Ha(e)&&dn(e)==g}function Wa(e){if(!Ha(e)||dn(e)!=b)return!1;var t=Ve(e);if(null===t)return!0;var r=ke.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&Me.call(r)==Ie}var Ya=rt?Ot(rt):function(e){return Ha(e)&&dn(e)==v};var Za=nt?Ot(nt):function(e){return Ha(e)&&ro(e)==y};function Ja(e){return"string"==typeof e||!Ba(e)&&Ha(e)&&dn(e)==w}function Xa(e){return"symbol"==typeof e||Ha(e)&&dn(e)==_}var $a=it?Ot(it):function(e){return Ha(e)&&qa(e.length)&&!!Fe[dn(e)]};var Qa=Ni(An),es=Ni((function(e,t){return e<=t}));function ts(e){if(!e)return[];if(Ca(e))return Ja(e)?Gt(e):bi(e);if($e&&e[$e])return function(e){for(var t,r=[];!(t=e.next()).done;)r.push(t.value);return r}(e[$e]());var t=ro(e);return(t==m?Ft:t==y?Kt:Ps)(e)}function rs(e){return e?(e=os(e))===1/0||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}function ns(e){var t=rs(e),r=t%1;return t==t?r?t-r:t:0}function is(e){return e?Yr(ns(e),0,4294967295):0}function os(e){if("number"==typeof e)return e;if(Xa(e))return NaN;if(Ka(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Ka(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Y,"");var r=oe.test(e);return r||se.test(e)?He(e.slice(2),r?2:8):ie.test(e)?NaN:+e}function as(e){return vi(e,_s(e))}function ss(e){return null==e?"":Xn(e)}var us=wi((function(e,t){if(fo(t)||Ca(t))vi(t,ws(t),e);else for(var r in t)ke.call(t,r)&&qr(e,r,t[r])})),cs=wi((function(e,t){vi(t,_s(t),e)})),hs=wi((function(e,t,r,n){vi(t,_s(t),e,n)})),fs=wi((function(e,t,r,n){vi(t,ws(t),e,n)})),ls=Hi(Wr);var ds=Un((function(e,t){e=me(e);var r=-1,n=t.length,i=n>2?t[2]:void 0;for(i&&so(t[0],t[1],i)&&(n=1);++r1),t})),vi(e,Gi(e),r),n&&(r=Zr(r,7,qi));for(var i=t.length;i--;)Qn(r,t[i]);return r}));var Es=Hi((function(e,t){return null==e?{}:function(e,t){return Bn(e,t,(function(t,r){return gs(e,r)}))}(e,t)}));function As(e,t){if(null==e)return{};var r=dt(Gi(e),(function(e){return[e]}));return t=Ji(t),Bn(e,r,(function(e,r){return t(e,r[0])}))}var xs=Ui(ws),Is=Ui(_s);function Ps(e){return null==e?[]:Tt(e,ws(e))}var Os=ki((function(e,t,r){return t=t.toLowerCase(),e+(r?Ts(t):t)}));function Ts(e){return Ls(ss(e).toLowerCase())}function Rs(e){return(e=ss(e))&&e.replace(ce,jt).replace(Be,"")}var Bs=ki((function(e,t,r){return e+(r?"-":"")+t.toLowerCase()})),Ns=ki((function(e,t,r){return e+(r?" ":"")+t.toLowerCase()})),Cs=Mi("toLowerCase");var js=ki((function(e,t,r){return e+(r?"_":"")+t.toLowerCase()}));var zs=ki((function(e,t,r){return e+(r?" ":"")+Ls(t)}));var Us=ki((function(e,t,r){return e+(r?" ":"")+t.toUpperCase()})),Ls=Mi("toUpperCase");function Fs(e,t,r){return e=ss(e),void 0===(t=r?void 0:t)?function(e){return ze.test(e)}(e)?function(e){return e.match(Ce)||[]}(e):function(e){return e.match(ee)||[]}(e):e.match(t)||[]}var Ds=Un((function(e,t){try{return ot(e,void 0,t)}catch(e){return La(e)?e:new le(e)}})),qs=Hi((function(e,t){return st(t,(function(t){t=Ao(t),Gr(e,t,va(e[t],e))})),e}));function Ks(e){return function(){return e}}var Hs=xi(),Vs=xi(!0);function Gs(e){return e}function Ws(e){return Mn("function"==typeof e?e:Zr(e,1))}var Ys=Un((function(e,t){return function(r){return vn(r,e,t)}})),Zs=Un((function(e,t){return function(r){return vn(e,r,t)}}));function Js(e,t,r){var n=ws(t),i=hn(t,n);null!=r||Ka(t)&&(i.length||!n.length)||(r=t,t=e,e=this,i=hn(t,ws(t)));var o=!(Ka(r)&&"chain"in r&&!r.chain),a=Fa(e);return st(i,(function(r){var n=t[r];e[r]=n,a&&(e.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=e(this.__wrapped__),i=r.__actions__=bi(this.__actions__);return i.push({func:n,args:arguments,thisArg:e}),r.__chain__=t,r}return n.apply(e,pt([this.value()],arguments))})})),e}function Xs(){}var $s=Ti(dt),Qs=Ti(ct),eu=Ti(bt);function tu(e){return uo(e)?Et(Ao(e)):function(e){return function(t){return fn(t,e)}}(e)}var ru=Bi(),nu=Bi(!0);function iu(){return[]}function ou(){return!1}var au=Oi((function(e,t){return e+t}),0),su=ji("ceil"),uu=Oi((function(e,t){return e/t}),1),cu=ji("floor");var hu,fu=Oi((function(e,t){return e*t}),1),lu=ji("round"),du=Oi((function(e,t){return e-t}),0);return xr.after=function(e,t){if("function"!=typeof t)throw new ve(o);return e=ns(e),function(){if(--e<1)return t.apply(this,arguments)}},xr.ary=ga,xr.assign=us,xr.assignIn=cs,xr.assignInWith=hs,xr.assignWith=fs,xr.at=ls,xr.before=ba,xr.bind=va,xr.bindAll=qs,xr.bindKey=ya,xr.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Ba(e)?e:[e]},xr.chain=ta,xr.chunk=function(e,t,r){t=(r?so(e,t,r):void 0===t)?1:or(ns(t),0);var i=null==e?0:e.length;if(!i||t<1)return[];for(var o=0,a=0,s=n($t(i/t));oi?0:i+r),(n=void 0===n||n>i?i:ns(n))<0&&(n+=i),n=r>n?0:is(n);r>>0)?(e=ss(e))&&("string"==typeof t||null!=t&&!Ya(t))&&!(t=Xn(t))&&Lt(e)?ci(Gt(e),0,r):e.split(t,r):[]},xr.spread=function(e,t){if("function"!=typeof e)throw new ve(o);return t=null==t?0:or(ns(t),0),Un((function(r){var n=r[t],i=ci(r,0,t);return n&&pt(i,n),ot(e,this,i)}))},xr.tail=function(e){var t=null==e?0:e.length;return t?Vn(e,1,t):[]},xr.take=function(e,t,r){return e&&e.length?Vn(e,0,(t=r||void 0===t?1:ns(t))<0?0:t):[]},xr.takeRight=function(e,t,r){var n=null==e?0:e.length;return n?Vn(e,(t=n-(t=r||void 0===t?1:ns(t)))<0?0:t,n):[]},xr.takeRightWhile=function(e,t){return e&&e.length?ti(e,Ji(t,3),!1,!0):[]},xr.takeWhile=function(e,t){return e&&e.length?ti(e,Ji(t,3)):[]},xr.tap=function(e,t){return t(e),e},xr.throttle=function(e,t,r){var n=!0,i=!0;if("function"!=typeof e)throw new ve(o);return Ka(r)&&(n="leading"in r?!!r.leading:n,i="trailing"in r?!!r.trailing:i),wa(e,t,{leading:n,maxWait:t,trailing:i})},xr.thru=ra,xr.toArray=ts,xr.toPairs=xs,xr.toPairsIn=Is,xr.toPath=function(e){return Ba(e)?dt(e,Ao):Xa(e)?[e]:bi(Eo(ss(e)))},xr.toPlainObject=as,xr.transform=function(e,t,r){var n=Ba(e),i=n||za(e)||$a(e);if(t=Ji(t,4),null==r){var o=e&&e.constructor;r=i?n?new o:[]:Ka(e)&&Fa(o)?Ir(Ve(e)):{}}return(i?st:un)(e,(function(e,n,i){return t(r,e,n,i)})),r},xr.unary=function(e){return ga(e,1)},xr.union=Ho,xr.unionBy=Vo,xr.unionWith=Go,xr.uniq=function(e){return e&&e.length?$n(e):[]},xr.uniqBy=function(e,t){return e&&e.length?$n(e,Ji(t,2)):[]},xr.uniqWith=function(e,t){return t="function"==typeof t?t:void 0,e&&e.length?$n(e,void 0,t):[]},xr.unset=function(e,t){return null==e||Qn(e,t)},xr.unzip=Wo,xr.unzipWith=Yo,xr.update=function(e,t,r){return null==e?e:ei(e,t,ai(r))},xr.updateWith=function(e,t,r,n){return n="function"==typeof n?n:void 0,null==e?e:ei(e,t,ai(r),n)},xr.values=Ps,xr.valuesIn=function(e){return null==e?[]:Tt(e,_s(e))},xr.without=Zo,xr.words=Fs,xr.wrap=function(e,t){return Aa(ai(t),e)},xr.xor=Jo,xr.xorBy=Xo,xr.xorWith=$o,xr.zip=Qo,xr.zipObject=function(e,t){return ii(e||[],t||[],qr)},xr.zipObjectDeep=function(e,t){return ii(e||[],t||[],Dn)},xr.zipWith=ea,xr.entries=xs,xr.entriesIn=Is,xr.extend=cs,xr.extendWith=hs,Js(xr,xr),xr.add=au,xr.attempt=Ds,xr.camelCase=Os,xr.capitalize=Ts,xr.ceil=su,xr.clamp=function(e,t,r){return void 0===r&&(r=t,t=void 0),void 0!==r&&(r=(r=os(r))==r?r:0),void 0!==t&&(t=(t=os(t))==t?t:0),Yr(os(e),t,r)},xr.clone=function(e){return Zr(e,4)},xr.cloneDeep=function(e){return Zr(e,5)},xr.cloneDeepWith=function(e,t){return Zr(e,5,t="function"==typeof t?t:void 0)},xr.cloneWith=function(e,t){return Zr(e,4,t="function"==typeof t?t:void 0)},xr.conformsTo=function(e,t){return null==t||Jr(e,t,ws(t))},xr.deburr=Rs,xr.defaultTo=function(e,t){return null==e||e!=e?t:e},xr.divide=uu,xr.endsWith=function(e,t,r){e=ss(e),t=Xn(t);var n=e.length,i=r=void 0===r?n:Yr(ns(r),0,n);return(r-=t.length)>=0&&e.slice(r,i)==t},xr.eq=Pa,xr.escape=function(e){return(e=ss(e))&&L.test(e)?e.replace(z,zt):e},xr.escapeRegExp=function(e){return(e=ss(e))&&W.test(e)?e.replace(G,"\\$&"):e},xr.every=function(e,t,r){var n=Ba(e)?ct:tn;return r&&so(e,t,r)&&(t=void 0),n(e,Ji(t,3))},xr.find=oa,xr.findIndex=Ro,xr.findKey=function(e,t){return yt(e,Ji(t,3),un)},xr.findLast=aa,xr.findLastIndex=Bo,xr.findLastKey=function(e,t){return yt(e,Ji(t,3),cn)},xr.floor=cu,xr.forEach=sa,xr.forEachRight=ua,xr.forIn=function(e,t){return null==e?e:an(e,Ji(t,3),_s)},xr.forInRight=function(e,t){return null==e?e:sn(e,Ji(t,3),_s)},xr.forOwn=function(e,t){return e&&un(e,Ji(t,3))},xr.forOwnRight=function(e,t){return e&&cn(e,Ji(t,3))},xr.get=ms,xr.gt=Oa,xr.gte=Ta,xr.has=function(e,t){return null!=e&&no(e,t,mn)},xr.hasIn=gs,xr.head=Co,xr.identity=Gs,xr.includes=function(e,t,r,n){e=Ca(e)?e:Ps(e),r=r&&!n?ns(r):0;var i=e.length;return r<0&&(r=or(i+r,0)),Ja(e)?r<=i&&e.indexOf(t,r)>-1:!!i&&_t(e,t,r)>-1},xr.indexOf=function(e,t,r){var n=null==e?0:e.length;if(!n)return-1;var i=null==r?0:ns(r);return i<0&&(i=or(n+i,0)),_t(e,t,i)},xr.inRange=function(e,t,r){return t=rs(t),void 0===r?(r=t,t=0):r=rs(r),function(e,t,r){return e>=ar(t,r)&&e=-9007199254740991&&e<=9007199254740991},xr.isSet=Za,xr.isString=Ja,xr.isSymbol=Xa,xr.isTypedArray=$a,xr.isUndefined=function(e){return void 0===e},xr.isWeakMap=function(e){return Ha(e)&&ro(e)==S},xr.isWeakSet=function(e){return Ha(e)&&"[object WeakSet]"==dn(e)},xr.join=function(e,t){return null==e?"":nr.call(e,t)},xr.kebabCase=Bs,xr.last=Lo,xr.lastIndexOf=function(e,t,r){var n=null==e?0:e.length;if(!n)return-1;var i=n;return void 0!==r&&(i=(i=ns(r))<0?or(n+i,0):ar(i,n-1)),t==t?function(e,t,r){for(var n=r+1;n--;)if(e[n]===t)return n;return n}(e,t,i):wt(e,Mt,i,!0)},xr.lowerCase=Ns,xr.lowerFirst=Cs,xr.lt=Qa,xr.lte=es,xr.max=function(e){return e&&e.length?rn(e,Gs,pn):void 0},xr.maxBy=function(e,t){return e&&e.length?rn(e,Ji(t,2),pn):void 0},xr.mean=function(e){return kt(e,Gs)},xr.meanBy=function(e,t){return kt(e,Ji(t,2))},xr.min=function(e){return e&&e.length?rn(e,Gs,An):void 0},xr.minBy=function(e,t){return e&&e.length?rn(e,Ji(t,2),An):void 0},xr.stubArray=iu,xr.stubFalse=ou,xr.stubObject=function(){return{}},xr.stubString=function(){return""},xr.stubTrue=function(){return!0},xr.multiply=fu,xr.nth=function(e,t){return e&&e.length?Tn(e,ns(t)):void 0},xr.noConflict=function(){return We._===this&&(We._=Pe),this},xr.noop=Xs,xr.now=ma,xr.pad=function(e,t,r){e=ss(e);var n=(t=ns(t))?Vt(e):0;if(!t||n>=t)return e;var i=(t-n)/2;return Ri(Qt(i),r)+e+Ri($t(i),r)},xr.padEnd=function(e,t,r){e=ss(e);var n=(t=ns(t))?Vt(e):0;return t&&nt){var n=e;e=t,t=n}if(r||e%1||t%1){var i=cr();return ar(e+i*(t-e+Ke("1e-"+((i+"").length-1))),t)}return jn(e,t)},xr.reduce=function(e,t,r){var n=Ba(e)?mt:xt,i=arguments.length<3;return n(e,Ji(t,4),r,i,Qr)},xr.reduceRight=function(e,t,r){var n=Ba(e)?gt:xt,i=arguments.length<3;return n(e,Ji(t,4),r,i,en)},xr.repeat=function(e,t,r){return t=(r?so(e,t,r):void 0===t)?1:ns(t),zn(ss(e),t)},xr.replace=function(){var e=arguments,t=ss(e[0]);return e.length<3?t:t.replace(e[1],e[2])},xr.result=function(e,t,r){var n=-1,i=(t=si(t,e)).length;for(i||(i=1,e=void 0);++n9007199254740991)return[];var r=4294967295,n=ar(e,4294967295);e-=4294967295;for(var i=Pt(n,t=Ji(t));++r=o)return e;var s=r-Vt(n);if(s<1)return n;var u=a?ci(a,0,s).join(""):e.slice(0,s);if(void 0===i)return u+n;if(a&&(s+=u.length-s),Ya(i)){if(e.slice(s).search(i)){var c,h=u;for(i.global||(i=ge(i.source,ss(ne.exec(i))+"g")),i.lastIndex=0;c=i.exec(h);)var f=c.index;u=u.slice(0,void 0===f?s:f)}}else if(e.indexOf(Xn(i),s)!=s){var l=u.lastIndexOf(i);l>-1&&(u=u.slice(0,l))}return u+n},xr.unescape=function(e){return(e=ss(e))&&U.test(e)?e.replace(j,Wt):e},xr.uniqueId=function(e){var t=++Ee;return ss(e)+t},xr.upperCase=Us,xr.upperFirst=Ls,xr.each=sa,xr.eachRight=ua,xr.first=Co,Js(xr,(hu={},un(xr,(function(e,t){ke.call(xr.prototype,t)||(hu[t]=e)})),hu),{chain:!1}),xr.VERSION="4.17.20",st(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){xr[e].placeholder=xr})),st(["drop","take"],(function(e,t){Tr.prototype[e]=function(r){r=void 0===r?1:or(ns(r),0);var n=this.__filtered__&&!t?new Tr(this):this.clone();return n.__filtered__?n.__takeCount__=ar(r,n.__takeCount__):n.__views__.push({size:ar(r,4294967295),type:e+(n.__dir__<0?"Right":"")}),n},Tr.prototype[e+"Right"]=function(t){return this.reverse()[e](t).reverse()}})),st(["filter","map","takeWhile"],(function(e,t){var r=t+1,n=1==r||3==r;Tr.prototype[e]=function(e){var t=this.clone();return t.__iteratees__.push({iteratee:Ji(e,3),type:r}),t.__filtered__=t.__filtered__||n,t}})),st(["head","last"],(function(e,t){var r="take"+(t?"Right":"");Tr.prototype[e]=function(){return this[r](1).value()[0]}})),st(["initial","tail"],(function(e,t){var r="drop"+(t?"":"Right");Tr.prototype[e]=function(){return this.__filtered__?new Tr(this):this[r](1)}})),Tr.prototype.compact=function(){return this.filter(Gs)},Tr.prototype.find=function(e){return this.filter(e).head()},Tr.prototype.findLast=function(e){return this.reverse().find(e)},Tr.prototype.invokeMap=Un((function(e,t){return"function"==typeof e?new Tr(this):this.map((function(r){return vn(r,e,t)}))})),Tr.prototype.reject=function(e){return this.filter(ka(Ji(e)))},Tr.prototype.slice=function(e,t){e=ns(e);var r=this;return r.__filtered__&&(e>0||t<0)?new Tr(r):(e<0?r=r.takeRight(-e):e&&(r=r.drop(e)),void 0!==t&&(r=(t=ns(t))<0?r.dropRight(-t):r.take(t-e)),r)},Tr.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},Tr.prototype.toArray=function(){return this.take(4294967295)},un(Tr.prototype,(function(e,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),n=/^(?:head|last)$/.test(t),i=xr[n?"take"+("last"==t?"Right":""):t],o=n||/^find/.test(t);i&&(xr.prototype[t]=function(){var t=this.__wrapped__,a=n?[1]:arguments,s=t instanceof Tr,u=a[0],c=s||Ba(t),h=function(e){var t=i.apply(xr,pt([e],a));return n&&f?t[0]:t};c&&r&&"function"==typeof u&&1!=u.length&&(s=c=!1);var f=this.__chain__,l=!!this.__actions__.length,d=o&&!f,p=s&&!l;if(!o&&c){t=p?t:new Tr(this);var m=e.apply(t,a);return m.__actions__.push({func:ra,args:[h],thisArg:void 0}),new Or(m,f)}return d&&p?e.apply(this,a):(m=this.thru(h),d?n?m.value()[0]:m.value():m)})})),st(["pop","push","shift","sort","splice","unshift"],(function(e){var t=ye[e],r=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",n=/^(?:pop|shift)$/.test(e);xr.prototype[e]=function(){var e=arguments;if(n&&!this.__chain__){var i=this.value();return t.apply(Ba(i)?i:[],e)}return this[r]((function(r){return t.apply(Ba(r)?r:[],e)}))}})),un(Tr.prototype,(function(e,t){var r=xr[t];if(r){var n=r.name+"";ke.call(vr,n)||(vr[n]=[]),vr[n].push({name:t,func:r})}})),vr[Ii(void 0,2).name]=[{name:"wrapper",func:void 0}],Tr.prototype.clone=function(){var e=new Tr(this.__wrapped__);return e.__actions__=bi(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=bi(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=bi(this.__views__),e},Tr.prototype.reverse=function(){if(this.__filtered__){var e=new Tr(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},Tr.prototype.value=function(){var e=this.__wrapped__.value(),t=this.__dir__,r=Ba(e),n=t<0,i=r?e.length:0,o=function(e,t,r){var n=-1,i=r.length;for(;++n=this.__values__.length;return{done:e,value:e?void 0:this.__values__[this.__index__++]}},xr.prototype.plant=function(e){for(var t,r=this;r instanceof Pr;){var n=Io(r);n.__index__=0,n.__values__=void 0,t?i.__wrapped__=n:t=n;var i=n;r=r.__wrapped__}return i.__wrapped__=e,t},xr.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof Tr){var t=e;return this.__actions__.length&&(t=new Tr(this)),(t=t.reverse()).__actions__.push({func:ra,args:[Ko],thisArg:void 0}),new Or(t,this.__chain__)}return this.thru(Ko)},xr.prototype.toJSON=xr.prototype.valueOf=xr.prototype.value=function(){return ri(this.__wrapped__,this.__actions__)},xr.prototype.first=xr.prototype.head,$e&&(xr.prototype[$e]=function(){return this}),xr}();We._=Yt,void 0===(i=function(){return Yt}.call(t,r,t,n))||(n.exports=i)}).call(this)}).call(this,r(8),r(28)(e))},function(e,t,r){"use strict";var n=r(17),i=r(3);e.exports={checkState:function(e,t){if(!e)throw new n.InvalidState(t)},checkArgument:function(e,t,r,i){if(!e)throw new n.InvalidArgument(t,r,i)},checkArgumentType:function(e,t,o){if(o=o||"(unknown name)",i.isString(t)){if("Buffer"===t){if(!r(0).Buffer.isBuffer(e))throw new n.InvalidArgumentType(e,t,o)}else if(typeof e!==t)throw new n.InvalidArgumentType(e,t,o)}else if(!(e instanceof t))throw new n.InvalidArgumentType(e,t.name,o)}}},function(e,t,r){"use strict";(function(t){var n=r(0),i=(r(45),r(7),r(4));function o(e,t){if(e.length!==t.length)return!1;for(var r=e.length,n=0;n>24&255),r.push(e>>16&255),r.push(e>>8&255),r.push(255&e),t.from(r)},integerFromBuffer:function(e){return i.checkArgumentType(e,"Buffer","buffer"),e[0]<<24|e[1]<<16|e[2]<<8|e[3]},integerFromSingleByteBuffer:function(e){return i.checkArgumentType(e,"Buffer","buffer"),e[0]},bufferToHex:function(e){return i.checkArgumentType(e,"Buffer","buffer"),e.toString("hex")},reverse:function(e){return t.from(e).reverse()}},e.exports.NULL_HASH=e.exports.fill(t.alloc(32),0),e.exports.EMPTY_BUFFER=t.alloc(0)}).call(this,r(0).Buffer)},function(e,t,r){(function(e){!function(e,t){"use strict";function n(e,t){if(!e)throw new Error(t||"Assertion failed")}function i(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function o(e,t,r){if(o.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var a;"object"==typeof e?e.exports=o:t.BN=o,o.BN=o,o.wordSize=26;try{a=r(207).Buffer}catch(e){}function s(e,t,r){for(var n=0,i=Math.min(e.length,r),o=t;o=49&&a<=54?a-49+10:a>=17&&a<=22?a-17+10:15&a}return n}function u(e,t,r,n){for(var i=0,o=Math.min(e.length,r),a=t;a=49?s-49+10:s>=17?s-17+10:s}return i}o.isBN=function(e){return e instanceof o||null!==e&&"object"==typeof e&&e.constructor.wordSize===o.wordSize&&Array.isArray(e.words)},o.max=function(e,t){return e.cmp(t)>0?e:t},o.min=function(e,t){return e.cmp(t)<0?e:t},o.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),n(t===(0|t)&&t>=2&&t<=36);var i=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&i++,16===t?this._parseHex(e,i):this._parseBase(e,t,i),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(n(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initArray=function(e,t,r){if(n("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var i=0;i=0;i-=3)a=e[i]|e[i-1]<<8|e[i-2]<<16,this.words[o]|=a<>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);else if("le"===r)for(i=0,o=0;i>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);return this.strip()},o.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)i=s(e,r,r+6),this.words[n]|=i<>>26-o&4194303,(o+=24)>=26&&(o-=26,n++);r+6!==t&&(i=s(e,t,r+6),this.words[n]|=i<>>26-o&4194303),this.strip()},o.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var n=0,i=1;i<=67108863;i*=t)n++;n--,i=i/t|0;for(var o=e.length-r,a=o%n,s=Math.min(o,o-a)+r,c=0,h=r;h1&&0===this.words[this.length-1];)this.length--;return this._normSign()},o.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},o.prototype.inspect=function(){return(this.red?""};var c=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],h=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],f=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function l(e,t,r){r.negative=t.negative^e.negative;var n=e.length+t.length|0;r.length=n,n=n-1|0;var i=0|e.words[0],o=0|t.words[0],a=i*o,s=67108863&a,u=a/67108864|0;r.words[0]=s;for(var c=1;c>>26,f=67108863&u,l=Math.min(c,t.length-1),d=Math.max(0,c-e.length+1);d<=l;d++){var p=c-d|0;h+=(a=(i=0|e.words[p])*(o=0|t.words[d])+f)/67108864|0,f=67108863&a}r.words[c]=0|f,u=0|h}return 0!==u?r.words[c]=0|u:r.length--,r.strip()}o.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var i=0,o=0,a=0;a>>24-i&16777215)||a!==this.length-1?c[6-u.length]+u+r:u+r,(i+=2)>=26&&(i-=26,a--)}for(0!==o&&(r=o.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var l=h[e],d=f[e];r="";var p=this.clone();for(p.negative=0;!p.isZero();){var m=p.modn(d).toString(e);r=(p=p.idivn(d)).isZero()?m+r:c[l-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}n(!1,"Base should be between 2 and 36")},o.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&n(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},o.prototype.toJSON=function(){return this.toString(16)},o.prototype.toBuffer=function(e,t){return n(void 0!==a),this.toArrayLike(a,e,t)},o.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},o.prototype.toArrayLike=function(e,t,r){var i=this.byteLength(),o=r||Math.max(1,i);n(i<=o,"byte array longer than desired length"),n(o>0,"Requested array length <= 0"),this.strip();var a,s,u="le"===t,c=new e(o),h=this.clone();if(u){for(s=0;!h.isZero();s++)a=h.andln(255),h.iushrn(8),c[s]=a;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},o.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},o.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},o.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},o.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},o.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},o.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},o.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var n=0;ne.length?this.clone().ixor(e):e.clone().ixor(this)},o.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},o.prototype.inotn=function(e){n("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var i=0;i0&&(this.words[i]=~this.words[i]&67108863>>26-r),this.strip()},o.prototype.notn=function(e){return this.clone().inotn(e)},o.prototype.setn=function(e,t){n("number"==typeof e&&e>=0);var r=e/26|0,i=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,n=e):(r=e,n=this);for(var i=0,o=0;o>>26;for(;0!==i&&o>>26;if(this.length=r.length,0!==i)this.words[this.length]=i,this.length++;else if(r!==this)for(;oe.length?this.clone().iadd(e):e.clone().iadd(this)},o.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,n,i=this.cmp(e);if(0===i)return this.negative=0,this.length=1,this.words[0]=0,this;i>0?(r=this,n=e):(r=e,n=this);for(var o=0,a=0;a>26,this.words[a]=67108863&t;for(;0!==o&&a>26,this.words[a]=67108863&t;if(0===o&&a>>13,d=0|a[1],p=8191&d,m=d>>>13,g=0|a[2],b=8191&g,v=g>>>13,y=0|a[3],w=8191&y,_=y>>>13,S=0|a[4],M=8191&S,k=S>>>13,E=0|a[5],A=8191&E,x=E>>>13,I=0|a[6],P=8191&I,O=I>>>13,T=0|a[7],R=8191&T,B=T>>>13,N=0|a[8],C=8191&N,j=N>>>13,z=0|a[9],U=8191&z,L=z>>>13,F=0|s[0],D=8191&F,q=F>>>13,K=0|s[1],H=8191&K,V=K>>>13,G=0|s[2],W=8191&G,Y=G>>>13,Z=0|s[3],J=8191&Z,X=Z>>>13,$=0|s[4],Q=8191&$,ee=$>>>13,te=0|s[5],re=8191&te,ne=te>>>13,ie=0|s[6],oe=8191&ie,ae=ie>>>13,se=0|s[7],ue=8191&se,ce=se>>>13,he=0|s[8],fe=8191&he,le=he>>>13,de=0|s[9],pe=8191&de,me=de>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(c+(n=Math.imul(f,D))|0)+((8191&(i=(i=Math.imul(f,q))+Math.imul(l,D)|0))<<13)|0;c=((o=Math.imul(l,q))+(i>>>13)|0)+(ge>>>26)|0,ge&=67108863,n=Math.imul(p,D),i=(i=Math.imul(p,q))+Math.imul(m,D)|0,o=Math.imul(m,q);var be=(c+(n=n+Math.imul(f,H)|0)|0)+((8191&(i=(i=i+Math.imul(f,V)|0)+Math.imul(l,H)|0))<<13)|0;c=((o=o+Math.imul(l,V)|0)+(i>>>13)|0)+(be>>>26)|0,be&=67108863,n=Math.imul(b,D),i=(i=Math.imul(b,q))+Math.imul(v,D)|0,o=Math.imul(v,q),n=n+Math.imul(p,H)|0,i=(i=i+Math.imul(p,V)|0)+Math.imul(m,H)|0,o=o+Math.imul(m,V)|0;var ve=(c+(n=n+Math.imul(f,W)|0)|0)+((8191&(i=(i=i+Math.imul(f,Y)|0)+Math.imul(l,W)|0))<<13)|0;c=((o=o+Math.imul(l,Y)|0)+(i>>>13)|0)+(ve>>>26)|0,ve&=67108863,n=Math.imul(w,D),i=(i=Math.imul(w,q))+Math.imul(_,D)|0,o=Math.imul(_,q),n=n+Math.imul(b,H)|0,i=(i=i+Math.imul(b,V)|0)+Math.imul(v,H)|0,o=o+Math.imul(v,V)|0,n=n+Math.imul(p,W)|0,i=(i=i+Math.imul(p,Y)|0)+Math.imul(m,W)|0,o=o+Math.imul(m,Y)|0;var ye=(c+(n=n+Math.imul(f,J)|0)|0)+((8191&(i=(i=i+Math.imul(f,X)|0)+Math.imul(l,J)|0))<<13)|0;c=((o=o+Math.imul(l,X)|0)+(i>>>13)|0)+(ye>>>26)|0,ye&=67108863,n=Math.imul(M,D),i=(i=Math.imul(M,q))+Math.imul(k,D)|0,o=Math.imul(k,q),n=n+Math.imul(w,H)|0,i=(i=i+Math.imul(w,V)|0)+Math.imul(_,H)|0,o=o+Math.imul(_,V)|0,n=n+Math.imul(b,W)|0,i=(i=i+Math.imul(b,Y)|0)+Math.imul(v,W)|0,o=o+Math.imul(v,Y)|0,n=n+Math.imul(p,J)|0,i=(i=i+Math.imul(p,X)|0)+Math.imul(m,J)|0,o=o+Math.imul(m,X)|0;var we=(c+(n=n+Math.imul(f,Q)|0)|0)+((8191&(i=(i=i+Math.imul(f,ee)|0)+Math.imul(l,Q)|0))<<13)|0;c=((o=o+Math.imul(l,ee)|0)+(i>>>13)|0)+(we>>>26)|0,we&=67108863,n=Math.imul(A,D),i=(i=Math.imul(A,q))+Math.imul(x,D)|0,o=Math.imul(x,q),n=n+Math.imul(M,H)|0,i=(i=i+Math.imul(M,V)|0)+Math.imul(k,H)|0,o=o+Math.imul(k,V)|0,n=n+Math.imul(w,W)|0,i=(i=i+Math.imul(w,Y)|0)+Math.imul(_,W)|0,o=o+Math.imul(_,Y)|0,n=n+Math.imul(b,J)|0,i=(i=i+Math.imul(b,X)|0)+Math.imul(v,J)|0,o=o+Math.imul(v,X)|0,n=n+Math.imul(p,Q)|0,i=(i=i+Math.imul(p,ee)|0)+Math.imul(m,Q)|0,o=o+Math.imul(m,ee)|0;var _e=(c+(n=n+Math.imul(f,re)|0)|0)+((8191&(i=(i=i+Math.imul(f,ne)|0)+Math.imul(l,re)|0))<<13)|0;c=((o=o+Math.imul(l,ne)|0)+(i>>>13)|0)+(_e>>>26)|0,_e&=67108863,n=Math.imul(P,D),i=(i=Math.imul(P,q))+Math.imul(O,D)|0,o=Math.imul(O,q),n=n+Math.imul(A,H)|0,i=(i=i+Math.imul(A,V)|0)+Math.imul(x,H)|0,o=o+Math.imul(x,V)|0,n=n+Math.imul(M,W)|0,i=(i=i+Math.imul(M,Y)|0)+Math.imul(k,W)|0,o=o+Math.imul(k,Y)|0,n=n+Math.imul(w,J)|0,i=(i=i+Math.imul(w,X)|0)+Math.imul(_,J)|0,o=o+Math.imul(_,X)|0,n=n+Math.imul(b,Q)|0,i=(i=i+Math.imul(b,ee)|0)+Math.imul(v,Q)|0,o=o+Math.imul(v,ee)|0,n=n+Math.imul(p,re)|0,i=(i=i+Math.imul(p,ne)|0)+Math.imul(m,re)|0,o=o+Math.imul(m,ne)|0;var Se=(c+(n=n+Math.imul(f,oe)|0)|0)+((8191&(i=(i=i+Math.imul(f,ae)|0)+Math.imul(l,oe)|0))<<13)|0;c=((o=o+Math.imul(l,ae)|0)+(i>>>13)|0)+(Se>>>26)|0,Se&=67108863,n=Math.imul(R,D),i=(i=Math.imul(R,q))+Math.imul(B,D)|0,o=Math.imul(B,q),n=n+Math.imul(P,H)|0,i=(i=i+Math.imul(P,V)|0)+Math.imul(O,H)|0,o=o+Math.imul(O,V)|0,n=n+Math.imul(A,W)|0,i=(i=i+Math.imul(A,Y)|0)+Math.imul(x,W)|0,o=o+Math.imul(x,Y)|0,n=n+Math.imul(M,J)|0,i=(i=i+Math.imul(M,X)|0)+Math.imul(k,J)|0,o=o+Math.imul(k,X)|0,n=n+Math.imul(w,Q)|0,i=(i=i+Math.imul(w,ee)|0)+Math.imul(_,Q)|0,o=o+Math.imul(_,ee)|0,n=n+Math.imul(b,re)|0,i=(i=i+Math.imul(b,ne)|0)+Math.imul(v,re)|0,o=o+Math.imul(v,ne)|0,n=n+Math.imul(p,oe)|0,i=(i=i+Math.imul(p,ae)|0)+Math.imul(m,oe)|0,o=o+Math.imul(m,ae)|0;var Me=(c+(n=n+Math.imul(f,ue)|0)|0)+((8191&(i=(i=i+Math.imul(f,ce)|0)+Math.imul(l,ue)|0))<<13)|0;c=((o=o+Math.imul(l,ce)|0)+(i>>>13)|0)+(Me>>>26)|0,Me&=67108863,n=Math.imul(C,D),i=(i=Math.imul(C,q))+Math.imul(j,D)|0,o=Math.imul(j,q),n=n+Math.imul(R,H)|0,i=(i=i+Math.imul(R,V)|0)+Math.imul(B,H)|0,o=o+Math.imul(B,V)|0,n=n+Math.imul(P,W)|0,i=(i=i+Math.imul(P,Y)|0)+Math.imul(O,W)|0,o=o+Math.imul(O,Y)|0,n=n+Math.imul(A,J)|0,i=(i=i+Math.imul(A,X)|0)+Math.imul(x,J)|0,o=o+Math.imul(x,X)|0,n=n+Math.imul(M,Q)|0,i=(i=i+Math.imul(M,ee)|0)+Math.imul(k,Q)|0,o=o+Math.imul(k,ee)|0,n=n+Math.imul(w,re)|0,i=(i=i+Math.imul(w,ne)|0)+Math.imul(_,re)|0,o=o+Math.imul(_,ne)|0,n=n+Math.imul(b,oe)|0,i=(i=i+Math.imul(b,ae)|0)+Math.imul(v,oe)|0,o=o+Math.imul(v,ae)|0,n=n+Math.imul(p,ue)|0,i=(i=i+Math.imul(p,ce)|0)+Math.imul(m,ue)|0,o=o+Math.imul(m,ce)|0;var ke=(c+(n=n+Math.imul(f,fe)|0)|0)+((8191&(i=(i=i+Math.imul(f,le)|0)+Math.imul(l,fe)|0))<<13)|0;c=((o=o+Math.imul(l,le)|0)+(i>>>13)|0)+(ke>>>26)|0,ke&=67108863,n=Math.imul(U,D),i=(i=Math.imul(U,q))+Math.imul(L,D)|0,o=Math.imul(L,q),n=n+Math.imul(C,H)|0,i=(i=i+Math.imul(C,V)|0)+Math.imul(j,H)|0,o=o+Math.imul(j,V)|0,n=n+Math.imul(R,W)|0,i=(i=i+Math.imul(R,Y)|0)+Math.imul(B,W)|0,o=o+Math.imul(B,Y)|0,n=n+Math.imul(P,J)|0,i=(i=i+Math.imul(P,X)|0)+Math.imul(O,J)|0,o=o+Math.imul(O,X)|0,n=n+Math.imul(A,Q)|0,i=(i=i+Math.imul(A,ee)|0)+Math.imul(x,Q)|0,o=o+Math.imul(x,ee)|0,n=n+Math.imul(M,re)|0,i=(i=i+Math.imul(M,ne)|0)+Math.imul(k,re)|0,o=o+Math.imul(k,ne)|0,n=n+Math.imul(w,oe)|0,i=(i=i+Math.imul(w,ae)|0)+Math.imul(_,oe)|0,o=o+Math.imul(_,ae)|0,n=n+Math.imul(b,ue)|0,i=(i=i+Math.imul(b,ce)|0)+Math.imul(v,ue)|0,o=o+Math.imul(v,ce)|0,n=n+Math.imul(p,fe)|0,i=(i=i+Math.imul(p,le)|0)+Math.imul(m,fe)|0,o=o+Math.imul(m,le)|0;var Ee=(c+(n=n+Math.imul(f,pe)|0)|0)+((8191&(i=(i=i+Math.imul(f,me)|0)+Math.imul(l,pe)|0))<<13)|0;c=((o=o+Math.imul(l,me)|0)+(i>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,n=Math.imul(U,H),i=(i=Math.imul(U,V))+Math.imul(L,H)|0,o=Math.imul(L,V),n=n+Math.imul(C,W)|0,i=(i=i+Math.imul(C,Y)|0)+Math.imul(j,W)|0,o=o+Math.imul(j,Y)|0,n=n+Math.imul(R,J)|0,i=(i=i+Math.imul(R,X)|0)+Math.imul(B,J)|0,o=o+Math.imul(B,X)|0,n=n+Math.imul(P,Q)|0,i=(i=i+Math.imul(P,ee)|0)+Math.imul(O,Q)|0,o=o+Math.imul(O,ee)|0,n=n+Math.imul(A,re)|0,i=(i=i+Math.imul(A,ne)|0)+Math.imul(x,re)|0,o=o+Math.imul(x,ne)|0,n=n+Math.imul(M,oe)|0,i=(i=i+Math.imul(M,ae)|0)+Math.imul(k,oe)|0,o=o+Math.imul(k,ae)|0,n=n+Math.imul(w,ue)|0,i=(i=i+Math.imul(w,ce)|0)+Math.imul(_,ue)|0,o=o+Math.imul(_,ce)|0,n=n+Math.imul(b,fe)|0,i=(i=i+Math.imul(b,le)|0)+Math.imul(v,fe)|0,o=o+Math.imul(v,le)|0;var Ae=(c+(n=n+Math.imul(p,pe)|0)|0)+((8191&(i=(i=i+Math.imul(p,me)|0)+Math.imul(m,pe)|0))<<13)|0;c=((o=o+Math.imul(m,me)|0)+(i>>>13)|0)+(Ae>>>26)|0,Ae&=67108863,n=Math.imul(U,W),i=(i=Math.imul(U,Y))+Math.imul(L,W)|0,o=Math.imul(L,Y),n=n+Math.imul(C,J)|0,i=(i=i+Math.imul(C,X)|0)+Math.imul(j,J)|0,o=o+Math.imul(j,X)|0,n=n+Math.imul(R,Q)|0,i=(i=i+Math.imul(R,ee)|0)+Math.imul(B,Q)|0,o=o+Math.imul(B,ee)|0,n=n+Math.imul(P,re)|0,i=(i=i+Math.imul(P,ne)|0)+Math.imul(O,re)|0,o=o+Math.imul(O,ne)|0,n=n+Math.imul(A,oe)|0,i=(i=i+Math.imul(A,ae)|0)+Math.imul(x,oe)|0,o=o+Math.imul(x,ae)|0,n=n+Math.imul(M,ue)|0,i=(i=i+Math.imul(M,ce)|0)+Math.imul(k,ue)|0,o=o+Math.imul(k,ce)|0,n=n+Math.imul(w,fe)|0,i=(i=i+Math.imul(w,le)|0)+Math.imul(_,fe)|0,o=o+Math.imul(_,le)|0;var xe=(c+(n=n+Math.imul(b,pe)|0)|0)+((8191&(i=(i=i+Math.imul(b,me)|0)+Math.imul(v,pe)|0))<<13)|0;c=((o=o+Math.imul(v,me)|0)+(i>>>13)|0)+(xe>>>26)|0,xe&=67108863,n=Math.imul(U,J),i=(i=Math.imul(U,X))+Math.imul(L,J)|0,o=Math.imul(L,X),n=n+Math.imul(C,Q)|0,i=(i=i+Math.imul(C,ee)|0)+Math.imul(j,Q)|0,o=o+Math.imul(j,ee)|0,n=n+Math.imul(R,re)|0,i=(i=i+Math.imul(R,ne)|0)+Math.imul(B,re)|0,o=o+Math.imul(B,ne)|0,n=n+Math.imul(P,oe)|0,i=(i=i+Math.imul(P,ae)|0)+Math.imul(O,oe)|0,o=o+Math.imul(O,ae)|0,n=n+Math.imul(A,ue)|0,i=(i=i+Math.imul(A,ce)|0)+Math.imul(x,ue)|0,o=o+Math.imul(x,ce)|0,n=n+Math.imul(M,fe)|0,i=(i=i+Math.imul(M,le)|0)+Math.imul(k,fe)|0,o=o+Math.imul(k,le)|0;var Ie=(c+(n=n+Math.imul(w,pe)|0)|0)+((8191&(i=(i=i+Math.imul(w,me)|0)+Math.imul(_,pe)|0))<<13)|0;c=((o=o+Math.imul(_,me)|0)+(i>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,n=Math.imul(U,Q),i=(i=Math.imul(U,ee))+Math.imul(L,Q)|0,o=Math.imul(L,ee),n=n+Math.imul(C,re)|0,i=(i=i+Math.imul(C,ne)|0)+Math.imul(j,re)|0,o=o+Math.imul(j,ne)|0,n=n+Math.imul(R,oe)|0,i=(i=i+Math.imul(R,ae)|0)+Math.imul(B,oe)|0,o=o+Math.imul(B,ae)|0,n=n+Math.imul(P,ue)|0,i=(i=i+Math.imul(P,ce)|0)+Math.imul(O,ue)|0,o=o+Math.imul(O,ce)|0,n=n+Math.imul(A,fe)|0,i=(i=i+Math.imul(A,le)|0)+Math.imul(x,fe)|0,o=o+Math.imul(x,le)|0;var Pe=(c+(n=n+Math.imul(M,pe)|0)|0)+((8191&(i=(i=i+Math.imul(M,me)|0)+Math.imul(k,pe)|0))<<13)|0;c=((o=o+Math.imul(k,me)|0)+(i>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,n=Math.imul(U,re),i=(i=Math.imul(U,ne))+Math.imul(L,re)|0,o=Math.imul(L,ne),n=n+Math.imul(C,oe)|0,i=(i=i+Math.imul(C,ae)|0)+Math.imul(j,oe)|0,o=o+Math.imul(j,ae)|0,n=n+Math.imul(R,ue)|0,i=(i=i+Math.imul(R,ce)|0)+Math.imul(B,ue)|0,o=o+Math.imul(B,ce)|0,n=n+Math.imul(P,fe)|0,i=(i=i+Math.imul(P,le)|0)+Math.imul(O,fe)|0,o=o+Math.imul(O,le)|0;var Oe=(c+(n=n+Math.imul(A,pe)|0)|0)+((8191&(i=(i=i+Math.imul(A,me)|0)+Math.imul(x,pe)|0))<<13)|0;c=((o=o+Math.imul(x,me)|0)+(i>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,n=Math.imul(U,oe),i=(i=Math.imul(U,ae))+Math.imul(L,oe)|0,o=Math.imul(L,ae),n=n+Math.imul(C,ue)|0,i=(i=i+Math.imul(C,ce)|0)+Math.imul(j,ue)|0,o=o+Math.imul(j,ce)|0,n=n+Math.imul(R,fe)|0,i=(i=i+Math.imul(R,le)|0)+Math.imul(B,fe)|0,o=o+Math.imul(B,le)|0;var Te=(c+(n=n+Math.imul(P,pe)|0)|0)+((8191&(i=(i=i+Math.imul(P,me)|0)+Math.imul(O,pe)|0))<<13)|0;c=((o=o+Math.imul(O,me)|0)+(i>>>13)|0)+(Te>>>26)|0,Te&=67108863,n=Math.imul(U,ue),i=(i=Math.imul(U,ce))+Math.imul(L,ue)|0,o=Math.imul(L,ce),n=n+Math.imul(C,fe)|0,i=(i=i+Math.imul(C,le)|0)+Math.imul(j,fe)|0,o=o+Math.imul(j,le)|0;var Re=(c+(n=n+Math.imul(R,pe)|0)|0)+((8191&(i=(i=i+Math.imul(R,me)|0)+Math.imul(B,pe)|0))<<13)|0;c=((o=o+Math.imul(B,me)|0)+(i>>>13)|0)+(Re>>>26)|0,Re&=67108863,n=Math.imul(U,fe),i=(i=Math.imul(U,le))+Math.imul(L,fe)|0,o=Math.imul(L,le);var Be=(c+(n=n+Math.imul(C,pe)|0)|0)+((8191&(i=(i=i+Math.imul(C,me)|0)+Math.imul(j,pe)|0))<<13)|0;c=((o=o+Math.imul(j,me)|0)+(i>>>13)|0)+(Be>>>26)|0,Be&=67108863;var Ne=(c+(n=Math.imul(U,pe))|0)+((8191&(i=(i=Math.imul(U,me))+Math.imul(L,pe)|0))<<13)|0;return c=((o=Math.imul(L,me))+(i>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,u[0]=ge,u[1]=be,u[2]=ve,u[3]=ye,u[4]=we,u[5]=_e,u[6]=Se,u[7]=Me,u[8]=ke,u[9]=Ee,u[10]=Ae,u[11]=xe,u[12]=Ie,u[13]=Pe,u[14]=Oe,u[15]=Te,u[16]=Re,u[17]=Be,u[18]=Ne,0!==c&&(u[19]=c,r.length++),r};function p(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(d=l),o.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?d(this,e,t):r<63?l(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var n=0,i=0,o=0;o>>26)|0)>>>26,a&=67108863}r.words[o]=s,n=a,a=i}return 0!==n?r.words[o]=n:r.length--,r.strip()}(this,e,t):p(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=o.prototype._countBits(e)-1,n=0;n>=1;return n},m.prototype.permute=function(e,t,r,n,i,o){for(var a=0;a>>=1)i++;return 1<>>=13,r[2*a+1]=8191&o,o>>>=13;for(a=2*t;a>=26,t+=i/67108864|0,t+=o>>>26,this.words[r]=67108863&o}return 0!==t&&(this.words[r]=t,this.length++),this},o.prototype.muln=function(e){return this.clone().imuln(e)},o.prototype.sqr=function(){return this.mul(this)},o.prototype.isqr=function(){return this.imul(this.clone())},o.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>i}return t}(e);if(0===t.length)return new o(1);for(var r=this,n=0;n=0);var t,r=e%26,i=(e-r)/26,o=67108863>>>26-r<<26-r;if(0!==r){var a=0;for(t=0;t>>26-r}a&&(this.words[t]=a,this.length++)}if(0!==i){for(t=this.length-1;t>=0;t--)this.words[t+i]=this.words[t];for(t=0;t=0),i=t?(t-t%26)/26:0;var o=e%26,a=Math.min((e-o)/26,this.length),s=67108863^67108863>>>o<a)for(this.length-=a,c=0;c=0&&(0!==h||c>=i);c--){var f=0|this.words[c];this.words[c]=h<<26-o|f>>>o,h=f&s}return u&&0!==h&&(u.words[u.length++]=h),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},o.prototype.ishrn=function(e,t,r){return n(0===this.negative),this.iushrn(e,t,r)},o.prototype.shln=function(e){return this.clone().ishln(e)},o.prototype.ushln=function(e){return this.clone().iushln(e)},o.prototype.shrn=function(e){return this.clone().ishrn(e)},o.prototype.ushrn=function(e){return this.clone().iushrn(e)},o.prototype.testn=function(e){n("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,i=1<=0);var t=e%26,r=(e-t)/26;if(n(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var i=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},o.prototype.isubn=function(e){if(n("number"==typeof e),n(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(u/67108864|0),this.words[i+r]=67108863&o}for(;i>26,this.words[i+r]=67108863&o;if(0===s)return this.strip();for(n(-1===s),s=0,i=0;i>26,this.words[i]=67108863&o;return this.negative=1,this.strip()},o.prototype._wordDiv=function(e,t){var r=(this.length,e.length),n=this.clone(),i=e,a=0|i.words[i.length-1];0!==(r=26-this._countBits(a))&&(i=i.ushln(r),n.iushln(r),a=0|i.words[i.length-1]);var s,u=n.length-i.length;if("mod"!==t){(s=new o(null)).length=u+1,s.words=new Array(s.length);for(var c=0;c=0;f--){var l=67108864*(0|n.words[i.length+f])+(0|n.words[i.length+f-1]);for(l=Math.min(l/a|0,67108863),n._ishlnsubmul(i,l,f);0!==n.negative;)l--,n.negative=0,n._ishlnsubmul(i,1,f),n.isZero()||(n.negative^=1);s&&(s.words[f]=l)}return s&&s.strip(),n.strip(),"div"!==t&&0!==r&&n.iushrn(r),{div:s||null,mod:n}},o.prototype.divmod=function(e,t,r){return n(!e.isZero()),this.isZero()?{div:new o(0),mod:new o(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(i=s.div.neg()),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.iadd(e)),{div:i,mod:a}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(i=s.div.neg()),{div:i,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.isub(e)),{div:s.div,mod:a}):e.length>this.length||this.cmp(e)<0?{div:new o(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new o(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new o(this.modn(e.words[0]))}:this._wordDiv(e,t);var i,a,s},o.prototype.div=function(e){return this.divmod(e,"div",!1).div},o.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},o.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},o.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,n=e.ushrn(1),i=e.andln(1),o=r.cmp(n);return o<0||1===i&&0===o?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},o.prototype.modn=function(e){n(e<=67108863);for(var t=(1<<26)%e,r=0,i=this.length-1;i>=0;i--)r=(t*r+(0|this.words[i]))%e;return r},o.prototype.idivn=function(e){n(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var i=(0|this.words[r])+67108864*t;this.words[r]=i/e|0,t=i%e}return this.strip()},o.prototype.divn=function(e){return this.clone().idivn(e)},o.prototype.egcd=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i=new o(1),a=new o(0),s=new o(0),u=new o(1),c=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++c;for(var h=r.clone(),f=t.clone();!t.isZero();){for(var l=0,d=1;0==(t.words[0]&d)&&l<26;++l,d<<=1);if(l>0)for(t.iushrn(l);l-- >0;)(i.isOdd()||a.isOdd())&&(i.iadd(h),a.isub(f)),i.iushrn(1),a.iushrn(1);for(var p=0,m=1;0==(r.words[0]&m)&&p<26;++p,m<<=1);if(p>0)for(r.iushrn(p);p-- >0;)(s.isOdd()||u.isOdd())&&(s.iadd(h),u.isub(f)),s.iushrn(1),u.iushrn(1);t.cmp(r)>=0?(t.isub(r),i.isub(s),a.isub(u)):(r.isub(t),s.isub(i),u.isub(a))}return{a:s,b:u,gcd:r.iushln(c)}},o.prototype._invmp=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i,a=new o(1),s=new o(0),u=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var c=0,h=1;0==(t.words[0]&h)&&c<26;++c,h<<=1);if(c>0)for(t.iushrn(c);c-- >0;)a.isOdd()&&a.iadd(u),a.iushrn(1);for(var f=0,l=1;0==(r.words[0]&l)&&f<26;++f,l<<=1);if(f>0)for(r.iushrn(f);f-- >0;)s.isOdd()&&s.iadd(u),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),a.isub(s)):(r.isub(t),s.isub(a))}return(i=0===t.cmpn(1)?a:s).cmpn(0)<0&&i.iadd(e),i},o.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var n=0;t.isEven()&&r.isEven();n++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var i=t.cmp(r);if(i<0){var o=t;t=r,r=o}else if(0===i||0===r.cmpn(1))break;t.isub(r)}return r.iushln(n)},o.prototype.invm=function(e){return this.egcd(e).a.umod(e)},o.prototype.isEven=function(){return 0==(1&this.words[0])},o.prototype.isOdd=function(){return 1==(1&this.words[0])},o.prototype.andln=function(e){return this.words[0]&e},o.prototype.bincn=function(e){n("number"==typeof e);var t=e%26,r=(e-t)/26,i=1<>>26,s&=67108863,this.words[a]=s}return 0!==o&&(this.words[a]=o,this.length++),this},o.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},o.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),n(e<=67108863,"Number is too big");var i=0|this.words[0];t=i===e?0:ie.length)return 1;if(this.length=0;r--){var n=0|this.words[r],i=0|e.words[r];if(n!==i){ni&&(t=1);break}}return t},o.prototype.gtn=function(e){return 1===this.cmpn(e)},o.prototype.gt=function(e){return 1===this.cmp(e)},o.prototype.gten=function(e){return this.cmpn(e)>=0},o.prototype.gte=function(e){return this.cmp(e)>=0},o.prototype.ltn=function(e){return-1===this.cmpn(e)},o.prototype.lt=function(e){return-1===this.cmp(e)},o.prototype.lten=function(e){return this.cmpn(e)<=0},o.prototype.lte=function(e){return this.cmp(e)<=0},o.prototype.eqn=function(e){return 0===this.cmpn(e)},o.prototype.eq=function(e){return 0===this.cmp(e)},o.red=function(e){return new S(e)},o.prototype.toRed=function(e){return n(!this.red,"Already a number in reduction context"),n(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},o.prototype.fromRed=function(){return n(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},o.prototype._forceRed=function(e){return this.red=e,this},o.prototype.forceRed=function(e){return n(!this.red,"Already a number in reduction context"),this._forceRed(e)},o.prototype.redAdd=function(e){return n(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},o.prototype.redIAdd=function(e){return n(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},o.prototype.redSub=function(e){return n(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},o.prototype.redISub=function(e){return n(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},o.prototype.redShl=function(e){return n(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},o.prototype.redMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},o.prototype.redIMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},o.prototype.redSqr=function(){return n(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},o.prototype.redISqr=function(){return n(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},o.prototype.redSqrt=function(){return n(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},o.prototype.redInvm=function(){return n(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},o.prototype.redNeg=function(){return n(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},o.prototype.redPow=function(e){return n(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function b(e,t){this.name=e,this.p=new o(t,16),this.n=this.p.bitLength(),this.k=new o(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){b.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){b.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function w(){b.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function _(){b.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function S(e){if("string"==typeof e){var t=o._prime(e);this.m=t.p,this.prime=t}else n(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function M(e){S.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new o(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}b.prototype._tmp=function(){var e=new o(null);return e.words=new Array(Math.ceil(this.n/13)),e},b.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var n=t0?r.isub(this.p):void 0!==r.strip?r.strip():r._strip(),r},b.prototype.split=function(e,t){e.iushrn(this.n,0,t)},b.prototype.imulK=function(e){return e.imul(this.k)},i(v,b),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),n=0;n>>22,i=o}i>>>=22,e.words[n-10]=i,0===i&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=i,t=n}return 0!==t&&(e.words[e.length++]=t),e},o._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new w;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new _}return g[e]=t,t},S.prototype._verify1=function(e){n(0===e.negative,"red works only with positives"),n(e.red,"red works only with red numbers")},S.prototype._verify2=function(e,t){n(0==(e.negative|t.negative),"red works only with positives"),n(e.red&&e.red===t.red,"red works only with red numbers")},S.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},S.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},S.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},S.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},S.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},S.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},S.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},S.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},S.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},S.prototype.isqr=function(e){return this.imul(e,e.clone())},S.prototype.sqr=function(e){return this.mul(e,e)},S.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(n(t%2==1),3===t){var r=this.m.add(new o(1)).iushrn(2);return this.pow(e,r)}for(var i=this.m.subn(1),a=0;!i.isZero()&&0===i.andln(1);)a++,i.iushrn(1);n(!i.isZero());var s=new o(1).toRed(this),u=s.redNeg(),c=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new o(2*h*h).toRed(this);0!==this.pow(h,c).cmp(u);)h.redIAdd(u);for(var f=this.pow(h,i),l=this.pow(e,i.addn(1).iushrn(1)),d=this.pow(e,i),p=a;0!==d.cmp(s);){for(var m=d,g=0;0!==m.cmp(s);g++)m=m.redSqr();n(g=0;n--){for(var c=t.words[n],h=u-1;h>=0;h--){var f=c>>h&1;i!==r[0]&&(i=this.sqr(i)),0!==f||0!==a?(a<<=1,a|=f,(4===++s||0===n&&0===h)&&(i=this.mul(i,r[a]),s=0,a=0)):s=0}u=26}return i},S.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},S.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},o.mont=function(e){return new M(e)},i(M,S),M.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},M.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},M.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),o=i;return i.cmp(this.m)>=0?o=i.isub(this.m):i.cmpn(0)<0&&(o=i.iadd(this.m)),o._forceRed(this)},M.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new o(0)._forceRed(this);var r=e.mul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),a=i;return i.cmp(this.m)>=0?a=i.isub(this.m):i.cmpn(0)<0&&(a=i.iadd(this.m)),a._forceRed(this)},M.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(28)(e))},function(e,t,r){"use strict";var n=r(3),i=function(e){return!!n.isString(e)&&/^[0-9a-fA-F]+$/.test(e)};e.exports={isValidJSON:function(e){var t;if(!n.isString(e))return!1;try{t=JSON.parse(e)}catch(e){return!1}return"object"==typeof t},isHexa:i,isHexaString:i,cloneArray:function(e){return[].concat(e)},defineImmutable:function(e,t){return Object.keys(t).forEach((function(r){Object.defineProperty(e,r,{configurable:!1,enumerable:!0,value:t[r]})})),e},isNaturalNumber:function(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e&&e>=0}}},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t){var r,n,i=e.exports={};function o(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(e){if(r===setTimeout)return setTimeout(e,0);if((r===o||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r="function"==typeof setTimeout?setTimeout:o}catch(e){r=o}try{n="function"==typeof clearTimeout?clearTimeout:a}catch(e){n=a}}();var u,c=[],h=!1,f=-1;function l(){h&&u&&(h=!1,u.length?c=u.concat(c):f=-1,c.length&&d())}function d(){if(!h){var e=s(l);h=!0;for(var t=c.length;t;){for(u=c,c=[];++f1)for(var r=1;re.size?r=n.trim(r,o):o0&&0==(127&e[e.length-1])&&(e.length<=1||0==(128&e[e.length-2])))throw new Error("non-minimally encoded script number");return n.fromSM(e,{endian:"little"})},n.prototype.toScriptNumBuffer=function(){return this.toSM({endian:"little"})},n.trim=function(e,t){return e.slice(t-e.length,e.length)},n.pad=function(e,r,n){for(var i=t.alloc(n),o=0;oa)n=e(n);else if(n73)return!1;if(48!==e[0])return!1;if(e[1]!==e.length-3)return!1;var t=e[3];if(5+t>=e.length)return!1;var r=e[5+t];if(t+r+7!==e.length)return!1;var n=e.slice(4);if(2!==e[2])return!1;if(0===t)return!1;if(128&n[0])return!1;if(t>1&&0===n[0]&&!(128&n[1]))return!1;var i=e.slice(6+t);return 2===e[6+t-2]&&(0!==r&&(!(128&i[0])&&!(r>1&&0===i[0]&&!(128&i[1]))))},u.prototype.hasLowS=function(){return!this.s.lt(new n(1))&&!this.s.gt(new n("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0","hex"))},u.prototype.hasDefinedHashtype=function(){if(!s.isNaturalNumber(this.nhashtype))return!1;var e=this.nhashtype&~u.SIGHASH_ANYONECANPAY;return!(eu.SIGHASH_SINGLE)},u.prototype.toTxFormat=function(){var e=this.toDER(),r=t.alloc(1);return r.writeUInt8(this.nhashtype,0),t.concat([e,r])},u.SIGHASH_ALL=1,u.SIGHASH_NONE=2,u.SIGHASH_SINGLE=3,u.SIGHASH_ANYONECANPAY=128,e.exports=u}).call(this,r(0).Buffer)},function(e,t,r){e.exports=r(181),e.exports.Interpreter=r(368)},function(e,t,r){"use strict";var n=t,i=r(6),o=r(16),a=r(134);n.assert=o,n.toArray=a.toArray,n.zero2=a.zero2,n.toHex=a.toHex,n.encode=a.encode,n.getNAF=function(e,t,r){var n=new Array(Math.max(e.bitLength(),r)+1);n.fill(0);for(var i=1<(i>>1)-1?(i>>1)-u:u,o.isubn(s)):s=0,n[a]=s,o.iushrn(1)}return n},n.getJSF=function(e,t){var r=[[],[]];e=e.clone(),t=t.clone();for(var n=0,i=0;e.cmpn(-n)>0||t.cmpn(-i)>0;){var o,a,s,u=e.andln(3)+n&3,c=t.andln(3)+i&3;if(3===u&&(u=-1),3===c&&(c=-1),0==(1&u))o=0;else o=3!==(s=e.andln(7)+n&7)&&5!==s||2!==c?u:-u;if(r[0].push(o),0==(1&c))a=0;else a=3!==(s=t.andln(7)+i&7)&&5!==s||2!==u?c:-c;r[1].push(a),2*n===o+1&&(n=1-n),2*i===a+1&&(i=1-i),e.iushrn(1),t.iushrn(1)}return r},n.cachedProperty=function(e,t,r){var n="_"+t;e.prototype[t]=function(){return void 0!==this[n]?this[n]:this[n]=r.call(this)}},n.parseBytes=function(e){return"string"==typeof e?n.toArray(e,"hex"):e},n.intFromLE=function(e){return new i(e,"hex","le")}},function(e,t){function r(e,t){if(!e)throw new Error(t||"Assertion failed")}e.exports=r,r.equal=function(e,t,r){if(e!=t)throw new Error(r||"Assertion failed: "+e+" != "+t)}},function(e,t,r){"use strict";var n=r(3);function i(e,t){return e.replace("{0}",t[0]).replace("{1}",t[1]).replace("{2}",t[2])}var o=function(e,t){var r=function(){if(n.isString(t.message))this.message=i(t.message,arguments);else{if(!n.isFunction(t.message))throw new Error("Invalid error definition for "+t.name);this.message=t.message.apply(null,arguments)}this.stack=this.message+"\n"+(new Error).stack};return(r.prototype=Object.create(e.prototype)).name=e.prototype.name+t.name,e[t.name]=r,t.errors&&a(r,t.errors),r},a=function(e,t){n.each(t,(function(t){o(e,t)}))},s={Error:function(){this.message="Internal error",this.stack=this.message+"\n"+(new Error).stack}};s.Error.prototype=Object.create(Error.prototype),s.Error.prototype.name="bitcore.Error";var u,c=r(328);u=s.Error,a(u,c),e.exports=s.Error,e.exports.extend=function(e){return o(s.Error,e)}},function(e,t,r){"use strict";var n=r(16),i=r(1);function o(e,t){return 55296==(64512&e.charCodeAt(t))&&(!(t<0||t+1>=e.length)&&56320==(64512&e.charCodeAt(t+1)))}function a(e){return(e>>>24|e>>>8&65280|e<<8&16711680|(255&e)<<24)>>>0}function s(e){return 1===e.length?"0"+e:e}function u(e){return 7===e.length?"0"+e:6===e.length?"00"+e:5===e.length?"000"+e:4===e.length?"0000"+e:3===e.length?"00000"+e:2===e.length?"000000"+e:1===e.length?"0000000"+e:e}t.inherits=i,t.toArray=function(e,t){if(Array.isArray(e))return e.slice();if(!e)return[];var r=[];if("string"==typeof e)if(t){if("hex"===t)for((e=e.replace(/[^a-z0-9]+/gi,"")).length%2!=0&&(e="0"+e),i=0;i>6|192,r[n++]=63&a|128):o(e,i)?(a=65536+((1023&a)<<10)+(1023&e.charCodeAt(++i)),r[n++]=a>>18|240,r[n++]=a>>12&63|128,r[n++]=a>>6&63|128,r[n++]=63&a|128):(r[n++]=a>>12|224,r[n++]=a>>6&63|128,r[n++]=63&a|128)}else for(i=0;i>>0}return a},t.split32=function(e,t){for(var r=new Array(4*e.length),n=0,i=0;n>>24,r[i+1]=o>>>16&255,r[i+2]=o>>>8&255,r[i+3]=255&o):(r[i+3]=o>>>24,r[i+2]=o>>>16&255,r[i+1]=o>>>8&255,r[i]=255&o)}return r},t.rotr32=function(e,t){return e>>>t|e<<32-t},t.rotl32=function(e,t){return e<>>32-t},t.sum32=function(e,t){return e+t>>>0},t.sum32_3=function(e,t,r){return e+t+r>>>0},t.sum32_4=function(e,t,r,n){return e+t+r+n>>>0},t.sum32_5=function(e,t,r,n,i){return e+t+r+n+i>>>0},t.sum64=function(e,t,r,n){var i=e[t],o=n+e[t+1]>>>0,a=(o>>0,e[t+1]=o},t.sum64_hi=function(e,t,r,n){return(t+n>>>0>>0},t.sum64_lo=function(e,t,r,n){return t+n>>>0},t.sum64_4_hi=function(e,t,r,n,i,o,a,s){var u=0,c=t;return u+=(c=c+n>>>0)>>0)>>0)>>0},t.sum64_4_lo=function(e,t,r,n,i,o,a,s){return t+n+o+s>>>0},t.sum64_5_hi=function(e,t,r,n,i,o,a,s,u,c){var h=0,f=t;return h+=(f=f+n>>>0)>>0)>>0)>>0)>>0},t.sum64_5_lo=function(e,t,r,n,i,o,a,s,u,c){return t+n+o+s+c>>>0},t.rotr64_hi=function(e,t,r){return(t<<32-r|e>>>r)>>>0},t.rotr64_lo=function(e,t,r){return(e<<32-r|t>>>r)>>>0},t.shr64_hi=function(e,t,r){return e>>>r},t.shr64_lo=function(e,t,r){return(e<<32-r|t>>>r)>>>0}},function(e,t,r){"use strict";(function(t){var n=r(10),i=r(38),o=r(11),a=r(7),s=r(32),u=r(3),c=r(4);function h(e,t){if(!(this instanceof h))return new h(e,t);if(c.checkArgument(e,"First argument is required, please include public key data."),e instanceof h)return e;t=t||{};var r=this._classifyArgs(e,t);return r.point.validate(),a.defineImmutable(this,{point:r.point,compressed:r.compressed,network:r.network||s.defaultNetwork}),this}h.prototype._classifyArgs=function(e,r){var n={compressed:u.isUndefined(r.compressed)||r.compressed};if(e instanceof i)n.point=e;else if(e.x&&e.y)n=h._transformObject(e);else if("string"==typeof e)n=h._transformDER(t.from(e,"hex"));else if(h._isBuffer(e))n=h._transformDER(e);else{if(!h._isPrivateKey(e))throw new TypeError("First argument is an unrecognized data format.");n=h._transformPrivateKey(e)}return n.network||(n.network=u.isUndefined(r.network)?void 0:s.get(r.network)),n},h._isPrivateKey=function(e){return e instanceof r(48)},h._isBuffer=function(e){return e instanceof t||e instanceof Uint8Array},h._transformPrivateKey=function(e){c.checkArgument(h._isPrivateKey(e),"Must be an instance of PrivateKey");var t={};return t.point=i.getG().mul(e.bn),t.compressed=e.compressed,t.network=e.network,t},h._transformDER=function(e,t){c.checkArgument(h._isBuffer(e),"Must be a hex buffer of DER encoded public key");var r,o,a,s,f={};if(t=!!u.isUndefined(t)||t,4!==e[0]&&(t||6!==e[0]&&7!==e[0]))if(3===e[0])a=e.slice(1),r=new n(a),(f=h._transformX(!0,r)).compressed=!0;else{if(2!==e[0])throw new TypeError("Invalid DER format public key");a=e.slice(1),r=new n(a),(f=h._transformX(!1,r)).compressed=!0}else{if(a=e.slice(1,33),s=e.slice(33,65),32!==a.length||32!==s.length||65!==e.length)throw new TypeError("Length of x and y must be 32 bytes");r=new n(a),o=new n(s),f.point=new i(r,o),f.compressed=!1}return f},h._transformX=function(e,t){c.checkArgument("boolean"==typeof e,"Must specify whether y is odd or not (true or false)");var r={};return r.point=i.fromX(e,t),r},h._transformObject=function(e){var t=new n(e.x,"hex"),r=new n(e.y,"hex");return new h(new i(t,r),{compressed:e.compressed})},h.fromPrivateKey=function(e){c.checkArgument(h._isPrivateKey(e),"Must be an instance of PrivateKey");var t=h._transformPrivateKey(e);return new h(t.point,{compressed:t.compressed,network:t.network})},h.fromDER=h.fromBuffer=function(e,t){c.checkArgument(h._isBuffer(e),"Must be a hex buffer of DER encoded public key");var r=h._transformDER(e,t);return new h(r.point,{compressed:r.compressed})},h.fromPoint=function(e,t){return c.checkArgument(e instanceof i,"First argument must be an instance of Point."),new h(e,{compressed:t})},h.fromString=function(e,r){var n=t.from(e,r||"hex"),i=h._transformDER(n);return new h(i.point,{compressed:i.compressed})},h.fromX=function(e,t){var r=h._transformX(e,t);return new h(r.point,{compressed:r.compressed})},h.getValidationError=function(e){var t;try{new h(e)}catch(e){t=e}return t},h.isValid=function(e){return!h.getValidationError(e)},h.prototype.toObject=h.prototype.toJSON=function(){return{x:this.point.getX().toString("hex",2),y:this.point.getY().toString("hex",2),compressed:this.compressed}},h.prototype.toBuffer=h.prototype.toDER=function(){var e,r=this.point.getX(),n=this.point.getY(),i=r.toBuffer({size:32}),o=n.toBuffer({size:32});return this.compressed?(e=o[o.length-1]%2?t.from([3]):t.from([2]),t.concat([e,i])):(e=t.from([4]),t.concat([e,i,o]))},h.prototype._getID=function(){return o.sha256ripemd160(this.toBuffer())},h.prototype.toAddress=function(e,t){return r(20).fromPublicKey(this,e||this.network,t)},h.prototype.toString=function(){return this.toDER().toString("hex")},h.prototype.inspect=function(){return""},e.exports=h}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4),o=r(17),a=r(49),s=r(366),u=r(32),c=r(11),h=r(7),f=r(19);function l(e,t,r,o){if(!(this instanceof l))return new l(e,t,r);if(n.isArray(e)&&n.isNumber(t))return l.createMultisig(e,t,r,!1,o);if(e instanceof l)return e;if(i.checkArgument(e,"First argument is required, please include address data.","guide/address.html"),t&&!u.get(t))throw new TypeError('Second argument must be "livenet" or "testnet".');if(r&&r!==l.PayToPublicKeyHash&&r!==l.PayToScriptHash&&r!==l.PayToWitnessPublicKeyHash&&r!==l.PayToWitnessScriptHash)throw new TypeError('Third argument must be "pubkeyhash", "scripthash", "witnesspubkeyhash", or "witnessscripthash".');var a=this._classifyArguments(e,t,r);return a.network=a.network||u.get(t)||u.defaultNetwork,a.type=a.type||r||l.PayToPublicKeyHash,h.defineImmutable(this,{hashBuffer:a.hashBuffer,network:a.network,type:a.type}),this}l.prototype._classifyArguments=function(e,r,i){if(!(e instanceof t||e instanceof Uint8Array)||20!==e.length&&32!==e.length){if((e instanceof t||e instanceof Uint8Array)&&e.length>=21)return l._transformBuffer(e,r,i);if(e instanceof f)return l._transformPublicKey(e,r,i);if(e instanceof d)return l._transformScript(e,r);if("string"==typeof e)return l._transformString(e,r,i);if(n.isObject(e))return l._transformObject(e);throw new TypeError("First argument is an unrecognized data format.")}return l._transformHash(e,r,i)},l.PayToPublicKeyHash="pubkeyhash",l.PayToScriptHash="scripthash",l.PayToWitnessPublicKeyHash="witnesspubkeyhash",l.PayToWitnessScriptHash="witnessscripthash",l._transformHash=function(e,r,n){var i={};if(!(e instanceof t||e instanceof Uint8Array))throw new TypeError("Address supplied is not a buffer.");if(20!==e.length&&32!==e.length)throw new TypeError("Address hashbuffers must be either 20 or 32 bytes.");return i.hashBuffer=e,i.network=u.get(r)||u.defaultNetwork,i.type=n,i},l._transformObject=function(e){return i.checkArgument(e.hash||e.hashBuffer,"Must provide a `hash` or `hashBuffer` property"),i.checkArgument(e.type,"Must provide a `type` property"),{hashBuffer:e.hash?t.from(e.hash,"hex"):e.hashBuffer,network:u.get(e.network)||u.defaultNetwork,type:e.type}},l._classifyFromVersion=function(e){var t={};if(e.length>21){var r=s.decode(e.toString("utf8"));if(0!==r.version)throw new TypeError("Only witness v0 addresses are supported.");if(20===r.data.length)t.type=l.PayToWitnessPublicKeyHash;else{if(32!==r.data.length)throw new TypeError("Witness data must be either 20 or 32 bytes.");t.type=l.PayToWitnessScriptHash}t.network=u.get(r.prefix,"bech32prefix")}else{var n=u.get(e[0],"pubkeyhash"),i=u.get(e[0],"scripthash");n?(t.network=n,t.type=l.PayToPublicKeyHash):i&&(t.network=i,t.type=l.PayToScriptHash)}return t},l._transformBuffer=function(e,r,n){var i={};if(!(e instanceof t||e instanceof Uint8Array))throw new TypeError("Address supplied is not a buffer.");if(e.length<21)throw new TypeError("Address buffer is incorrect length.");var o=u.get(r),a=l._classifyFromVersion(e);if(r&&!o)throw new TypeError("Unknown network");if(!a.network||o&&o.xpubkey!==a.network.xpubkey)throw new TypeError("Address has mismatched network type.");if(!a.type||n&&n!==a.type)throw new TypeError("Address has mismatched type.");return e.length>21?i.hashBuffer=s.decode(e.toString("utf8")).data:i.hashBuffer=e.slice(1),i.network=a.network,i.type=a.type,i},l._transformPublicKey=function(e,t,r){var n={};if(!(e instanceof f))throw new TypeError("Address must be an instance of PublicKey.");if(r&&r!==l.PayToScriptHash&&r!==l.PayToWitnessPublicKeyHash&&r!==l.PayToPublicKeyHash)throw new TypeError("Type must be either pubkeyhash, witnesspubkeyhash, or scripthash to transform public key.");if(!e.compressed&&(r===l.PayToScriptHash||r===l.PayToWitnessPublicKeyHash))throw new TypeError("Witness addresses must use compressed public keys.");return r===l.PayToScriptHash?n.hashBuffer=c.sha256ripemd160(d.buildWitnessV0Out(e).toBuffer()):n.hashBuffer=c.sha256ripemd160(e.toBuffer()),n.type=r||l.PayToPublicKeyHash,n},l._transformScript=function(e,t){i.checkArgument(e instanceof d,"script must be a Script instance");var r=e.getAddressInfo(t);if(!r)throw new o.Script.CantDeriveAddress(e);return r},l.createMultisig=function(e,t,r,i,o){if(r=r||e[0].network||u.defaultNetwork,o&&o!==l.PayToScriptHash&&o!==l.PayToWitnessScriptHash)throw new TypeError("Type must be either scripthash or witnessscripthash to create multisig.");if(i||o===l.PayToWitnessScriptHash){e=n.map(e,f);for(var a=0;a100)throw new TypeError("address string is too long");if(r&&!u.get(r))throw new TypeError("Unknown network");e=e.trim();try{return l._transformBuffer(t.from(e,"utf8"),r,n)}catch(e){if(n===l.PayToWitnessPublicKeyHash||n===l.PayToWitnessScriptHash)throw e}var i=a.decode(e);return l._transformBuffer(i,r,n)},l.fromPublicKey=function(e,t,r){var n=l._transformPublicKey(e,t,r);return t=t||u.defaultNetwork,new l(n.hashBuffer,t,n.type)},l.fromPublicKeyHash=function(e,t){var r=l._transformHash(e);return new l(r.hashBuffer,t,l.PayToPublicKeyHash)},l.fromScriptHash=function(e,t,r){i.checkArgument(e,"hash parameter is required");var n=l._transformHash(e);if(r===l.PayToWitnessScriptHash&&32!==e.length)throw new TypeError("Address hashbuffer must be exactly 32 bytes for v0 witness script hash.");r=r||l.PayToScriptHash;return new l(n.hashBuffer,t,r)},l.payingTo=function(e,t,r){var n;i.checkArgument(e,"script is required"),i.checkArgument(e instanceof d,"script must be instance of Script"),n=r===l.PayToWitnessScriptHash?c.sha256(e.toBuffer()):c.sha256ripemd160(e.toBuffer());r=r||l.PayToScriptHash;return l.fromScriptHash(n,t,r)},l.fromScript=function(e,t){i.checkArgument(e instanceof d,"script must be a Script instance");var r=l._transformScript(e,t);return new l(r.hashBuffer,t,r.type)},l.fromBuffer=function(e,t,r){var n=l._transformBuffer(e,t,r);return new l(n.hashBuffer,n.network,n.type)},l.fromString=function(e,t,r){var n=l._transformString(e,t,r);return new l(n.hashBuffer,n.network,n.type)},l.fromObject=function(e){return i.checkState(h.isHexa(e.hash),'Unexpected hash property, "'+e.hash+'", expected to be hex.'),new l(t.from(e.hash,"hex"),e.network,e.type)},l.getValidationError=function(e,t,r){var n;try{new l(e,t,r)}catch(e){n=e}return n},l.isValid=function(e,t,r){return!l.getValidationError(e,t,r)},l.prototype.isPayToPublicKeyHash=function(){return this.type===l.PayToPublicKeyHash},l.prototype.isPayToScriptHash=function(){return this.type===l.PayToScriptHash},l.prototype.isPayToWitnessPublicKeyHash=function(){return this.type===l.PayToWitnessPublicKeyHash},l.prototype.isPayToWitnessScriptHash=function(){return this.type===l.PayToWitnessScriptHash},l.prototype.toBuffer=function(){if(this.isPayToWitnessPublicKeyHash()||this.isPayToWitnessScriptHash())return t.from(this.toString(),"utf8");var e=t.from([this.network[this.type]]);return t.concat([e,this.hashBuffer])},l.prototype.toObject=l.prototype.toJSON=function(){return{hash:this.hashBuffer.toString("hex"),type:this.type,network:this.network.toString()}},l.prototype.toString=function(){if(this.isPayToWitnessPublicKeyHash()||this.isPayToWitnessScriptHash()){var e=this.network.bech32prefix;return s.encode(e,0,this.hashBuffer)}return a.encode(this.toBuffer())},l.prototype.inspect=function(){return""},e.exports=l;var d=r(14)}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4),o=r(5),a=r(10),s=function e(r){if(!(this instanceof e))return new e(r);if(!n.isUndefined(r))if(t.isBuffer(r))this.set({buf:r});else if(n.isString(r))this.set({buf:t.from(r,"hex")});else{if(!n.isObject(r))throw new TypeError("Unrecognized argument for BufferReader");var i=r;this.set(i)}};s.prototype.set=function(e){return this.buf=e.buf||this.buf||void 0,this.pos=e.pos||this.pos||0,this},s.prototype.eof=function(){return!this.buf||this.pos>=this.buf.length},s.prototype.finished=s.prototype.eof,s.prototype.read=function(e){i.checkArgument(!n.isUndefined(e),"Must specify a length");var t=this.buf.slice(this.pos,this.pos+e);return this.pos=this.pos+e,t},s.prototype.readAll=function(){var e=this.buf.slice(this.pos,this.buf.length);return this.pos=this.buf.length,e},s.prototype.readUInt8=function(){var e=this.buf.readUInt8(this.pos);return this.pos=this.pos+1,e},s.prototype.readUInt16BE=function(){var e=this.buf.readUInt16BE(this.pos);return this.pos=this.pos+2,e},s.prototype.readUInt16LE=function(){var e=this.buf.readUInt16LE(this.pos);return this.pos=this.pos+2,e},s.prototype.readUInt32BE=function(){var e=this.buf.readUInt32BE(this.pos);return this.pos=this.pos+4,e},s.prototype.readUInt32LE=function(){var e=this.buf.readUInt32LE(this.pos);return this.pos=this.pos+4,e},s.prototype.readInt32LE=function(){var e=this.buf.readInt32LE(this.pos);return this.pos=this.pos+4,e},s.prototype.readUInt64BEBN=function(){var e=this.buf.slice(this.pos,this.pos+8),t=a.fromBuffer(e);return this.pos=this.pos+8,t},s.prototype.readUInt64LEBN=function(){var e,t=this.buf.readUInt32LE(this.pos),r=4294967296*this.buf.readUInt32LE(this.pos+4)+t;if(r<=9007199254740991)e=new a(r);else{var n=Array.prototype.slice.call(this.buf,this.pos,this.pos+8);e=new a(n,10,"le")}return this.pos=this.pos+8,e},s.prototype.readVarintNum=function(){var e=this.readUInt8();switch(e){case 253:return this.readUInt16LE();case 254:return this.readUInt32LE();case 255:var t=this.readUInt64LEBN().toNumber();if(t<=Math.pow(2,53))return t;throw new Error("number too large to retain precision - use readVarintBN");default:return e}},s.prototype.readVarLengthBuffer=function(){var e=this.readVarintNum(),t=this.read(e);return i.checkState(t.length===e,"Invalid length while reading varlength buffer. Expected to read: "+e+" and read "+t.length),t},s.prototype.readVarintBuf=function(){switch(this.buf.readUInt8(this.pos)){case 253:return this.read(3);case 254:return this.read(5);case 255:return this.read(9);default:return this.read(1)}},s.prototype.readVarintBN=function(){var e=this.readUInt8();switch(e){case 253:return new a(this.readUInt16LE());case 254:return new a(this.readUInt32LE());case 255:return this.readUInt64LEBN();default:return new a(e)}},s.prototype.reverse=function(){for(var e=t.alloc(this.buf.length),r=0;r9007199254740991?"transaction txout satoshis greater than max safe integer":this._satoshis!==this._satoshisBN.toNumber()?"transaction txout satoshis has corrupted value":this._satoshis<0&&"transaction txout negative"},f.prototype.toObject=f.prototype.toJSON=function(){var e={satoshis:this.satoshis};return e.script=this._scriptBuffer.toString("hex"),e},f.fromObject=function(e){return new f(e)},f.prototype.setScriptFromBuffer=function(e){this._scriptBuffer=e;try{this._script=u.fromBuffer(this._scriptBuffer),this._script._isOutput=!0}catch(e){if(!(e instanceof h.Script.InvalidBuffer))throw e;this._script=null}},f.prototype.setScript=function(e){if(e instanceof u)this._scriptBuffer=e.toBuffer(),this._script=e,this._script._isOutput=!0;else if(n.isString(e))this._script=u.fromString(e),this._scriptBuffer=this._script.toBuffer(),this._script._isOutput=!0;else{if(!o.isBuffer(e))throw new TypeError("Invalid argument type: script");this.setScriptFromBuffer(e)}return this},f.prototype.inspect=function(){var e;return e=this.script?this.script.inspect():this._scriptBuffer.toString("hex"),""},f.fromBufferReader=function(e){var r={};r.satoshis=e.readUInt64LEBN();var n=e.readVarintNum();return r.script=0!==n?e.read(n):t.from([]),new f(r)},f.prototype.toBufferWriter=function(e){e||(e=new s),e.writeUInt64LEBN(this._satoshisBN);var t=this._scriptBuffer;return e.writeVarintNum(t.length),e.write(t),e},e.exports=f}).call(this,r(0).Buffer)},function(e,t,r){var n;!function(i){"use strict";var o,a=/^-?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i,s=Math.ceil,u=Math.floor,c="[BigNumber Error] ",h=c+"Number primitive has more than 15 significant digits: ",f=1e14,l=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],d=1e9;function p(e){var t=0|e;return e>0||e===t?t:t-1}function m(e){for(var t,r,n=1,i=e.length,o=e[0]+"";nc^r?1:-1;for(s=(u=i.length)<(c=o.length)?u:c,a=0;ao[a]^r?1:-1;return u==c?0:u>c^r?1:-1}function b(e,t,r,n){if(er||e!==u(e))throw Error(c+(n||"Argument")+("number"==typeof e?er?" out of range: ":" not an integer: ":" not a primitive number: ")+String(e))}function v(e){var t=e.c.length-1;return p(e.e/14)==t&&e.c[t]%2!=0}function y(e,t){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(t<0?"e":"e+")+t}function w(e,t,r){var n,i;if(t<0){for(i=r+".";++t;i+=r);e=i+e}else if(++t>(n=e.length)){for(i=r,t-=n;--t;i+=r);e+=i}else tB?m.c=m.e=null:e.e=10;f/=10,c++);return void(c>B?m.c=m.e=null:(m.e=c,m.c=[e]))}p=String(e)}else{if(!a.test(p=String(e)))return i(m,p,l);m.s=45==p.charCodeAt(0)?(p=p.slice(1),-1):1}(c=p.indexOf("."))>-1&&(p=p.replace(".","")),(f=p.search(/e/i))>0?(c<0&&(c=f),c+=+p.slice(f+1),p=p.substring(0,f)):c<0&&(c=p.length)}else{if(b(t,2,U.length,"Base"),10==t)return K(m=new L(e),I+m.e+1,P);if(p=String(e),l="number"==typeof e){if(0*e!=0)return i(m,p,l,t);if(m.s=1/e<0?(p=p.slice(1),-1):1,L.DEBUG&&p.replace(/^0\.0*|\./,"").length>15)throw Error(h+e)}else m.s=45===p.charCodeAt(0)?(p=p.slice(1),-1):1;for(r=U.slice(0,t),c=f=0,d=p.length;fc){c=d;continue}}else if(!s&&(p==p.toUpperCase()&&(p=p.toLowerCase())||p==p.toLowerCase()&&(p=p.toUpperCase()))){s=!0,f=-1,c=0;continue}return i(m,String(e),l,t)}l=!1,(c=(p=n(p,t,10,m.s)).indexOf("."))>-1?p=p.replace(".",""):c=p.length}for(f=0;48===p.charCodeAt(f);f++);for(d=p.length;48===p.charCodeAt(--d););if(p=p.slice(f,++d)){if(d-=f,l&&L.DEBUG&&d>15&&(e>9007199254740991||e!==u(e)))throw Error(h+m.s*e);if((c=c-f-1)>B)m.c=m.e=null;else if(c=T)?y(u,a):w(u,a,"0");else if(o=(e=K(new L(e),t,r)).e,s=(u=m(e.c)).length,1==n||2==n&&(t<=o||o<=O)){for(;ss){if(--t>0)for(u+=".";t--;u+="0");}else if((t+=o-s)>0)for(o+1==s&&(u+=".");t--;u+="0");return e.s<0&&i?"-"+u:u}function D(e,t){for(var r,n=1,i=new L(e[0]);n=10;i/=10,n++);return(r=n+14*r-1)>B?e.c=e.e=null:r=10;c/=10,i++);if((o=t-i)<0)o+=14,a=t,p=(h=m[d=0])/g[i-a-1]%10|0;else if((d=s((o+1)/14))>=m.length){if(!n)break e;for(;m.length<=d;m.push(0));h=p=0,i=1,a=(o%=14)-14+1}else{for(h=c=m[d],i=1;c>=10;c/=10,i++);p=(a=(o%=14)-14+i)<0?0:h/g[i-a-1]%10|0}if(n=n||t<0||null!=m[d+1]||(a<0?h:h%g[i-a-1]),n=r<4?(p||n)&&(0==r||r==(e.s<0?3:2)):p>5||5==p&&(4==r||n||6==r&&(o>0?a>0?h/g[i-a]:0:m[d-1])%10&1||r==(e.s<0?8:7)),t<1||!m[0])return m.length=0,n?(t-=e.e+1,m[0]=g[(14-t%14)%14],e.e=-t||0):m[0]=e.e=0,e;if(0==o?(m.length=d,c=1,d--):(m.length=d+1,c=g[14-o],m[d]=a>0?u(h/g[i-a]%g[a])*c:0),n)for(;;){if(0==d){for(o=1,a=m[0];a>=10;a/=10,o++);for(a=m[0]+=c,c=1;a>=10;a/=10,c++);o!=c&&(e.e++,m[0]==f&&(m[0]=1));break}if(m[d]+=c,m[d]!=f)break;m[d--]=0,c=1}for(o=m.length;0===m[--o];m.pop());}e.e>B?e.c=e.e=null:e.e=T?y(t,r):w(t,r,"0"),e.s<0?"-"+t:t)}return L.clone=e,L.ROUND_UP=0,L.ROUND_DOWN=1,L.ROUND_CEIL=2,L.ROUND_FLOOR=3,L.ROUND_HALF_UP=4,L.ROUND_HALF_DOWN=5,L.ROUND_HALF_EVEN=6,L.ROUND_HALF_CEIL=7,L.ROUND_HALF_FLOOR=8,L.EUCLID=9,L.config=L.set=function(e){var t,r;if(null!=e){if("object"!=typeof e)throw Error(c+"Object expected: "+e);if(e.hasOwnProperty(t="DECIMAL_PLACES")&&(b(r=e[t],0,d,t),I=r),e.hasOwnProperty(t="ROUNDING_MODE")&&(b(r=e[t],0,8,t),P=r),e.hasOwnProperty(t="EXPONENTIAL_AT")&&((r=e[t])&&r.pop?(b(r[0],-d,0,t),b(r[1],0,d,t),O=r[0],T=r[1]):(b(r,-d,d,t),O=-(T=r<0?-r:r))),e.hasOwnProperty(t="RANGE"))if((r=e[t])&&r.pop)b(r[0],-d,-1,t),b(r[1],1,d,t),R=r[0],B=r[1];else{if(b(r,-d,d,t),!r)throw Error(c+t+" cannot be zero: "+r);R=-(B=r<0?-r:r)}if(e.hasOwnProperty(t="CRYPTO")){if((r=e[t])!==!!r)throw Error(c+t+" not true or false: "+r);if(r){if("undefined"==typeof crypto||!crypto||!crypto.getRandomValues&&!crypto.randomBytes)throw N=!r,Error(c+"crypto unavailable");N=r}else N=r}if(e.hasOwnProperty(t="MODULO_MODE")&&(b(r=e[t],0,9,t),C=r),e.hasOwnProperty(t="POW_PRECISION")&&(b(r=e[t],0,d,t),j=r),e.hasOwnProperty(t="FORMAT")){if("object"!=typeof(r=e[t]))throw Error(c+t+" not an object: "+r);z=r}if(e.hasOwnProperty(t="ALPHABET")){if("string"!=typeof(r=e[t])||/^.?$|[+\-.\s]|(.).*\1/.test(r))throw Error(c+t+" invalid: "+r);U=r}}return{DECIMAL_PLACES:I,ROUNDING_MODE:P,EXPONENTIAL_AT:[O,T],RANGE:[R,B],CRYPTO:N,MODULO_MODE:C,POW_PRECISION:j,FORMAT:z,ALPHABET:U}},L.isBigNumber=function(e){if(!e||!0!==e._isBigNumber)return!1;if(!L.DEBUG)return!0;var t,r,n=e.c,i=e.e,o=e.s;e:if("[object Array]"=={}.toString.call(n)){if((1===o||-1===o)&&i>=-d&&i<=d&&i===u(i)){if(0===n[0]){if(0===i&&1===n.length)return!0;break e}if((t=(i+1)%14)<1&&(t+=14),String(n[0]).length==t){for(t=0;t=f||r!==u(r))break e;if(0!==r)return!0}}}else if(null===n&&null===i&&(null===o||1===o||-1===o))return!0;throw Error(c+"Invalid BigNumber: "+e)},L.maximum=L.max=function(){return D(arguments,A.lt)},L.minimum=L.min=function(){return D(arguments,A.gt)},L.random=(o=9007199254740992*Math.random()&2097151?function(){return u(9007199254740992*Math.random())}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)},function(e){var t,r,n,i,a,h=0,f=[],p=new L(x);if(null==e?e=I:b(e,0,d),i=s(e/14),N)if(crypto.getRandomValues){for(t=crypto.getRandomValues(new Uint32Array(i*=2));h>>11))>=9e15?(r=crypto.getRandomValues(new Uint32Array(2)),t[h]=r[0],t[h+1]=r[1]):(f.push(a%1e14),h+=2);h=i/2}else{if(!crypto.randomBytes)throw N=!1,Error(c+"crypto unavailable");for(t=crypto.randomBytes(i*=7);h=9e15?crypto.randomBytes(7).copy(t,h):(f.push(a%1e14),h+=7);h=i/7}if(!N)for(;h=10;a/=10,h++);h<14&&(n-=14-h)}return p.e=n,p.c=f,p}),L.sum=function(){for(var e=1,t=arguments,r=new L(t[0]);er-1&&(null==a[i+1]&&(a[i+1]=0),a[i+1]+=a[i]/r|0,a[i]%=r)}return a.reverse()}return function(t,n,i,o,a){var s,u,c,h,f,l,d,p,g=t.indexOf("."),b=I,v=P;for(g>=0&&(h=j,j=0,t=t.replace(".",""),l=(p=new L(n)).pow(t.length-g),j=h,p.c=e(w(m(l.c),l.e,"0"),10,i,"0123456789"),p.e=p.c.length),c=h=(d=e(t,n,i,a?(s=U,"0123456789"):(s="0123456789",U))).length;0==d[--h];d.pop());if(!d[0])return s.charAt(0);if(g<0?--c:(l.c=d,l.e=c,l.s=o,d=(l=r(l,p,b,v,i)).c,f=l.r,c=l.e),g=d[u=c+b+1],h=i/2,f=f||u<0||null!=d[u+1],f=v<4?(null!=g||f)&&(0==v||v==(l.s<0?3:2)):g>h||g==h&&(4==v||f||6==v&&1&d[u-1]||v==(l.s<0?8:7)),u<1||!d[0])t=f?w(s.charAt(1),-b,s.charAt(0)):s.charAt(0);else{if(d.length=u,f)for(--i;++d[--u]>i;)d[u]=0,u||(++c,d=[1].concat(d));for(h=d.length;!d[--h];);for(g=0,t="";g<=h;t+=s.charAt(d[g++]));t=w(t,c,s.charAt(0))}return t}}(),r=function(){function e(e,t,r){var n,i,o,a,s=0,u=e.length,c=t%1e7,h=t/1e7|0;for(e=e.slice();u--;)s=((i=c*(o=e[u]%1e7)+(n=h*o+(a=e[u]/1e7|0)*c)%1e7*1e7+s)/r|0)+(n/1e7|0)+h*a,e[u]=i%r;return s&&(e=[s].concat(e)),e}function t(e,t,r,n){var i,o;if(r!=n)o=r>n?1:-1;else for(i=o=0;it[i]?1:-1;break}return o}function r(e,t,r,n){for(var i=0;r--;)e[r]-=i,i=e[r]1;e.splice(0,1));}return function(n,i,o,a,s){var c,h,l,d,m,g,b,v,y,w,_,S,M,k,E,A,x,I=n.s==i.s?1:-1,P=n.c,O=i.c;if(!(P&&P[0]&&O&&O[0]))return new L(n.s&&i.s&&(P?!O||P[0]!=O[0]:O)?P&&0==P[0]||!O?0*I:I/0:NaN);for(y=(v=new L(I)).c=[],I=o+(h=n.e-i.e)+1,s||(s=f,h=p(n.e/14)-p(i.e/14),I=I/14|0),l=0;O[l]==(P[l]||0);l++);if(O[l]>(P[l]||0)&&h--,I<0)y.push(1),d=!0;else{for(k=P.length,A=O.length,l=0,I+=2,(m=u(s/(O[0]+1)))>1&&(O=e(O,m,s),P=e(P,m,s),A=O.length,k=P.length),M=A,_=(w=P.slice(0,A)).length;_=s/2&&E++;do{if(m=0,(c=t(O,w,A,_))<0){if(S=w[0],A!=_&&(S=S*s+(w[1]||0)),(m=u(S/E))>1)for(m>=s&&(m=s-1),b=(g=e(O,m,s)).length,_=w.length;1==t(g,w,b,_);)m--,r(g,A=10;I/=10,l++);K(v,o+(v.e=l+14*h-1)+1,a,d)}else v.e=h,v.r=+d;return v}}(),_=/^(-?)0([xbo])(?=\w[\w.]*$)/i,S=/^([^.]+)\.$/,M=/^\.([^.]+)$/,k=/^-?(Infinity|NaN)$/,E=/^\s*\+(?=[\w.])|^\s+|\s+$/g,i=function(e,t,r,n){var i,o=r?t:t.replace(E,"");if(k.test(o))e.s=isNaN(o)?null:o<0?-1:1;else{if(!r&&(o=o.replace(_,(function(e,t,r){return i="x"==(r=r.toLowerCase())?16:"b"==r?2:8,n&&n!=i?e:t})),n&&(i=n,o=o.replace(S,"$1").replace(M,"0.$1")),t!=o))return new L(o,i);if(L.DEBUG)throw Error(c+"Not a"+(n?" base "+n:"")+" number: "+t);e.s=null}e.c=e.e=null},A.absoluteValue=A.abs=function(){var e=new L(this);return e.s<0&&(e.s=1),e},A.comparedTo=function(e,t){return g(this,new L(e,t))},A.decimalPlaces=A.dp=function(e,t){var r,n,i,o=this;if(null!=e)return b(e,0,d),null==t?t=P:b(t,0,8),K(new L(o),e+o.e+1,t);if(!(r=o.c))return null;if(n=14*((i=r.length-1)-p(this.e/14)),i=r[i])for(;i%10==0;i/=10,n--);return n<0&&(n=0),n},A.dividedBy=A.div=function(e,t){return r(this,new L(e,t),I,P)},A.dividedToIntegerBy=A.idiv=function(e,t){return r(this,new L(e,t),0,1)},A.exponentiatedBy=A.pow=function(e,t){var r,n,i,o,a,h,f,l,d=this;if((e=new L(e)).c&&!e.isInteger())throw Error(c+"Exponent not an integer: "+H(e));if(null!=t&&(t=new L(t)),a=e.e>14,!d.c||!d.c[0]||1==d.c[0]&&!d.e&&1==d.c.length||!e.c||!e.c[0])return l=new L(Math.pow(+H(d),a?2-v(e):+H(e))),t?l.mod(t):l;if(h=e.s<0,t){if(t.c?!t.c[0]:!t.s)return new L(NaN);(n=!h&&d.isInteger()&&t.isInteger())&&(d=d.mod(t))}else{if(e.e>9&&(d.e>0||d.e<-1||(0==d.e?d.c[0]>1||a&&d.c[1]>=24e7:d.c[0]<8e13||a&&d.c[0]<=9999975e7)))return o=d.s<0&&v(e)?-0:0,d.e>-1&&(o=1/o),new L(h?1/o:o);j&&(o=s(j/14+2))}for(a?(r=new L(.5),h&&(e.s=1),f=v(e)):f=(i=Math.abs(+H(e)))%2,l=new L(x);;){if(f){if(!(l=l.times(d)).c)break;o?l.c.length>o&&(l.c.length=o):n&&(l=l.mod(t))}if(i){if(0===(i=u(i/2)))break;f=i%2}else if(K(e=e.times(r),e.e+1,1),e.e>14)f=v(e);else{if(0===(i=+H(e)))break;f=i%2}d=d.times(d),o?d.c&&d.c.length>o&&(d.c.length=o):n&&(d=d.mod(t))}return n?l:(h&&(l=x.div(l)),t?l.mod(t):o?K(l,j,P,void 0):l)},A.integerValue=function(e){var t=new L(this);return null==e?e=P:b(e,0,8),K(t,t.e+1,e)},A.isEqualTo=A.eq=function(e,t){return 0===g(this,new L(e,t))},A.isFinite=function(){return!!this.c},A.isGreaterThan=A.gt=function(e,t){return g(this,new L(e,t))>0},A.isGreaterThanOrEqualTo=A.gte=function(e,t){return 1===(t=g(this,new L(e,t)))||0===t},A.isInteger=function(){return!!this.c&&p(this.e/14)>this.c.length-2},A.isLessThan=A.lt=function(e,t){return g(this,new L(e,t))<0},A.isLessThanOrEqualTo=A.lte=function(e,t){return-1===(t=g(this,new L(e,t)))||0===t},A.isNaN=function(){return!this.s},A.isNegative=function(){return this.s<0},A.isPositive=function(){return this.s>0},A.isZero=function(){return!!this.c&&0==this.c[0]},A.minus=function(e,t){var r,n,i,o,a=this,s=a.s;if(t=(e=new L(e,t)).s,!s||!t)return new L(NaN);if(s!=t)return e.s=-t,a.plus(e);var u=a.e/14,c=e.e/14,h=a.c,l=e.c;if(!u||!c){if(!h||!l)return h?(e.s=-t,e):new L(l?a:NaN);if(!h[0]||!l[0])return l[0]?(e.s=-t,e):new L(h[0]?a:3==P?-0:0)}if(u=p(u),c=p(c),h=h.slice(),s=u-c){for((o=s<0)?(s=-s,i=h):(c=u,i=l),i.reverse(),t=s;t--;i.push(0));i.reverse()}else for(n=(o=(s=h.length)<(t=l.length))?s:t,s=t=0;t0)for(;t--;h[r++]=0);for(t=f-1;n>s;){if(h[--n]=0;){for(r=0,d=w[i]%1e7,m=w[i]/1e7|0,o=i+(a=u);o>i;)r=((c=d*(c=y[--a]%1e7)+(s=m*c+(h=y[a]/1e7|0)*d)%1e7*1e7+g[o]+r)/b|0)+(s/1e7|0)+m*h,g[o--]=c%b;g[o]=r}return r?++n:g.splice(0,1),q(e,g,n)},A.negated=function(){var e=new L(this);return e.s=-e.s||null,e},A.plus=function(e,t){var r,n=this,i=n.s;if(t=(e=new L(e,t)).s,!i||!t)return new L(NaN);if(i!=t)return e.s=-t,n.minus(e);var o=n.e/14,a=e.e/14,s=n.c,u=e.c;if(!o||!a){if(!s||!u)return new L(i/0);if(!s[0]||!u[0])return u[0]?e:new L(s[0]?n:0*i)}if(o=p(o),a=p(a),s=s.slice(),i=o-a){for(i>0?(a=o,r=u):(i=-i,r=s),r.reverse();i--;r.push(0));r.reverse()}for((i=s.length)-(t=u.length)<0&&(r=u,u=s,s=r,t=i),i=0;t;)i=(s[--t]=s[t]+u[t]+i)/f|0,s[t]=f===s[t]?0:s[t]%f;return i&&(s=[i].concat(s),++a),q(e,s,a)},A.precision=A.sd=function(e,t){var r,n,i,o=this;if(null!=e&&e!==!!e)return b(e,1,d),null==t?t=P:b(t,0,8),K(new L(o),e,t);if(!(r=o.c))return null;if(n=14*(i=r.length-1)+1,i=r[i]){for(;i%10==0;i/=10,n--);for(i=r[0];i>=10;i/=10,n++);}return e&&o.e+1>n&&(n=o.e+1),n},A.shiftedBy=function(e){return b(e,-9007199254740991,9007199254740991),this.times("1e"+e)},A.squareRoot=A.sqrt=function(){var e,t,n,i,o,a=this,s=a.c,u=a.s,c=a.e,h=I+4,f=new L("0.5");if(1!==u||!s||!s[0])return new L(!u||u<0&&(!s||s[0])?NaN:s?a:1/0);if(0==(u=Math.sqrt(+H(a)))||u==1/0?(((t=m(s)).length+c)%2==0&&(t+="0"),u=Math.sqrt(+t),c=p((c+1)/2)-(c<0||c%2),n=new L(t=u==1/0?"5e"+c:(t=u.toExponential()).slice(0,t.indexOf("e")+1)+c)):n=new L(u+""),n.c[0])for((u=(c=n.e)+h)<3&&(u=0);;)if(o=n,n=f.times(o.plus(r(a,o,h,1))),m(o.c).slice(0,u)===(t=m(n.c)).slice(0,u)){if(n.e0&&m>0){for(o=m%s||s,f=p.substr(0,o);o0&&(f+=h+p.slice(o)),d&&(f="-"+f)}n=l?f+(r.decimalSeparator||"")+((u=+r.fractionGroupSize)?l.replace(new RegExp("\\d{"+u+"}\\B","g"),"$&"+(r.fractionGroupSeparator||"")):l):f}return(r.prefix||"")+n+(r.suffix||"")},A.toFraction=function(e){var t,n,i,o,a,s,u,h,f,d,p,g,b=this,v=b.c;if(null!=e&&(!(u=new L(e)).isInteger()&&(u.c||1!==u.s)||u.lt(x)))throw Error(c+"Argument "+(u.isInteger()?"out of range: ":"not an integer: ")+H(u));if(!v)return new L(b);for(t=new L(x),f=n=new L(x),i=h=new L(x),g=m(v),a=t.e=g.length-b.e-1,t.c[0]=l[(s=a%14)<0?14+s:s],e=!e||u.comparedTo(t)>0?a>0?t:f:u,s=B,B=1/0,u=new L(g),h.c[0]=0;d=r(u,t,0,1),1!=(o=n.plus(d.times(i))).comparedTo(e);)n=i,i=o,f=h.plus(d.times(o=f)),h=o,t=u.minus(d.times(o=t)),u=o;return o=r(e.minus(n),i,0,1),h=h.plus(o.times(f)),n=n.plus(o.times(i)),h.s=f.s=b.s,p=r(f,i,a*=2,P).minus(b).abs().comparedTo(r(h,n,a,P).minus(b).abs())<1?[f,i]:[h,n],B=s,p},A.toNumber=function(){return+H(this)},A.toPrecision=function(e,t){return null!=e&&b(e,1,d),F(this,e,t,2)},A.toString=function(e){var t,r=this,i=r.s,o=r.e;return null===o?i?(t="Infinity",i<0&&(t="-"+t)):t="NaN":(null==e?t=o<=O||o>=T?y(m(r.c),o):w(m(r.c),o,"0"):10===e?t=w(m((r=K(new L(r),I+o+1,P)).c),r.e,"0"):(b(e,2,U.length,"Base"),t=n(w(m(r.c),o,"0"),10,e,i,!0)),i<0&&r.c[0]&&(t="-"+t)),t},A.valueOf=A.toJSON=function(){return H(this)},A._isBigNumber=!0,null!=t&&L.set(t),L}()).default=o.BigNumber=o,void 0===(n=function(){return o}.call(t,r,t,e))||(e.exports=n)}()},function(e,t,r){"use strict";var n=r(1),i=r(72),o=r(74),a=r(75),s=r(25);function u(e){s.call(this,"digest"),this._hash=e}n(u,s),u.prototype._update=function(e){this._hash.update(e)},u.prototype._final=function(){return this._hash.digest()},e.exports=function(e){return"md5"===(e=e.toLowerCase())?new i:"rmd160"===e||"ripemd160"===e?new o:new u(a(e))}},function(e,t,r){var n=r(2).Buffer,i=r(221).Transform,o=r(39).StringDecoder;function a(e){i.call(this),this.hashMode="string"==typeof e,this.hashMode?this[e]=this._finalOrDigest:this.final=this._finalOrDigest,this._final&&(this.__final=this._final,this._final=null),this._decoder=null,this._encoding=null}r(1)(a,i),a.prototype.update=function(e,t,r){"string"==typeof e&&(e=n.from(e,t));var i=this._update(e);return this.hashMode?this:(r&&(i=this._toString(i,r)),i)},a.prototype.setAutoPadding=function(){},a.prototype.getAuthTag=function(){throw new Error("trying to get auth tag in unsupported state")},a.prototype.setAuthTag=function(){throw new Error("trying to set auth tag in unsupported state")},a.prototype.setAAD=function(){throw new Error("trying to set aad in unsupported state")},a.prototype._transform=function(e,t,r){var n;try{this.hashMode?this._update(e):this.push(this._update(e))}catch(e){n=e}finally{r(n)}},a.prototype._flush=function(e){var t;try{this.push(this.__final())}catch(e){t=e}e(t)},a.prototype._finalOrDigest=function(e){var t=this.__final()||n.alloc(0);return e&&(t=this._toString(t,e,!0)),t},a.prototype._toString=function(e,t,r){if(this._decoder||(this._decoder=new o(t),this._encoding=t),this._encoding!==t)throw new Error("can't switch encodings");var n=this._decoder.write(e);return r&&(n+=this._decoder.end()),n},e.exports=a},function(e,t,r){"use strict";(function(t){r(0);var n=r(13),i=r(14),o=r(22),a=r(21),s=r(12),u=r(10),c=r(11),h=r(61),f=r(4),l=r(3),d=function(e,h,f,l){var d,p=r(102),m=r(103),g=p.shallowCopy(e);for((l=new i(l)).removeCodeseparators(),d=0;d=g.outputs.length)return t.from("0000000000000000000000000000000000000000000000000000000000000001","hex");for(g.outputs.length=f+1,d=0;d0&&a.length>i&&!a.warned){a.warned=!0;var u=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=e,u.type=t,u.count=a.length,s=u,console&&console.warn&&console.warn(s)}return e}function l(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function d(e,t,r){var n={fired:!1,wrapFn:void 0,target:e,type:t,listener:r},i=l.bind(n);return i.listener=r,n.wrapFn=i,i}function p(e,t,r){var n=e._events;if(void 0===n)return[];var i=n[t];return void 0===i?[]:"function"==typeof i?r?[i.listener||i]:[i]:r?function(e){for(var t=new Array(e.length),r=0;r0&&(a=t[0]),a instanceof Error)throw a;var s=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw s.context=a,s}var u=i[e];if(void 0===u)return!1;if("function"==typeof u)o(u,this,t);else{var c=u.length,h=g(u,c);for(r=0;r=0;o--)if(r[o]===t||r[o].listener===t){a=r[o].listener,i=o;break}if(i<0)return this;0===i?r.shift():function(e,t){for(;t+1=0;n--)this.removeListener(e,t[n]);return this},s.prototype.listeners=function(e){return p(this,e,!0)},s.prototype.rawListeners=function(e){return p(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):m.call(e,t)},s.prototype.listenerCount=m,s.prototype.eventNames=function(){return this._eventsCount>0?n(this._events):[]}},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},function(e,t,r){"use strict";var n=r(54),i=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};e.exports=f;var o=Object.create(r(40));o.inherits=r(1);var a=r(122),s=r(78);o.inherits(f,a);for(var u=i(s.prototype),c=0;c4294967295)throw new RangeError("requested too many random bytes");var r=i.allocUnsafe(e);if(e>0)if(e>65536)for(var a=0;a=1?s[e][0]:s[e];n.isArray(t)||(t=[t]);var r=function(t){return a[i][t]===e};for(var i in a)if(n.some(t,r))return a[i]}function h(e){var t=new u;return o.defineImmutable(t,{name:e.name,alias:e.alias,pubkeyhash:e.pubkeyhash,privatekey:e.privatekey,scripthash:e.scripthash,bech32prefix:e.bech32prefix,xpubkey:e.xpubkey,xprivkey:e.xprivkey}),e.networkMagic&&o.defineImmutable(t,{networkMagic:i.integerAsBuffer(e.networkMagic)}),e.port&&o.defineImmutable(t,{port:e.port}),e.dnsSeeds&&o.defineImmutable(t,{dnsSeeds:e.dnsSeeds}),n.each(t,(function(e){n.isUndefined(e)||n.isObject(e)||(s[e]||(s[e]=[]),s[e].push(t))})),a.push(t),t}u.prototype.toString=function(){return this.name},h({name:"livenet",alias:"mainnet",pubkeyhash:0,privatekey:128,scripthash:5,bech32prefix:"bc",xpubkey:76067358,xprivkey:76066276,networkMagic:4190024921,port:8333,dnsSeeds:["seed.bitcoin.sipa.be","dnsseed.bluematt.me","dnsseed.bitcoin.dashjr.org","seed.bitcoinstats.com","seed.bitnodes.io","bitseed.xf2.org"]});var f=c("livenet");h({name:"testnet",alias:"test",pubkeyhash:111,privatekey:239,scripthash:196,bech32prefix:"tb",xpubkey:70617039,xprivkey:70615956,networkMagic:185665799,port:18333,dnsSeeds:["testnet-seed.bitcoin.petertodd.org","testnet-seed.bluematt.me","testnet-seed.alexykot.me","testnet-seed.bitcoin.schildbach.de"]});var l=c("testnet");h({name:"regtest",alias:"dev",pubkeyhash:111,privatekey:239,scripthash:196,bech32prefix:"bcrt",xpubkey:70617039,xprivkey:70615956,networkMagic:4206867930,port:18444,dnsSeeds:[]});var d=c("regtest");e.exports={add:h,remove:function(e){for(var t=0;t=0&&delete s[r][t]}},defaultNetwork:f,livenet:f,mainnet:f,testnet:l,regtest:d,get:c,enableRegtest:function(){l.regtestEnabled=!0},disableRegtest:function(){l.regtestEnabled=!1}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.DataCIDSize=t.MessageMatch=t.MsigVesting=t.SectorInfo=t.BeaconEntry=t.PoStProof=t.ElectionProof=t.BlockMsg=t.Ticket=t.BlockTemplate=t.MiningBaseInfo=t.MpoolUpdate=t.MpoolConfig=t.VoucherCreateResult=t.PaychStatus=t.ChannelInfo=t.VoucherSpec=t.ModVerifyParams=t.Merge=t.PaymentInfo=t.SignedVoucher=t.ChannelAvailableFunds=t.SyncState=t.ActiveSync=t.RetrievalEvent=t.KeyInfo=t.Import=t.DataTransferChannel=t.DataSize=t.CommPRet=t.SignedStorageAsk=t.StorageAsk=t.RetrievalOrder=t.QueryOffer=t.RetrievalPeer=t.StartDealParams=t.DealInfo=t.DataRef=t.ImportRes=t.FileRef=t.ObjStat=t.CirculatingSupply=t.DealCollateralBounds=t.MarketDeal=t.DealState=t.DealProposal=t.MarketBalance=t.MsgLookup=t.SectorLocation=t.SectorExpiration=t.SectorPreCommitOnChainInfo=t.SectorPreCommitInfo=t.Fault=t.Partition=t.Deadline=t.PowerPair=t.MinerInfo=t.Stats=t.NatInfo=t.PubsubScore=t.Score=t.AddrInfo=t.WorkerKeyChange=t.MinerPower=t.Claim=t.DeadlineInfo=t.SectorOnChainInfo=t.ActorState=t.Actor=t.ExecutionTrace=t.GasTrace=t.Loc=t.MsgGasCost=t.InvocResult=t.WrappedMessage=t.ComputeStateOutput=t.MinerSectors=t.MessageReceipt=t.BlockMessages=t.HeadChange=t.MessagePartial=t.Message=t.Version=t.TipSet=t.BlockHeader=t.Cid=t.NewAddressType=t.SigType=t.MethodMultisig=t.MethodInit=t.TEST_DEFAULT_HD_PATH=t.DEFAULT_HD_PATH=void 0,t.DEFAULT_HD_PATH="m/44'/461'/0/0/1",t.TEST_DEFAULT_HD_PATH="m/44'/1'/0/0/1",t.MethodInit={Constructor:1,Exec:2},t.MethodMultisig={Constructor:1,Propose:2,Approve:3,Cancel:4,AddSigner:5,RemoveSigner:6,SwapSigner:7,ChangeNumApprovalsThreshold:8},function(e){e[e.SigTypeSecp256k1=1]="SigTypeSecp256k1",e[e.SigTypeBLS=2]="SigTypeBLS"}(t.SigType||(t.SigType={})),function(e){e.BLS="bls",e.SECP256K1="secp256k1",e.SECP256K1_LEDGER="secp256k1-ledger"}(t.NewAddressType||(t.NewAddressType={}));var n=function(){};t.Cid=n;var i=function(){};t.BlockHeader=i;var o=function(){};t.TipSet=o;var a=function(){};t.Version=a;var s=function(){};t.Message=s;var u=function(){};t.MessagePartial=u;var c=function(){};t.HeadChange=c;var h=function(){};t.BlockMessages=h;var f=function(){};t.MessageReceipt=f;var l=function(){};t.MinerSectors=l;var d=function(){};t.ComputeStateOutput=d;var p=function(){};t.WrappedMessage=p;var m=function(){};t.InvocResult=m;var g=function(){};t.MsgGasCost=g;var b=function(){};t.Loc=b;var v=function(){};t.GasTrace=v;var y=function(){};t.ExecutionTrace=y;var w=function(){};t.Actor=w;var _=function(){};t.ActorState=_;var S=function(){};t.SectorOnChainInfo=S;var M=function(){};t.DeadlineInfo=M;var k=function(){};t.Claim=k;var E=function(){};t.MinerPower=E;var A=function(){};t.WorkerKeyChange=A;var x=function(){};t.AddrInfo=x;var I=function(){};t.Score=I;var P=function(){};t.PubsubScore=P;var O=function(){};t.NatInfo=O;var T=function(){};t.Stats=T;var R=function(){};t.MinerInfo=R;var B=function(){};t.PowerPair=B;var N=function(){};t.Deadline=N;var C=function(){};t.Partition=C;var j=function(){};t.Fault=j;var z=function(){};t.SectorPreCommitInfo=z;var U=function(){};t.SectorPreCommitOnChainInfo=U;var L=function(){};t.SectorExpiration=L;var F=function(){};t.SectorLocation=F;var D=function(){};t.MsgLookup=D;var q=function(){};t.MarketBalance=q;var K=function(){};t.DealProposal=K;var H=function(){};t.DealState=H;var V=function(){};t.MarketDeal=V;var G=function(){};t.DealCollateralBounds=G;var W=function(){};t.CirculatingSupply=W;var Y=function(){};t.ObjStat=Y;var Z=function(){};t.FileRef=Z;var J=function(){};t.ImportRes=J;var X=function(){};t.DataRef=X;var $=function(){};t.DealInfo=$;var Q=function(){};t.StartDealParams=Q;var ee=function(){};t.RetrievalPeer=ee;var te=function(){};t.QueryOffer=te;var re=function(){};t.RetrievalOrder=re;var ne=function(){};t.StorageAsk=ne;var ie=function(){};t.SignedStorageAsk=ie;var oe=function(){};t.CommPRet=oe;var ae=function(){};t.DataSize=ae;var se=function(){};t.DataTransferChannel=se;var ue=function(){};t.Import=ue;var ce=function(){};t.KeyInfo=ce;var he=function(){};t.RetrievalEvent=he;var fe=function(){};t.ActiveSync=fe;var le=function(){};t.SyncState=le;var de=function(){};t.ChannelAvailableFunds=de;var pe=function(){};t.SignedVoucher=pe;var me=function(){};t.PaymentInfo=me;var ge=function(){};t.Merge=ge;var be=function(){};t.ModVerifyParams=be;var ve=function(){};t.VoucherSpec=ve;var ye=function(){};t.ChannelInfo=ye;var we=function(){};t.PaychStatus=we;var _e=function(){};t.VoucherCreateResult=_e;var Se=function(){};t.MpoolConfig=Se;var Me=function(){};t.MpoolUpdate=Me;var ke=function(){};t.MiningBaseInfo=ke;var Ee=function(){};t.BlockTemplate=Ee;var Ae=function(){};t.Ticket=Ae;var xe=function(){};t.BlockMsg=xe;var Ie=function(){};t.ElectionProof=Ie;var Pe=function(){};t.PoStProof=Pe;var Oe=function(){};t.BeaconEntry=Oe;var Te=function(){};t.SectorInfo=Te;var Re=function(){};t.MsigVesting=Re;var Be=function(){};t.MessageMatch=Be;var Ne=function(){};t.DataCIDSize=Ne},function(e,t,r){(function(t){const n=r(209),i=r(240),o=r(57).util,a=r(152),s=r(308),{MethodInit:u,MethodPaych:c}=r(310),h=r(311),{getDigest:f,getCoinTypeFromPath:l,addressAsBytes:d,bytesToAddress:p,tryToPrivateKeyBuffer:m}=r(154),{ProtocolIndicator:g}=r(157);function b(e,r){"string"==typeof e&&(e=t.from(e,"hex"));const n=i.fromSeed(e).derivePath(r);let o=!1;return"1"===l(r)&&(o=!0),new h(n.privateKey,o)}function v(e){if("0"==e)return t.from("");const r=new s(e,10),n=r.toArrayLike(t,"be",r.byteLength());return t.concat([t.from("00","hex"),n])}function y(e){if(!("to"in e)||"string"!=typeof e.to)throw new Error("'to' is a required field and has to be a 'string'");if(!("from"in e)||"string"!=typeof e.from)throw new Error("'from' is a required field and has to be a 'string'");if(!("nonce"in e)||"number"!=typeof e.nonce)throw new Error("'nonce' is a required field and has to be a 'number'");if(!("value"in e)||"string"!=typeof e.value||""===e.value||e.value.includes("-"))throw new Error("'value' is a required field and has to be a 'string' but not empty or negative");if(!("gasfeecap"in e)||"string"!=typeof e.gasfeecap)throw new Error("'gasfeecap' is a required field and has to be a 'string'");if(!("gaspremium"in e)||"string"!=typeof e.gaspremium)throw new Error("'gaspremium' is a required field and has to be a 'string'");if(!("gaslimit"in e)||"number"!=typeof e.gaslimit)throw new Error("'gaslimit' is a required field and has to be a 'number'");if(!("method"in e)||"number"!=typeof e.method)throw new Error("'method' is a required field and has to be a 'number'");if(!("params"in e)||"string"!=typeof e.params)throw new Error("'params' is a required field and has to be a 'string'");const r=d(e.to),n=d(e.from),i=v(e.value),a=v(e.gasfeecap),s=v(e.gaspremium),u=[0,r,n,e.nonce,i,e.gaslimit,a,s,e.method,t.from(e.params,"base64")];return o.serialize(u)}function w(e,r){"object"==typeof e&&(e=y(e)),"string"==typeof e&&(e=t.from(e,"hex")),r=m(r);const n=f(e),i=a.ecdsaSign(n,r);return t.concat([t.from(i.signature),t.from([i.recid])])}function _(e,t){if("object"!=typeof e)throw new Error("'message' need to be an object. Cannot be under CBOR format.");const r=w(e,t),n={};return n.message=e,n.signature={data:r.toString("base64"),type:g.SECP256K1},n}e.exports={generateMnemonic:function(){return n.generateMnemonic(256)},keyDerive:function(e,t,r){if(void 0===r)throw new Error("'password' argument must be of type string or an instance of Buffer or ArrayBuffer. Received undefined");return b(n.mnemonicToSeedSync(e,r),t)},keyDeriveFromSeed:b,keyRecover:function(e,t){return e=m(e),new h(e,t)},transactionSerialize:function(e){const r=y(e);return t.from(r).toString("hex")},transactionSerializeRaw:y,transactionParse:function(e,r){const n=o.deserialize(t.from(e,"hex"));if(0!==n[0])throw new Error("Unsupported version");if(n.length<10)throw new Error("The cbor is missing some fields... please verify you have 9 fields.");const i={};if(i.to=p(n[1],r),i.from=p(n[2],r),i.nonce=n[3],1===n[4][0])throw new Error("Value cant be negative");return i.value=new s(n[4].toString("hex"),16).toString(10),i.gaslimit=n[5],i.gasfeecap=new s(n[6].toString("hex"),16).toString(10),i.gaspremium=new s(n[7].toString("hex"),16).toString(10),i.method=n[8],i.params=n[9].toString(),i},transactionSign:_,transactionSignLotus:function(e,t){const r=_(e,t);return JSON.stringify({Message:{From:r.message.from,GasLimit:r.message.gaslimit,GasFeeCap:r.message.gasfeecap,GasPremium:r.message.gaspremium,Method:r.message.method,Nonce:r.message.nonce,Params:e.params,To:r.message.to,Value:r.message.value},Signature:{Data:r.signature.data,Type:r.signature.type}})},transactionSignRaw:w,verifySignature:function(e,r){"object"==typeof r&&(r=y(r)),"string"==typeof r&&(r=t.from(r,"hex")),"string"==typeof e&&(e="="===e.slice(-1)?t.from(e,"base64"):t.from(e,"hex"));const n=f(r),i=a.ecdsaRecover(e.slice(0,-1),e[64],n,!1);return a.ecdsaVerify(e.slice(0,-1),n,i)},addressAsBytes:d,bytesToAddress:p}}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n={};function i(e,t,r){r||(r=Error);var i=function(e){var r,n;function i(r,n,i){return e.call(this,function(e,r,n){return"string"==typeof t?t:t(e,r,n)}(r,n,i))||this}return n=e,(r=i).prototype=Object.create(n.prototype),r.prototype.constructor=r,r.__proto__=n,i}(r);i.prototype.name=r.name,i.prototype.code=e,n[e]=i}function o(e,t){if(Array.isArray(e)){var r=e.length;return e=e.map((function(e){return String(e)})),r>2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:2===r?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}return"of ".concat(t," ").concat(String(e))}i("ERR_INVALID_OPT_VALUE",(function(e,t){return'The value "'+t+'" is invalid for option "'+e+'"'}),TypeError),i("ERR_INVALID_ARG_TYPE",(function(e,t,r){var n,i,a,s;if("string"==typeof t&&(i="not ",t.substr(!a||a<0?0:+a,i.length)===i)?(n="must not be",t=t.replace(/^not /,"")):n="must be",function(e,t,r){return(void 0===r||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}(e," argument"))s="The ".concat(e," ").concat(n," ").concat(o(t,"type"));else{var u=function(e,t,r){return"number"!=typeof r&&(r=0),!(r+t.length>e.length)&&-1!==e.indexOf(t,r)}(e,".")?"property":"argument";s='The "'.concat(e,'" ').concat(u," ").concat(n," ").concat(o(t,"type"))}return s+=". Received type ".concat(typeof r)}),TypeError),i("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF"),i("ERR_METHOD_NOT_IMPLEMENTED",(function(e){return"The "+e+" method is not implemented"})),i("ERR_STREAM_PREMATURE_CLOSE","Premature close"),i("ERR_STREAM_DESTROYED",(function(e){return"Cannot call "+e+" after a stream was destroyed"})),i("ERR_MULTIPLE_CALLBACK","Callback called multiple times"),i("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable"),i("ERR_STREAM_WRITE_AFTER_END","write after end"),i("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError),i("ERR_UNKNOWN_ENCODING",(function(e){return"Unknown encoding: "+e}),TypeError),i("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event"),e.exports.codes=n},function(e,t,r){"use strict";(function(t){var n=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};e.exports=c;var i=r(113),o=r(117);r(1)(c,i);for(var a=n(o.prototype),s=0;s=this._finalSize&&(this._update(this._block),this._block.fill(0));var r=8*this._len;if(r<=4294967295)this._block.writeUInt32BE(r,this._blockSize-4);else{var n=(4294967295&r)>>>0,i=(r-n)/4294967296;this._block.writeUInt32BE(i,this._blockSize-8),this._block.writeUInt32BE(n,this._blockSize-4)}this._update(this._block);var o=this._hash();return e?o.toString(e):o},i.prototype._update=function(){throw new Error("_update must be implemented by subclass")},e.exports=i},function(e,t,r){"use strict";(function(t){var n=r(10),i=r(5),o=new(0,r(31).ec)("secp256k1"),a=o.curve.point.bind(o.curve),s=o.curve.pointFromX.bind(o.curve),u=function(e,t,r){try{var n=a(e,t,r)}catch(e){throw new Error("Invalid Point")}return n.validate(),n};u.prototype=Object.getPrototypeOf(o.curve.point()),u.fromX=function(e,t){try{var r=s(t,e)}catch(e){throw new Error("Invalid X")}return r.validate(),r},u.getG=function(){return o.curve.g},u.getN=function(){return new n(o.curve.n.toArray())},u.prototype._getX=u.prototype.getX,u.prototype.getX=function(){return new n(this._getX().toArray())},u.prototype._getY=u.prototype.getY,u.prototype.getY=function(){return new n(this._getY().toArray())},u.prototype.validate=function(){if(this.isInfinity())throw new Error("Point cannot be equal to Infinity");var e;try{e=s(this.getX(),this.getY().isOdd())}catch(e){throw new Error("Point does not lie on the curve")}if(0!==e.y.cmp(this.y))throw new Error("Invalid y value for curve.");if(!this.mul(u.getN()).isInfinity())throw new Error("Point times N must be infinity");return this},u.pointToCompressed=function(e){var r,n=e.getX().toBuffer({size:32}),o=e.getY().toBuffer({size:32});return r=o[o.length-1]%2?t.from([3]):t.from([2]),i.concat([r,n])},e.exports=u}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n=r(2).Buffer,i=n.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function o(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(n.isEncoding===i||!i(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=u,this.end=c,t=4;break;case"utf8":this.fillLast=s,t=4;break;case"base64":this.text=h,this.end=f,t=3;break;default:return this.write=l,void(this.end=d)}this.lastNeed=0,this.lastTotal=0,this.lastChar=n.allocUnsafe(t)}function a(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e){var t=this.lastTotal-this.lastNeed,r=function(e,t,r){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==r?r:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function u(e,t){if((e.length-t)%2==0){var r=e.toString("utf16le",t);if(r){var n=r.charCodeAt(r.length-1);if(n>=55296&&n<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function c(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,r)}return t}function h(e,t){var r=(e.length-t)%3;return 0===r?e.toString("base64",t):(this.lastNeed=3-r,this.lastTotal=3,1===r?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-r))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function l(e){return e.toString(this.encoding)}function d(e){return e&&e.length?this.write(e):""}t.StringDecoder=o,o.prototype.write=function(e){if(0===e.length)return"";var t,r;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r=0)return i>0&&(e.lastNeed=i-1),i;if(--n=0)return i>0&&(e.lastNeed=i-2),i;if(--n=0)return i>0&&(2===i?i=0:e.lastNeed=i-3),i;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=r;var n=e.length-(r-this.lastNeed);return e.copy(this.lastChar,0,n),e.toString("utf8",t,n)},o.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,r){(function(e){function r(e){return Object.prototype.toString.call(e)}t.isArray=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===r(e)},t.isBoolean=function(e){return"boolean"==typeof e},t.isNull=function(e){return null===e},t.isNullOrUndefined=function(e){return null==e},t.isNumber=function(e){return"number"==typeof e},t.isString=function(e){return"string"==typeof e},t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=function(e){return void 0===e},t.isRegExp=function(e){return"[object RegExp]"===r(e)},t.isObject=function(e){return"object"==typeof e&&null!==e},t.isDate=function(e){return"[object Date]"===r(e)},t.isError=function(e){return"[object Error]"===r(e)||e instanceof Error},t.isFunction=function(e){return"function"==typeof e},t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=e.isBuffer}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n=r(18),i=r(16);function o(){this.pending=null,this.pendingTotal=0,this.blockSize=this.constructor.blockSize,this.outSize=this.constructor.outSize,this.hmacStrength=this.constructor.hmacStrength,this.padLength=this.constructor.padLength/8,this.endian="big",this._delta8=this.blockSize/8,this._delta32=this.blockSize/32}t.BlockHash=o,o.prototype.update=function(e,t){if(e=n.toArray(e,t),this.pending?this.pending=this.pending.concat(e):this.pending=e,this.pendingTotal+=e.length,this.pending.length>=this._delta8){var r=(e=this.pending).length%this._delta8;this.pending=e.slice(e.length-r,e.length),0===this.pending.length&&(this.pending=null),e=n.join32(e,0,e.length-r,this.endian);for(var i=0;i>>24&255,n[i++]=e>>>16&255,n[i++]=e>>>8&255,n[i++]=255&e}else for(n[i++]=255&e,n[i++]=e>>>8&255,n[i++]=e>>>16&255,n[i++]=e>>>24&255,n[i++]=0,n[i++]=0,n[i++]=0,n[i++]=0,o=8;o({encode:a,decode:s}),""],["base2","0",o(1),"01"],["base8","7",o(3),"01234567"],["base10","9",n,"0123456789"],["base16","f",o(4),"0123456789abcdef"],["base16upper","F",o(4),"0123456789ABCDEF"],["base32hex","v",o(5),"0123456789abcdefghijklmnopqrstuv"],["base32hexupper","V",o(5),"0123456789ABCDEFGHIJKLMNOPQRSTUV"],["base32hexpad","t",o(5),"0123456789abcdefghijklmnopqrstuv="],["base32hexpadupper","T",o(5),"0123456789ABCDEFGHIJKLMNOPQRSTUV="],["base32","b",o(5),"abcdefghijklmnopqrstuvwxyz234567"],["base32upper","B",o(5),"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"],["base32pad","c",o(5),"abcdefghijklmnopqrstuvwxyz234567="],["base32padupper","C",o(5),"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="],["base32z","h",o(5),"ybndrfg8ejkmcpqxot1uwisza345h769"],["base36","k",n,"0123456789abcdefghijklmnopqrstuvwxyz"],["base36upper","K",n,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"],["base58btc","z",n,"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],["base58flickr","Z",n,"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"],["base64","m",o(6),"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"],["base64pad","M",o(6),"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="],["base64url","u",o(6),"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"],["base64urlpad","U",o(6),"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="]],c=u.reduce((e,t)=>(e[t[0]]=new i(t[0],t[1],t[2],t[3]),e),{}),h=u.reduce((e,t)=>(e[t[1]]=c[t[0]],e),{});e.exports={names:c,codes:h}},function(e,t,r){"use strict";t.TextEncoder=TextEncoder,t.TextDecoder=TextDecoder},function(e,t,r){"use strict";(function(t){var n=r(317); +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */function i(e,t){if(e===t)return 0;for(var r=e.length,n=t.length,i=0,o=Math.min(r,n);i=0;c--)if(h[c]!==f[c])return!1;for(c=h.length-1;c>=0;c--)if(s=h[c],!y(e[s],t[s],r,n))return!1;return!0}(e,t,r,n))}return r?e===t:e==t}function w(e){return"[object Arguments]"==Object.prototype.toString.call(e)}function _(e,t){if(!e||!t)return!1;if("[object RegExp]"==Object.prototype.toString.call(t))return t.test(e);try{if(e instanceof t)return!0}catch(e){}return!Error.isPrototypeOf(t)&&!0===t.call({},e)}function S(e,t,r,n){var i;if("function"!=typeof t)throw new TypeError('"block" argument must be a function');"string"==typeof r&&(n=r,r=null),i=function(e){var t;try{e()}catch(e){t=e}return t}(t),n=(r&&r.name?" ("+r.name+").":".")+(n?" "+n:"."),e&&!i&&b(i,r,"Missing expected exception"+n);var o="string"==typeof n,s=!e&&i&&!r;if((!e&&a.isError(i)&&o&&_(i,r)||s)&&b(i,r,"Got unwanted exception"+n),e&&i&&r&&!_(i,r)||!e&&i)throw i}l.AssertionError=function(e){this.name="AssertionError",this.actual=e.actual,this.expected=e.expected,this.operator=e.operator,e.message?(this.message=e.message,this.generatedMessage=!1):(this.message=function(e){return m(g(e.actual),128)+" "+e.operator+" "+m(g(e.expected),128)}(this),this.generatedMessage=!0);var t=e.stackStartFunction||b;if(Error.captureStackTrace)Error.captureStackTrace(this,t);else{var r=new Error;if(r.stack){var n=r.stack,i=p(t),o=n.indexOf("\n"+i);if(o>=0){var a=n.indexOf("\n",o+1);n=n.substring(a+1)}this.stack=n}}},a.inherits(l.AssertionError,Error),l.fail=b,l.ok=v,l.equal=function(e,t,r){e!=t&&b(e,t,r,"==",l.equal)},l.notEqual=function(e,t,r){e==t&&b(e,t,r,"!=",l.notEqual)},l.deepEqual=function(e,t,r){y(e,t,!1)||b(e,t,r,"deepEqual",l.deepEqual)},l.deepStrictEqual=function(e,t,r){y(e,t,!0)||b(e,t,r,"deepStrictEqual",l.deepStrictEqual)},l.notDeepEqual=function(e,t,r){y(e,t,!1)&&b(e,t,r,"notDeepEqual",l.notDeepEqual)},l.notDeepStrictEqual=function e(t,r,n){y(t,r,!0)&&b(t,r,n,"notDeepStrictEqual",e)},l.strictEqual=function(e,t,r){e!==t&&b(e,t,r,"===",l.strictEqual)},l.notStrictEqual=function(e,t,r){e===t&&b(e,t,r,"!==",l.notStrictEqual)},l.throws=function(e,t,r){S(!0,e,t,r)},l.doesNotThrow=function(e,t,r){S(!1,e,t,r)},l.ifError=function(e){if(e)throw e},l.strict=n((function e(t,r){t||b(t,!0,r,"==",e)}),l,{equal:l.strictEqual,deepEqual:l.deepStrictEqual,notEqual:l.notStrictEqual,notDeepEqual:l.notDeepStrictEqual}),l.strict.strict=l.strict;var M=Object.keys||function(e){var t=[];for(var r in e)s.call(e,r)&&t.push(r);return t}}).call(this,r(8))},function(e,t,r){(function(t){e.exports=function(e,r){for(var n=Math.min(e.length,r.length),i=new t(n),o=0;o"},e.exports=d}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(65),o=(r(0),r(11).sha256sha256),a=function e(r){if(!(this instanceof e))return new e(r);if(t.isBuffer(r)){var n=r;this.fromBuffer(n)}else if("string"==typeof r){var i=r;this.fromString(i)}else r&&this.set(r)};a.prototype.set=function(e){return this.buf=e.buf||this.buf||void 0,this},a.validChecksum=function(e,r){return n.isString(e)&&(e=t.from(i.decode(e))),n.isString(r)&&(r=t.from(i.decode(r))),r||(r=e.slice(-4),e=e.slice(0,-4)),a.checksum(e).toString("hex")===r.toString("hex")},a.decode=function(e){if("string"!=typeof e)throw new Error("Input must be a string");var r=t.from(i.decode(e));if(r.length<4)throw new Error("Input string too short");var n=r.slice(0,-4),a=r.slice(-4),s=o(n).slice(0,4);if(a.toString("hex")!==s.toString("hex"))throw new Error("Checksum mismatch");return n},a.checksum=function(e){return o(e).slice(0,4)},a.encode=function(e){if(!t.isBuffer(e))throw new Error("Input must be a buffer");var r=t.alloc(e.length+4),n=a.checksum(e);return e.copy(r),n.copy(r,e.length),i.encode(r)},a.prototype.fromBuffer=function(e){return this.buf=e,this},a.prototype.fromString=function(e){var t=a.decode(e);return this.buf=t,this},a.prototype.toBuffer=function(){return this.buf},a.prototype.toString=function(){return a.encode(this.buf)},e.exports=a}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4);const o=r(17);var a=r(12),s=(r(0),r(5)),u=r(7),c=r(14),h=r(26),f=r(22);const l=Math.pow(2,31),d=Math.pow(2,22),p=Math.pow(2,16)-1;function m(e){return this instanceof m?e?this._fromObject(e):void 0:new m(e)}m.MAXINT=4294967295,m.DEFAULT_SEQNUMBER=4294967295,m.DEFAULT_LOCKTIME_SEQNUMBER=4294967294,m.DEFAULT_RBF_SEQNUMBER=4294967293,m.SEQUENCE_LOCKTIME_TYPE_FLAG=d,Object.defineProperty(m.prototype,"script",{configurable:!1,enumerable:!0,get:function(){return this.isNull()?null:(this._script||(this._script=new c(this._scriptBuffer),this._script._isInput=!0),this._script)}}),m.fromObject=function(e){return i.checkArgument(n.isObject(e)),(new m)._fromObject(e)},m.prototype._fromObject=function(e){var r;if(r=n.isString(e.prevTxId)&&u.isHexa(e.prevTxId)?t.from(e.prevTxId,"hex"):e.prevTxId,this.witnesses=[],this.output=e.output?e.output instanceof f?e.output:new f(e.output):void 0,this.prevTxId=r||e.txidbuf,this.outputIndex=n.isUndefined(e.outputIndex)?e.txoutnum:e.outputIndex,this.sequenceNumber=n.isUndefined(e.sequenceNumber)?n.isUndefined(e.seqnum)?4294967295:e.seqnum:e.sequenceNumber,n.isUndefined(e.script)&&n.isUndefined(e.scriptBuffer))throw new o.Transaction.Input.MissingScript;return this.setScript(e.scriptBuffer||e.script),this},m.prototype.toObject=m.prototype.toJSON=function(){var e={prevTxId:this.prevTxId.toString("hex"),outputIndex:this.outputIndex,sequenceNumber:this.sequenceNumber,script:this._scriptBuffer.toString("hex")};return this.script&&(e.scriptString=this.script.toString()),this.output&&(e.output=this.output.toObject()),e},m.fromBufferReader=function(e){var t=new m;return t.prevTxId=e.readReverse(32),t.outputIndex=e.readUInt32LE(),t._scriptBuffer=e.readVarLengthBuffer(),t.sequenceNumber=e.readUInt32LE(),t},m.prototype.toBufferWriter=function(e){e||(e=new a),e.writeReverse(this.prevTxId),e.writeUInt32LE(this.outputIndex);var t=this._scriptBuffer;return e.writeVarintNum(t.length),e.write(t),e.writeUInt32LE(this.sequenceNumber),e},m.prototype.setScript=function(e){if(this._script=null,e instanceof c)this._script=e,this._script._isInput=!0,this._scriptBuffer=e.toBuffer();else if(u.isHexa(e))this._scriptBuffer=t.from(e,"hex");else if(n.isString(e))this._script=new c(e),this._script._isInput=!0,this._scriptBuffer=this._script.toBuffer();else{if(!s.isBuffer(e))throw new TypeError("Invalid argument type: script");this._scriptBuffer=t.from(e)}return this},m.prototype.getSignatures=function(){throw new o.AbstractMethodInvoked("Trying to sign unsupported output type (only P2PKH and P2SH multisig inputs are supported) for input: "+JSON.stringify(this))},m.prototype.getSatoshisBuffer=function(){return i.checkState(this.output instanceof f),i.checkState(this.output._satoshisBN),(new a).writeUInt64LEBN(this.output._satoshisBN).toBuffer()},m.prototype.isFullySigned=function(){throw new o.AbstractMethodInvoked("Input#isFullySigned")},m.prototype.isFinal=function(){return this.sequenceNumber!==m.MAXINT},m.prototype.addSignature=function(){throw new o.AbstractMethodInvoked("Input#addSignature")},m.prototype.clearSignatures=function(){throw new o.AbstractMethodInvoked("Input#clearSignatures")},m.prototype.hasWitnesses=function(){return!!(this.witnesses&&this.witnesses.length>0)},m.prototype.getWitnesses=function(){return this.witnesses},m.prototype.setWitnesses=function(e){this.witnesses=e},m.prototype.isValidSignature=function(e,t,r){return r=r||"ecdsa",t.signature.nhashtype=t.sigtype,h.verify(e,t.signature,t.publicKey,t.inputIndex,this.output.script,r)},m.prototype.isNull=function(){return"0000000000000000000000000000000000000000000000000000000000000000"===this.prevTxId.toString("hex")&&4294967295===this.outputIndex},m.prototype._estimateSize=function(){return this.toBufferWriter().toBuffer().length},m.prototype.lockForSeconds=function(e){if(i.checkArgument(n.isNumber(e)),e<0||e>=33553920)throw new o.Transaction.Input.LockTimeRange;return e=parseInt(Math.floor(e/512)),this.sequenceNumber=e|d,this},m.prototype.lockUntilBlockHeight=function(e){if(i.checkArgument(n.isNumber(e)),e<0||e>=p)throw new o.Transaction.Input.BlockHeightOutOfRange;return this.sequenceNumber=e,this},m.prototype.getLockTime=function(){return this.sequenceNumber&l?null:this.sequenceNumber&d?512*(65535&this.sequenceNumber):65535&this.sequenceNumber},e.exports=m}).call(this,r(0).Buffer)},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4),o=r(51),a=r(5),s=r(7),u=r(19),c=r(17),h=r(13);function f(e){if(!(this instanceof f))return new f(e);if(e instanceof f)return e;if(n.isObject(e))return this._fromObject(e);throw new c.InvalidArgument("TransactionSignatures must be instantiated from an object")}o(f,h),f.prototype._fromObject=function(e){return this._checkObjectArgs(e),this.publicKey=new u(e.publicKey),this.prevTxId=a.isBuffer(e.prevTxId)?e.prevTxId:t.from(e.prevTxId,"hex"),this.outputIndex=e.outputIndex,this.inputIndex=e.inputIndex,this.signature=e.signature instanceof h?e.signature:a.isBuffer(e.signature)?h.fromBuffer(e.signature):h.fromString(e.signature),this.sigtype=e.sigtype,this},f.prototype._checkObjectArgs=function(e){i.checkArgument(u(e.publicKey),"publicKey"),i.checkArgument(!n.isUndefined(e.inputIndex),"inputIndex"),i.checkArgument(!n.isUndefined(e.outputIndex),"outputIndex"),i.checkState(n.isNumber(e.inputIndex),"inputIndex must be a number"),i.checkState(n.isNumber(e.outputIndex),"outputIndex must be a number"),i.checkArgument(e.signature,"signature"),i.checkArgument(e.prevTxId,"prevTxId"),i.checkState(e.signature instanceof h||a.isBuffer(e.signature)||s.isHexa(e.signature),"signature must be a buffer or hexa value"),i.checkState(a.isBuffer(e.prevTxId)||s.isHexa(e.prevTxId),"prevTxId must be a buffer or hexa value"),i.checkArgument(e.sigtype,"sigtype"),i.checkState(n.isNumber(e.sigtype),"sigtype must be a number")},f.prototype.toObject=f.prototype.toJSON=function(){return{publicKey:this.publicKey.toString(),prevTxId:this.prevTxId.toString("hex"),outputIndex:this.outputIndex,inputIndex:this.inputIndex,signature:this.signature.toString(),sigtype:this.sigtype}},f.fromObject=function(e){return i.checkArgument(e),new f(e)},e.exports=f}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},i=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]r)?t=("rmd160"===e?new u:c(e)).update(t).digest():t.length0?this.redN=null:(this._maxwellTrick=!0,this.redN=this.n.toRed(this.red))}function c(e,t){this.curve=e,this.type=t,this.precomputed=null}e.exports=u,u.prototype.point=function(){throw new Error("Not implemented")},u.prototype.validate=function(){throw new Error("Not implemented")},u.prototype._fixedNafMul=function(e,t){s(e.precomputed);var r=e._getDoubles(),n=o(t,1,this._bitLength),i=(1<=u;t--)c=(c<<1)+n[t];a.push(c)}for(var h=this.jpoint(null,null,null),f=this.jpoint(null,null,null),l=i;l>0;l--){for(u=0;u=0;c--){for(t=0;c>=0&&0===a[c];c--)t++;if(c>=0&&t++,u=u.dblp(t),c<0)break;var h=a[c];s(0!==h),u="affine"===e.type?h>0?u.mixedAdd(i[h-1>>1]):u.mixedAdd(i[-h-1>>1].neg()):h>0?u.add(i[h-1>>1]):u.add(i[-h-1>>1].neg())}return"affine"===e.type?u.toP():u},u.prototype._wnafMulAdd=function(e,t,r,n,i){for(var s=this._wnafT1,u=this._wnafT2,c=this._wnafT3,h=0,f=0;f=1;f-=2){var d=f-1,p=f;if(1===s[d]&&1===s[p]){var m=[t[d],null,null,t[p]];0===t[d].y.cmp(t[p].y)?(m[1]=t[d].add(t[p]),m[2]=t[d].toJ().mixedAdd(t[p].neg())):0===t[d].y.cmp(t[p].y.redNeg())?(m[1]=t[d].toJ().mixedAdd(t[p]),m[2]=t[d].add(t[p].neg())):(m[1]=t[d].toJ().mixedAdd(t[p]),m[2]=t[d].toJ().mixedAdd(t[p].neg()));var g=[-3,-1,-5,-7,0,7,5,1,3],b=a(r[d],r[p]);h=Math.max(b[0].length,h),c[d]=new Array(h),c[p]=new Array(h);for(var v=0;v=0;f--){for(var M=0;f>=0;){var k=!0;for(v=0;v=0&&M++,_=_.dblp(M),f<0)break;for(v=0;v0?E=u[v][A-1>>1]:A<0&&(E=u[v][-A-1>>1].neg()),_="affine"===E.type?_.mixedAdd(E):_.add(E))}}for(f=0;f=Math.ceil((e.bitLength()+1)/t.step)},c.prototype._getDoubles=function(e,t){if(this.precomputed&&this.precomputed.doubles)return this.precomputed.doubles;for(var r=[this],n=this,i=0;i 2 bytes.");const r=i.decode(e);if(!t.isValidCode(r))throw new Error("multihash unknown function code: 0x"+r.toString(16));e=e.slice(i.decode.bytes);const n=i.decode(e);if(n<0)throw new Error("multihash invalid length: "+n);if((e=e.slice(i.decode.bytes)).length!==n)throw new Error("multihash length inconsistent: 0x"+a(e,"base16"));return{code:r,name:c[r],length:n,digest:e}},t.encode=function(e,r,n){if(!e||void 0===r)throw new Error("multihash encode requires at least two args: digest, code");const o=t.coerceCode(r);if(!(e instanceof Uint8Array))throw new Error("digest should be a Uint8Array");if(null==n&&(n=e.length),n&&e.length!==n)throw new Error("digest length should be equal to specified length.");const a=i.encode(o),s=i.encode(n);return u([a,s,e],a.length+s.length+e.length)},t.coerceCode=function(e){let r=e;if("string"==typeof e){if(void 0===o[e])throw new Error("Unrecognized hash function named: "+e);r=o[e]}if("number"!=typeof r)throw new Error("Hash function code should be a number. Got: "+r);if(void 0===c[r]&&!t.isAppCode(r))throw new Error("Unrecognized function code: "+r);return r},t.isAppCode=function(e){return e>0&&e<16},t.isValidCode=function(e){return!!t.isAppCode(e)||!!c[e]},t.validate=h,t.prefix=function(e){return h(e),e.subarray(0,2)}},function(e,t,r){"use strict";const n=r(59),i=r(148),o=r(146),a=r(42),s=r(301),u=r(302),c=r(89),h=r(149),f=r(151),l=Object.keys(a).reduce((e,t)=>(e[a[t]]=t,e),{});class d{constructor(e,t,r,a){if(p.isCID(e)){const t=e;return this.version=t.version,this.codec=t.codec,this.multihash=t.multihash,void(this.multibaseName=t.multibaseName||(0===t.version?"base58btc":"base32"))}if("string"==typeof e){const t=i.isEncoded(e);if(t){const r=i.decode(e);this.version=parseInt(r.slice(0,1).toString("hex"),16),this.codec=o.getCodec(r.slice(1)),this.multihash=o.rmPrefix(r.slice(1)),this.multibaseName=t}else this.version=0,this.codec="dag-pb",this.multihash=n.fromB58String(e),this.multibaseName="base58btc";return d.validateCID(this),void Object.defineProperty(this,"string",{value:e})}if(e instanceof Uint8Array){const t=e.slice(0,1),r=parseInt(t.toString("hex"),16);if(1===r){const t=e;this.version=r,this.codec=o.getCodec(t.slice(1)),this.multihash=o.rmPrefix(t.slice(1)),this.multibaseName="base32"}else this.version=0,this.codec="dag-pb",this.multihash=e,this.multibaseName="base58btc";d.validateCID(this)}else this.version=e,"number"==typeof t&&(t=l[t]),this.codec=t,this.multihash=r,this.multibaseName=a||(0===e?"base58btc":"base32"),d.validateCID(this)}get bytes(){let e=this._bytes;if(!e){if(0===this.version)e=this.multihash;else{if(1!==this.version)throw new Error("unsupported version");{const t=o.getCodeVarint(this.codec);e=c([[1],t,this.multihash],1+t.byteLength+this.multihash.byteLength)}}Object.defineProperty(this,"_bytes",{value:e})}return e}get prefix(){const e=o.getCodeVarint(this.codec),t=n.prefix(this.multihash);return c([[this.version],e,t],1+e.byteLength+t.byteLength)}get code(){return a[this.codec]}toV0(){if("dag-pb"!==this.codec)throw new Error("Cannot convert a non dag-pb CID to CIDv0");const{name:e,length:t}=n.decode(this.multihash);if("sha2-256"!==e)throw new Error("Cannot convert non sha2-256 multihash CID to CIDv0");if(32!==t)throw new Error("Cannot convert non 32 byte multihash CID to CIDv0");return new p(0,this.codec,this.multihash)}toV1(){return new p(1,this.codec,this.multihash)}toBaseEncodedString(e=this.multibaseName){if(this.string&&e===this.multibaseName)return this.string;let t=null;if(0===this.version){if("base58btc"!==e)throw new Error("not supported with CIDv0, to support different bases, please migrate the instance do CIDv1, you can do that through cid.toV1()");t=n.toB58String(this.multihash)}else{if(1!==this.version)throw new Error("unsupported version");t=h(i.encode(e,this.bytes))}return e===this.multibaseName&&Object.defineProperty(this,"string",{value:t}),t}[Symbol.for("nodejs.util.inspect.custom")](){return"CID("+this.toString()+")"}toString(e){return this.toBaseEncodedString(e)}toJSON(){return{codec:this.codec,version:this.version,hash:this.multihash}}equals(e){return this.codec===e.codec&&this.version===e.version&&f(this.multihash,e.multihash)}static validateCID(e){const t=s.checkCIDComponents(e);if(t)throw new Error(t)}}const p=u(d,{className:"CID",symbolName:"@ipld/js-cid/CID"});p.codecs=a,e.exports=p},function(e,t,r){"use strict";(function(t){var n=r(10),i=r(38),o=r(13),a=r(19),s=r(68),u=r(11),c=r(5),h=r(3),f=r(4),l=function e(t){if(!(this instanceof e))return new e(t);t&&this.set(t)};l.prototype.set=function(e){return this.hashbuf=e.hashbuf||this.hashbuf,this.endian=e.endian||this.endian,this.privkey=e.privkey||this.privkey,this.pubkey=e.pubkey||(this.privkey?this.privkey.publicKey:this.pubkey),this.sig=e.sig||this.sig,this.k=e.k||this.k,this.verified=e.verified||this.verified,this},l.prototype.privkey2pubkey=function(){this.pubkey=this.privkey.toPublicKey()},l.prototype.calci=function(){for(var e=0;e<4;e++){var t;this.sig.i=e;try{t=this.toPublicKey()}catch(e){console.error(e);continue}if(t.point.eq(this.pubkey.point))return this.sig.compressed=this.pubkey.compressed,this}throw this.sig.i=void 0,new Error("Unable to find valid recovery factor")},l.fromString=function(e){var t=JSON.parse(e);return new l(t)},l.prototype.randomK=function(){var e,t=i.getN();do{e=n.fromBuffer(s.getRandomBuffer(32))}while(!e.lt(t)||!e.gt(n.Zero));return this.k=e,this},l.prototype.deterministicK=function(e){h.isUndefined(e)&&(e=0);var r=t.alloc(32);r.fill(1);var o=t.alloc(32);o.fill(0);var a=this.privkey.bn.toBuffer({size:32}),s="little"===this.endian?c.reverse(this.hashbuf):this.hashbuf;o=u.sha256hmac(t.concat([r,t.from([0]),a,s]),o),r=u.sha256hmac(r,o),o=u.sha256hmac(t.concat([r,t.from([1]),a,s]),o),r=u.sha256hmac(r,o),r=u.sha256hmac(r,o);for(var f=n.fromBuffer(r),l=i.getN(),d=0;d>1,c=i.getN(),h=i.getG(),l=u?r.add(c):r,d=i.fromX(s,l);if(!d.mul(c).isInfinity())throw new Error("nR is not a valid curve point");var p=t.neg().umod(c),m=r.invm(c),g=d.mul(o).add(h.mul(p)).mul(m);return a.fromPoint(g,this.sig.compressed)},l.prototype.sigError=function(){if(!c.isBuffer(this.hashbuf)||32!==this.hashbuf.length)return"hashbuf must be a 32 byte buffer";var e=this.sig.r,t=this.sig.s;if(!(e.gt(n.Zero)&&e.lt(i.getN())&&t.gt(n.Zero)&&t.lt(i.getN())))return"r and s not in range";var r=n.fromBuffer(this.hashbuf,this.endian?{endian:this.endian}:void 0),o=i.getN(),a=t.invm(o),s=a.mul(r).umod(o),u=a.mul(e).umod(o),h=i.getG().mulAdd(s,this.pubkey.point,u);return h.isInfinity()?"p is infinity":0!==h.getX().umod(o).cmp(e)&&"Invalid signature"},l.toLowS=function(e){return e.gt(n.fromBuffer(t.from("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0","hex")))&&(e=i.getN().sub(e)),e},l.prototype._findSignature=function(e,t){var r,o,a,s=i.getN(),u=i.getG(),c=0;do{(!this.k||c>0)&&this.deterministicK(c),c++,r=this.k,o=u.mul(r).x.umod(s),a=r.invm(s).mul(t.add(e.mul(o))).umod(s)}while(o.cmp(n.Zero)<=0||a.cmp(n.Zero)<=0);return{s:a=l.toLowS(a),r:o}},l.prototype.sign=function(){var e=this.hashbuf,t=this.privkey,r=t.bn;f.checkState(e&&t&&r,new Error("invalid parameters")),f.checkState(c.isBuffer(e)&&32===e.length,new Error("hashbuf must be a 32 byte buffer"));var i=n.fromBuffer(e,this.endian?{endian:this.endian}:void 0),a=this._findSignature(r,i);return a.compressed=this.pubkey.compressed,this.sig=new o(a),this},l.prototype.signRandomK=function(){return this.randomK(),this.sign()},l.prototype.toString=function(){var e={};return this.hashbuf&&(e.hashbuf=this.hashbuf.toString("hex")),this.privkey&&(e.privkey=this.privkey.toString()),this.pubkey&&(e.pubkey=this.pubkey.toString()),this.sig&&(e.sig=this.sig.toString()),this.k&&(e.k=this.k.toString()),JSON.stringify(e)},l.prototype.verify=function(){return this.sigError()?this.verified=!1:this.verified=!0,this},l.sign=function(e,t,r){return l().set({hashbuf:e,endian:r,privkey:t}).sign().sig},l.verify=function(e,t,r,n){return l().set({hashbuf:e,endian:n,sig:t,pubkey:r}).verify().verified},e.exports=l}).call(this,r(0).Buffer)},function(e,t,r){var n=r(2).Buffer;function i(e){n.isBuffer(e)||(e=n.from(e));for(var t=e.length/4|0,r=new Array(t),i=0;i>>24]^h[p>>>16&255]^f[m>>>8&255]^l[255&g]^t[b++],a=c[p>>>24]^h[m>>>16&255]^f[g>>>8&255]^l[255&d]^t[b++],s=c[m>>>24]^h[g>>>16&255]^f[d>>>8&255]^l[255&p]^t[b++],u=c[g>>>24]^h[d>>>16&255]^f[p>>>8&255]^l[255&m]^t[b++],d=o,p=a,m=s,g=u;return o=(n[d>>>24]<<24|n[p>>>16&255]<<16|n[m>>>8&255]<<8|n[255&g])^t[b++],a=(n[p>>>24]<<24|n[m>>>16&255]<<16|n[g>>>8&255]<<8|n[255&d])^t[b++],s=(n[m>>>24]<<24|n[g>>>16&255]<<16|n[d>>>8&255]<<8|n[255&p])^t[b++],u=(n[g>>>24]<<24|n[d>>>16&255]<<16|n[p>>>8&255]<<8|n[255&m])^t[b++],[o>>>=0,a>>>=0,s>>>=0,u>>>=0]}var s=[0,1,2,4,8,16,32,64,128,27,54],u=function(){for(var e=new Array(256),t=0;t<256;t++)e[t]=t<128?t<<1:t<<1^283;for(var r=[],n=[],i=[[],[],[],[]],o=[[],[],[],[]],a=0,s=0,u=0;u<256;++u){var c=s^s<<1^s<<2^s<<3^s<<4;c=c>>>8^255&c^99,r[a]=c,n[c]=a;var h=e[a],f=e[h],l=e[f],d=257*e[c]^16843008*c;i[0][a]=d<<24|d>>>8,i[1][a]=d<<16|d>>>16,i[2][a]=d<<8|d>>>24,i[3][a]=d,d=16843009*l^65537*f^257*h^16843008*a,o[0][c]=d<<24|d>>>8,o[1][c]=d<<16|d>>>16,o[2][c]=d<<8|d>>>24,o[3][c]=d,0===a?a=s=1:(a=h^e[e[e[l^h]]],s^=e[e[s]])}return{SBOX:r,INV_SBOX:n,SUB_MIX:i,INV_SUB_MIX:o}}();function c(e){this._key=i(e),this._reset()}c.blockSize=16,c.keySize=32,c.prototype.blockSize=c.blockSize,c.prototype.keySize=c.keySize,c.prototype._reset=function(){for(var e=this._key,t=e.length,r=t+6,n=4*(r+1),i=[],o=0;o>>24,a=u.SBOX[a>>>24]<<24|u.SBOX[a>>>16&255]<<16|u.SBOX[a>>>8&255]<<8|u.SBOX[255&a],a^=s[o/t|0]<<24):t>6&&o%t==4&&(a=u.SBOX[a>>>24]<<24|u.SBOX[a>>>16&255]<<16|u.SBOX[a>>>8&255]<<8|u.SBOX[255&a]),i[o]=i[o-t]^a}for(var c=[],h=0;h>>24]]^u.INV_SUB_MIX[1][u.SBOX[l>>>16&255]]^u.INV_SUB_MIX[2][u.SBOX[l>>>8&255]]^u.INV_SUB_MIX[3][u.SBOX[255&l]]}this._nRounds=r,this._keySchedule=i,this._invKeySchedule=c},c.prototype.encryptBlockRaw=function(e){return a(e=i(e),this._keySchedule,u.SUB_MIX,u.SBOX,this._nRounds)},c.prototype.encryptBlock=function(e){var t=this.encryptBlockRaw(e),r=n.allocUnsafe(16);return r.writeUInt32BE(t[0],0),r.writeUInt32BE(t[1],4),r.writeUInt32BE(t[2],8),r.writeUInt32BE(t[3],12),r},c.prototype.decryptBlock=function(e){var t=(e=i(e))[1];e[1]=e[3],e[3]=t;var r=a(e,this._invKeySchedule,u.INV_SUB_MIX,u.INV_SBOX,this._nRounds),o=n.allocUnsafe(16);return o.writeUInt32BE(r[0],0),o.writeUInt32BE(r[3],4),o.writeUInt32BE(r[2],8),o.writeUInt32BE(r[1],12),o},c.prototype.scrub=function(){o(this._keySchedule),o(this._invKeySchedule),o(this._key)},e.exports.AES=c},function(e,t,r){var n=r(2).Buffer,i=r(72);e.exports=function(e,t,r,o){if(n.isBuffer(e)||(e=n.from(e,"binary")),t&&(n.isBuffer(t)||(t=n.from(t,"binary")),8!==t.length))throw new RangeError("salt should be Buffer with 8 byte length");for(var a=r/8,s=n.alloc(a),u=n.alloc(o||0),c=n.alloc(0);a>0||o>0;){var h=new i;h.update(c),h.update(e),t&&h.update(t),c=h.digest();var f=0;if(a>0){var l=s.length-a;f=Math.min(a,c.length),c.copy(s,l,0,f),a-=f}if(f0){var d=u.length-o,p=Math.min(o,c.length-f);c.copy(u,d,f,f+p),o-=p}}return c.fill(0),{key:s,iv:u}}},function(e,t,r){var n=r(351),i=r(358),o=r(359),a=r(94),s=r(79),u=r(2).Buffer;function c(e){var t;"object"!=typeof e||u.isBuffer(e)||(t=e.passphrase,e=e.key),"string"==typeof e&&(e=u.from(e));var r,c,h=o(e,t),f=h.tag,l=h.data;switch(f){case"CERTIFICATE":c=n.certificate.decode(l,"der").tbsCertificate.subjectPublicKeyInfo;case"PUBLIC KEY":switch(c||(c=n.PublicKey.decode(l,"der")),r=c.algorithm.algorithm.join(".")){case"1.2.840.113549.1.1.1":return n.RSAPublicKey.decode(c.subjectPublicKey.data,"der");case"1.2.840.10045.2.1":return c.subjectPrivateKey=c.subjectPublicKey,{type:"ec",data:c};case"1.2.840.10040.4.1":return c.algorithm.params.pub_key=n.DSAparam.decode(c.subjectPublicKey.data,"der"),{type:"dsa",data:c.algorithm.params};default:throw new Error("unknown key id "+r)}case"ENCRYPTED PRIVATE KEY":l=function(e,t){var r=e.algorithm.decrypt.kde.kdeparams.salt,n=parseInt(e.algorithm.decrypt.kde.kdeparams.iters.toString(),10),o=i[e.algorithm.decrypt.cipher.algo.join(".")],c=e.algorithm.decrypt.cipher.iv,h=e.subjectPrivateKey,f=parseInt(o.split("-")[1],10)/8,l=s.pbkdf2Sync(t,r,n,f,"sha1"),d=a.createDecipheriv(o,l,c),p=[];return p.push(d.update(h)),p.push(d.final()),u.concat(p)}(l=n.EncryptedPrivateKey.decode(l,"der"),t);case"PRIVATE KEY":switch(r=(c=n.PrivateKey.decode(l,"der")).algorithm.algorithm.join(".")){case"1.2.840.113549.1.1.1":return n.RSAPrivateKey.decode(c.subjectPrivateKey,"der");case"1.2.840.10045.2.1":return{curve:c.algorithm.curve,privateKey:n.ECPrivateKey.decode(c.subjectPrivateKey,"der").privateKey};case"1.2.840.10040.4.1":return c.algorithm.params.priv_key=n.DSAparam.decode(c.subjectPrivateKey,"der"),{type:"dsa",params:c.algorithm.params};default:throw new Error("unknown key id "+r)}case"RSA PUBLIC KEY":return n.RSAPublicKey.decode(l,"der");case"RSA PRIVATE KEY":return n.RSAPrivateKey.decode(l,"der");case"DSA PRIVATE KEY":return{type:"dsa",params:n.DSAPrivateKey.decode(l,"der")};case"EC PRIVATE KEY":return{curve:(l=n.ECPrivateKey.decode(l,"der")).parameters.value,privateKey:l.privateKey};default:throw new Error("unknown key type "+f)}}e.exports=c,c.signature=n.signature},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(80),o=r(0),a="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".split(""),s=function e(r){if(!(this instanceof e))return new e(r);if(t.isBuffer(r)){var n=r;this.fromBuffer(n)}else if("string"==typeof r){var i=r;this.fromString(i)}else r&&this.set(r)};s.validCharacters=function(e){return o.Buffer.isBuffer(e)&&(e=e.toString()),n.every(n.map(e,(function(e){return n.includes(a,e)})))},s.prototype.set=function(e){return this.buf=e.buf||this.buf||void 0,this},s.encode=function(e){if(!o.Buffer.isBuffer(e))throw new Error("Input should be a buffer");return i.encode(e)},s.decode=function(e){if("string"!=typeof e)throw new Error("Input should be a string");return t.from(i.decode(e))},s.prototype.fromBuffer=function(e){return this.buf=e,this},s.prototype.fromString=function(e){var t=s.decode(e);return this.buf=t,this},s.prototype.toBuffer=function(){return this.buf},s.prototype.toString=function(){return s.encode(this.buf)},e.exports=s}).call(this,r(0).Buffer)},function(e,t,r){e.exports=r(102),e.exports.Input=r(103),e.exports.Output=r(22),e.exports.UnspentOutput=r(182),e.exports.Signature=r(52),e.exports.Sighash=r(26),e.exports.SighashWitness=r(67)},function(e,t,r){"use strict";(function(t){var n=r(13),i=(r(14),r(22),r(21)),o=r(12),a=(r(10),r(11)),s=r(61),u=r(4),c=r(3),h=function(e,r,s,u,c){var h,f,l;if(!(r&n.SIGHASH_ANYONECANPAY)){for(var d=[],p=0;p>>=8)}return r},e.exports=i}).call(this,r(9),r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(10),o=r(5),a=r(21),s=r(12),u=r(11),c=(r(7),r(4)),h=function e(t){if(!(this instanceof e))return new e(t);var r=e._from(t);return this.version=r.version,this.prevHash=r.prevHash,this.merkleRoot=r.merkleRoot,this.time=r.time,this.timestamp=r.time,this.bits=r.bits,this.nonce=r.nonce,r.hash&&c.checkState(this.hash===r.hash,"Argument object hash property does not match block hash."),this};h._from=function(e){var t={};if(o.isBuffer(e))t=h._fromBufferReader(a(e));else{if(!n.isObject(e))throw new TypeError("Unrecognized argument for BlockHeader");t=h._fromObject(e)}return t},h._fromObject=function(e){c.checkArgument(e,"data is required");var r=e.prevHash,i=e.merkleRoot;return n.isString(e.prevHash)&&(r=o.reverse(t.from(e.prevHash,"hex"))),n.isString(e.merkleRoot)&&(i=o.reverse(t.from(e.merkleRoot,"hex"))),{hash:e.hash,version:e.version,prevHash:r,merkleRoot:i,time:e.time,timestamp:e.time,bits:e.bits,nonce:e.nonce}},h.fromObject=function(e){var t=h._fromObject(e);return new h(t)},h.fromRawBlock=function(e){o.isBuffer(e)||(e=t.from(e,"binary"));var r=a(e);r.pos=h.Constants.START_OF_HEADER;var n=h._fromBufferReader(r);return new h(n)},h.fromBuffer=function(e){var t=h._fromBufferReader(a(e));return new h(t)},h.fromString=function(e){var r=t.from(e,"hex");return h.fromBuffer(r)},h._fromBufferReader=function(e){var t={};return t.version=e.readInt32LE(),t.prevHash=e.read(32),t.merkleRoot=e.read(32),t.time=e.readUInt32LE(),t.bits=e.readUInt32LE(),t.nonce=e.readUInt32LE(),t},h.fromBufferReader=function(e){var t=h._fromBufferReader(e);return new h(t)},h.prototype.toObject=h.prototype.toJSON=function(){return{hash:this.hash,version:this.version,prevHash:o.reverse(this.prevHash).toString("hex"),merkleRoot:o.reverse(this.merkleRoot).toString("hex"),time:this.time,bits:this.bits,nonce:this.nonce}},h.prototype.toBuffer=function(){return this.toBufferWriter().concat()},h.prototype.toString=function(){return this.toBuffer().toString("hex")},h.prototype.toBufferWriter=function(e){return e||(e=new s),e.writeInt32LE(this.version),e.write(this.prevHash),e.write(this.merkleRoot),e.writeUInt32LE(this.time),e.writeUInt32LE(this.bits),e.writeUInt32LE(this.nonce),e},h.prototype.getTargetDifficulty=function(e){e=e||this.bits;for(var t=new i(16777215&e),r=8*((e>>>24)-3);r-- >0;)t=t.mul(new i(2));return t},h.prototype.getDifficulty=function(){var e=this.getTargetDifficulty(486604799).mul(new i(Math.pow(10,8))),t=this.getTargetDifficulty(),r=e.div(t).toString(10),n=r.length-8;return r=r.slice(0,n)+"."+r.slice(n),parseFloat(r)},h.prototype._getHash=function(){var e=this.toBuffer();return u.sha256sha256(e)};var f={configurable:!1,enumerable:!0,get:function(){return this._id||(this._id=a(this._getHash()).readReverse().toString("hex")),this._id},set:n.noop};Object.defineProperty(h.prototype,"id",f),Object.defineProperty(h.prototype,"hash",f),h.prototype.validTimestamp=function(){var e=Math.round((new Date).getTime()/1e3);return!(this.time>e+h.Constants.MAX_TIME_OFFSET)},h.prototype.validProofOfWork=function(){var e=new i(this.id,"hex"),t=this.getTargetDifficulty();return!(e.cmp(t)>0)},h.prototype.inspect=function(){return""},h.Constants={START_OF_HEADER:8,MAX_TIME_OFFSET:7200,LARGEST_HASH:new i("10000000000000000000000000000000000000000000000000000000000000000","hex")},e.exports=h}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n,i=this&&this.__extends||(n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)},function(e,t){function r(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},a=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]>>32-t}function c(e,t,r,n,i,o,a){return u(e+(t&r|~t&n)+i+o|0,a)+t|0}function h(e,t,r,n,i,o,a){return u(e+(t&n|r&~n)+i+o|0,a)+t|0}function f(e,t,r,n,i,o,a){return u(e+(t^r^n)+i+o|0,a)+t|0}function l(e,t,r,n,i,o,a){return u(e+(r^(t|~n))+i+o|0,a)+t|0}n(s,i),s.prototype._update=function(){for(var e=a,t=0;t<16;++t)e[t]=this._block.readInt32LE(4*t);var r=this._a,n=this._b,i=this._c,o=this._d;r=c(r,n,i,o,e[0],3614090360,7),o=c(o,r,n,i,e[1],3905402710,12),i=c(i,o,r,n,e[2],606105819,17),n=c(n,i,o,r,e[3],3250441966,22),r=c(r,n,i,o,e[4],4118548399,7),o=c(o,r,n,i,e[5],1200080426,12),i=c(i,o,r,n,e[6],2821735955,17),n=c(n,i,o,r,e[7],4249261313,22),r=c(r,n,i,o,e[8],1770035416,7),o=c(o,r,n,i,e[9],2336552879,12),i=c(i,o,r,n,e[10],4294925233,17),n=c(n,i,o,r,e[11],2304563134,22),r=c(r,n,i,o,e[12],1804603682,7),o=c(o,r,n,i,e[13],4254626195,12),i=c(i,o,r,n,e[14],2792965006,17),r=h(r,n=c(n,i,o,r,e[15],1236535329,22),i,o,e[1],4129170786,5),o=h(o,r,n,i,e[6],3225465664,9),i=h(i,o,r,n,e[11],643717713,14),n=h(n,i,o,r,e[0],3921069994,20),r=h(r,n,i,o,e[5],3593408605,5),o=h(o,r,n,i,e[10],38016083,9),i=h(i,o,r,n,e[15],3634488961,14),n=h(n,i,o,r,e[4],3889429448,20),r=h(r,n,i,o,e[9],568446438,5),o=h(o,r,n,i,e[14],3275163606,9),i=h(i,o,r,n,e[3],4107603335,14),n=h(n,i,o,r,e[8],1163531501,20),r=h(r,n,i,o,e[13],2850285829,5),o=h(o,r,n,i,e[2],4243563512,9),i=h(i,o,r,n,e[7],1735328473,14),r=f(r,n=h(n,i,o,r,e[12],2368359562,20),i,o,e[5],4294588738,4),o=f(o,r,n,i,e[8],2272392833,11),i=f(i,o,r,n,e[11],1839030562,16),n=f(n,i,o,r,e[14],4259657740,23),r=f(r,n,i,o,e[1],2763975236,4),o=f(o,r,n,i,e[4],1272893353,11),i=f(i,o,r,n,e[7],4139469664,16),n=f(n,i,o,r,e[10],3200236656,23),r=f(r,n,i,o,e[13],681279174,4),o=f(o,r,n,i,e[0],3936430074,11),i=f(i,o,r,n,e[3],3572445317,16),n=f(n,i,o,r,e[6],76029189,23),r=f(r,n,i,o,e[9],3654602809,4),o=f(o,r,n,i,e[12],3873151461,11),i=f(i,o,r,n,e[15],530742520,16),r=l(r,n=f(n,i,o,r,e[2],3299628645,23),i,o,e[0],4096336452,6),o=l(o,r,n,i,e[7],1126891415,10),i=l(i,o,r,n,e[14],2878612391,15),n=l(n,i,o,r,e[5],4237533241,21),r=l(r,n,i,o,e[12],1700485571,6),o=l(o,r,n,i,e[3],2399980690,10),i=l(i,o,r,n,e[10],4293915773,15),n=l(n,i,o,r,e[1],2240044497,21),r=l(r,n,i,o,e[8],1873313359,6),o=l(o,r,n,i,e[15],4264355552,10),i=l(i,o,r,n,e[6],2734768916,15),n=l(n,i,o,r,e[13],1309151649,21),r=l(r,n,i,o,e[4],4149444226,6),o=l(o,r,n,i,e[11],3174756917,10),i=l(i,o,r,n,e[2],718787259,15),n=l(n,i,o,r,e[9],3951481745,21),this._a=this._a+r|0,this._b=this._b+n|0,this._c=this._c+i|0,this._d=this._d+o|0},s.prototype._digest=function(){this._block[this._blockOffset++]=128,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=o.allocUnsafe(16);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e},e.exports=s},function(e,t,r){"use strict";var n=r(35).codes.ERR_STREAM_PREMATURE_CLOSE;function i(){}e.exports=function e(t,r,o){if("function"==typeof r)return e(t,null,r);r||(r={}),o=function(e){var t=!1;return function(){if(!t){t=!0;for(var r=arguments.length,n=new Array(r),i=0;i>>32-t}function m(e,t,r,n,i,o,a,s){return p(e+(t^r^n)+o+a|0,s)+i|0}function g(e,t,r,n,i,o,a,s){return p(e+(t&r|~t&n)+o+a|0,s)+i|0}function b(e,t,r,n,i,o,a,s){return p(e+((t|~r)^n)+o+a|0,s)+i|0}function v(e,t,r,n,i,o,a,s){return p(e+(t&n|r&~n)+o+a|0,s)+i|0}function y(e,t,r,n,i,o,a,s){return p(e+(t^(r|~n))+o+a|0,s)+i|0}i(d,o),d.prototype._update=function(){for(var e=a,t=0;t<16;++t)e[t]=this._block.readInt32LE(4*t);for(var r=0|this._a,n=0|this._b,i=0|this._c,o=0|this._d,d=0|this._e,w=0|this._a,_=0|this._b,S=0|this._c,M=0|this._d,k=0|this._e,E=0;E<80;E+=1){var A,x;E<16?(A=m(r,n,i,o,d,e[s[E]],f[0],c[E]),x=y(w,_,S,M,k,e[u[E]],l[0],h[E])):E<32?(A=g(r,n,i,o,d,e[s[E]],f[1],c[E]),x=v(w,_,S,M,k,e[u[E]],l[1],h[E])):E<48?(A=b(r,n,i,o,d,e[s[E]],f[2],c[E]),x=b(w,_,S,M,k,e[u[E]],l[2],h[E])):E<64?(A=v(r,n,i,o,d,e[s[E]],f[3],c[E]),x=g(w,_,S,M,k,e[u[E]],l[3],h[E])):(A=y(r,n,i,o,d,e[s[E]],f[4],c[E]),x=m(w,_,S,M,k,e[u[E]],l[4],h[E])),r=d,d=o,o=p(i,10),i=n,n=A,w=k,k=M,M=p(S,10),S=_,_=x}var I=this._b+i+M|0;this._b=this._c+o+k|0,this._c=this._d+d+w|0,this._d=this._e+r+_|0,this._e=this._a+n+S|0,this._a=I},d.prototype._digest=function(){this._block[this._blockOffset++]=128,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=n.alloc?n.alloc(20):new n(20);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e.writeInt32LE(this._e,16),e},e.exports=d},function(e,t,r){(t=e.exports=function(e){e=e.toLowerCase();var r=t[e];if(!r)throw new Error(e+" is not supported (we accept pull requests)");return new r}).sha=r(217),t.sha1=r(218),t.sha224=r(219),t.sha256=r(120),t.sha384=r(220),t.sha512=r(121)},function(e,t,r){(t=e.exports=r(122)).Stream=t,t.Readable=t,t.Writable=r(78),t.Duplex=r(29),t.Transform=r(126),t.PassThrough=r(226)},function(e,t,r){var n=r(0),i=n.Buffer;function o(e,t){for(var r in e)t[r]=e[r]}function a(e,t,r){return i(e,t,r)}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?e.exports=n:(o(n,t),t.Buffer=a),o(i,a),a.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return i(e,t,r)},a.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var n=i(e);return void 0!==t?"string"==typeof r?n.fill(t,r):n.fill(t):n.fill(0),n},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return i(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n.SlowBuffer(e)}},function(e,t,r){"use strict";(function(t,n,i){var o=r(54);function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,r){var n=e.entry;e.entry=null;for(;n;){var i=n.callback;t.pendingcb--,i(r),n=n.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=v;var s,u=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?n:o.nextTick;v.WritableState=b;var c=Object.create(r(40));c.inherits=r(1);var h={deprecate:r(118)},f=r(123),l=r(77).Buffer,d=i.Uint8Array||function(){};var p,m=r(124);function g(){}function b(e,t){s=s||r(29),e=e||{};var n=t instanceof s;this.objectMode=!!e.objectMode,n&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var i=e.highWaterMark,c=e.writableHighWaterMark,h=this.objectMode?16:16384;this.highWaterMark=i||0===i?i:n&&(c||0===c)?c:h,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var r=e._writableState,n=r.sync,i=r.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(r),t)!function(e,t,r,n,i){--t.pendingcb,r?(o.nextTick(i,n),o.nextTick(k,e,t),e._writableState.errorEmitted=!0,e.emit("error",n)):(i(n),e._writableState.errorEmitted=!0,e.emit("error",n),k(e,t))}(e,r,n,t,i);else{var a=S(r);a||r.corked||r.bufferProcessing||!r.bufferedRequest||_(e,r),n?u(w,e,r,a,i):w(e,r,a,i)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function v(e){if(s=s||r(29),!(p.call(v,this)||this instanceof s))return new v(e);this._writableState=new b(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function y(e,t,r,n,i,o,a){t.writelen=n,t.writecb=a,t.writing=!0,t.sync=!0,r?e._writev(i,t.onwrite):e._write(i,o,t.onwrite),t.sync=!1}function w(e,t,r,n){r||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,n(),k(e,t)}function _(e,t){t.bufferProcessing=!0;var r=t.bufferedRequest;if(e._writev&&r&&r.next){var n=t.bufferedRequestCount,i=new Array(n),o=t.corkedRequestsFree;o.entry=r;for(var s=0,u=!0;r;)i[s]=r,r.isBuf||(u=!1),r=r.next,s+=1;i.allBuffers=u,y(e,t,!0,t.length,i,"",o.finish),t.pendingcb++,t.lastBufferedRequest=null,o.next?(t.corkedRequestsFree=o.next,o.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;r;){var c=r.chunk,h=r.encoding,f=r.callback;if(y(e,t,!1,t.objectMode?1:c.length,c,h,f),r=r.next,t.bufferedRequestCount--,t.writing)break}null===r&&(t.lastBufferedRequest=null)}t.bufferedRequest=r,t.bufferProcessing=!1}function S(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function M(e,t){e._final((function(r){t.pendingcb--,r&&e.emit("error",r),t.prefinished=!0,e.emit("prefinish"),k(e,t)}))}function k(e,t){var r=S(t);return r&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,o.nextTick(M,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),r}c.inherits(v,f),b.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(b.prototype,"buffer",{get:h.deprecate((function(){return this.getBuffer()}),"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(p=Function.prototype[Symbol.hasInstance],Object.defineProperty(v,Symbol.hasInstance,{value:function(e){return!!p.call(this,e)||this===v&&(e&&e._writableState instanceof b)}})):p=function(e){return e instanceof this},v.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},v.prototype.write=function(e,t,r){var n,i=this._writableState,a=!1,s=!i.objectMode&&(n=e,l.isBuffer(n)||n instanceof d);return s&&!l.isBuffer(e)&&(e=function(e){return l.from(e)}(e)),"function"==typeof t&&(r=t,t=null),s?t="buffer":t||(t=i.defaultEncoding),"function"!=typeof r&&(r=g),i.ended?function(e,t){var r=new Error("write after end");e.emit("error",r),o.nextTick(t,r)}(this,r):(s||function(e,t,r,n){var i=!0,a=!1;return null===r?a=new TypeError("May not write null values to stream"):"string"==typeof r||void 0===r||t.objectMode||(a=new TypeError("Invalid non-string/buffer chunk")),a&&(e.emit("error",a),o.nextTick(n,a),i=!1),i}(this,i,e,r))&&(i.pendingcb++,a=function(e,t,r,n,i,o){if(!r){var a=function(e,t,r){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=l.from(t,r));return t}(t,n,i);n!==a&&(r=!0,i="buffer",n=a)}var s=t.objectMode?1:n.length;t.length+=s;var u=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(v.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),v.prototype._write=function(e,t,r){r(new Error("_write() is not implemented"))},v.prototype._writev=null,v.prototype.end=function(e,t,r){var n=this._writableState;"function"==typeof e?(r=e,e=null,t=null):"function"==typeof t&&(r=t,t=null),null!=e&&this.write(e,t),n.corked&&(n.corked=1,this.uncork()),n.ending||n.finished||function(e,t,r){t.ending=!0,k(e,t),r&&(t.finished?o.nextTick(r):e.once("finish",r));t.ended=!0,e.writable=!1}(this,n,r)},Object.defineProperty(v.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),v.prototype.destroy=m.destroy,v.prototype._undestroy=m.undestroy,v.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,r(9),r(125).setImmediate,r(8))},function(e,t,r){t.pbkdf2=r(231),t.pbkdf2Sync=r(129)},function(e,t,r){var n=r(245);e.exports=n("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")},function(e,t,r){var n;function i(e){this.rand=e}if(e.exports=function(e){return n||(n=new i(null)),n.generate(e)},e.exports.Rand=i,i.prototype.generate=function(e){return this._rand(e)},i.prototype._rand=function(e){if(this.rand.getBytes)return this.rand.getBytes(e);for(var t=new Uint8Array(e),r=0;r>2,r=(3&e[0])<<8|e[1],t?31===t?n*(r?NaN:Infinity):n*Math.pow(2,t-25)*(1024+r):5.960464477539063e-8*n*r},t.arrayBufferToBignumber=function(e){const t=e.byteLength;let r="";for(let i=0;i{const t=new Map,r=Object.keys(e),n=r.length;for(let i=0;ie*s+t,t.buildInt64=(e,r,n,o)=>{const s=t.buildInt32(e,r),u=t.buildInt32(n,o);return s>2097151?new i(s).times(a).plus(u):s*a+u},t.writeHalf=function(e,t){const r=n.allocUnsafe(4);r.writeFloatBE(t,0);const i=r.readUInt32BE(0);if(0!=(8191&i))return!1;var o=i>>16&32768;const a=i>>23&255,s=8388607&i;if(a>=113&&a<=142)o+=(a-112<<10)+(s>>13);else{if(!(a>=103&&a<113))return!1;if(s&(1<<126-a)-1)return!1;o+=s+8388608>>126-a}return e.writeUInt16BE(o,0),!0},t.keySorter=function(e,t){var r=e[0].byteLength,n=t[0].byteLength;return r>n?1:n>r?-1:e[0].compare(t[0])},t.isNegativeZero=e=>0===e&&1/e<0,t.nextPowerOf2=e=>{let t=0;if(e&&!(e&e-1))return e;for(;0!==e;)e>>=1,t+=1;return 1<o.decode(e),encodeText:e=>a.encode(e),concat:function(e,t){const r=new Uint8Array(t);let n=0;for(const t of e)r.set(t,n),n+=t.length;return r}}},function(e,t,r){"use strict";const{names:n}=r(43),{TextEncoder:i}=r(44),o=new i;e.exports=function(e,t="utf8"){if("utf8"===t||"utf-8"===t)return o.encode(e);if("ascii"===t)return function(e){const t=new Uint8Array(e.length);for(let r=0;re+t.length,0));const r=new Uint8Array(t);let n=0;for(const t of e)r.set(t,n),n+=t.length;return r}},function(e,t,r){var n=r(299),i=r(300);e.exports={blake2b:n.blake2b,blake2bHex:n.blake2bHex,blake2bInit:n.blake2bInit,blake2bUpdate:n.blake2bUpdate,blake2bFinal:n.blake2bFinal,blake2s:i.blake2s,blake2sHex:i.blake2sHex,blake2sInit:i.blake2sInit,blake2sUpdate:i.blake2sUpdate,blake2sFinal:i.blake2sFinal}},function(e,t,r){"use strict";(function(t,n){var i=e.exports;i.version="v"+r(326).version,i.versionGuard=function(e){if(void 0!==e){throw new Error("More than one instance of bitcore-lib found. Please make sure to require bitcore-lib and check that submodules do not also include their own bitcore-lib dependency.")}},i.versionGuard(t._bitcore),t._bitcore=i.version,i.crypto={},i.crypto.BN=r(10),i.crypto.ECDSA=r(61),i.crypto.Hash=r(11),i.crypto.Random=r(68),i.crypto.Point=r(38),i.crypto.Signature=r(13),i.encoding={},i.encoding.Base58=r(65),i.encoding.Base58Check=r(49),i.encoding.BufferReader=r(21),i.encoding.BufferWriter=r(12),i.encoding.Varint=r(374),i.util={},i.util.buffer=r(5),i.util.js=r(7),i.util.preconditions=r(4),i.errors=r(17),i.Address=r(20),i.Block=r(375),i.MerkleBlock=r(183),i.BlockHeader=r(69),i.HDPrivateKey=r(184),i.HDPublicKey=r(185),i.Message=r(377),i.Networks=r(32),i.Opcode=r(101),i.PrivateKey=r(48),i.PublicKey=r(19),i.Script=r(14),i.Transaction=r(66),i.URI=r(378),i.Unit=r(104),i.deps={},i.deps.bnjs=r(160),i.deps.bs58=r(80),i.deps.Buffer=n,i.deps.elliptic=r(31),i.deps._=r(3),i.Transaction.sighash=r(26)}).call(this,r(8),r(0).Buffer)},function(e,t,r){"use strict";t.randomBytes=t.rng=t.pseudoRandomBytes=t.prng=r(30),t.createHash=t.Hash=r(24),t.createHmac=t.Hmac=r(55);var n=r(329),i=Object.keys(n),o=["sha1","sha224","sha256","sha384","sha512","md5","rmd160"].concat(i);t.getHashes=function(){return o};var a=r(79);t.pbkdf2=a.pbkdf2,t.pbkdf2Sync=a.pbkdf2Sync;var s=r(330);t.Cipher=s.Cipher,t.createCipher=s.createCipher,t.Cipheriv=s.Cipheriv,t.createCipheriv=s.createCipheriv,t.Decipher=s.Decipher,t.createDecipher=s.createDecipher,t.Decipheriv=s.Decipheriv,t.createDecipheriv=s.createDecipheriv,t.getCiphers=s.getCiphers,t.listCiphers=s.listCiphers;var u=r(345);t.DiffieHellmanGroup=u.DiffieHellmanGroup,t.createDiffieHellmanGroup=u.createDiffieHellmanGroup,t.getDiffieHellman=u.getDiffieHellman,t.createDiffieHellman=u.createDiffieHellman,t.DiffieHellman=u.DiffieHellman;var c=r(348);t.createSign=c.createSign,t.Sign=c.Sign,t.createVerify=c.createVerify,t.Verify=c.Verify,t.createECDH=r(361);var h=r(362);t.publicEncrypt=h.publicEncrypt,t.privateEncrypt=h.privateEncrypt,t.publicDecrypt=h.publicDecrypt,t.privateDecrypt=h.privateDecrypt;var f=r(365);t.randomFill=f.randomFill,t.randomFillSync=f.randomFillSync,t.createCredentials=function(){throw new Error(["sorry, createCredentials is not implemented yet","we accept pull requests","https://github.com/crypto-browserify/crypto-browserify"].join("\n"))},t.constants={DH_CHECK_P_NOT_SAFE_PRIME:2,DH_CHECK_P_NOT_PRIME:1,DH_UNABLE_TO_CHECK_GENERATOR:4,DH_NOT_SUITABLE_GENERATOR:8,NPN_ENABLED:1,ALPN_ENABLED:1,RSA_PKCS1_PADDING:1,RSA_SSLV23_PADDING:2,RSA_NO_PADDING:3,RSA_PKCS1_OAEP_PADDING:4,RSA_X931_PADDING:5,RSA_PKCS1_PSS_PADDING:6,POINT_CONVERSION_COMPRESSED:2,POINT_CONVERSION_UNCOMPRESSED:4,POINT_CONVERSION_HYBRID:6}},function(e,t,r){"use strict";var n=r(16);function i(e){this.options=e,this.type=this.options.type,this.blockSize=8,this._init(),this.buffer=new Array(this.blockSize),this.bufferOff=0}e.exports=i,i.prototype._init=function(){},i.prototype.update=function(e){return 0===e.length?[]:"decrypt"===this.type?this._updateDecrypt(e):this._updateEncrypt(e)},i.prototype._buffer=function(e,t){for(var r=Math.min(this.buffer.length-this.bufferOff,e.length-t),n=0;n0;n--)t+=this._buffer(e,t),r+=this._flushBuffer(i,r);return t+=this._buffer(e,t),i},i.prototype.final=function(e){var t,r;return e&&(t=this.update(e)),r="encrypt"===this.type?this._finalEncrypt():this._finalDecrypt(),t?t.concat(r):r},i.prototype._pad=function(e,t){if(0===t)return!1;for(;t=0||!r.umod(e.prime1)||!r.umod(e.prime2);)r=new n(i(t));return r}e.exports=o,o.getr=a}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n,i=r(0),o=i.Buffer,a={};for(n in i)i.hasOwnProperty(n)&&"SlowBuffer"!==n&&"Buffer"!==n&&(a[n]=i[n]);var s=a.Buffer={};for(n in o)o.hasOwnProperty(n)&&"allocUnsafe"!==n&&"allocUnsafeSlow"!==n&&(s[n]=o[n]);if(a.Buffer.prototype=o.prototype,s.from&&s.from!==Uint8Array.from||(s.from=function(e,t,r){if("number"==typeof e)throw new TypeError('The "value" argument must not be of type number. Received type '+typeof e);if(e&&void 0===e.length)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof e);return o(e,t,r)}),s.alloc||(s.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError('The "size" argument must be of type number. Received type '+typeof e);if(e<0||e>=2*(1<<30))throw new RangeError('The value "'+e+'" is invalid for option "size"');var n=o(e);return t&&0!==t.length?"string"==typeof r?n.fill(t,r):n.fill(t):n.fill(0),n}),!a.kStringMaxLength)try{a.kStringMaxLength=t.binding("buffer").kStringMaxLength}catch(e){}a.constants||(a.constants={MAX_LENGTH:a.kMaxLength},a.kStringMaxLength&&(a.constants.MAX_STRING_LENGTH=a.kStringMaxLength)),e.exports=a}).call(this,r(9))},function(e,t,r){"use strict";const n=r(99).Reporter,i=r(47).EncoderBuffer,o=r(47).DecoderBuffer,a=r(16),s=["seq","seqof","set","setof","objid","bool","gentime","utctime","null_","enum","int","objDesc","bitstr","bmpstr","charstr","genstr","graphstr","ia5str","iso646str","numstr","octstr","printstr","t61str","unistr","utf8str","videostr"],u=["key","obj","use","optional","explicit","implicit","def","choice","any","contains"].concat(s);function c(e,t,r){const n={};this._baseState=n,n.name=r,n.enc=e,n.parent=t||null,n.children=null,n.tag=null,n.args=null,n.reverseArgs=null,n.choice=null,n.optional=!1,n.any=!1,n.obj=!1,n.use=null,n.useDecoder=null,n.key=null,n.default=null,n.explicit=null,n.implicit=null,n.contains=null,n.parent||(n.children=[],this._wrap())}e.exports=c;const h=["enc","parent","children","tag","args","reverseArgs","choice","optional","any","obj","use","alteredUse","key","default","explicit","implicit","contains"];c.prototype.clone=function(){const e=this._baseState,t={};h.forEach((function(r){t[r]=e[r]}));const r=new this.constructor(t.parent);return r._baseState=t,r},c.prototype._wrap=function(){const e=this._baseState;u.forEach((function(t){this[t]=function(){const r=new this.constructor(this);return e.children.push(r),r[t].apply(r,arguments)}}),this)},c.prototype._init=function(e){const t=this._baseState;a(null===t.parent),e.call(this),t.children=t.children.filter((function(e){return e._baseState.parent===this}),this),a.equal(t.children.length,1,"Root node can have only one child")},c.prototype._useArgs=function(e){const t=this._baseState,r=e.filter((function(e){return e instanceof this.constructor}),this);e=e.filter((function(e){return!(e instanceof this.constructor)}),this),0!==r.length&&(a(null===t.children),t.children=r,r.forEach((function(e){e._baseState.parent=this}),this)),0!==e.length&&(a(null===t.args),t.args=e,t.reverseArgs=e.map((function(e){if("object"!=typeof e||e.constructor!==Object)return e;const t={};return Object.keys(e).forEach((function(r){r==(0|r)&&(r|=0);const n=e[r];t[n]=r})),t})))},["_peekTag","_decodeTag","_use","_decodeStr","_decodeObjid","_decodeTime","_decodeNull","_decodeInt","_decodeBool","_decodeList","_encodeComposite","_encodeStr","_encodeObjid","_encodeTime","_encodeNull","_encodeInt","_encodeBool"].forEach((function(e){c.prototype[e]=function(){const t=this._baseState;throw new Error(e+" not implemented for encoding: "+t.enc)}})),s.forEach((function(e){c.prototype[e]=function(){const t=this._baseState,r=Array.prototype.slice.call(arguments);return a(null===t.tag),t.tag=e,this._useArgs(r),this}})),c.prototype.use=function(e){a(e);const t=this._baseState;return a(null===t.use),t.use=e,this},c.prototype.optional=function(){return this._baseState.optional=!0,this},c.prototype.def=function(e){const t=this._baseState;return a(null===t.default),t.default=e,t.optional=!0,this},c.prototype.explicit=function(e){const t=this._baseState;return a(null===t.explicit&&null===t.implicit),t.explicit=e,this},c.prototype.implicit=function(e){const t=this._baseState;return a(null===t.explicit&&null===t.implicit),t.implicit=e,this},c.prototype.obj=function(){const e=this._baseState,t=Array.prototype.slice.call(arguments);return e.obj=!0,0!==t.length&&this._useArgs(t),this},c.prototype.key=function(e){const t=this._baseState;return a(null===t.key),t.key=e,this},c.prototype.any=function(){return this._baseState.any=!0,this},c.prototype.choice=function(e){const t=this._baseState;return a(null===t.choice),t.choice=e,this._useArgs(Object.keys(e).map((function(t){return e[t]}))),this},c.prototype.contains=function(e){const t=this._baseState;return a(null===t.use),t.contains=e,this},c.prototype._decode=function(e,t){const r=this._baseState;if(null===r.parent)return e.wrapResult(r.children[0]._decode(e,t));let n,i=r.default,a=!0,s=null;if(null!==r.key&&(s=e.enterKey(r.key)),r.optional){let n=null;if(null!==r.explicit?n=r.explicit:null!==r.implicit?n=r.implicit:null!==r.tag&&(n=r.tag),null!==n||r.any){if(a=this._peekTag(e,n,r.any),e.isError(a))return a}else{const n=e.save();try{null===r.choice?this._decodeGeneric(r.tag,e,t):this._decodeChoice(e,t),a=!0}catch(e){a=!1}e.restore(n)}}if(r.obj&&a&&(n=e.enterObject()),a){if(null!==r.explicit){const t=this._decodeTag(e,r.explicit);if(e.isError(t))return t;e=t}const n=e.offset;if(null===r.use&&null===r.choice){let t;r.any&&(t=e.save());const n=this._decodeTag(e,null!==r.implicit?r.implicit:r.tag,r.any);if(e.isError(n))return n;r.any?i=e.raw(t):e=n}if(t&&t.track&&null!==r.tag&&t.track(e.path(),n,e.length,"tagged"),t&&t.track&&null!==r.tag&&t.track(e.path(),e.offset,e.length,"content"),r.any||(i=null===r.choice?this._decodeGeneric(r.tag,e,t):this._decodeChoice(e,t)),e.isError(i))return i;if(r.any||null!==r.choice||null===r.children||r.children.forEach((function(r){r._decode(e,t)})),r.contains&&("octstr"===r.tag||"bitstr"===r.tag)){const n=new o(i);i=this._getUse(r.contains,e._reporterState.obj)._decode(n,t)}}return r.obj&&a&&(i=e.leaveObject(n)),null===r.key||null===i&&!0!==a?null!==s&&e.exitKey(s):e.leaveKey(s,r.key,i),i},c.prototype._decodeGeneric=function(e,t,r){const n=this._baseState;return"seq"===e||"set"===e?null:"seqof"===e||"setof"===e?this._decodeList(t,e,n.args[0],r):/str$/.test(e)?this._decodeStr(t,e,r):"objid"===e&&n.args?this._decodeObjid(t,n.args[0],n.args[1],r):"objid"===e?this._decodeObjid(t,null,null,r):"gentime"===e||"utctime"===e?this._decodeTime(t,e,r):"null_"===e?this._decodeNull(t,r):"bool"===e?this._decodeBool(t,r):"objDesc"===e?this._decodeStr(t,e,r):"int"===e||"enum"===e?this._decodeInt(t,n.args&&n.args[0],r):null!==n.use?this._getUse(n.use,t._reporterState.obj)._decode(t,r):t.error("unknown tag: "+e)},c.prototype._getUse=function(e,t){const r=this._baseState;return r.useDecoder=this._use(e,t),a(null===r.useDecoder._baseState.parent),r.useDecoder=r.useDecoder._baseState.children[0],r.implicit!==r.useDecoder._baseState.implicit&&(r.useDecoder=r.useDecoder.clone(),r.useDecoder._baseState.implicit=r.implicit),r.useDecoder},c.prototype._decodeChoice=function(e,t){const r=this._baseState;let n=null,i=!1;return Object.keys(r.choice).some((function(o){const a=e.save(),s=r.choice[o];try{const r=s._decode(e,t);if(e.isError(r))return!1;n={type:o,value:r},i=!0}catch(t){return e.restore(a),!1}return!0}),this),i?n:e.error("Choice not matched")},c.prototype._createEncoderBuffer=function(e){return new i(e,this.reporter)},c.prototype._encode=function(e,t,r){const n=this._baseState;if(null!==n.default&&n.default===e)return;const i=this._encodeValue(e,t,r);return void 0===i||this._skipDefault(i,t,r)?void 0:i},c.prototype._encodeValue=function(e,t,r){const i=this._baseState;if(null===i.parent)return i.children[0]._encode(e,t||new n);let o=null;if(this.reporter=t,i.optional&&void 0===e){if(null===i.default)return;e=i.default}let a=null,s=!1;if(i.any)o=this._createEncoderBuffer(e);else if(i.choice)o=this._encodeChoice(e,t);else if(i.contains)a=this._getUse(i.contains,r)._encode(e,t),s=!0;else if(i.children)a=i.children.map((function(r){if("null_"===r._baseState.tag)return r._encode(null,t,e);if(null===r._baseState.key)return t.error("Child should have a key");const n=t.enterKey(r._baseState.key);if("object"!=typeof e)return t.error("Child expected, but input is not object");const i=r._encode(e[r._baseState.key],t,e);return t.leaveKey(n),i}),this).filter((function(e){return e})),a=this._createEncoderBuffer(a);else if("seqof"===i.tag||"setof"===i.tag){if(!i.args||1!==i.args.length)return t.error("Too many args for : "+i.tag);if(!Array.isArray(e))return t.error("seqof/setof, but data is not Array");const r=this.clone();r._baseState.implicit=null,a=this._createEncoderBuffer(e.map((function(r){const n=this._baseState;return this._getUse(n.args[0],e)._encode(r,t)}),r))}else null!==i.use?o=this._getUse(i.use,r)._encode(e,t):(a=this._encodePrimitive(i.tag,e),s=!0);if(!i.any&&null===i.choice){const e=null!==i.implicit?i.implicit:i.tag,r=null===i.implicit?"universal":"context";null===e?null===i.use&&t.error("Tag could be omitted only for .use()"):null===i.use&&(o=this._encodeComposite(e,s,r,a))}return null!==i.explicit&&(o=this._encodeComposite(i.explicit,!1,"context",o)),o},c.prototype._encodeChoice=function(e,t){const r=this._baseState,n=r.choice[e.type];return n||a(!1,e.type+" not found in "+JSON.stringify(Object.keys(r.choice))),n._encode(e.value,t)},c.prototype._encodePrimitive=function(e,t){const r=this._baseState;if(/str$/.test(e))return this._encodeStr(t,e);if("objid"===e&&r.args)return this._encodeObjid(t,r.reverseArgs[0],r.args[1]);if("objid"===e)return this._encodeObjid(t,null,null);if("gentime"===e||"utctime"===e)return this._encodeTime(t,e);if("null_"===e)return this._encodeNull();if("int"===e||"enum"===e)return this._encodeInt(t,r.args&&r.reverseArgs[0]);if("bool"===e)return this._encodeBool(t);if("objDesc"===e)return this._encodeStr(t,e);throw new Error("Unsupported tag: "+e)},c.prototype._isNumstr=function(e){return/^[0-9 ]*$/.test(e)},c.prototype._isPrintstr=function(e){return/^[A-Za-z0-9 '()+,-./:=?]*$/.test(e)}},function(e,t,r){"use strict";const n=r(1);function i(e){this._reporterState={obj:null,path:[],options:e||{},errors:[]}}function o(e,t){this.path=e,this.rethrow(t)}t.Reporter=i,i.prototype.isError=function(e){return e instanceof o},i.prototype.save=function(){const e=this._reporterState;return{obj:e.obj,pathLen:e.path.length}},i.prototype.restore=function(e){const t=this._reporterState;t.obj=e.obj,t.path=t.path.slice(0,e.pathLen)},i.prototype.enterKey=function(e){return this._reporterState.path.push(e)},i.prototype.exitKey=function(e){const t=this._reporterState;t.path=t.path.slice(0,e-1)},i.prototype.leaveKey=function(e,t,r){const n=this._reporterState;this.exitKey(e),null!==n.obj&&(n.obj[t]=r)},i.prototype.path=function(){return this._reporterState.path.join("/")},i.prototype.enterObject=function(){const e=this._reporterState,t=e.obj;return e.obj={},t},i.prototype.leaveObject=function(e){const t=this._reporterState,r=t.obj;return t.obj=e,r},i.prototype.error=function(e){let t;const r=this._reporterState,n=e instanceof o;if(t=n?e:new o(r.path.map((function(e){return"["+JSON.stringify(e)+"]"})).join(""),e.message||e,e.stack),!r.options.partial)throw t;return n||r.errors.push(t),t},i.prototype.wrapResult=function(e){const t=this._reporterState;return t.options.partial?{result:this.isError(e)?null:e,errors:t.errors}:e},n(o,Error),o.prototype.rethrow=function(e){if(this.message=e+" at: "+(this.path||"(shallow)"),Error.captureStackTrace&&Error.captureStackTrace(this,o),!this.stack)try{throw new Error(this.message)}catch(e){this.stack=e.stack}return this}},function(e,t,r){"use strict";function n(e){const t={};return Object.keys(e).forEach((function(r){(0|r)==r&&(r|=0);const n=e[r];t[n]=r})),t}t.tagClass={0:"universal",1:"application",2:"context",3:"private"},t.tagClassByName=n(t.tagClass),t.tag={0:"end",1:"bool",2:"int",3:"bitstr",4:"octstr",5:"null_",6:"objid",7:"objDesc",8:"external",9:"real",10:"enum",11:"embed",12:"utf8str",13:"relativeOid",16:"seq",17:"set",18:"numstr",19:"printstr",20:"t61str",21:"videostr",22:"ia5str",23:"utctime",24:"gentime",25:"graphstr",26:"iso646str",27:"genstr",28:"unistr",29:"charstr",30:"bmpstr"},t.tagByName=n(t.tag)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4),o=r(5),a=r(7);function s(e){if(!(this instanceof s))return new s(e);var t;if(n.isNumber(e))t=e;else{if(!n.isString(e))throw new TypeError('Unrecognized num type: "'+typeof e+'" for Opcode');t=s.map[e]}return a.defineImmutable(this,{num:t}),this}for(var u in s.fromBuffer=function(e){return i.checkArgument(o.isBuffer(e)),new s(Number("0x"+e.toString("hex")))},s.fromNumber=function(e){return i.checkArgument(n.isNumber(e)),new s(e)},s.fromString=function(e){i.checkArgument(n.isString(e));var t=s.map[e];if(void 0===t)throw new TypeError("Invalid opcodestr");return new s(t)},s.prototype.toHex=function(){return this.num.toString(16)},s.prototype.toBuffer=function(){return t.from(this.toHex(),"hex")},s.prototype.toNumber=function(){return this.num},s.prototype.toString=function(){var e=s.reverseMap[this.num];if(void 0===e)throw new Error("Opcode does not have a string representation");return e},s.smallInt=function(e){return i.checkArgument(n.isNumber(e),"Invalid Argument: n should be number"),i.checkArgument(e>=0&&e<=16,"Invalid Argument: n must be between 0 and 16"),0===e?s("OP_0"):new s(s.map.OP_1+e-1)},s.map={OP_FALSE:0,OP_0:0,OP_PUSHDATA1:76,OP_PUSHDATA2:77,OP_PUSHDATA4:78,OP_1NEGATE:79,OP_RESERVED:80,OP_TRUE:81,OP_1:81,OP_2:82,OP_3:83,OP_4:84,OP_5:85,OP_6:86,OP_7:87,OP_8:88,OP_9:89,OP_10:90,OP_11:91,OP_12:92,OP_13:93,OP_14:94,OP_15:95,OP_16:96,OP_NOP:97,OP_VER:98,OP_IF:99,OP_NOTIF:100,OP_VERIF:101,OP_VERNOTIF:102,OP_ELSE:103,OP_ENDIF:104,OP_VERIFY:105,OP_RETURN:106,OP_TOALTSTACK:107,OP_FROMALTSTACK:108,OP_2DROP:109,OP_2DUP:110,OP_3DUP:111,OP_2OVER:112,OP_2ROT:113,OP_2SWAP:114,OP_IFDUP:115,OP_DEPTH:116,OP_DROP:117,OP_DUP:118,OP_NIP:119,OP_OVER:120,OP_PICK:121,OP_ROLL:122,OP_ROT:123,OP_SWAP:124,OP_TUCK:125,OP_CAT:126,OP_SUBSTR:127,OP_LEFT:128,OP_RIGHT:129,OP_SIZE:130,OP_INVERT:131,OP_AND:132,OP_OR:133,OP_XOR:134,OP_EQUAL:135,OP_EQUALVERIFY:136,OP_RESERVED1:137,OP_RESERVED2:138,OP_1ADD:139,OP_1SUB:140,OP_2MUL:141,OP_2DIV:142,OP_NEGATE:143,OP_ABS:144,OP_NOT:145,OP_0NOTEQUAL:146,OP_ADD:147,OP_SUB:148,OP_MUL:149,OP_DIV:150,OP_MOD:151,OP_LSHIFT:152,OP_RSHIFT:153,OP_BOOLAND:154,OP_BOOLOR:155,OP_NUMEQUAL:156,OP_NUMEQUALVERIFY:157,OP_NUMNOTEQUAL:158,OP_LESSTHAN:159,OP_GREATERTHAN:160,OP_LESSTHANOREQUAL:161,OP_GREATERTHANOREQUAL:162,OP_MIN:163,OP_MAX:164,OP_WITHIN:165,OP_RIPEMD160:166,OP_SHA1:167,OP_SHA256:168,OP_HASH160:169,OP_HASH256:170,OP_CODESEPARATOR:171,OP_CHECKSIG:172,OP_CHECKSIGVERIFY:173,OP_CHECKMULTISIG:174,OP_CHECKMULTISIGVERIFY:175,OP_CHECKLOCKTIMEVERIFY:177,OP_CHECKSEQUENCEVERIFY:178,OP_NOP1:176,OP_NOP2:177,OP_NOP3:178,OP_NOP4:179,OP_NOP5:180,OP_NOP6:181,OP_NOP7:182,OP_NOP8:183,OP_NOP9:184,OP_NOP10:185,OP_PUBKEYHASH:253,OP_PUBKEY:254,OP_INVALIDOPCODE:255},s.reverseMap=[],s.map)s.reverseMap[s.map[u]]=u;n.extend(s,s.map),s.isSmallIntOp=function(e){return e instanceof s&&(e=e.toNumber()),e===s.map.OP_0||e>=s.map.OP_1&&e<=s.map.OP_16},s.prototype.inspect=function(){return""},e.exports=s}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4),o=r(0),a=t.compare||r(369),s=r(17),u=r(5),c=r(7),h=r(21),f=r(12),l=r(11),d=r(13),p=r(26),m=r(67),g=r(20),b=r(182),v=r(103),y=v.PublicKeyHash,w=v.PublicKey,_=v.MultiSigScriptHash,S=v.MultiSig,M=r(22),k=r(14),E=r(48),A=r(10);function x(e,t){if(!(this instanceof x))return new x(e);if(this.inputs=[],this.outputs=[],this._inputAmount=void 0,this._outputAmount=void 0,e){if(e instanceof x)return x.shallowCopy(e);if(c.isHexa(e))this.fromString(e);else if(u.isBuffer(e))this.fromBuffer(e);else{if(!n.isObject(e))throw new s.InvalidArgument("Must provide an object or string to deserialize a transaction");this.fromObject(e,t)}}else this._newTransaction()}x.DUST_AMOUNT=546,x.FEE_SECURITY_MARGIN=150,x.MAX_MONEY=21e14,x.NLOCKTIME_BLOCKHEIGHT_LIMIT=5e8,x.NLOCKTIME_MAX_VALUE=4294967295,x.FEE_PER_KB=1e5,x.CHANGE_OUTPUT_MAX_SIZE=62,x.MAXIMUM_EXTRA_SIZE=26,x.shallowCopy=function(e){return new x(e.toBuffer())};var I={configurable:!1,enumerable:!0,get:function(){return this._hash=new h(this._getHash()).readReverse().toString("hex"),this._hash}},P={configurable:!1,enumerable:!0,get:function(){return new h(this._getWitnessHash()).readReverse().toString("hex")}};Object.defineProperty(x.prototype,"witnessHash",P),Object.defineProperty(x.prototype,"hash",I),Object.defineProperty(x.prototype,"id",I);var O={configurable:!1,enumerable:!0,get:function(){return this._getInputAmount()}};Object.defineProperty(x.prototype,"inputAmount",O),O.get=function(){return this._getOutputAmount()},Object.defineProperty(x.prototype,"outputAmount",O),x.prototype._getHash=function(){return l.sha256sha256(this.toBuffer(!0))},x.prototype._getWitnessHash=function(){return l.sha256sha256(this.toBuffer(!1))},x.prototype.serialize=function(e){return!0===e||e&&e.disableAll?this.uncheckedSerialize():this.checkedSerialize(e)},x.prototype.uncheckedSerialize=x.prototype.toString=function(){return this.toBuffer().toString("hex")},x.prototype.checkedSerialize=function(e){var t=this.getSerializationError(e);if(t)throw t.message+=" - For more information please see: https://bitcore.io/api/lib/transaction#serialization-checks",t;return this.uncheckedSerialize()},x.prototype.invalidSatoshis=function(){for(var e=!1,t=0;tr)return this._missingChange()?new s.Transaction.ChangeAddressMissing("Fee is too large and no change address was provided"):new s.Transaction.FeeError.TooLarge("expected less than "+r+" but got "+t)}if(!e.disableSmallFees){var i=Math.ceil(this._estimateFee()/x.FEE_SECURITY_MARGIN);if(t"},x.prototype.toBuffer=function(e){var t=new f;return this.toBufferWriter(t,e).toBuffer()},x.prototype.hasWitnesses=function(){for(var e=0;e=x.NLOCKTIME_BLOCKHEIGHT_LIMIT)throw new s.Transaction.BlockHeightTooHigh;if(e<0)throw new s.Transaction.NLockTimeOutOfRange;for(var t=0;te.prevTxId.toString("hex")===o.txId&&e.outputIndex===o.outputIndex);i.push(e),e>=0&&(this.inputs[e]=this._getInputFrom(o,t,r,n))}return i},x.prototype._selectInputType=function(e,t,r){var n;return e=new b(e),t&&r?e.script.isMultisigOut()?n=S:(e.script.isScriptHashOut()||e.script.isWitnessScriptHashOut())&&(n=_):n=e.script.isPublicKeyHashOut()||e.script.isWitnessPublicKeyHashOut()||e.script.isScriptHashOut()?y:e.script.isPublicKeyOut()?w:v,n},x.prototype._getInputFrom=function(e,t,r,n){e=new b(e);return new(this._selectInputType(e,t,r))({output:new M({script:e.script,satoshis:e.satoshis}),prevTxId:e.txId,outputIndex:e.outputIndex,sequenceNumber:e.sequenceNumber,script:k.empty()},...t&&r?[t,r,!1,n]:[])},x.prototype._fromNonP2SH=function(e){const t=this._getInputFrom(e);this.addInput(t)},x.prototype._fromMultisigUtxo=function(e,t,r,n){i.checkArgument(r<=t.length,"Number of required signatures must be greater than the number of public keys");const o=this._getInputFrom(e,t,r,n);this.addInput(o)},x.prototype.addInput=function(e,t,r){if(i.checkArgumentType(e,v,"input"),!e.output&&(n.isUndefined(t)||n.isUndefined(r)))throw new s.Transaction.NeedMoreInfo("Need information about the UTXO script and satoshis");return e.output||!t||n.isUndefined(r)||(t=t instanceof k?t:new k(t),i.checkArgumentType(r,"number","satoshis"),e.output=new M({script:t,satoshis:r})),this.uncheckedAddInput(e)},x.prototype.uncheckedAddInput=function(e){return i.checkArgumentType(e,v,"input"),this.inputs.push(e),this._inputAmount=void 0,this._updateChangeOutput(),this},x.prototype.hasAllUtxoInfo=function(){return n.every(this.inputs.map((function(e){return!!e.output})))},x.prototype.fee=function(e){return i.checkArgument(n.isNumber(e),"amount must be a number"),this._fee=e,this._updateChangeOutput(),this},x.prototype.feePerKb=function(e){return i.checkArgument(n.isNumber(e),"amount must be a number"),this._feePerKb=e,this._updateChangeOutput(),this},x.prototype.feePerByte=function(e){return i.checkArgument(n.isNumber(e),"amount must be a number"),this._feePerByte=e,this._updateChangeOutput(),this},x.prototype.change=function(e){return i.checkArgument(e,"address is required"),this._changeScript=k.fromAddress(e),this._updateChangeOutput(),this},x.prototype.getChangeOutput=function(){return n.isUndefined(this._changeIndex)?null:this.outputs[this._changeIndex]},x.prototype.to=function(e,t){if(n.isArray(e)){var r=this;return n.each(e,(function(e){r.to(e.address,e.satoshis)})),this}return i.checkArgument(c.isNaturalNumber(t),"Amount is expected to be a positive integer"),this.addOutput(new M({script:k(new g(e)),satoshis:t})),this},x.prototype.addData=function(e){return this.addOutput(new M({script:k.buildDataOut(e),satoshis:0})),this},x.prototype.addOutput=function(e){return i.checkArgumentType(e,M,"output"),this._addOutput(e),this._updateChangeOutput(),this},x.prototype.clearOutputs=function(){return this.outputs=[],this._clearSignatures(),this._outputAmount=void 0,this._changeIndex=void 0,this._updateChangeOutput(),this},x.prototype._addOutput=function(e){this.outputs.push(e),this._outputAmount=void 0},x.prototype._getOutputAmount=function(){if(n.isUndefined(this._outputAmount)){var e=this;this._outputAmount=0,n.each(this.outputs,(function(t){e._outputAmount+=t.satoshis}))}return this._outputAmount},x.prototype._getInputAmount=function(){return n.isUndefined(this._inputAmount)&&(this._inputAmount=n.sumBy(this.inputs,(function(e){if(n.isUndefined(e.output))throw new s.Transaction.Input.MissingPreviousOutput;return e.output.satoshis}))),this._inputAmount},x.prototype._updateChangeOutput=function(){if(this._changeScript){this._clearSignatures(),n.isUndefined(this._changeIndex)||this._removeOutput(this._changeIndex);var e=this._getUnspentValue()-this.getFee();e>0?(this._changeIndex=this.outputs.length,this._addOutput(new M({script:this._changeScript,satoshis:e}))):this._changeIndex=void 0}},x.prototype.getFee=function(){return this.isCoinbase()?0:n.isUndefined(this._fee)?this._changeScript?this._estimateFee():this._getUnspentValue():this._fee},x.prototype._estimateFee=function(){var e=this._estimateSize(),t=this._getUnspentValue(),r=this._feePerByte||(this._feePerKb||x.FEE_PER_KB)/1e3;function n(e){return e*r}var i=Math.ceil(n(e)),o=Math.ceil(n(e)+n(x.CHANGE_OUTPUT_MAX_SIZE));return!this._changeScript||t<=o?i:o},x.prototype._getUnspentValue=function(){return this._getInputAmount()-this._getOutputAmount()},x.prototype._clearSignatures=function(){n.each(this.inputs,(function(e){e.clearSignatures()}))},x.prototype._estimateSize=function(){var e=x.MAXIMUM_EXTRA_SIZE;return n.each(this.inputs,(function(t){e+=t._estimateSize()})),n.each(this.outputs,(function(t){e+=t.script.toBuffer().length+9})),e},x.prototype._removeOutput=function(e){var t=this.outputs[e];this.outputs=n.without(this.outputs,t),this._outputAmount=void 0},x.prototype.removeOutput=function(e){this._removeOutput(e),this._updateChangeOutput()},x.prototype.sort=function(){return this.sortInputs((function(e){var t=Array.prototype.concat.apply([],e);let r=0;return t.forEach(e=>{e.i=r++}),t.sort((function(e,t){return a(e.prevTxId,t.prevTxId)||e.outputIndex-t.outputIndex||e.i-t.i})),t})),this.sortOutputs((function(e){var t=Array.prototype.concat.apply([],e);let r=0;return t.forEach(e=>{e.i=r++}),t.sort((function(e,t){return e.satoshis-t.satoshis||a(e.script.toBuffer(),t.script.toBuffer())||e.i-t.i})),t})),this},x.prototype.shuffleOutputs=function(){return this.sortOutputs(n.shuffle)},x.prototype.sortOutputs=function(e){var t=e(this.outputs);return this._newOutputOrder(t)},x.prototype.sortInputs=function(e){return this.inputs=e(this.inputs),this._clearSignatures(),this},x.prototype._newOutputOrder=function(e){if(this.outputs.length!==e.length||0!==n.difference(this.outputs,e).length)throw new s.Transaction.InvalidSorting;if(!n.isUndefined(this._changeIndex)){var t=this.outputs[this._changeIndex];this._changeIndex=n.findIndex(e,t)}return this.outputs=e,this},x.prototype.removeInput=function(e,t){var r;if((r=!t&&n.isNumber(e)?e:n.findIndex(this.inputs,(function(r){return r.prevTxId.toString("hex")===e&&r.outputIndex===t})))<0||r>=this.inputs.length)throw new s.Transaction.InvalidIndex(r,this.inputs.length);var i=this.inputs[r];this.inputs=n.without(this.inputs,i),this._inputAmount=void 0,this._updateChangeOutput()},x.prototype.sign=function(e,t,r){i.checkState(this.hasAllUtxoInfo(),"Not all utxo information is available to sign the transaction.");var o=this;return n.isArray(e)?(n.each(e,(function(e){o.sign(e,t,r)})),this):(n.each(this.getSignatures(e,t,r),(function(e){o.applySignature(e,r)})),this)},x.prototype.getSignatures=function(e,t,r){e=new E(e),t=t||d.SIGHASH_ALL;var i=this,o=[],a=l.sha256ripemd160(e.publicKey.toBuffer());return n.each(this.inputs,(function(s,u){n.each(s.getSignatures(i,e,u,t,a,r),(function(e){o.push(e)}))})),o},x.prototype.applySignature=function(e,t){return this.inputs[e.inputIndex].addSignature(this,e,t),this},x.prototype.isFullySigned=function(){return n.each(this.inputs,(function(e){if(e.isFullySigned===v.prototype.isFullySigned)throw new s.Transaction.UnableToVerifySignature("Unrecognized script kind, or not enough information to execute script.This usually happens when creating a transaction from a serialized transaction")})),n.every(n.map(this.inputs,(function(e){return e.isFullySigned()})))},x.prototype.isValidSignature=function(e,t){if(this.inputs[e.inputIndex].isValidSignature===v.prototype.isValidSignature)throw new s.Transaction.UnableToVerifySignature("Unrecognized script kind, or not enough information to execute script.This usually happens when creating a transaction from a serialized transaction");return this.inputs[e.inputIndex].isValidSignature(this,e,t)},x.prototype.verifySignature=function(e,t,r,o,a,s,u){if(n.isUndefined(a)&&(a=0),1===a){var h,l=o.toBuffer(),d=new f;return d.writeVarintNum(l.length),d.write(l),s?(i.checkState(c.isNaturalNumber(s)),h=(new f).writeUInt64LEBN(new A(s)).toBuffer()):h=this.inputs[r].getSatoshisBuffer(),m.verify(this,e,t,r,d.toBuffer(),h,u)}return p.verify(this,e,t,r,o,u)},x.prototype.verify=function(){if(0===this.inputs.length)return"transaction txins empty";if(0===this.outputs.length)return"transaction txouts empty";for(var e=new A(0),t=0;t1e6)return"transaction over the maximum block size";var i={};for(t=0;t100)return"coinbase transaction script size invalid"}else for(t=0;t=v.MAXINT-1&&(t.sequenceNumber=v.DEFAULT_RBF_SEQNUMBER)}return this},x.prototype.setVersion=function(e){return i.checkArgument(c.isNaturalNumber(e)&&e<=2,"Wrong version number"),this.version=e,this},e.exports=x}).call(this,r(0).Buffer)},function(e,t,r){e.exports=r(50),e.exports.PublicKey=r(370),e.exports.PublicKeyHash=r(371),e.exports.MultiSig=r(372),e.exports.MultiSigScriptHash=r(373)},function(e,t,r){"use strict";var n=r(3),i=r(17),o=r(4),a={BTC:[1e8,8],mBTC:[1e5,5],uBTC:[100,2],bits:[100,2],satoshis:[1,0]};function s(e,t){if(!(this instanceof s))return new s(e,t);if(n.isNumber(t)){if(t<=0)throw new i.Unit.InvalidRate(t);e/=t,t=s.BTC}this._value=this._from(e,t);var r=this;Object.keys(a).forEach((function(e){Object.defineProperty(r,e,{get:function(){return r.to(e)},enumerable:!0})}))}Object.keys(a).forEach((function(e){s[e]=e})),s.fromObject=function(e){return o.checkArgument(n.isObject(e),"Argument is expected to be an object"),new s(e.amount,e.code)},s.fromBTC=function(e){return new s(e,s.BTC)},s.fromMillis=s.fromMilis=function(e){return new s(e,s.mBTC)},s.fromMicros=s.fromBits=function(e){return new s(e,s.bits)},s.fromSatoshis=function(e){return new s(e,s.satoshis)},s.fromFiat=function(e,t){return new s(e,t)},s.prototype._from=function(e,t){if(!a[t])throw new i.Unit.UnknownCode(t);return parseInt((e*a[t][0]).toFixed())},s.prototype.to=function(e){if(n.isNumber(e)){if(e<=0)throw new i.Unit.InvalidRate(e);return parseFloat((this.BTC*e).toFixed(2))}if(!a[e])throw new i.Unit.UnknownCode(e);var t=this._value/a[e][0];return parseFloat(t.toFixed(a[e][1]))},s.prototype.toBTC=function(){return this.to(s.BTC)},s.prototype.toMillis=s.prototype.toMilis=function(){return this.to(s.mBTC)},s.prototype.toMicros=s.prototype.toBits=function(){return this.to(s.bits)},s.prototype.toSatoshis=function(){return this.to(s.satoshis)},s.prototype.atRate=function(e){return this.to(e)},s.prototype.toString=function(){return this.satoshis+" satoshis"},s.prototype.toObject=s.prototype.toJSON=function(){return{amount:this.BTC,code:s.BTC}},s.prototype.inspect=function(){return""},e.exports=s},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.LightWalletSigner=t.LightWalletProvider=t.MetamaskSnapHelper=t.WsJsonRpcConnector=t.HttpJsonRpcConnector=t.MetamaskSigner=t.MnemonicSigner=t.MetamaskWalletProvider=t.LotusWalletProvider=t.MnemonicWalletProvider=t.LotusClient=void 0;var n=r(189);Object.defineProperty(t,"LotusClient",{enumerable:!0,get:function(){return n.LotusClient}});var i=r(208);Object.defineProperty(t,"MnemonicWalletProvider",{enumerable:!0,get:function(){return i.MnemonicWalletProvider}});var o=r(322);Object.defineProperty(t,"LotusWalletProvider",{enumerable:!0,get:function(){return o.LotusWalletProvider}});var a=r(323);Object.defineProperty(t,"MetamaskWalletProvider",{enumerable:!0,get:function(){return a.MetamaskWalletProvider}});var s=r(324);Object.defineProperty(t,"LightWalletProvider",{enumerable:!0,get:function(){return s.LightWalletProvider}});var u=r(110);Object.defineProperty(t,"MnemonicSigner",{enumerable:!0,get:function(){return u.MnemonicSigner}});var c=r(159);Object.defineProperty(t,"MetamaskSigner",{enumerable:!0,get:function(){return c.MetamaskSigner}});var h=r(186);Object.defineProperty(t,"LightWalletSigner",{enumerable:!0,get:function(){return h.LightWalletSigner}});var f=r(107);Object.defineProperty(t,"HttpJsonRpcConnector",{enumerable:!0,get:function(){return f.HttpJsonRpcConnector}});var l=r(70);Object.defineProperty(t,"WsJsonRpcConnector",{enumerable:!0,get:function(){return l.WsJsonRpcConnector}});var d=r(402);Object.defineProperty(t,"MetamaskSnapHelper",{enumerable:!0,get:function(){return d.MetamaskSnapHelper}})},function(e,t,r){"use strict";var n,i=this&&this.__extends||(n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)},function(e,t){function r(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)});Object.defineProperty(t,"__esModule",{value:!0}),t.ConnectionError=t.ResponseError=t.JsonRpcError=t.JsonRpcResponse=t.JsonRpcErrorResponse=void 0;var o=function(){};t.JsonRpcErrorResponse=o;var a=function(){};t.JsonRpcResponse=a;var s=function(e){function t(r){var n=e.call(this,r.message)||this;return n.code=r.code,n.message=r.message,n.data=r.data,Object.setPrototypeOf(n,t.prototype),n}return i(t,e),t}(Error);t.JsonRpcError=s;var u=function(e){function t(r,n){var i=e.call(this,n)||this;return i.code=r,i.message=n,Object.setPrototypeOf(i,t.prototype),i}return i(t,e),t}(Error);t.ResponseError=u;var c=function(e){function t(r){var n=e.call(this,r.message)||this;return Object.setPrototypeOf(n,t.prototype),n}return i(t,e),t}(Error);t.ConnectionError=c},function(e,t,r){"use strict";var n,i=this&&this.__extends||(n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)},function(e,t){function r(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}),o=this&&this.__assign||function(){return(o=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]>1,h=-7,f=r?i-1:0,l=r?-1:1,d=e[t+f];for(f+=l,o=d&(1<<-h)-1,d>>=-h,h+=s;h>0;o=256*o+e[t+f],f+=l,h-=8);for(a=o&(1<<-h)-1,o>>=-h,h+=n;h>0;a=256*a+e[t+f],f+=l,h-=8);if(0===o)o=1-c;else{if(o===u)return a?NaN:1/0*(d?-1:1);a+=Math.pow(2,n),o-=c}return(d?-1:1)*a*Math.pow(2,o-n)},t.write=function(e,t,r,n,i,o){var a,s,u,c=8*o-i-1,h=(1<>1,l=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,d=n?0:o-1,p=n?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=h):(a=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-a))<1&&(a--,u*=2),(t+=a+f>=1?l/u:l*Math.pow(2,1-f))*u>=2&&(a++,u/=2),a+f>=h?(s=0,a=h):a+f>=1?(s=(t*u-1)*Math.pow(2,i),a+=f):(s=t*Math.pow(2,f-1)*Math.pow(2,i),a=0));i>=8;e[r+d]=255&s,d+=p,s/=256,i-=8);for(a=a<0;e[r+d]=255&a,d+=p,a/=256,c-=8);e[r+d-p]|=128*m}},function(e,t){var r={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==r.call(e)}},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.hasOwnProperty.call(e,r)&&n(t,e,r);return i(t,e),t},a=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},s=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=0?(this.addresses[t]="",this.privKeys[e]="",this.defaultAddressIndex!==t?[3,3]:[4,this.getAddresses()]):[3,3];case 1:return(r=n.sent()).length>0?[4,this.setDefaultAddress(r[0])]:[3,3];case 2:n.sent(),n.label=3;case 3:return[2]}}))}))},e.prototype.getPrivateKey=function(e){return a(this,void 0,void 0,(function(){return s(this,(function(t){return[2,this.privKeys[e]]}))}))},e.prototype.getDefaultAddress=function(){return a(this,void 0,void 0,(function(){return s(this,(function(e){switch(e.label){case 0:return 0!==this.addresses.length?[3,2]:[4,this.initAddresses()];case 1:e.sent(),e.label=2;case 2:return[2,this.addresses[this.defaultAddressIndex]]}}))}))},e.prototype.setDefaultAddress=function(e){return a(this,void 0,void 0,(function(){var t;return s(this,(function(r){return(t=this.addresses.indexOf(e))>=0&&(this.defaultAddressIndex=t),[2]}))}))},e.prototype.hasAddress=function(e){return a(this,void 0,void 0,(function(){return s(this,(function(t){return[2,this.addresses.indexOf(e)>=0]}))}))},e.prototype.sign=function(e){return a(this,void 0,void 0,(function(){var t,r;return s(this,(function(n){switch(n.label){case 0:return 0!==this.addresses.length?[3,2]:[4,this.initAddresses()];case 1:n.sent(),n.label=2;case 2:if(!this.privKeys[e.From])throw new Error("From address not found");return t=this.privKeys[e.From],r=u.transactionSignLotus(this.messageToSigner(e),t),[2,JSON.parse(r)]}}))}))},e.prototype.getPassword=function(){return a(this,void 0,void 0,(function(){var e;return s(this,(function(t){switch(t.label){case 0:return"string"!=typeof this.password?[3,1]:(e=this.password,[3,3]);case 1:return[4,this.password()];case 2:e=t.sent(),t.label=3;case 3:return[2,e]}}))}))},e.prototype.getMnemonic=function(){return a(this,void 0,void 0,(function(){var e;return s(this,(function(t){switch(t.label){case 0:return"string"!=typeof this.mnemonic?[3,1]:(e=this.mnemonic,[3,3]);case 1:return[4,this.mnemonic()];case 2:e=t.sent(),t.label=3;case 3:return[2,e]}}))}))},e.prototype.messageToSigner=function(e){return{to:e.To,from:e.From,nonce:e.Nonce,value:e.Value.toString(),gaslimit:Number(e.GasLimit.toString()),gasfeecap:e.GasFeeCap.toString(),gaspremium:e.GasPremium.toString(),method:e.Method,params:e.Params}},e}();t.MnemonicSigner=h},function(e,t,r){"use strict";var n=r(2).Buffer,i=r(112).Transform;function o(e){i.call(this),this._block=n.allocUnsafe(e),this._blockSize=e,this._blockOffset=0,this._length=[0,0,0,0],this._finalized=!1}r(1)(o,i),o.prototype._transform=function(e,t,r){var n=null;try{this.update(e,t)}catch(e){n=e}r(n)},o.prototype._flush=function(e){var t=null;try{this.push(this.digest())}catch(e){t=e}e(t)},o.prototype.update=function(e,t){if(function(e,t){if(!n.isBuffer(e)&&"string"!=typeof e)throw new TypeError(t+" must be a string or a buffer")}(e,"Data"),this._finalized)throw new Error("Digest already called");n.isBuffer(e)||(e=n.from(e,t));for(var r=this._block,i=0;this._blockOffset+e.length-i>=this._blockSize;){for(var o=this._blockOffset;o0;++a)this._length[a]+=s,(s=this._length[a]/4294967296|0)>0&&(this._length[a]-=4294967296*s);return this},o.prototype._update=function(){throw new Error("_update is not implemented")},o.prototype.digest=function(e){if(this._finalized)throw new Error("Digest already called");this._finalized=!0;var t=this._digest();void 0!==e&&(t=t.toString(e)),this._block.fill(0),this._blockOffset=0;for(var r=0;r<4;++r)this._length[r]=0;return t},o.prototype._digest=function(){throw new Error("_digest is not implemented")},e.exports=o},function(e,t,r){(t=e.exports=r(113)).Stream=t,t.Readable=t,t.Writable=r(117),t.Duplex=r(36),t.Transform=r(119),t.PassThrough=r(215),t.finished=r(73),t.pipeline=r(216)},function(e,t,r){"use strict";(function(t,n){var i;e.exports=E,E.ReadableState=k;r(27).EventEmitter;var o=function(e,t){return e.listeners(t).length},a=r(114),s=r(0).Buffer,u=t.Uint8Array||function(){};var c,h=r(210);c=h&&h.debuglog?h.debuglog("stream"):function(){};var f,l,d,p=r(211),m=r(115),g=r(116).getHighWaterMark,b=r(35).codes,v=b.ERR_INVALID_ARG_TYPE,y=b.ERR_STREAM_PUSH_AFTER_EOF,w=b.ERR_METHOD_NOT_IMPLEMENTED,_=b.ERR_STREAM_UNSHIFT_AFTER_END_EVENT;r(1)(E,a);var S=m.errorOrDestroy,M=["error","close","destroy","pause","resume"];function k(e,t,n){i=i||r(36),e=e||{},"boolean"!=typeof n&&(n=t instanceof i),this.objectMode=!!e.objectMode,n&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=g(this,e,"readableHighWaterMark",n),this.buffer=new p,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=!1!==e.emitClose,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(f||(f=r(39).StringDecoder),this.decoder=new f(e.encoding),this.encoding=e.encoding)}function E(e){if(i=i||r(36),!(this instanceof E))return new E(e);var t=this instanceof i;this._readableState=new k(e,this,t),this.readable=!0,e&&("function"==typeof e.read&&(this._read=e.read),"function"==typeof e.destroy&&(this._destroy=e.destroy)),a.call(this)}function A(e,t,r,n,i){c("readableAddChunk",t);var o,a=e._readableState;if(null===t)a.reading=!1,function(e,t){if(c("onEofChunk"),t.ended)return;if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,t.sync?P(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,O(e)))}(e,a);else if(i||(o=function(e,t){var r;n=t,s.isBuffer(n)||n instanceof u||"string"==typeof t||void 0===t||e.objectMode||(r=new v("chunk",["string","Buffer","Uint8Array"],t));var n;return r}(a,t)),o)S(e,o);else if(a.objectMode||t&&t.length>0)if("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===s.prototype||(t=function(e){return s.from(e)}(t)),n)a.endEmitted?S(e,new _):x(e,a,t,!0);else if(a.ended)S(e,new y);else{if(a.destroyed)return!1;a.reading=!1,a.decoder&&!r?(t=a.decoder.write(t),a.objectMode||0!==t.length?x(e,a,t,!1):T(e,a)):x(e,a,t,!1)}else n||(a.reading=!1,T(e,a));return!a.ended&&(a.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=1073741824?e=1073741824:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function P(e){var t=e._readableState;c("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(c("emitReadable",t.flowing),t.emittedReadable=!0,n.nextTick(O,e))}function O(e){var t=e._readableState;c("emitReadable_",t.destroyed,t.length,t.ended),t.destroyed||!t.length&&!t.ended||(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,j(e)}function T(e,t){t.readingMore||(t.readingMore=!0,n.nextTick(R,e,t))}function R(e,t){for(;!t.reading&&!t.ended&&(t.length0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount("data")>0&&e.resume()}function N(e){c("readable nexttick read 0"),e.read(0)}function C(e,t){c("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),j(e),t.flowing&&!t.reading&&e.read(0)}function j(e){var t=e._readableState;for(c("flow",t.flowing);t.flowing&&null!==e.read(););}function z(e,t){return 0===t.length?null:(t.objectMode?r=t.buffer.shift():!e||e>=t.length?(r=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):r=t.buffer.consume(e,t.decoder),r);var r}function U(e){var t=e._readableState;c("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,n.nextTick(L,t,e))}function L(e,t){if(c("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&0===e.length&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var r=t._writableState;(!r||r.autoDestroy&&r.finished)&&t.destroy()}}function F(e,t){for(var r=0,n=e.length;r=t.highWaterMark:t.length>0)||t.ended))return c("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?U(this):P(this),null;if(0===(e=I(e,t))&&t.ended)return 0===t.length&&U(this),null;var n,i=t.needReadable;return c("need readable",i),(0===t.length||t.length-e0?z(e,t):null)?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),0===t.length&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&U(this)),null!==n&&this.emit("data",n),n},E.prototype._read=function(e){S(this,new w("_read()"))},E.prototype.pipe=function(e,t){var r=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,c("pipe count=%d opts=%j",i.pipesCount,t);var a=(!t||!1!==t.end)&&e!==n.stdout&&e!==n.stderr?u:g;function s(t,n){c("onunpipe"),t===r&&n&&!1===n.hasUnpiped&&(n.hasUnpiped=!0,c("cleanup"),e.removeListener("close",p),e.removeListener("finish",m),e.removeListener("drain",h),e.removeListener("error",d),e.removeListener("unpipe",s),r.removeListener("end",u),r.removeListener("end",g),r.removeListener("data",l),f=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||h())}function u(){c("onend"),e.end()}i.endEmitted?n.nextTick(a):r.once("end",a),e.on("unpipe",s);var h=function(e){return function(){var t=e._readableState;c("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&o(e,"data")&&(t.flowing=!0,j(e))}}(r);e.on("drain",h);var f=!1;function l(t){c("ondata");var n=e.write(t);c("dest.write",n),!1===n&&((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==F(i.pipes,e))&&!f&&(c("false write response, pause",i.awaitDrain),i.awaitDrain++),r.pause())}function d(t){c("onerror",t),g(),e.removeListener("error",d),0===o(e,"error")&&S(e,t)}function p(){e.removeListener("finish",m),g()}function m(){c("onfinish"),e.removeListener("close",p),g()}function g(){c("unpipe"),r.unpipe(e)}return r.on("data",l),function(e,t,r){if("function"==typeof e.prependListener)return e.prependListener(t,r);e._events&&e._events[t]?Array.isArray(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]:e.on(t,r)}(e,"error",d),e.once("close",p),e.once("finish",m),e.emit("pipe",r),i.flowing||(c("pipe resume"),r.resume()),e},E.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r)),this;if(!e){var n=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var o=0;o0,!1!==i.flowing&&this.resume()):"readable"===e&&(i.endEmitted||i.readableListening||(i.readableListening=i.needReadable=!0,i.flowing=!1,i.emittedReadable=!1,c("on readable",i.length,i.reading),i.length?P(this):i.reading||n.nextTick(N,this))),r},E.prototype.addListener=E.prototype.on,E.prototype.removeListener=function(e,t){var r=a.prototype.removeListener.call(this,e,t);return"readable"===e&&n.nextTick(B,this),r},E.prototype.removeAllListeners=function(e){var t=a.prototype.removeAllListeners.apply(this,arguments);return"readable"!==e&&void 0!==e||n.nextTick(B,this),t},E.prototype.resume=function(){var e=this._readableState;return e.flowing||(c("resume"),e.flowing=!e.readableListening,function(e,t){t.resumeScheduled||(t.resumeScheduled=!0,n.nextTick(C,e,t))}(this,e)),e.paused=!1,this},E.prototype.pause=function(){return c("call pause flowing=%j",this._readableState.flowing),!1!==this._readableState.flowing&&(c("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this},E.prototype.wrap=function(e){var t=this,r=this._readableState,n=!1;for(var i in e.on("end",(function(){if(c("wrapped end"),r.decoder&&!r.ended){var e=r.decoder.end();e&&e.length&&t.push(e)}t.push(null)})),e.on("data",(function(i){(c("wrapped data"),r.decoder&&(i=r.decoder.write(i)),r.objectMode&&null==i)||(r.objectMode||i&&i.length)&&(t.push(i)||(n=!0,e.pause()))})),e)void 0===this[i]&&"function"==typeof e[i]&&(this[i]=function(t){return function(){return e[t].apply(e,arguments)}}(i));for(var o=0;o-1))throw new _(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(E.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(E.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),E.prototype._write=function(e,t,r){r(new m("_write()"))},E.prototype._writev=null,E.prototype.end=function(e,t,r){var i=this._writableState;return"function"==typeof e?(r=e,e=null,t=null):"function"==typeof t&&(r=t,t=null),null!=e&&this.write(e,t),i.corked&&(i.corked=1,this.uncork()),i.ending||function(e,t,r){t.ending=!0,T(e,t),r&&(t.finished?n.nextTick(r):e.once("finish",r));t.ended=!0,e.writable=!1}(this,i,r),this},Object.defineProperty(E.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}}),Object.defineProperty(E.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),E.prototype.destroy=f.destroy,E.prototype._undestroy=f.undestroy,E.prototype._destroy=function(e,t){t(e)}}).call(this,r(8),r(9))},function(e,t,r){(function(t){function r(e){try{if(!t.localStorage)return!1}catch(e){return!1}var r=t.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=function(e,t){if(r("noDeprecation"))return e;var n=!1;return function(){if(!n){if(r("throwDeprecation"))throw new Error(t);r("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}}}).call(this,r(8))},function(e,t,r){"use strict";e.exports=h;var n=r(35).codes,i=n.ERR_METHOD_NOT_IMPLEMENTED,o=n.ERR_MULTIPLE_CALLBACK,a=n.ERR_TRANSFORM_ALREADY_TRANSFORMING,s=n.ERR_TRANSFORM_WITH_LENGTH_0,u=r(36);function c(e,t){var r=this._transformState;r.transforming=!1;var n=r.writecb;if(null===n)return this.emit("error",new o);r.writechunk=null,r.writecb=null,null!=t&&this.push(t),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.length>>2|e<<30)^(e>>>13|e<<19)^(e>>>22|e<<10)}function l(e){return(e>>>6|e<<26)^(e>>>11|e<<21)^(e>>>25|e<<7)}function d(e){return(e>>>7|e<<25)^(e>>>18|e<<14)^e>>>3}n(u,i),u.prototype.init=function(){return this._a=1779033703,this._b=3144134277,this._c=1013904242,this._d=2773480762,this._e=1359893119,this._f=2600822924,this._g=528734635,this._h=1541459225,this},u.prototype._update=function(e){for(var t,r=this._w,n=0|this._a,i=0|this._b,o=0|this._c,s=0|this._d,u=0|this._e,p=0|this._f,m=0|this._g,g=0|this._h,b=0;b<16;++b)r[b]=e.readInt32BE(4*b);for(;b<64;++b)r[b]=0|(((t=r[b-2])>>>17|t<<15)^(t>>>19|t<<13)^t>>>10)+r[b-7]+d(r[b-15])+r[b-16];for(var v=0;v<64;++v){var y=g+l(u)+c(u,p,m)+a[v]+r[v]|0,w=f(n)+h(n,i,o)|0;g=m,m=p,p=u,u=s+y|0,s=o,o=i,i=n,n=y+w|0}this._a=n+this._a|0,this._b=i+this._b|0,this._c=o+this._c|0,this._d=s+this._d|0,this._e=u+this._e|0,this._f=p+this._f|0,this._g=m+this._g|0,this._h=g+this._h|0},u.prototype._hash=function(){var e=o.allocUnsafe(32);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e.writeInt32BE(this._h,28),e},e.exports=u},function(e,t,r){var n=r(1),i=r(37),o=r(2).Buffer,a=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591],s=new Array(160);function u(){this.init(),this._w=s,i.call(this,128,112)}function c(e,t,r){return r^e&(t^r)}function h(e,t,r){return e&t|r&(e|t)}function f(e,t){return(e>>>28|t<<4)^(t>>>2|e<<30)^(t>>>7|e<<25)}function l(e,t){return(e>>>14|t<<18)^(e>>>18|t<<14)^(t>>>9|e<<23)}function d(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^e>>>7}function p(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^(e>>>7|t<<25)}function m(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^e>>>6}function g(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^(e>>>6|t<<26)}function b(e,t){return e>>>0>>0?1:0}n(u,i),u.prototype.init=function(){return this._ah=1779033703,this._bh=3144134277,this._ch=1013904242,this._dh=2773480762,this._eh=1359893119,this._fh=2600822924,this._gh=528734635,this._hh=1541459225,this._al=4089235720,this._bl=2227873595,this._cl=4271175723,this._dl=1595750129,this._el=2917565137,this._fl=725511199,this._gl=4215389547,this._hl=327033209,this},u.prototype._update=function(e){for(var t=this._w,r=0|this._ah,n=0|this._bh,i=0|this._ch,o=0|this._dh,s=0|this._eh,u=0|this._fh,v=0|this._gh,y=0|this._hh,w=0|this._al,_=0|this._bl,S=0|this._cl,M=0|this._dl,k=0|this._el,E=0|this._fl,A=0|this._gl,x=0|this._hl,I=0;I<32;I+=2)t[I]=e.readInt32BE(4*I),t[I+1]=e.readInt32BE(4*I+4);for(;I<160;I+=2){var P=t[I-30],O=t[I-30+1],T=d(P,O),R=p(O,P),B=m(P=t[I-4],O=t[I-4+1]),N=g(O,P),C=t[I-14],j=t[I-14+1],z=t[I-32],U=t[I-32+1],L=R+j|0,F=T+C+b(L,R)|0;F=(F=F+B+b(L=L+N|0,N)|0)+z+b(L=L+U|0,U)|0,t[I]=F,t[I+1]=L}for(var D=0;D<160;D+=2){F=t[D],L=t[D+1];var q=h(r,n,i),K=h(w,_,S),H=f(r,w),V=f(w,r),G=l(s,k),W=l(k,s),Y=a[D],Z=a[D+1],J=c(s,u,v),X=c(k,E,A),$=x+W|0,Q=y+G+b($,x)|0;Q=(Q=(Q=Q+J+b($=$+X|0,X)|0)+Y+b($=$+Z|0,Z)|0)+F+b($=$+L|0,L)|0;var ee=V+K|0,te=H+q+b(ee,V)|0;y=v,x=A,v=u,A=E,u=s,E=k,s=o+Q+b(k=M+$|0,M)|0,o=i,M=S,i=n,S=_,n=r,_=w,r=Q+te+b(w=$+ee|0,$)|0}this._al=this._al+w|0,this._bl=this._bl+_|0,this._cl=this._cl+S|0,this._dl=this._dl+M|0,this._el=this._el+k|0,this._fl=this._fl+E|0,this._gl=this._gl+A|0,this._hl=this._hl+x|0,this._ah=this._ah+r+b(this._al,w)|0,this._bh=this._bh+n+b(this._bl,_)|0,this._ch=this._ch+i+b(this._cl,S)|0,this._dh=this._dh+o+b(this._dl,M)|0,this._eh=this._eh+s+b(this._el,k)|0,this._fh=this._fh+u+b(this._fl,E)|0,this._gh=this._gh+v+b(this._gl,A)|0,this._hh=this._hh+y+b(this._hl,x)|0},u.prototype._hash=function(){var e=o.allocUnsafe(64);function t(t,r,n){e.writeInt32BE(t,n),e.writeInt32BE(r,n+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),t(this._gh,this._gl,48),t(this._hh,this._hl,56),e},e.exports=u},function(e,t,r){"use strict";(function(t,n){var i=r(54);e.exports=y;var o,a=r(109);y.ReadableState=v;r(27).EventEmitter;var s=function(e,t){return e.listeners(t).length},u=r(123),c=r(77).Buffer,h=t.Uint8Array||function(){};var f=Object.create(r(40));f.inherits=r(1);var l=r(222),d=void 0;d=l&&l.debuglog?l.debuglog("stream"):function(){};var p,m=r(223),g=r(124);f.inherits(y,u);var b=["error","close","destroy","pause","resume"];function v(e,t){e=e||{};var n=t instanceof(o=o||r(29));this.objectMode=!!e.objectMode,n&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var i=e.highWaterMark,a=e.readableHighWaterMark,s=this.objectMode?16:16384;this.highWaterMark=i||0===i?i:n&&(a||0===a)?a:s,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new m,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(p||(p=r(39).StringDecoder),this.decoder=new p(e.encoding),this.encoding=e.encoding)}function y(e){if(o=o||r(29),!(this instanceof y))return new y(e);this._readableState=new v(e,this),this.readable=!0,e&&("function"==typeof e.read&&(this._read=e.read),"function"==typeof e.destroy&&(this._destroy=e.destroy)),u.call(this)}function w(e,t,r,n,i){var o,a=e._readableState;null===t?(a.reading=!1,function(e,t){if(t.ended)return;if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,M(e)}(e,a)):(i||(o=function(e,t){var r;n=t,c.isBuffer(n)||n instanceof h||"string"==typeof t||void 0===t||e.objectMode||(r=new TypeError("Invalid non-string/buffer chunk"));var n;return r}(a,t)),o?e.emit("error",o):a.objectMode||t&&t.length>0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===c.prototype||(t=function(e){return c.from(e)}(t)),n?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):_(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!r?(t=a.decoder.write(t),a.objectMode||0!==t.length?_(e,a,t,!1):E(e,a)):_(e,a,t,!1))):n||(a.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=8388608?e=8388608:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function M(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(d("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?i.nextTick(k,e):k(e))}function k(e){d("emit readable"),e.emit("readable"),P(e)}function E(e,t){t.readingMore||(t.readingMore=!0,i.nextTick(A,e,t))}function A(e,t){for(var r=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(r=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):r=function(e,t,r){var n;eo.length?o.length:e;if(a===o.length?i+=o:i+=o.slice(0,e),0===(e-=a)){a===o.length?(++n,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=o.slice(a));break}++n}return t.length-=n,i}(e,t):function(e,t){var r=c.allocUnsafe(e),n=t.head,i=1;n.data.copy(r),e-=n.data.length;for(;n=n.next;){var o=n.data,a=e>o.length?o.length:e;if(o.copy(r,r.length-e,0,a),0===(e-=a)){a===o.length?(++i,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=o.slice(a));break}++i}return t.length-=i,r}(e,t);return n}(e,t.buffer,t.decoder),r);var r}function T(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,i.nextTick(R,t,e))}function R(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function B(e,t){for(var r=0,n=e.length;r=t.highWaterMark||t.ended))return d("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?T(this):M(this),null;if(0===(e=S(e,t))&&t.ended)return 0===t.length&&T(this),null;var n,i=t.needReadable;return d("need readable",i),(0===t.length||t.length-e0?O(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&T(this)),null!==n&&this.emit("data",n),n},y.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},y.prototype.pipe=function(e,t){var r=this,o=this._readableState;switch(o.pipesCount){case 0:o.pipes=e;break;case 1:o.pipes=[o.pipes,e];break;default:o.pipes.push(e)}o.pipesCount+=1,d("pipe count=%d opts=%j",o.pipesCount,t);var u=(!t||!1!==t.end)&&e!==n.stdout&&e!==n.stderr?h:y;function c(t,n){d("onunpipe"),t===r&&n&&!1===n.hasUnpiped&&(n.hasUnpiped=!0,d("cleanup"),e.removeListener("close",b),e.removeListener("finish",v),e.removeListener("drain",f),e.removeListener("error",g),e.removeListener("unpipe",c),r.removeListener("end",h),r.removeListener("end",y),r.removeListener("data",m),l=!0,!o.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function h(){d("onend"),e.end()}o.endEmitted?i.nextTick(u):r.once("end",u),e.on("unpipe",c);var f=function(e){return function(){var t=e._readableState;d("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&s(e,"data")&&(t.flowing=!0,P(e))}}(r);e.on("drain",f);var l=!1;var p=!1;function m(t){d("ondata"),p=!1,!1!==e.write(t)||p||((1===o.pipesCount&&o.pipes===e||o.pipesCount>1&&-1!==B(o.pipes,e))&&!l&&(d("false write response, pause",r._readableState.awaitDrain),r._readableState.awaitDrain++,p=!0),r.pause())}function g(t){d("onerror",t),y(),e.removeListener("error",g),0===s(e,"error")&&e.emit("error",t)}function b(){e.removeListener("finish",v),y()}function v(){d("onfinish"),e.removeListener("close",b),y()}function y(){d("unpipe"),r.unpipe(e)}return r.on("data",m),function(e,t,r){if("function"==typeof e.prependListener)return e.prependListener(t,r);e._events&&e._events[t]?a(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]:e.on(t,r)}(e,"error",g),e.once("close",b),e.once("finish",v),e.emit("pipe",r),o.flowing||(d("pipe resume"),r.resume()),e},y.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r)),this;if(!e){var n=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var o=0;o=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},r(225),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,r(8))},function(e,t,r){"use strict";e.exports=a;var n=r(29),i=Object.create(r(40));function o(e,t){var r=this._transformState;r.transforming=!1;var n=r.writecb;if(!n)return this.emit("error",new Error("write callback called multiple times"));r.writechunk=null,r.writecb=null,null!=t&&this.push(t),n(e);var i=this._readableState;i.reading=!1,(i.needReadable||i.lengthr||t!=t)throw new TypeError("Bad key length")}},function(e,t,r){(function(t){var r;if(t.browser)r="utf-8";else if(t.version){r=parseInt(t.version.split(".")[0].slice(1),10)>=6?"utf-8":"binary"}else r="utf-8";e.exports=r}).call(this,r(9))},function(e,t,r){var n=r(130),i=r(74),o=r(75),a=r(2).Buffer,s=r(127),u=r(128),c=r(131),h=a.alloc(128),f={md5:16,sha1:20,sha224:28,sha256:32,sha384:48,sha512:64,rmd160:20,ripemd160:20};function l(e,t,r){var s=function(e){function t(t){return o(e).update(t).digest()}return"rmd160"===e||"ripemd160"===e?function(e){return(new i).update(e).digest()}:"md5"===e?n:t}(e),u="sha512"===e||"sha384"===e?128:64;t.length>u?t=s(t):t.length>8,a=255&i;o?r.push(o,a):r.push(a)}return r},n.zero2=i,n.toHex=o,n.encode=function(e,t){return"hex"===t?o(e):e}},function(e,t,r){"use strict";var n=t;n.base=r(56),n.short=r(249),n.mont=r(250),n.edwards=r(251)},function(e,t,r){"use strict";var n=r(18).rotr32;function i(e,t,r){return e&t^~e&r}function o(e,t,r){return e&t^e&r^t&r}function a(e,t,r){return e^t^r}t.ft_1=function(e,t,r,n){return 0===e?i(t,r,n):1===e||3===e?a(t,r,n):2===e?o(t,r,n):void 0},t.ch32=i,t.maj32=o,t.p32=a,t.s0_256=function(e){return n(e,2)^n(e,13)^n(e,22)},t.s1_256=function(e){return n(e,6)^n(e,11)^n(e,25)},t.g0_256=function(e){return n(e,7)^n(e,18)^e>>>3},t.g1_256=function(e){return n(e,17)^n(e,19)^e>>>10}},function(e,t,r){"use strict";var n=r(18),i=r(41),o=r(136),a=r(16),s=n.sum32,u=n.sum32_4,c=n.sum32_5,h=o.ch32,f=o.maj32,l=o.s0_256,d=o.s1_256,p=o.g0_256,m=o.g1_256,g=i.BlockHash,b=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function v(){if(!(this instanceof v))return new v;g.call(this),this.h=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],this.k=b,this.W=new Array(64)}n.inherits(v,g),e.exports=v,v.blockSize=512,v.outSize=256,v.hmacStrength=192,v.padLength=64,v.prototype._update=function(e,t){for(var r=this.W,n=0;n<16;n++)r[n]=e[t+n];for(;n0){const r={};return i.forEach(n=>{"object"==typeof t[n]?r[n]=e(t[n]):r[n]=t[n]}),r}return t}(e)}(t=e.exports).codec=i.DAG_CBOR,t.defaultHashAlg=i.SHA2_256;const f={42:e=>(e=e.slice(1),new a(e))};let l=65536;let d=67108864,p=null;t.configureDecoder=e=>{let t=f;e?("number"==typeof e.size&&(l=e.size),"number"==typeof e.maxSize&&(d=e.maxSize),e.tags&&(t=Object.assign({},f,e&&e.tags))):(l=65536,d=67108864);const r={tags:t,size:l};p=new n.Decoder(r),l=r.size},t.configureDecoder(),t.serialize=e=>{const t=h(e);return n.encode(t)},t.deserialize=e=>{if(e.length>l&&e.length<=d&&t.configureDecoder({size:e.length}),e.length>l)throw new Error("Data is too large to deserialize with current decoder");const r=p.decodeAll(e);if(1!==r.length)throw new Error("Extraneous CBOR data found beyond initial top-level object");return r[0]},t.cid=async(e,r)=>{const n={cidVersion:1,hashAlg:t.defaultHashAlg},s=Object.assign(n,r),u=await o(e,s.hashAlg),c=i.print[t.codec];return new a(s.cidVersion,c,u)}},function(e,t,r){"use strict";(function(t){const{Buffer:n}=r(0),i=r(108),o=r(23).BigNumber,a=r(272),s=r(85),u=r(58),c=r(142),h=r(143),{URL:f}=r(144);class l{constructor(e){!(e=e||{}).size||e.size<65536?e.size=65536:e.size=s.nextPowerOf2(e.size),this._heap=new ArrayBuffer(e.size),this._heap8=new Uint8Array(this._heap),this._buffer=n.from(this._heap),this._reset(),this._knownTags=Object.assign({0:e=>new Date(e),1:e=>new Date(1e3*e),2:e=>s.arrayBufferToBignumber(e),3:e=>u.NEG_ONE.minus(s.arrayBufferToBignumber(e)),4:e=>u.TEN.pow(e[0]).times(e[1]),5:e=>u.TWO.pow(e[0]).times(e[1]),32:e=>new f(e),35:e=>new RegExp(e)},e.tags),this.parser=a(t,{log:console.log.bind(console),pushInt:this.pushInt.bind(this),pushInt32:this.pushInt32.bind(this),pushInt32Neg:this.pushInt32Neg.bind(this),pushInt64:this.pushInt64.bind(this),pushInt64Neg:this.pushInt64Neg.bind(this),pushFloat:this.pushFloat.bind(this),pushFloatSingle:this.pushFloatSingle.bind(this),pushFloatDouble:this.pushFloatDouble.bind(this),pushTrue:this.pushTrue.bind(this),pushFalse:this.pushFalse.bind(this),pushUndefined:this.pushUndefined.bind(this),pushNull:this.pushNull.bind(this),pushInfinity:this.pushInfinity.bind(this),pushInfinityNeg:this.pushInfinityNeg.bind(this),pushNaN:this.pushNaN.bind(this),pushNaNNeg:this.pushNaNNeg.bind(this),pushArrayStart:this.pushArrayStart.bind(this),pushArrayStartFixed:this.pushArrayStartFixed.bind(this),pushArrayStartFixed32:this.pushArrayStartFixed32.bind(this),pushArrayStartFixed64:this.pushArrayStartFixed64.bind(this),pushObjectStart:this.pushObjectStart.bind(this),pushObjectStartFixed:this.pushObjectStartFixed.bind(this),pushObjectStartFixed32:this.pushObjectStartFixed32.bind(this),pushObjectStartFixed64:this.pushObjectStartFixed64.bind(this),pushByteString:this.pushByteString.bind(this),pushByteStringStart:this.pushByteStringStart.bind(this),pushUtf8String:this.pushUtf8String.bind(this),pushUtf8StringStart:this.pushUtf8StringStart.bind(this),pushSimpleUnassigned:this.pushSimpleUnassigned.bind(this),pushTagUnassigned:this.pushTagUnassigned.bind(this),pushTagStart:this.pushTagStart.bind(this),pushTagStart4:this.pushTagStart4.bind(this),pushTagStart8:this.pushTagStart8.bind(this),pushBreak:this.pushBreak.bind(this)},this._heap)}get _depth(){return this._parents.length}get _currentParent(){return this._parents[this._depth-1]}get _ref(){return this._currentParent.ref}_closeParent(){var e=this._parents.pop();if(e.length>0)throw new Error(`Missing ${e.length} elements`);switch(e.type){case u.PARENT.TAG:this._push(this.createTag(e.ref[0],e.ref[1]));break;case u.PARENT.BYTE_STRING:this._push(this.createByteString(e.ref,e.length));break;case u.PARENT.UTF8_STRING:this._push(this.createUtf8String(e.ref,e.length));break;case u.PARENT.MAP:if(e.values%2>0)throw new Error("Odd number of elements in the map");this._push(this.createMap(e.ref,e.length));break;case u.PARENT.OBJECT:if(e.values%2>0)throw new Error("Odd number of elements in the map");this._push(this.createObject(e.ref,e.length));break;case u.PARENT.ARRAY:this._push(this.createArray(e.ref,e.length))}this._currentParent&&this._currentParent.type===u.PARENT.TAG&&this._dec()}_dec(){const e=this._currentParent;e.length<0||(e.length--,0===e.length&&this._closeParent())}_push(e,t){const r=this._currentParent;switch(r.values++,r.type){case u.PARENT.ARRAY:case u.PARENT.BYTE_STRING:case u.PARENT.UTF8_STRING:r.length>-1?this._ref[this._ref.length-r.length]=e:this._ref.push(e),this._dec();break;case u.PARENT.OBJECT:null!=r.tmpKey?(this._ref[r.tmpKey]=e,r.tmpKey=null,this._dec()):(r.tmpKey=e,"string"!=typeof r.tmpKey&&(r.type=u.PARENT.MAP,r.ref=s.buildMap(r.ref)));break;case u.PARENT.MAP:null!=r.tmpKey?(this._ref.set(r.tmpKey,e),r.tmpKey=null,this._dec()):r.tmpKey=e;break;case u.PARENT.TAG:this._ref.push(e),t||this._dec();break;default:throw new Error("Unknown parent type")}}_createParent(e,t,r){this._parents[this._depth]={type:t,length:r,ref:e,values:0,tmpKey:null}}_reset(){this._res=[],this._parents=[{type:u.PARENT.ARRAY,length:-1,ref:this._res,values:0,tmpKey:null}]}createTag(e,t){const r=this._knownTags[e];return r?r(t):new h(e,t)}createMap(e,t){return e}createObject(e,t){return e}createArray(e,t){return e}createByteString(e,t){return n.concat(e)}createByteStringFromHeap(e,t){return e===t?n.alloc(0):n.from(this._heap.slice(e,t))}createInt(e){return e}createInt32(e,t){return s.buildInt32(e,t)}createInt64(e,t,r,n){return s.buildInt64(e,t,r,n)}createFloat(e){return e}createFloatSingle(e,t,r,n){return i.read([e,t,r,n],0,!1,23,4)}createFloatDouble(e,t,r,n,o,a,s,u){return i.read([e,t,r,n,o,a,s,u],0,!1,52,8)}createInt32Neg(e,t){return-1-s.buildInt32(e,t)}createInt64Neg(e,t,r,n){const i=s.buildInt32(e,t),a=s.buildInt32(r,n);return i>u.MAX_SAFE_HIGH?u.NEG_ONE.minus(new o(i).times(u.SHIFT32).plus(a)):-1-(i*u.SHIFT32+a)}createTrue(){return!0}createFalse(){return!1}createNull(){return null}createUndefined(){}createInfinity(){return 1/0}createInfinityNeg(){return-1/0}createNaN(){return NaN}createNaNNeg(){return NaN}createUtf8String(e,t){return e.join("")}createUtf8StringFromHeap(e,t){return e===t?"":this._buffer.toString("utf8",e,t)}createSimpleUnassigned(e){return new c(e)}pushInt(e){this._push(this.createInt(e))}pushInt32(e,t){this._push(this.createInt32(e,t))}pushInt64(e,t,r,n){this._push(this.createInt64(e,t,r,n))}pushFloat(e){this._push(this.createFloat(e))}pushFloatSingle(e,t,r,n){this._push(this.createFloatSingle(e,t,r,n))}pushFloatDouble(e,t,r,n,i,o,a,s){this._push(this.createFloatDouble(e,t,r,n,i,o,a,s))}pushInt32Neg(e,t){this._push(this.createInt32Neg(e,t))}pushInt64Neg(e,t,r,n){this._push(this.createInt64Neg(e,t,r,n))}pushTrue(){this._push(this.createTrue())}pushFalse(){this._push(this.createFalse())}pushNull(){this._push(this.createNull())}pushUndefined(){this._push(this.createUndefined())}pushInfinity(){this._push(this.createInfinity())}pushInfinityNeg(){this._push(this.createInfinityNeg())}pushNaN(){this._push(this.createNaN())}pushNaNNeg(){this._push(this.createNaNNeg())}pushArrayStart(){this._createParent([],u.PARENT.ARRAY,-1)}pushArrayStartFixed(e){this._createArrayStartFixed(e)}pushArrayStartFixed32(e,t){const r=s.buildInt32(e,t);this._createArrayStartFixed(r)}pushArrayStartFixed64(e,t,r,n){const i=s.buildInt64(e,t,r,n);this._createArrayStartFixed(i)}pushObjectStart(){this._createObjectStartFixed(-1)}pushObjectStartFixed(e){this._createObjectStartFixed(e)}pushObjectStartFixed32(e,t){const r=s.buildInt32(e,t);this._createObjectStartFixed(r)}pushObjectStartFixed64(e,t,r,n){const i=s.buildInt64(e,t,r,n);this._createObjectStartFixed(i)}pushByteStringStart(){this._parents[this._depth]={type:u.PARENT.BYTE_STRING,length:-1,ref:[],values:0,tmpKey:null}}pushByteString(e,t){this._push(this.createByteStringFromHeap(e,t))}pushUtf8StringStart(){this._parents[this._depth]={type:u.PARENT.UTF8_STRING,length:-1,ref:[],values:0,tmpKey:null}}pushUtf8String(e,t){this._push(this.createUtf8StringFromHeap(e,t))}pushSimpleUnassigned(e){this._push(this.createSimpleUnassigned(e))}pushTagStart(e){this._parents[this._depth]={type:u.PARENT.TAG,length:1,ref:[e]}}pushTagStart4(e,t){this.pushTagStart(s.buildInt32(e,t))}pushTagStart8(e,t,r,n){this.pushTagStart(s.buildInt64(e,t,r,n))}pushTagUnassigned(e){this._push(this.createTag(e))}pushBreak(){if(this._currentParent.length>-1)throw new Error("Unexpected break");this._closeParent()}_createObjectStartFixed(e){0!==e?this._createParent({},u.PARENT.OBJECT,e):this._push(this.createObject({}))}_createArrayStartFixed(e){0!==e?this._createParent(new Array(e),u.PARENT.ARRAY,e):this._push(this.createArray([]))}_decode(e){if(0===e.byteLength)throw new Error("Input too short");this._reset(),this._heap8.set(e);const t=this.parser.parse(e.byteLength);if(this._depth>1){for(;0===this._currentParent.length;)this._closeParent();if(this._depth>1)throw new Error("Undeterminated nesting")}if(t>0)throw new Error("Failed to parse");if(0===this._res.length)throw new Error("No valid result")}decodeFirst(e){return this._decode(e),this._res[0]}decodeAll(e){return this._decode(e),this._res}static decode(e,t){"string"==typeof e&&(e=n.from(e,t||"hex"));return new l({size:e.length}).decodeFirst(e)}static decodeAll(e,t){"string"==typeof e&&(e=n.from(e,t||"hex"));return new l({size:e.length}).decodeAll(e)}}l.decodeFirst=l.decode,e.exports=l}).call(this,r(8))},function(e,t,r){"use strict";const n=r(58),i=n.MT,o=n.SIMPLE,a=n.SYMS;class s{constructor(e){if("number"!=typeof e)throw new Error("Invalid Simple type: "+typeof e);if(e<0||e>255||(0|e)!==e)throw new Error("value must be a small positive integer: "+e);this.value=e}toString(){return"simple("+this.value+")"}inspect(){return"simple("+this.value+")"}encodeCBOR(e){return e._pushInt(this.value,i.SIMPLE_FLOAT)}static isSimple(e){return e instanceof s}static decode(e,t){switch(null==t&&(t=!0),e){case o.FALSE:return!1;case o.TRUE:return!0;case o.NULL:return t?null:a.NULL;case o.UNDEFINED:return t?void 0:a.UNDEFINED;case-1:if(!t)throw new Error("Invalid BREAK");return a.BREAK;default:return new s(e)}}}e.exports=s},function(e,t,r){"use strict";class n{constructor(e,t,r){if(this.tag=e,this.value=t,this.err=r,"number"!=typeof this.tag)throw new Error("Invalid tag type ("+typeof this.tag+")");if(this.tag<0||(0|this.tag)!==this.tag)throw new Error("Tag must be a positive integer: "+this.tag)}toString(){return`${this.tag}(${JSON.stringify(this.value)})`}encodeCBOR(e){return e._pushTag(this.tag),e.pushAny(this.value)}convert(e){var t,r;if("function"!=typeof(r=null!=e?e[this.tag]:void 0)&&"function"!=typeof(r=n["_tag"+this.tag]))return this;try{return r.call(n,this.value)}catch(e){return t=e,this.err=t,this}}}e.exports=n},function(e,t,r){"use strict";const{URLWithLegacySupport:n,format:i,URLSearchParams:o,defaultBase:a}=r(145),s=r(273);e.exports={URL:n,URLSearchParams:o,format:i,relative:s,defaultBase:a}},function(e,t,r){"use strict";const n=self.location?self.location.protocol+"//"+self.location.host:"",i=self.URL;e.exports={URLWithLegacySupport:class{constructor(e="",t=n){this.super=new i(e,t),this.path=this.pathname+this.search,this.auth=this.username&&this.password?this.username+":"+this.password:null,this.query=this.search&&this.search.startsWith("?")?this.search.slice(1):null}get hash(){return this.super.hash}get host(){return this.super.host}get hostname(){return this.super.hostname}get href(){return this.super.href}get origin(){return this.super.origin}get password(){return this.super.password}get pathname(){return this.super.pathname}get port(){return this.super.port}get protocol(){return this.super.protocol}get search(){return this.super.search}get searchParams(){return this.super.searchParams}get username(){return this.super.username}set hash(e){this.super.hash=e}set host(e){this.super.host=e}set hostname(e){this.super.hostname=e}set href(e){this.super.href=e}set origin(e){this.super.origin=e}set password(e){this.super.password=e}set pathname(e){this.super.pathname=e}set port(e){this.super.port=e}set protocol(e){this.super.protocol=e}set search(e){this.super.search=e}set searchParams(e){this.super.searchParams=e}set username(e){this.super.username=e}createObjectURL(e){return this.super.createObjectURL(e)}revokeObjectURL(e){this.super.revokeObjectURL(e)}toJSON(){return this.super.toJSON()}toString(){return this.super.toString()}format(){return this.toString()}},URLSearchParams:self.URLSearchParams,defaultBase:n,format:function(e){if("string"==typeof e){return new i(e).toString()}if(!(e instanceof i)){const t=e.username&&e.password?`${e.username}:${e.password}@`:"",r=e.auth?e.auth+"@":"",n=e.port?":"+e.port:"",i=e.protocol?e.protocol+"//":"",o=e.host||"",a=e.hostname||"",s=e.search||(e.query?"?"+e.query:""),u=e.hash||"",c=e.pathname||"";return`${i}${t||r}${o||a+n}${e.path||c+s}${u}`}}}},function(e,t,r){"use strict";const n=r(86),i=r(278),o=r(279),a=r(147),s=r(285);(t=e.exports).addPrefix=(e,t)=>{let r;if(e instanceof Uint8Array)r=a.varintUint8ArrayEncode(e);else{if(!o[e])throw new Error("multicodec not recognized");r=o[e]}return s([r,t],r.length+t.length)},t.rmPrefix=e=>(n.decode(e),e.slice(n.decode.bytes)),t.getCodec=e=>{const t=n.decode(e),r=i.get(t);if(void 0===r)throw new Error(`Code ${t} not found`);return r},t.getName=e=>i.get(e),t.getNumber=e=>{const t=o[e];if(void 0===t)throw new Error("Codec `"+e+"` not found");return n.decode(t)},t.getCode=e=>n.decode(e),t.getCodeVarint=e=>{const t=o[e];if(void 0===t)throw new Error("Codec `"+e+"` not found");return t},t.getVarint=e=>n.encode(e);const u=r(286);Object.assign(t,u),t.print=r(287)},function(e,t,r){"use strict";const n=r(86),i=r(280),o=r(284);function a(e){return parseInt(i(e,"base16"),16)}e.exports={numberToUint8Array:function(e){let t=e.toString(16);t.length%2==1&&(t="0"+t);return o(t,"base16")},uint8ArrayToNumber:a,varintUint8ArrayEncode:function(e){return Uint8Array.from(n.encode(a(e)))},varintEncode:function(e){return Uint8Array.from(n.encode(e))}}},function(e,t,r){"use strict";const n=r(43),{encodeText:i,decodeText:o,concat:a}=r(87);function s(e){if(n.names[e])return n.names[e];if(n.codes[e])return n.codes[e];throw new Error("Unsupported encoding: "+e)}(t=e.exports=function(e,t){if(!t)throw new Error("requires an encoded Uint8Array");const{name:r,codeBuf:n}=s(e);return function(e,t){s(e).decode(o(t))}(r,t),a([n,t],n.length+t.length)}).encode=function(e,t){const r=s(e),n=i(r.encode(t));return a([r.codeBuf,n],r.codeBuf.length+n.length)},t.decode=function(e){e instanceof Uint8Array&&(e=o(e));const t=e[0];return["f","F","v","V","t","T","b","B","c","C","h","k","K"].includes(t)&&(e=e.toLowerCase()),s(e[0]).decode(e.substring(1))},t.isEncoded=function(e){if(e instanceof Uint8Array&&(e=o(e)),"[object String]"!==Object.prototype.toString.call(e))return!1;try{return s(e[0]).name}catch(e){return!1}},t.encoding=s,t.encodingFromData=function(e){return e instanceof Uint8Array&&(e=o(e)),s(e[0])},t.names=Object.freeze(n.names),t.codes=Object.freeze(n.codes)},function(e,t,r){"use strict";const{names:n}=r(43),{TextDecoder:i}=r(44),o=new i("utf8");e.exports=function(e,t="utf8"){if("utf8"===t||"utf-8"===t)return o.decode(e);if("ascii"===t)return function(e){let t="";for(let r=0;r=5;)h+=n[c>>>u-5&31],u-=5;if(u>0&&(h+=n[c<<5-u&31]),o)for(;h.length%8!=0;)h+="=";return h}},function(e,t,r){(function(t){const n=r(90),i=r(312),o=r(153),a=r(313),s=r(45),{UnknownProtocolIndicator:u,InvalidPayloadLength:c,ProtocolNotSupported:h,InvalidChecksumAddress:f}=r(321),{ProtocolIndicator:l}=r(157),d=t.from([1,113,160,228,2,32]);function p(e){const r=n.blake2bInit(32);n.blake2bUpdate(r,e);const i=t.from(n.blake2bFinal(r));return t.concat([d,i])}function m(e){const r=n.blake2bInit(4);return n.blake2bUpdate(r,e),t.from(n.blake2bFinal(r))}e.exports={getCID:p,getDigest:function(e){const r=n.blake2bInit(32);return n.blake2bUpdate(r,p(e)),t.from(n.blake2bFinal(r))},getPayloadSECP256K1:function(e){const r=n.blake2bInit(20);return n.blake2bUpdate(r,e),t.from(n.blake2bFinal(r))},getChecksum:m,getCoinTypeFromPath:function(e){return e.split("/")[2].slice(0,-1)},addressAsBytes:function(e){let r,n,o;const s=e[1],d="0"+s;switch(Number(s)){case l.ID:if(e.length>18)throw new c;return t.concat([t.from(d,"hex"),t.from(a.unsigned.encode(e.substr(2)))]);case l.SECP256K1:case l.ACTOR:if(r=i(e.slice(2).toUpperCase(),"RFC4648"),n=r.slice(0,-4),o=t.from(r.slice(-4)),20!==n.byteLength)throw new c;break;case l.BLS:throw new h("BLS");default:throw new u}const p=t.concat([t.from(d,"hex"),t.from(n)]);if(m(p).toString("hex")!==o.toString("hex"))throw new f;return p},bytesToAddress:function(e,r){const n=e[0];switch(Number(n)){case l.ID:throw new h("ID");case l.SECP256K1:case l.ACTOR:if(20!==e.slice(1).length)throw new c;break;case l.BLS:throw new h("BLS");default:throw new u}const i=m(e);let a="f";return r&&(a="t"),a+=n,a+o(t.concat([e.slice(1),i]),"RFC4648",{padding:!1}).toLowerCase()},tryToPrivateKeyBuffer:function(e){return"string"==typeof e&&(e="="===e.slice(-1)?t.from(e,"base64"):t.from(e,"hex")),s(32===e.length),e}}}).call(this,r(0).Buffer)},function(e,t,r){(function(e){!function(e,t){"use strict";function n(e,t){if(!e)throw new Error(t||"Assertion failed")}function i(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function o(e,t,r){if(o.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var a;"object"==typeof e?e.exports=o:t.BN=o,o.BN=o,o.wordSize=26;try{a=r(315).Buffer}catch(e){}function s(e,t,r){for(var i=0,o=Math.min(e.length,r),a=0,s=t;s=49&&c<=54?c-49+10:c>=17&&c<=22?c-17+10:c,a|=u}return n(!(240&a),"Invalid character in "+e),i}function u(e,t,r,i){for(var o=0,a=0,s=Math.min(e.length,r),u=t;u=49?c-49+10:c>=17?c-17+10:c,n(c>=0&&a0?e:t},o.min=function(e,t){return e.cmp(t)<0?e:t},o.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),n(t===(0|t)&&t>=2&&t<=36);var i=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&i++,16===t?this._parseHex(e,i):this._parseBase(e,t,i),"-"===e[0]&&(this.negative=1),this._strip(),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(n(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initArray=function(e,t,r){if(n("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var i=0;i=0;i-=3)a=e[i]|e[i-1]<<8|e[i-2]<<16,this.words[o]|=a<>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);else if("le"===r)for(i=0,o=0;i>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);return this._strip()},o.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)i=s(e,r,r+6),this.words[n]|=i<>>26-o&4194303,(o+=24)>=26&&(o-=26,n++);r+6!==t&&(i=s(e,t,r+6),this.words[n]|=i<>>26-o&4194303),this._strip()},o.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var n=0,i=1;i<=67108863;i*=t)n++;n--,i=i/t|0;for(var o=e.length-r,a=o%n,s=Math.min(o,o-a)+r,c=0,h=r;h1&&0===this.words[this.length-1];)this.length--;return this._normSign()},o.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},"undefined"!=typeof Symbol&&"function"==typeof Symbol.for)try{o.prototype[Symbol.for("nodejs.util.inspect.custom")]=h}catch(e){o.prototype.inspect=h}else o.prototype.inspect=h;function h(){return(this.red?""}var f=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],d=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];o.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var i=0,o=0,a=0;a>>24-i&16777215)||a!==this.length-1?f[6-u.length]+u+r:u+r,(i+=2)>=26&&(i-=26,a--)}for(0!==o&&(r=o.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var c=l[e],h=d[e];r="";var p=this.clone();for(p.negative=0;!p.isZero();){var m=p.modrn(h).toString(e);r=(p=p.idivn(h)).isZero()?m+r:f[c-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}n(!1,"Base should be between 2 and 36")},o.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&n(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},o.prototype.toJSON=function(){return this.toString(16,2)},a&&(o.prototype.toBuffer=function(e,t){return this.toArrayLike(a,e,t)}),o.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)};function p(e,t,r){r.negative=t.negative^e.negative;var n=e.length+t.length|0;r.length=n,n=n-1|0;var i=0|e.words[0],o=0|t.words[0],a=i*o,s=67108863&a,u=a/67108864|0;r.words[0]=s;for(var c=1;c>>26,f=67108863&u,l=Math.min(c,t.length-1),d=Math.max(0,c-e.length+1);d<=l;d++){var p=c-d|0;h+=(a=(i=0|e.words[p])*(o=0|t.words[d])+f)/67108864|0,f=67108863&a}r.words[c]=0|f,u=0|h}return 0!==u?r.words[c]=0|u:r.length--,r._strip()}o.prototype.toArrayLike=function(e,t,r){this._strip();var i=this.byteLength(),o=r||Math.max(1,i);n(i<=o,"byte array longer than desired length"),n(o>0,"Requested array length <= 0");var a=function(e,t){return e.allocUnsafe?e.allocUnsafe(t):new e(t)}(e,o);return this["_toArrayLike"+("le"===t?"LE":"BE")](a,i),a},o.prototype._toArrayLikeLE=function(e,t){for(var r=0,n=0,i=0,o=0;i>8&255),r>16&255),6===o?(r>24&255),n=0,o=0):(n=a>>>24,o+=2)}if(r=0&&(e[r--]=a>>8&255),r>=0&&(e[r--]=a>>16&255),6===o?(r>=0&&(e[r--]=a>>24&255),n=0,o=0):(n=a>>>24,o+=2)}if(r>=0)for(e[r--]=n;r>=0;)e[r--]=0},Math.clz32?o.prototype._countBits=function(e){return 32-Math.clz32(e)}:o.prototype._countBits=function(e){var t=e,r=0;return t>=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},o.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},o.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},o.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},o.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},o.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},o.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},o.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var n=0;ne.length?this.clone().ixor(e):e.clone().ixor(this)},o.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},o.prototype.inotn=function(e){n("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var i=0;i0&&(this.words[i]=~this.words[i]&67108863>>26-r),this._strip()},o.prototype.notn=function(e){return this.clone().inotn(e)},o.prototype.setn=function(e,t){n("number"==typeof e&&e>=0);var r=e/26|0,i=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,n=e):(r=e,n=this);for(var i=0,o=0;o>>26;for(;0!==i&&o>>26;if(this.length=r.length,0!==i)this.words[this.length]=i,this.length++;else if(r!==this)for(;oe.length?this.clone().iadd(e):e.clone().iadd(this)},o.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,n,i=this.cmp(e);if(0===i)return this.negative=0,this.length=1,this.words[0]=0,this;i>0?(r=this,n=e):(r=e,n=this);for(var o=0,a=0;a>26,this.words[a]=67108863&t;for(;0!==o&&a>26,this.words[a]=67108863&t;if(0===o&&a>>13,d=0|a[1],p=8191&d,m=d>>>13,g=0|a[2],b=8191&g,v=g>>>13,y=0|a[3],w=8191&y,_=y>>>13,S=0|a[4],M=8191&S,k=S>>>13,E=0|a[5],A=8191&E,x=E>>>13,I=0|a[6],P=8191&I,O=I>>>13,T=0|a[7],R=8191&T,B=T>>>13,N=0|a[8],C=8191&N,j=N>>>13,z=0|a[9],U=8191&z,L=z>>>13,F=0|s[0],D=8191&F,q=F>>>13,K=0|s[1],H=8191&K,V=K>>>13,G=0|s[2],W=8191&G,Y=G>>>13,Z=0|s[3],J=8191&Z,X=Z>>>13,$=0|s[4],Q=8191&$,ee=$>>>13,te=0|s[5],re=8191&te,ne=te>>>13,ie=0|s[6],oe=8191&ie,ae=ie>>>13,se=0|s[7],ue=8191&se,ce=se>>>13,he=0|s[8],fe=8191&he,le=he>>>13,de=0|s[9],pe=8191&de,me=de>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(c+(n=Math.imul(f,D))|0)+((8191&(i=(i=Math.imul(f,q))+Math.imul(l,D)|0))<<13)|0;c=((o=Math.imul(l,q))+(i>>>13)|0)+(ge>>>26)|0,ge&=67108863,n=Math.imul(p,D),i=(i=Math.imul(p,q))+Math.imul(m,D)|0,o=Math.imul(m,q);var be=(c+(n=n+Math.imul(f,H)|0)|0)+((8191&(i=(i=i+Math.imul(f,V)|0)+Math.imul(l,H)|0))<<13)|0;c=((o=o+Math.imul(l,V)|0)+(i>>>13)|0)+(be>>>26)|0,be&=67108863,n=Math.imul(b,D),i=(i=Math.imul(b,q))+Math.imul(v,D)|0,o=Math.imul(v,q),n=n+Math.imul(p,H)|0,i=(i=i+Math.imul(p,V)|0)+Math.imul(m,H)|0,o=o+Math.imul(m,V)|0;var ve=(c+(n=n+Math.imul(f,W)|0)|0)+((8191&(i=(i=i+Math.imul(f,Y)|0)+Math.imul(l,W)|0))<<13)|0;c=((o=o+Math.imul(l,Y)|0)+(i>>>13)|0)+(ve>>>26)|0,ve&=67108863,n=Math.imul(w,D),i=(i=Math.imul(w,q))+Math.imul(_,D)|0,o=Math.imul(_,q),n=n+Math.imul(b,H)|0,i=(i=i+Math.imul(b,V)|0)+Math.imul(v,H)|0,o=o+Math.imul(v,V)|0,n=n+Math.imul(p,W)|0,i=(i=i+Math.imul(p,Y)|0)+Math.imul(m,W)|0,o=o+Math.imul(m,Y)|0;var ye=(c+(n=n+Math.imul(f,J)|0)|0)+((8191&(i=(i=i+Math.imul(f,X)|0)+Math.imul(l,J)|0))<<13)|0;c=((o=o+Math.imul(l,X)|0)+(i>>>13)|0)+(ye>>>26)|0,ye&=67108863,n=Math.imul(M,D),i=(i=Math.imul(M,q))+Math.imul(k,D)|0,o=Math.imul(k,q),n=n+Math.imul(w,H)|0,i=(i=i+Math.imul(w,V)|0)+Math.imul(_,H)|0,o=o+Math.imul(_,V)|0,n=n+Math.imul(b,W)|0,i=(i=i+Math.imul(b,Y)|0)+Math.imul(v,W)|0,o=o+Math.imul(v,Y)|0,n=n+Math.imul(p,J)|0,i=(i=i+Math.imul(p,X)|0)+Math.imul(m,J)|0,o=o+Math.imul(m,X)|0;var we=(c+(n=n+Math.imul(f,Q)|0)|0)+((8191&(i=(i=i+Math.imul(f,ee)|0)+Math.imul(l,Q)|0))<<13)|0;c=((o=o+Math.imul(l,ee)|0)+(i>>>13)|0)+(we>>>26)|0,we&=67108863,n=Math.imul(A,D),i=(i=Math.imul(A,q))+Math.imul(x,D)|0,o=Math.imul(x,q),n=n+Math.imul(M,H)|0,i=(i=i+Math.imul(M,V)|0)+Math.imul(k,H)|0,o=o+Math.imul(k,V)|0,n=n+Math.imul(w,W)|0,i=(i=i+Math.imul(w,Y)|0)+Math.imul(_,W)|0,o=o+Math.imul(_,Y)|0,n=n+Math.imul(b,J)|0,i=(i=i+Math.imul(b,X)|0)+Math.imul(v,J)|0,o=o+Math.imul(v,X)|0,n=n+Math.imul(p,Q)|0,i=(i=i+Math.imul(p,ee)|0)+Math.imul(m,Q)|0,o=o+Math.imul(m,ee)|0;var _e=(c+(n=n+Math.imul(f,re)|0)|0)+((8191&(i=(i=i+Math.imul(f,ne)|0)+Math.imul(l,re)|0))<<13)|0;c=((o=o+Math.imul(l,ne)|0)+(i>>>13)|0)+(_e>>>26)|0,_e&=67108863,n=Math.imul(P,D),i=(i=Math.imul(P,q))+Math.imul(O,D)|0,o=Math.imul(O,q),n=n+Math.imul(A,H)|0,i=(i=i+Math.imul(A,V)|0)+Math.imul(x,H)|0,o=o+Math.imul(x,V)|0,n=n+Math.imul(M,W)|0,i=(i=i+Math.imul(M,Y)|0)+Math.imul(k,W)|0,o=o+Math.imul(k,Y)|0,n=n+Math.imul(w,J)|0,i=(i=i+Math.imul(w,X)|0)+Math.imul(_,J)|0,o=o+Math.imul(_,X)|0,n=n+Math.imul(b,Q)|0,i=(i=i+Math.imul(b,ee)|0)+Math.imul(v,Q)|0,o=o+Math.imul(v,ee)|0,n=n+Math.imul(p,re)|0,i=(i=i+Math.imul(p,ne)|0)+Math.imul(m,re)|0,o=o+Math.imul(m,ne)|0;var Se=(c+(n=n+Math.imul(f,oe)|0)|0)+((8191&(i=(i=i+Math.imul(f,ae)|0)+Math.imul(l,oe)|0))<<13)|0;c=((o=o+Math.imul(l,ae)|0)+(i>>>13)|0)+(Se>>>26)|0,Se&=67108863,n=Math.imul(R,D),i=(i=Math.imul(R,q))+Math.imul(B,D)|0,o=Math.imul(B,q),n=n+Math.imul(P,H)|0,i=(i=i+Math.imul(P,V)|0)+Math.imul(O,H)|0,o=o+Math.imul(O,V)|0,n=n+Math.imul(A,W)|0,i=(i=i+Math.imul(A,Y)|0)+Math.imul(x,W)|0,o=o+Math.imul(x,Y)|0,n=n+Math.imul(M,J)|0,i=(i=i+Math.imul(M,X)|0)+Math.imul(k,J)|0,o=o+Math.imul(k,X)|0,n=n+Math.imul(w,Q)|0,i=(i=i+Math.imul(w,ee)|0)+Math.imul(_,Q)|0,o=o+Math.imul(_,ee)|0,n=n+Math.imul(b,re)|0,i=(i=i+Math.imul(b,ne)|0)+Math.imul(v,re)|0,o=o+Math.imul(v,ne)|0,n=n+Math.imul(p,oe)|0,i=(i=i+Math.imul(p,ae)|0)+Math.imul(m,oe)|0,o=o+Math.imul(m,ae)|0;var Me=(c+(n=n+Math.imul(f,ue)|0)|0)+((8191&(i=(i=i+Math.imul(f,ce)|0)+Math.imul(l,ue)|0))<<13)|0;c=((o=o+Math.imul(l,ce)|0)+(i>>>13)|0)+(Me>>>26)|0,Me&=67108863,n=Math.imul(C,D),i=(i=Math.imul(C,q))+Math.imul(j,D)|0,o=Math.imul(j,q),n=n+Math.imul(R,H)|0,i=(i=i+Math.imul(R,V)|0)+Math.imul(B,H)|0,o=o+Math.imul(B,V)|0,n=n+Math.imul(P,W)|0,i=(i=i+Math.imul(P,Y)|0)+Math.imul(O,W)|0,o=o+Math.imul(O,Y)|0,n=n+Math.imul(A,J)|0,i=(i=i+Math.imul(A,X)|0)+Math.imul(x,J)|0,o=o+Math.imul(x,X)|0,n=n+Math.imul(M,Q)|0,i=(i=i+Math.imul(M,ee)|0)+Math.imul(k,Q)|0,o=o+Math.imul(k,ee)|0,n=n+Math.imul(w,re)|0,i=(i=i+Math.imul(w,ne)|0)+Math.imul(_,re)|0,o=o+Math.imul(_,ne)|0,n=n+Math.imul(b,oe)|0,i=(i=i+Math.imul(b,ae)|0)+Math.imul(v,oe)|0,o=o+Math.imul(v,ae)|0,n=n+Math.imul(p,ue)|0,i=(i=i+Math.imul(p,ce)|0)+Math.imul(m,ue)|0,o=o+Math.imul(m,ce)|0;var ke=(c+(n=n+Math.imul(f,fe)|0)|0)+((8191&(i=(i=i+Math.imul(f,le)|0)+Math.imul(l,fe)|0))<<13)|0;c=((o=o+Math.imul(l,le)|0)+(i>>>13)|0)+(ke>>>26)|0,ke&=67108863,n=Math.imul(U,D),i=(i=Math.imul(U,q))+Math.imul(L,D)|0,o=Math.imul(L,q),n=n+Math.imul(C,H)|0,i=(i=i+Math.imul(C,V)|0)+Math.imul(j,H)|0,o=o+Math.imul(j,V)|0,n=n+Math.imul(R,W)|0,i=(i=i+Math.imul(R,Y)|0)+Math.imul(B,W)|0,o=o+Math.imul(B,Y)|0,n=n+Math.imul(P,J)|0,i=(i=i+Math.imul(P,X)|0)+Math.imul(O,J)|0,o=o+Math.imul(O,X)|0,n=n+Math.imul(A,Q)|0,i=(i=i+Math.imul(A,ee)|0)+Math.imul(x,Q)|0,o=o+Math.imul(x,ee)|0,n=n+Math.imul(M,re)|0,i=(i=i+Math.imul(M,ne)|0)+Math.imul(k,re)|0,o=o+Math.imul(k,ne)|0,n=n+Math.imul(w,oe)|0,i=(i=i+Math.imul(w,ae)|0)+Math.imul(_,oe)|0,o=o+Math.imul(_,ae)|0,n=n+Math.imul(b,ue)|0,i=(i=i+Math.imul(b,ce)|0)+Math.imul(v,ue)|0,o=o+Math.imul(v,ce)|0,n=n+Math.imul(p,fe)|0,i=(i=i+Math.imul(p,le)|0)+Math.imul(m,fe)|0,o=o+Math.imul(m,le)|0;var Ee=(c+(n=n+Math.imul(f,pe)|0)|0)+((8191&(i=(i=i+Math.imul(f,me)|0)+Math.imul(l,pe)|0))<<13)|0;c=((o=o+Math.imul(l,me)|0)+(i>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,n=Math.imul(U,H),i=(i=Math.imul(U,V))+Math.imul(L,H)|0,o=Math.imul(L,V),n=n+Math.imul(C,W)|0,i=(i=i+Math.imul(C,Y)|0)+Math.imul(j,W)|0,o=o+Math.imul(j,Y)|0,n=n+Math.imul(R,J)|0,i=(i=i+Math.imul(R,X)|0)+Math.imul(B,J)|0,o=o+Math.imul(B,X)|0,n=n+Math.imul(P,Q)|0,i=(i=i+Math.imul(P,ee)|0)+Math.imul(O,Q)|0,o=o+Math.imul(O,ee)|0,n=n+Math.imul(A,re)|0,i=(i=i+Math.imul(A,ne)|0)+Math.imul(x,re)|0,o=o+Math.imul(x,ne)|0,n=n+Math.imul(M,oe)|0,i=(i=i+Math.imul(M,ae)|0)+Math.imul(k,oe)|0,o=o+Math.imul(k,ae)|0,n=n+Math.imul(w,ue)|0,i=(i=i+Math.imul(w,ce)|0)+Math.imul(_,ue)|0,o=o+Math.imul(_,ce)|0,n=n+Math.imul(b,fe)|0,i=(i=i+Math.imul(b,le)|0)+Math.imul(v,fe)|0,o=o+Math.imul(v,le)|0;var Ae=(c+(n=n+Math.imul(p,pe)|0)|0)+((8191&(i=(i=i+Math.imul(p,me)|0)+Math.imul(m,pe)|0))<<13)|0;c=((o=o+Math.imul(m,me)|0)+(i>>>13)|0)+(Ae>>>26)|0,Ae&=67108863,n=Math.imul(U,W),i=(i=Math.imul(U,Y))+Math.imul(L,W)|0,o=Math.imul(L,Y),n=n+Math.imul(C,J)|0,i=(i=i+Math.imul(C,X)|0)+Math.imul(j,J)|0,o=o+Math.imul(j,X)|0,n=n+Math.imul(R,Q)|0,i=(i=i+Math.imul(R,ee)|0)+Math.imul(B,Q)|0,o=o+Math.imul(B,ee)|0,n=n+Math.imul(P,re)|0,i=(i=i+Math.imul(P,ne)|0)+Math.imul(O,re)|0,o=o+Math.imul(O,ne)|0,n=n+Math.imul(A,oe)|0,i=(i=i+Math.imul(A,ae)|0)+Math.imul(x,oe)|0,o=o+Math.imul(x,ae)|0,n=n+Math.imul(M,ue)|0,i=(i=i+Math.imul(M,ce)|0)+Math.imul(k,ue)|0,o=o+Math.imul(k,ce)|0,n=n+Math.imul(w,fe)|0,i=(i=i+Math.imul(w,le)|0)+Math.imul(_,fe)|0,o=o+Math.imul(_,le)|0;var xe=(c+(n=n+Math.imul(b,pe)|0)|0)+((8191&(i=(i=i+Math.imul(b,me)|0)+Math.imul(v,pe)|0))<<13)|0;c=((o=o+Math.imul(v,me)|0)+(i>>>13)|0)+(xe>>>26)|0,xe&=67108863,n=Math.imul(U,J),i=(i=Math.imul(U,X))+Math.imul(L,J)|0,o=Math.imul(L,X),n=n+Math.imul(C,Q)|0,i=(i=i+Math.imul(C,ee)|0)+Math.imul(j,Q)|0,o=o+Math.imul(j,ee)|0,n=n+Math.imul(R,re)|0,i=(i=i+Math.imul(R,ne)|0)+Math.imul(B,re)|0,o=o+Math.imul(B,ne)|0,n=n+Math.imul(P,oe)|0,i=(i=i+Math.imul(P,ae)|0)+Math.imul(O,oe)|0,o=o+Math.imul(O,ae)|0,n=n+Math.imul(A,ue)|0,i=(i=i+Math.imul(A,ce)|0)+Math.imul(x,ue)|0,o=o+Math.imul(x,ce)|0,n=n+Math.imul(M,fe)|0,i=(i=i+Math.imul(M,le)|0)+Math.imul(k,fe)|0,o=o+Math.imul(k,le)|0;var Ie=(c+(n=n+Math.imul(w,pe)|0)|0)+((8191&(i=(i=i+Math.imul(w,me)|0)+Math.imul(_,pe)|0))<<13)|0;c=((o=o+Math.imul(_,me)|0)+(i>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,n=Math.imul(U,Q),i=(i=Math.imul(U,ee))+Math.imul(L,Q)|0,o=Math.imul(L,ee),n=n+Math.imul(C,re)|0,i=(i=i+Math.imul(C,ne)|0)+Math.imul(j,re)|0,o=o+Math.imul(j,ne)|0,n=n+Math.imul(R,oe)|0,i=(i=i+Math.imul(R,ae)|0)+Math.imul(B,oe)|0,o=o+Math.imul(B,ae)|0,n=n+Math.imul(P,ue)|0,i=(i=i+Math.imul(P,ce)|0)+Math.imul(O,ue)|0,o=o+Math.imul(O,ce)|0,n=n+Math.imul(A,fe)|0,i=(i=i+Math.imul(A,le)|0)+Math.imul(x,fe)|0,o=o+Math.imul(x,le)|0;var Pe=(c+(n=n+Math.imul(M,pe)|0)|0)+((8191&(i=(i=i+Math.imul(M,me)|0)+Math.imul(k,pe)|0))<<13)|0;c=((o=o+Math.imul(k,me)|0)+(i>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,n=Math.imul(U,re),i=(i=Math.imul(U,ne))+Math.imul(L,re)|0,o=Math.imul(L,ne),n=n+Math.imul(C,oe)|0,i=(i=i+Math.imul(C,ae)|0)+Math.imul(j,oe)|0,o=o+Math.imul(j,ae)|0,n=n+Math.imul(R,ue)|0,i=(i=i+Math.imul(R,ce)|0)+Math.imul(B,ue)|0,o=o+Math.imul(B,ce)|0,n=n+Math.imul(P,fe)|0,i=(i=i+Math.imul(P,le)|0)+Math.imul(O,fe)|0,o=o+Math.imul(O,le)|0;var Oe=(c+(n=n+Math.imul(A,pe)|0)|0)+((8191&(i=(i=i+Math.imul(A,me)|0)+Math.imul(x,pe)|0))<<13)|0;c=((o=o+Math.imul(x,me)|0)+(i>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,n=Math.imul(U,oe),i=(i=Math.imul(U,ae))+Math.imul(L,oe)|0,o=Math.imul(L,ae),n=n+Math.imul(C,ue)|0,i=(i=i+Math.imul(C,ce)|0)+Math.imul(j,ue)|0,o=o+Math.imul(j,ce)|0,n=n+Math.imul(R,fe)|0,i=(i=i+Math.imul(R,le)|0)+Math.imul(B,fe)|0,o=o+Math.imul(B,le)|0;var Te=(c+(n=n+Math.imul(P,pe)|0)|0)+((8191&(i=(i=i+Math.imul(P,me)|0)+Math.imul(O,pe)|0))<<13)|0;c=((o=o+Math.imul(O,me)|0)+(i>>>13)|0)+(Te>>>26)|0,Te&=67108863,n=Math.imul(U,ue),i=(i=Math.imul(U,ce))+Math.imul(L,ue)|0,o=Math.imul(L,ce),n=n+Math.imul(C,fe)|0,i=(i=i+Math.imul(C,le)|0)+Math.imul(j,fe)|0,o=o+Math.imul(j,le)|0;var Re=(c+(n=n+Math.imul(R,pe)|0)|0)+((8191&(i=(i=i+Math.imul(R,me)|0)+Math.imul(B,pe)|0))<<13)|0;c=((o=o+Math.imul(B,me)|0)+(i>>>13)|0)+(Re>>>26)|0,Re&=67108863,n=Math.imul(U,fe),i=(i=Math.imul(U,le))+Math.imul(L,fe)|0,o=Math.imul(L,le);var Be=(c+(n=n+Math.imul(C,pe)|0)|0)+((8191&(i=(i=i+Math.imul(C,me)|0)+Math.imul(j,pe)|0))<<13)|0;c=((o=o+Math.imul(j,me)|0)+(i>>>13)|0)+(Be>>>26)|0,Be&=67108863;var Ne=(c+(n=Math.imul(U,pe))|0)+((8191&(i=(i=Math.imul(U,me))+Math.imul(L,pe)|0))<<13)|0;return c=((o=Math.imul(L,me))+(i>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,u[0]=ge,u[1]=be,u[2]=ve,u[3]=ye,u[4]=we,u[5]=_e,u[6]=Se,u[7]=Me,u[8]=ke,u[9]=Ee,u[10]=Ae,u[11]=xe,u[12]=Ie,u[13]=Pe,u[14]=Oe,u[15]=Te,u[16]=Re,u[17]=Be,u[18]=Ne,0!==c&&(u[19]=c,r.length++),r};function g(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var n=0,i=0,o=0;o>>26)|0)>>>26,a&=67108863}r.words[o]=s,n=a,a=i}return 0!==n?r.words[o]=n:r.length--,r._strip()}function b(e,t,r){return g(e,t,r)}function v(e,t){this.x=e,this.y=t}Math.imul||(m=p),o.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?m(this,e,t):r<63?p(this,e,t):r<1024?g(this,e,t):b(this,e,t)},v.prototype.makeRBT=function(e){for(var t=new Array(e),r=o.prototype._countBits(e)-1,n=0;n>=1;return n},v.prototype.permute=function(e,t,r,n,i,o){for(var a=0;a>>=1)i++;return 1<>>=13,r[2*a+1]=8191&o,o>>>=13;for(a=2*t;a>=26,r+=o/67108864|0,r+=a>>>26,this.words[i]=67108863&a}return 0!==r&&(this.words[i]=r,this.length++),t?this.ineg():this},o.prototype.muln=function(e){return this.clone().imuln(e)},o.prototype.sqr=function(){return this.mul(this)},o.prototype.isqr=function(){return this.imul(this.clone())},o.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>i&1}return t}(e);if(0===t.length)return new o(1);for(var r=this,n=0;n=0);var t,r=e%26,i=(e-r)/26,o=67108863>>>26-r<<26-r;if(0!==r){var a=0;for(t=0;t>>26-r}a&&(this.words[t]=a,this.length++)}if(0!==i){for(t=this.length-1;t>=0;t--)this.words[t+i]=this.words[t];for(t=0;t=0),i=t?(t-t%26)/26:0;var o=e%26,a=Math.min((e-o)/26,this.length),s=67108863^67108863>>>o<a)for(this.length-=a,c=0;c=0&&(0!==h||c>=i);c--){var f=0|this.words[c];this.words[c]=h<<26-o|f>>>o,h=f&s}return u&&0!==h&&(u.words[u.length++]=h),0===this.length&&(this.words[0]=0,this.length=1),this._strip()},o.prototype.ishrn=function(e,t,r){return n(0===this.negative),this.iushrn(e,t,r)},o.prototype.shln=function(e){return this.clone().ishln(e)},o.prototype.ushln=function(e){return this.clone().iushln(e)},o.prototype.shrn=function(e){return this.clone().ishrn(e)},o.prototype.ushrn=function(e){return this.clone().iushrn(e)},o.prototype.testn=function(e){n("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,i=1<=0);var t=e%26,r=(e-t)/26;if(n(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var i=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},o.prototype.isubn=function(e){if(n("number"==typeof e),n(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(u/67108864|0),this.words[i+r]=67108863&o}for(;i>26,this.words[i+r]=67108863&o;if(0===s)return this._strip();for(n(-1===s),s=0,i=0;i>26,this.words[i]=67108863&o;return this.negative=1,this._strip()},o.prototype._wordDiv=function(e,t){var r=(this.length,e.length),n=this.clone(),i=e,a=0|i.words[i.length-1];0!==(r=26-this._countBits(a))&&(i=i.ushln(r),n.iushln(r),a=0|i.words[i.length-1]);var s,u=n.length-i.length;if("mod"!==t){(s=new o(null)).length=u+1,s.words=new Array(s.length);for(var c=0;c=0;f--){var l=67108864*(0|n.words[i.length+f])+(0|n.words[i.length+f-1]);for(l=Math.min(l/a|0,67108863),n._ishlnsubmul(i,l,f);0!==n.negative;)l--,n.negative=0,n._ishlnsubmul(i,1,f),n.isZero()||(n.negative^=1);s&&(s.words[f]=l)}return s&&s._strip(),n._strip(),"div"!==t&&0!==r&&n.iushrn(r),{div:s||null,mod:n}},o.prototype.divmod=function(e,t,r){return n(!e.isZero()),this.isZero()?{div:new o(0),mod:new o(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(i=s.div.neg()),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.iadd(e)),{div:i,mod:a}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(i=s.div.neg()),{div:i,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.isub(e)),{div:s.div,mod:a}):e.length>this.length||this.cmp(e)<0?{div:new o(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new o(this.modrn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new o(this.modrn(e.words[0]))}:this._wordDiv(e,t);var i,a,s},o.prototype.div=function(e){return this.divmod(e,"div",!1).div},o.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},o.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},o.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,n=e.ushrn(1),i=e.andln(1),o=r.cmp(n);return o<0||1===i&&0===o?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},o.prototype.modrn=function(e){var t=e<0;t&&(e=-e),n(e<=67108863);for(var r=(1<<26)%e,i=0,o=this.length-1;o>=0;o--)i=(r*i+(0|this.words[o]))%e;return t?-i:i},o.prototype.modn=function(e){return this.modrn(e)},o.prototype.idivn=function(e){var t=e<0;t&&(e=-e),n(e<=67108863);for(var r=0,i=this.length-1;i>=0;i--){var o=(0|this.words[i])+67108864*r;this.words[i]=o/e|0,r=o%e}return this._strip(),t?this.ineg():this},o.prototype.divn=function(e){return this.clone().idivn(e)},o.prototype.egcd=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i=new o(1),a=new o(0),s=new o(0),u=new o(1),c=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++c;for(var h=r.clone(),f=t.clone();!t.isZero();){for(var l=0,d=1;0==(t.words[0]&d)&&l<26;++l,d<<=1);if(l>0)for(t.iushrn(l);l-- >0;)(i.isOdd()||a.isOdd())&&(i.iadd(h),a.isub(f)),i.iushrn(1),a.iushrn(1);for(var p=0,m=1;0==(r.words[0]&m)&&p<26;++p,m<<=1);if(p>0)for(r.iushrn(p);p-- >0;)(s.isOdd()||u.isOdd())&&(s.iadd(h),u.isub(f)),s.iushrn(1),u.iushrn(1);t.cmp(r)>=0?(t.isub(r),i.isub(s),a.isub(u)):(r.isub(t),s.isub(i),u.isub(a))}return{a:s,b:u,gcd:r.iushln(c)}},o.prototype._invmp=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i,a=new o(1),s=new o(0),u=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var c=0,h=1;0==(t.words[0]&h)&&c<26;++c,h<<=1);if(c>0)for(t.iushrn(c);c-- >0;)a.isOdd()&&a.iadd(u),a.iushrn(1);for(var f=0,l=1;0==(r.words[0]&l)&&f<26;++f,l<<=1);if(f>0)for(r.iushrn(f);f-- >0;)s.isOdd()&&s.iadd(u),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),a.isub(s)):(r.isub(t),s.isub(a))}return(i=0===t.cmpn(1)?a:s).cmpn(0)<0&&i.iadd(e),i},o.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var n=0;t.isEven()&&r.isEven();n++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var i=t.cmp(r);if(i<0){var o=t;t=r,r=o}else if(0===i||0===r.cmpn(1))break;t.isub(r)}return r.iushln(n)},o.prototype.invm=function(e){return this.egcd(e).a.umod(e)},o.prototype.isEven=function(){return 0==(1&this.words[0])},o.prototype.isOdd=function(){return 1==(1&this.words[0])},o.prototype.andln=function(e){return this.words[0]&e},o.prototype.bincn=function(e){n("number"==typeof e);var t=e%26,r=(e-t)/26,i=1<>>26,s&=67108863,this.words[a]=s}return 0!==o&&(this.words[a]=o,this.length++),this},o.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},o.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this._strip(),this.length>1)t=1;else{r&&(e=-e),n(e<=67108863,"Number is too big");var i=0|this.words[0];t=i===e?0:ie.length)return 1;if(this.length=0;r--){var n=0|this.words[r],i=0|e.words[r];if(n!==i){ni&&(t=1);break}}return t},o.prototype.gtn=function(e){return 1===this.cmpn(e)},o.prototype.gt=function(e){return 1===this.cmp(e)},o.prototype.gten=function(e){return this.cmpn(e)>=0},o.prototype.gte=function(e){return this.cmp(e)>=0},o.prototype.ltn=function(e){return-1===this.cmpn(e)},o.prototype.lt=function(e){return-1===this.cmp(e)},o.prototype.lten=function(e){return this.cmpn(e)<=0},o.prototype.lte=function(e){return this.cmp(e)<=0},o.prototype.eqn=function(e){return 0===this.cmpn(e)},o.prototype.eq=function(e){return 0===this.cmp(e)},o.red=function(e){return new E(e)},o.prototype.toRed=function(e){return n(!this.red,"Already a number in reduction context"),n(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},o.prototype.fromRed=function(){return n(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},o.prototype._forceRed=function(e){return this.red=e,this},o.prototype.forceRed=function(e){return n(!this.red,"Already a number in reduction context"),this._forceRed(e)},o.prototype.redAdd=function(e){return n(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},o.prototype.redIAdd=function(e){return n(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},o.prototype.redSub=function(e){return n(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},o.prototype.redISub=function(e){return n(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},o.prototype.redShl=function(e){return n(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},o.prototype.redMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},o.prototype.redIMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},o.prototype.redSqr=function(){return n(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},o.prototype.redISqr=function(){return n(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},o.prototype.redSqrt=function(){return n(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},o.prototype.redInvm=function(){return n(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},o.prototype.redNeg=function(){return n(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},o.prototype.redPow=function(e){return n(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var y={k256:null,p224:null,p192:null,p25519:null};function w(e,t){this.name=e,this.p=new o(t,16),this.n=this.p.bitLength(),this.k=new o(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function _(){w.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function S(){w.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function M(){w.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function k(){w.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function E(e){if("string"==typeof e){var t=o._prime(e);this.m=t.p,this.prime=t}else n(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function A(e){E.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new o(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}w.prototype._tmp=function(){var e=new o(null);return e.words=new Array(Math.ceil(this.n/13)),e},w.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var n=t0?r.isub(this.p):void 0!==r.strip?r.strip():r._strip(),r},w.prototype.split=function(e,t){e.iushrn(this.n,0,t)},w.prototype.imulK=function(e){return e.imul(this.k)},i(_,w),_.prototype.split=function(e,t){for(var r=Math.min(e.length,9),n=0;n>>22,i=o}i>>>=22,e.words[n-10]=i,0===i&&e.length>10?e.length-=10:e.length-=9},_.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=i,t=n}return 0!==t&&(e.words[e.length++]=t),e},o._prime=function(e){if(y[e])return y[e];var t;if("k256"===e)t=new _;else if("p224"===e)t=new S;else if("p192"===e)t=new M;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new k}return y[e]=t,t},E.prototype._verify1=function(e){n(0===e.negative,"red works only with positives"),n(e.red,"red works only with red numbers")},E.prototype._verify2=function(e,t){n(0==(e.negative|t.negative),"red works only with positives"),n(e.red&&e.red===t.red,"red works only with red numbers")},E.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):(c(e,e.umod(this.m)._forceRed(this)),e)},E.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},E.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},E.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},E.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},E.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},E.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},E.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},E.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},E.prototype.isqr=function(e){return this.imul(e,e.clone())},E.prototype.sqr=function(e){return this.mul(e,e)},E.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(n(t%2==1),3===t){var r=this.m.add(new o(1)).iushrn(2);return this.pow(e,r)}for(var i=this.m.subn(1),a=0;!i.isZero()&&0===i.andln(1);)a++,i.iushrn(1);n(!i.isZero());var s=new o(1).toRed(this),u=s.redNeg(),c=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new o(2*h*h).toRed(this);0!==this.pow(h,c).cmp(u);)h.redIAdd(u);for(var f=this.pow(h,i),l=this.pow(e,i.addn(1).iushrn(1)),d=this.pow(e,i),p=a;0!==d.cmp(s);){for(var m=d,g=0;0!==m.cmp(s);g++)m=m.redSqr();n(g=0;n--){for(var c=t.words[n],h=u-1;h>=0;h--){var f=c>>h&1;i!==r[0]&&(i=this.sqr(i)),0!==f||0!==a?(a<<=1,a|=f,(4===++s||0===n&&0===h)&&(i=this.mul(i,r[a]),s=0,a=0)):s=0}u=26}return i},E.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},E.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},o.mont=function(e){return new A(e)},i(A,E),A.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},A.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},A.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),o=i;return i.cmp(this.m)>=0?o=i.isub(this.m):i.cmpn(0)<0&&(o=i.iadd(this.m)),o._forceRed(this)},A.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new o(0)._forceRed(this);var r=e.mul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),a=i;return i.cmp(this.m)>=0?a=i.isub(this.m):i.cmpn(0)<0&&(a=i.iadd(this.m)),a._forceRed(this)},A.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(28)(e))},function(e,t,r){const n=r(2).Buffer;e.exports=class{constructor(e=n.from([])){this.buffer=e,this._bytesRead=0,this._bytesWrote=0}read(e){this._bytesRead+=e;const t=this.buffer.slice(0,e);return this.buffer=this.buffer.slice(e),t}write(e){e=n.from(e),this._bytesWrote+=e.length,this.buffer=n.concat([this.buffer,e])}get end(){return!this.buffer.length}get bytesRead(){return this._bytesRead}get bytesWrote(){return this._bytesWrote}}},function(e,t){e.exports={ProtocolIndicator:{ID:0,SECP256K1:1,ACTOR:2,BLS:3}}},function(e,t,r){"use strict";(function(e){var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},i=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=49&&a<=54?a-49+10:a>=17&&a<=22?a-17+10:15&a}return n}function u(e,t,r,n){for(var i=0,o=Math.min(e.length,r),a=t;a=49?s-49+10:s>=17?s-17+10:s}return i}o.isBN=function(e){return e instanceof o||null!==e&&"object"==typeof e&&e.constructor.wordSize===o.wordSize&&Array.isArray(e.words)},o.max=function(e,t){return e.cmp(t)>0?e:t},o.min=function(e,t){return e.cmp(t)<0?e:t},o.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),n(t===(0|t)&&t>=2&&t<=36);var i=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&i++,16===t?this._parseHex(e,i):this._parseBase(e,t,i),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(n(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initArray=function(e,t,r){if(n("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var i=0;i=0;i-=3)a=e[i]|e[i-1]<<8|e[i-2]<<16,this.words[o]|=a<>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);else if("le"===r)for(i=0,o=0;i>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);return this.strip()},o.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)i=s(e,r,r+6),this.words[n]|=i<>>26-o&4194303,(o+=24)>=26&&(o-=26,n++);r+6!==t&&(i=s(e,t,r+6),this.words[n]|=i<>>26-o&4194303),this.strip()},o.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var n=0,i=1;i<=67108863;i*=t)n++;n--,i=i/t|0;for(var o=e.length-r,a=o%n,s=Math.min(o,o-a)+r,c=0,h=r;h1&&0===this.words[this.length-1];)this.length--;return this._normSign()},o.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},o.prototype.inspect=function(){return(this.red?""};var c=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],h=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],f=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function l(e,t,r){r.negative=t.negative^e.negative;var n=e.length+t.length|0;r.length=n,n=n-1|0;var i=0|e.words[0],o=0|t.words[0],a=i*o,s=67108863&a,u=a/67108864|0;r.words[0]=s;for(var c=1;c>>26,f=67108863&u,l=Math.min(c,t.length-1),d=Math.max(0,c-e.length+1);d<=l;d++){var p=c-d|0;h+=(a=(i=0|e.words[p])*(o=0|t.words[d])+f)/67108864|0,f=67108863&a}r.words[c]=0|f,u=0|h}return 0!==u?r.words[c]=0|u:r.length--,r.strip()}o.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var i=0,o=0,a=0;a>>24-i&16777215)||a!==this.length-1?c[6-u.length]+u+r:u+r,(i+=2)>=26&&(i-=26,a--)}for(0!==o&&(r=o.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var l=h[e],d=f[e];r="";var p=this.clone();for(p.negative=0;!p.isZero();){var m=p.modn(d).toString(e);r=(p=p.idivn(d)).isZero()?m+r:c[l-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}n(!1,"Base should be between 2 and 36")},o.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&n(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},o.prototype.toJSON=function(){return this.toString(16)},o.prototype.toBuffer=function(e,t){return n(void 0!==a),this.toArrayLike(a,e,t)},o.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},o.prototype.toArrayLike=function(e,t,r){var i=this.byteLength(),o=r||Math.max(1,i);n(i<=o,"byte array longer than desired length"),n(o>0,"Requested array length <= 0"),this.strip();var a,s,u="le"===t,c=new e(o),h=this.clone();if(u){for(s=0;!h.isZero();s++)a=h.andln(255),h.iushrn(8),c[s]=a;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},o.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},o.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},o.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},o.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},o.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},o.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},o.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var n=0;ne.length?this.clone().ixor(e):e.clone().ixor(this)},o.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},o.prototype.inotn=function(e){n("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var i=0;i0&&(this.words[i]=~this.words[i]&67108863>>26-r),this.strip()},o.prototype.notn=function(e){return this.clone().inotn(e)},o.prototype.setn=function(e,t){n("number"==typeof e&&e>=0);var r=e/26|0,i=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,n=e):(r=e,n=this);for(var i=0,o=0;o>>26;for(;0!==i&&o>>26;if(this.length=r.length,0!==i)this.words[this.length]=i,this.length++;else if(r!==this)for(;oe.length?this.clone().iadd(e):e.clone().iadd(this)},o.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,n,i=this.cmp(e);if(0===i)return this.negative=0,this.length=1,this.words[0]=0,this;i>0?(r=this,n=e):(r=e,n=this);for(var o=0,a=0;a>26,this.words[a]=67108863&t;for(;0!==o&&a>26,this.words[a]=67108863&t;if(0===o&&a>>13,d=0|a[1],p=8191&d,m=d>>>13,g=0|a[2],b=8191&g,v=g>>>13,y=0|a[3],w=8191&y,_=y>>>13,S=0|a[4],M=8191&S,k=S>>>13,E=0|a[5],A=8191&E,x=E>>>13,I=0|a[6],P=8191&I,O=I>>>13,T=0|a[7],R=8191&T,B=T>>>13,N=0|a[8],C=8191&N,j=N>>>13,z=0|a[9],U=8191&z,L=z>>>13,F=0|s[0],D=8191&F,q=F>>>13,K=0|s[1],H=8191&K,V=K>>>13,G=0|s[2],W=8191&G,Y=G>>>13,Z=0|s[3],J=8191&Z,X=Z>>>13,$=0|s[4],Q=8191&$,ee=$>>>13,te=0|s[5],re=8191&te,ne=te>>>13,ie=0|s[6],oe=8191&ie,ae=ie>>>13,se=0|s[7],ue=8191&se,ce=se>>>13,he=0|s[8],fe=8191&he,le=he>>>13,de=0|s[9],pe=8191&de,me=de>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(c+(n=Math.imul(f,D))|0)+((8191&(i=(i=Math.imul(f,q))+Math.imul(l,D)|0))<<13)|0;c=((o=Math.imul(l,q))+(i>>>13)|0)+(ge>>>26)|0,ge&=67108863,n=Math.imul(p,D),i=(i=Math.imul(p,q))+Math.imul(m,D)|0,o=Math.imul(m,q);var be=(c+(n=n+Math.imul(f,H)|0)|0)+((8191&(i=(i=i+Math.imul(f,V)|0)+Math.imul(l,H)|0))<<13)|0;c=((o=o+Math.imul(l,V)|0)+(i>>>13)|0)+(be>>>26)|0,be&=67108863,n=Math.imul(b,D),i=(i=Math.imul(b,q))+Math.imul(v,D)|0,o=Math.imul(v,q),n=n+Math.imul(p,H)|0,i=(i=i+Math.imul(p,V)|0)+Math.imul(m,H)|0,o=o+Math.imul(m,V)|0;var ve=(c+(n=n+Math.imul(f,W)|0)|0)+((8191&(i=(i=i+Math.imul(f,Y)|0)+Math.imul(l,W)|0))<<13)|0;c=((o=o+Math.imul(l,Y)|0)+(i>>>13)|0)+(ve>>>26)|0,ve&=67108863,n=Math.imul(w,D),i=(i=Math.imul(w,q))+Math.imul(_,D)|0,o=Math.imul(_,q),n=n+Math.imul(b,H)|0,i=(i=i+Math.imul(b,V)|0)+Math.imul(v,H)|0,o=o+Math.imul(v,V)|0,n=n+Math.imul(p,W)|0,i=(i=i+Math.imul(p,Y)|0)+Math.imul(m,W)|0,o=o+Math.imul(m,Y)|0;var ye=(c+(n=n+Math.imul(f,J)|0)|0)+((8191&(i=(i=i+Math.imul(f,X)|0)+Math.imul(l,J)|0))<<13)|0;c=((o=o+Math.imul(l,X)|0)+(i>>>13)|0)+(ye>>>26)|0,ye&=67108863,n=Math.imul(M,D),i=(i=Math.imul(M,q))+Math.imul(k,D)|0,o=Math.imul(k,q),n=n+Math.imul(w,H)|0,i=(i=i+Math.imul(w,V)|0)+Math.imul(_,H)|0,o=o+Math.imul(_,V)|0,n=n+Math.imul(b,W)|0,i=(i=i+Math.imul(b,Y)|0)+Math.imul(v,W)|0,o=o+Math.imul(v,Y)|0,n=n+Math.imul(p,J)|0,i=(i=i+Math.imul(p,X)|0)+Math.imul(m,J)|0,o=o+Math.imul(m,X)|0;var we=(c+(n=n+Math.imul(f,Q)|0)|0)+((8191&(i=(i=i+Math.imul(f,ee)|0)+Math.imul(l,Q)|0))<<13)|0;c=((o=o+Math.imul(l,ee)|0)+(i>>>13)|0)+(we>>>26)|0,we&=67108863,n=Math.imul(A,D),i=(i=Math.imul(A,q))+Math.imul(x,D)|0,o=Math.imul(x,q),n=n+Math.imul(M,H)|0,i=(i=i+Math.imul(M,V)|0)+Math.imul(k,H)|0,o=o+Math.imul(k,V)|0,n=n+Math.imul(w,W)|0,i=(i=i+Math.imul(w,Y)|0)+Math.imul(_,W)|0,o=o+Math.imul(_,Y)|0,n=n+Math.imul(b,J)|0,i=(i=i+Math.imul(b,X)|0)+Math.imul(v,J)|0,o=o+Math.imul(v,X)|0,n=n+Math.imul(p,Q)|0,i=(i=i+Math.imul(p,ee)|0)+Math.imul(m,Q)|0,o=o+Math.imul(m,ee)|0;var _e=(c+(n=n+Math.imul(f,re)|0)|0)+((8191&(i=(i=i+Math.imul(f,ne)|0)+Math.imul(l,re)|0))<<13)|0;c=((o=o+Math.imul(l,ne)|0)+(i>>>13)|0)+(_e>>>26)|0,_e&=67108863,n=Math.imul(P,D),i=(i=Math.imul(P,q))+Math.imul(O,D)|0,o=Math.imul(O,q),n=n+Math.imul(A,H)|0,i=(i=i+Math.imul(A,V)|0)+Math.imul(x,H)|0,o=o+Math.imul(x,V)|0,n=n+Math.imul(M,W)|0,i=(i=i+Math.imul(M,Y)|0)+Math.imul(k,W)|0,o=o+Math.imul(k,Y)|0,n=n+Math.imul(w,J)|0,i=(i=i+Math.imul(w,X)|0)+Math.imul(_,J)|0,o=o+Math.imul(_,X)|0,n=n+Math.imul(b,Q)|0,i=(i=i+Math.imul(b,ee)|0)+Math.imul(v,Q)|0,o=o+Math.imul(v,ee)|0,n=n+Math.imul(p,re)|0,i=(i=i+Math.imul(p,ne)|0)+Math.imul(m,re)|0,o=o+Math.imul(m,ne)|0;var Se=(c+(n=n+Math.imul(f,oe)|0)|0)+((8191&(i=(i=i+Math.imul(f,ae)|0)+Math.imul(l,oe)|0))<<13)|0;c=((o=o+Math.imul(l,ae)|0)+(i>>>13)|0)+(Se>>>26)|0,Se&=67108863,n=Math.imul(R,D),i=(i=Math.imul(R,q))+Math.imul(B,D)|0,o=Math.imul(B,q),n=n+Math.imul(P,H)|0,i=(i=i+Math.imul(P,V)|0)+Math.imul(O,H)|0,o=o+Math.imul(O,V)|0,n=n+Math.imul(A,W)|0,i=(i=i+Math.imul(A,Y)|0)+Math.imul(x,W)|0,o=o+Math.imul(x,Y)|0,n=n+Math.imul(M,J)|0,i=(i=i+Math.imul(M,X)|0)+Math.imul(k,J)|0,o=o+Math.imul(k,X)|0,n=n+Math.imul(w,Q)|0,i=(i=i+Math.imul(w,ee)|0)+Math.imul(_,Q)|0,o=o+Math.imul(_,ee)|0,n=n+Math.imul(b,re)|0,i=(i=i+Math.imul(b,ne)|0)+Math.imul(v,re)|0,o=o+Math.imul(v,ne)|0,n=n+Math.imul(p,oe)|0,i=(i=i+Math.imul(p,ae)|0)+Math.imul(m,oe)|0,o=o+Math.imul(m,ae)|0;var Me=(c+(n=n+Math.imul(f,ue)|0)|0)+((8191&(i=(i=i+Math.imul(f,ce)|0)+Math.imul(l,ue)|0))<<13)|0;c=((o=o+Math.imul(l,ce)|0)+(i>>>13)|0)+(Me>>>26)|0,Me&=67108863,n=Math.imul(C,D),i=(i=Math.imul(C,q))+Math.imul(j,D)|0,o=Math.imul(j,q),n=n+Math.imul(R,H)|0,i=(i=i+Math.imul(R,V)|0)+Math.imul(B,H)|0,o=o+Math.imul(B,V)|0,n=n+Math.imul(P,W)|0,i=(i=i+Math.imul(P,Y)|0)+Math.imul(O,W)|0,o=o+Math.imul(O,Y)|0,n=n+Math.imul(A,J)|0,i=(i=i+Math.imul(A,X)|0)+Math.imul(x,J)|0,o=o+Math.imul(x,X)|0,n=n+Math.imul(M,Q)|0,i=(i=i+Math.imul(M,ee)|0)+Math.imul(k,Q)|0,o=o+Math.imul(k,ee)|0,n=n+Math.imul(w,re)|0,i=(i=i+Math.imul(w,ne)|0)+Math.imul(_,re)|0,o=o+Math.imul(_,ne)|0,n=n+Math.imul(b,oe)|0,i=(i=i+Math.imul(b,ae)|0)+Math.imul(v,oe)|0,o=o+Math.imul(v,ae)|0,n=n+Math.imul(p,ue)|0,i=(i=i+Math.imul(p,ce)|0)+Math.imul(m,ue)|0,o=o+Math.imul(m,ce)|0;var ke=(c+(n=n+Math.imul(f,fe)|0)|0)+((8191&(i=(i=i+Math.imul(f,le)|0)+Math.imul(l,fe)|0))<<13)|0;c=((o=o+Math.imul(l,le)|0)+(i>>>13)|0)+(ke>>>26)|0,ke&=67108863,n=Math.imul(U,D),i=(i=Math.imul(U,q))+Math.imul(L,D)|0,o=Math.imul(L,q),n=n+Math.imul(C,H)|0,i=(i=i+Math.imul(C,V)|0)+Math.imul(j,H)|0,o=o+Math.imul(j,V)|0,n=n+Math.imul(R,W)|0,i=(i=i+Math.imul(R,Y)|0)+Math.imul(B,W)|0,o=o+Math.imul(B,Y)|0,n=n+Math.imul(P,J)|0,i=(i=i+Math.imul(P,X)|0)+Math.imul(O,J)|0,o=o+Math.imul(O,X)|0,n=n+Math.imul(A,Q)|0,i=(i=i+Math.imul(A,ee)|0)+Math.imul(x,Q)|0,o=o+Math.imul(x,ee)|0,n=n+Math.imul(M,re)|0,i=(i=i+Math.imul(M,ne)|0)+Math.imul(k,re)|0,o=o+Math.imul(k,ne)|0,n=n+Math.imul(w,oe)|0,i=(i=i+Math.imul(w,ae)|0)+Math.imul(_,oe)|0,o=o+Math.imul(_,ae)|0,n=n+Math.imul(b,ue)|0,i=(i=i+Math.imul(b,ce)|0)+Math.imul(v,ue)|0,o=o+Math.imul(v,ce)|0,n=n+Math.imul(p,fe)|0,i=(i=i+Math.imul(p,le)|0)+Math.imul(m,fe)|0,o=o+Math.imul(m,le)|0;var Ee=(c+(n=n+Math.imul(f,pe)|0)|0)+((8191&(i=(i=i+Math.imul(f,me)|0)+Math.imul(l,pe)|0))<<13)|0;c=((o=o+Math.imul(l,me)|0)+(i>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,n=Math.imul(U,H),i=(i=Math.imul(U,V))+Math.imul(L,H)|0,o=Math.imul(L,V),n=n+Math.imul(C,W)|0,i=(i=i+Math.imul(C,Y)|0)+Math.imul(j,W)|0,o=o+Math.imul(j,Y)|0,n=n+Math.imul(R,J)|0,i=(i=i+Math.imul(R,X)|0)+Math.imul(B,J)|0,o=o+Math.imul(B,X)|0,n=n+Math.imul(P,Q)|0,i=(i=i+Math.imul(P,ee)|0)+Math.imul(O,Q)|0,o=o+Math.imul(O,ee)|0,n=n+Math.imul(A,re)|0,i=(i=i+Math.imul(A,ne)|0)+Math.imul(x,re)|0,o=o+Math.imul(x,ne)|0,n=n+Math.imul(M,oe)|0,i=(i=i+Math.imul(M,ae)|0)+Math.imul(k,oe)|0,o=o+Math.imul(k,ae)|0,n=n+Math.imul(w,ue)|0,i=(i=i+Math.imul(w,ce)|0)+Math.imul(_,ue)|0,o=o+Math.imul(_,ce)|0,n=n+Math.imul(b,fe)|0,i=(i=i+Math.imul(b,le)|0)+Math.imul(v,fe)|0,o=o+Math.imul(v,le)|0;var Ae=(c+(n=n+Math.imul(p,pe)|0)|0)+((8191&(i=(i=i+Math.imul(p,me)|0)+Math.imul(m,pe)|0))<<13)|0;c=((o=o+Math.imul(m,me)|0)+(i>>>13)|0)+(Ae>>>26)|0,Ae&=67108863,n=Math.imul(U,W),i=(i=Math.imul(U,Y))+Math.imul(L,W)|0,o=Math.imul(L,Y),n=n+Math.imul(C,J)|0,i=(i=i+Math.imul(C,X)|0)+Math.imul(j,J)|0,o=o+Math.imul(j,X)|0,n=n+Math.imul(R,Q)|0,i=(i=i+Math.imul(R,ee)|0)+Math.imul(B,Q)|0,o=o+Math.imul(B,ee)|0,n=n+Math.imul(P,re)|0,i=(i=i+Math.imul(P,ne)|0)+Math.imul(O,re)|0,o=o+Math.imul(O,ne)|0,n=n+Math.imul(A,oe)|0,i=(i=i+Math.imul(A,ae)|0)+Math.imul(x,oe)|0,o=o+Math.imul(x,ae)|0,n=n+Math.imul(M,ue)|0,i=(i=i+Math.imul(M,ce)|0)+Math.imul(k,ue)|0,o=o+Math.imul(k,ce)|0,n=n+Math.imul(w,fe)|0,i=(i=i+Math.imul(w,le)|0)+Math.imul(_,fe)|0,o=o+Math.imul(_,le)|0;var xe=(c+(n=n+Math.imul(b,pe)|0)|0)+((8191&(i=(i=i+Math.imul(b,me)|0)+Math.imul(v,pe)|0))<<13)|0;c=((o=o+Math.imul(v,me)|0)+(i>>>13)|0)+(xe>>>26)|0,xe&=67108863,n=Math.imul(U,J),i=(i=Math.imul(U,X))+Math.imul(L,J)|0,o=Math.imul(L,X),n=n+Math.imul(C,Q)|0,i=(i=i+Math.imul(C,ee)|0)+Math.imul(j,Q)|0,o=o+Math.imul(j,ee)|0,n=n+Math.imul(R,re)|0,i=(i=i+Math.imul(R,ne)|0)+Math.imul(B,re)|0,o=o+Math.imul(B,ne)|0,n=n+Math.imul(P,oe)|0,i=(i=i+Math.imul(P,ae)|0)+Math.imul(O,oe)|0,o=o+Math.imul(O,ae)|0,n=n+Math.imul(A,ue)|0,i=(i=i+Math.imul(A,ce)|0)+Math.imul(x,ue)|0,o=o+Math.imul(x,ce)|0,n=n+Math.imul(M,fe)|0,i=(i=i+Math.imul(M,le)|0)+Math.imul(k,fe)|0,o=o+Math.imul(k,le)|0;var Ie=(c+(n=n+Math.imul(w,pe)|0)|0)+((8191&(i=(i=i+Math.imul(w,me)|0)+Math.imul(_,pe)|0))<<13)|0;c=((o=o+Math.imul(_,me)|0)+(i>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,n=Math.imul(U,Q),i=(i=Math.imul(U,ee))+Math.imul(L,Q)|0,o=Math.imul(L,ee),n=n+Math.imul(C,re)|0,i=(i=i+Math.imul(C,ne)|0)+Math.imul(j,re)|0,o=o+Math.imul(j,ne)|0,n=n+Math.imul(R,oe)|0,i=(i=i+Math.imul(R,ae)|0)+Math.imul(B,oe)|0,o=o+Math.imul(B,ae)|0,n=n+Math.imul(P,ue)|0,i=(i=i+Math.imul(P,ce)|0)+Math.imul(O,ue)|0,o=o+Math.imul(O,ce)|0,n=n+Math.imul(A,fe)|0,i=(i=i+Math.imul(A,le)|0)+Math.imul(x,fe)|0,o=o+Math.imul(x,le)|0;var Pe=(c+(n=n+Math.imul(M,pe)|0)|0)+((8191&(i=(i=i+Math.imul(M,me)|0)+Math.imul(k,pe)|0))<<13)|0;c=((o=o+Math.imul(k,me)|0)+(i>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,n=Math.imul(U,re),i=(i=Math.imul(U,ne))+Math.imul(L,re)|0,o=Math.imul(L,ne),n=n+Math.imul(C,oe)|0,i=(i=i+Math.imul(C,ae)|0)+Math.imul(j,oe)|0,o=o+Math.imul(j,ae)|0,n=n+Math.imul(R,ue)|0,i=(i=i+Math.imul(R,ce)|0)+Math.imul(B,ue)|0,o=o+Math.imul(B,ce)|0,n=n+Math.imul(P,fe)|0,i=(i=i+Math.imul(P,le)|0)+Math.imul(O,fe)|0,o=o+Math.imul(O,le)|0;var Oe=(c+(n=n+Math.imul(A,pe)|0)|0)+((8191&(i=(i=i+Math.imul(A,me)|0)+Math.imul(x,pe)|0))<<13)|0;c=((o=o+Math.imul(x,me)|0)+(i>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,n=Math.imul(U,oe),i=(i=Math.imul(U,ae))+Math.imul(L,oe)|0,o=Math.imul(L,ae),n=n+Math.imul(C,ue)|0,i=(i=i+Math.imul(C,ce)|0)+Math.imul(j,ue)|0,o=o+Math.imul(j,ce)|0,n=n+Math.imul(R,fe)|0,i=(i=i+Math.imul(R,le)|0)+Math.imul(B,fe)|0,o=o+Math.imul(B,le)|0;var Te=(c+(n=n+Math.imul(P,pe)|0)|0)+((8191&(i=(i=i+Math.imul(P,me)|0)+Math.imul(O,pe)|0))<<13)|0;c=((o=o+Math.imul(O,me)|0)+(i>>>13)|0)+(Te>>>26)|0,Te&=67108863,n=Math.imul(U,ue),i=(i=Math.imul(U,ce))+Math.imul(L,ue)|0,o=Math.imul(L,ce),n=n+Math.imul(C,fe)|0,i=(i=i+Math.imul(C,le)|0)+Math.imul(j,fe)|0,o=o+Math.imul(j,le)|0;var Re=(c+(n=n+Math.imul(R,pe)|0)|0)+((8191&(i=(i=i+Math.imul(R,me)|0)+Math.imul(B,pe)|0))<<13)|0;c=((o=o+Math.imul(B,me)|0)+(i>>>13)|0)+(Re>>>26)|0,Re&=67108863,n=Math.imul(U,fe),i=(i=Math.imul(U,le))+Math.imul(L,fe)|0,o=Math.imul(L,le);var Be=(c+(n=n+Math.imul(C,pe)|0)|0)+((8191&(i=(i=i+Math.imul(C,me)|0)+Math.imul(j,pe)|0))<<13)|0;c=((o=o+Math.imul(j,me)|0)+(i>>>13)|0)+(Be>>>26)|0,Be&=67108863;var Ne=(c+(n=Math.imul(U,pe))|0)+((8191&(i=(i=Math.imul(U,me))+Math.imul(L,pe)|0))<<13)|0;return c=((o=Math.imul(L,me))+(i>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,u[0]=ge,u[1]=be,u[2]=ve,u[3]=ye,u[4]=we,u[5]=_e,u[6]=Se,u[7]=Me,u[8]=ke,u[9]=Ee,u[10]=Ae,u[11]=xe,u[12]=Ie,u[13]=Pe,u[14]=Oe,u[15]=Te,u[16]=Re,u[17]=Be,u[18]=Ne,0!==c&&(u[19]=c,r.length++),r};function p(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(d=l),o.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?d(this,e,t):r<63?l(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var n=0,i=0,o=0;o>>26)|0)>>>26,a&=67108863}r.words[o]=s,n=a,a=i}return 0!==n?r.words[o]=n:r.length--,r.strip()}(this,e,t):p(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=o.prototype._countBits(e)-1,n=0;n>=1;return n},m.prototype.permute=function(e,t,r,n,i,o){for(var a=0;a>>=1)i++;return 1<>>=13,r[2*a+1]=8191&o,o>>>=13;for(a=2*t;a>=26,t+=i/67108864|0,t+=o>>>26,this.words[r]=67108863&o}return 0!==t&&(this.words[r]=t,this.length++),this},o.prototype.muln=function(e){return this.clone().imuln(e)},o.prototype.sqr=function(){return this.mul(this)},o.prototype.isqr=function(){return this.imul(this.clone())},o.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>i}return t}(e);if(0===t.length)return new o(1);for(var r=this,n=0;n=0);var t,r=e%26,i=(e-r)/26,o=67108863>>>26-r<<26-r;if(0!==r){var a=0;for(t=0;t>>26-r}a&&(this.words[t]=a,this.length++)}if(0!==i){for(t=this.length-1;t>=0;t--)this.words[t+i]=this.words[t];for(t=0;t=0),i=t?(t-t%26)/26:0;var o=e%26,a=Math.min((e-o)/26,this.length),s=67108863^67108863>>>o<a)for(this.length-=a,c=0;c=0&&(0!==h||c>=i);c--){var f=0|this.words[c];this.words[c]=h<<26-o|f>>>o,h=f&s}return u&&0!==h&&(u.words[u.length++]=h),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},o.prototype.ishrn=function(e,t,r){return n(0===this.negative),this.iushrn(e,t,r)},o.prototype.shln=function(e){return this.clone().ishln(e)},o.prototype.ushln=function(e){return this.clone().iushln(e)},o.prototype.shrn=function(e){return this.clone().ishrn(e)},o.prototype.ushrn=function(e){return this.clone().iushrn(e)},o.prototype.testn=function(e){n("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,i=1<=0);var t=e%26,r=(e-t)/26;if(n(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var i=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},o.prototype.isubn=function(e){if(n("number"==typeof e),n(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(u/67108864|0),this.words[i+r]=67108863&o}for(;i>26,this.words[i+r]=67108863&o;if(0===s)return this.strip();for(n(-1===s),s=0,i=0;i>26,this.words[i]=67108863&o;return this.negative=1,this.strip()},o.prototype._wordDiv=function(e,t){var r=(this.length,e.length),n=this.clone(),i=e,a=0|i.words[i.length-1];0!==(r=26-this._countBits(a))&&(i=i.ushln(r),n.iushln(r),a=0|i.words[i.length-1]);var s,u=n.length-i.length;if("mod"!==t){(s=new o(null)).length=u+1,s.words=new Array(s.length);for(var c=0;c=0;f--){var l=67108864*(0|n.words[i.length+f])+(0|n.words[i.length+f-1]);for(l=Math.min(l/a|0,67108863),n._ishlnsubmul(i,l,f);0!==n.negative;)l--,n.negative=0,n._ishlnsubmul(i,1,f),n.isZero()||(n.negative^=1);s&&(s.words[f]=l)}return s&&s.strip(),n.strip(),"div"!==t&&0!==r&&n.iushrn(r),{div:s||null,mod:n}},o.prototype.divmod=function(e,t,r){return n(!e.isZero()),this.isZero()?{div:new o(0),mod:new o(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(i=s.div.neg()),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.iadd(e)),{div:i,mod:a}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(i=s.div.neg()),{div:i,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.isub(e)),{div:s.div,mod:a}):e.length>this.length||this.cmp(e)<0?{div:new o(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new o(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new o(this.modn(e.words[0]))}:this._wordDiv(e,t);var i,a,s},o.prototype.div=function(e){return this.divmod(e,"div",!1).div},o.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},o.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},o.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,n=e.ushrn(1),i=e.andln(1),o=r.cmp(n);return o<0||1===i&&0===o?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},o.prototype.modn=function(e){n(e<=67108863);for(var t=(1<<26)%e,r=0,i=this.length-1;i>=0;i--)r=(t*r+(0|this.words[i]))%e;return r},o.prototype.idivn=function(e){n(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var i=(0|this.words[r])+67108864*t;this.words[r]=i/e|0,t=i%e}return this.strip()},o.prototype.divn=function(e){return this.clone().idivn(e)},o.prototype.egcd=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i=new o(1),a=new o(0),s=new o(0),u=new o(1),c=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++c;for(var h=r.clone(),f=t.clone();!t.isZero();){for(var l=0,d=1;0==(t.words[0]&d)&&l<26;++l,d<<=1);if(l>0)for(t.iushrn(l);l-- >0;)(i.isOdd()||a.isOdd())&&(i.iadd(h),a.isub(f)),i.iushrn(1),a.iushrn(1);for(var p=0,m=1;0==(r.words[0]&m)&&p<26;++p,m<<=1);if(p>0)for(r.iushrn(p);p-- >0;)(s.isOdd()||u.isOdd())&&(s.iadd(h),u.isub(f)),s.iushrn(1),u.iushrn(1);t.cmp(r)>=0?(t.isub(r),i.isub(s),a.isub(u)):(r.isub(t),s.isub(i),u.isub(a))}return{a:s,b:u,gcd:r.iushln(c)}},o.prototype._invmp=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i,a=new o(1),s=new o(0),u=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var c=0,h=1;0==(t.words[0]&h)&&c<26;++c,h<<=1);if(c>0)for(t.iushrn(c);c-- >0;)a.isOdd()&&a.iadd(u),a.iushrn(1);for(var f=0,l=1;0==(r.words[0]&l)&&f<26;++f,l<<=1);if(f>0)for(r.iushrn(f);f-- >0;)s.isOdd()&&s.iadd(u),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),a.isub(s)):(r.isub(t),s.isub(a))}return(i=0===t.cmpn(1)?a:s).cmpn(0)<0&&i.iadd(e),i},o.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var n=0;t.isEven()&&r.isEven();n++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var i=t.cmp(r);if(i<0){var o=t;t=r,r=o}else if(0===i||0===r.cmpn(1))break;t.isub(r)}return r.iushln(n)},o.prototype.invm=function(e){return this.egcd(e).a.umod(e)},o.prototype.isEven=function(){return 0==(1&this.words[0])},o.prototype.isOdd=function(){return 1==(1&this.words[0])},o.prototype.andln=function(e){return this.words[0]&e},o.prototype.bincn=function(e){n("number"==typeof e);var t=e%26,r=(e-t)/26,i=1<>>26,s&=67108863,this.words[a]=s}return 0!==o&&(this.words[a]=o,this.length++),this},o.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},o.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),n(e<=67108863,"Number is too big");var i=0|this.words[0];t=i===e?0:ie.length)return 1;if(this.length=0;r--){var n=0|this.words[r],i=0|e.words[r];if(n!==i){ni&&(t=1);break}}return t},o.prototype.gtn=function(e){return 1===this.cmpn(e)},o.prototype.gt=function(e){return 1===this.cmp(e)},o.prototype.gten=function(e){return this.cmpn(e)>=0},o.prototype.gte=function(e){return this.cmp(e)>=0},o.prototype.ltn=function(e){return-1===this.cmpn(e)},o.prototype.lt=function(e){return-1===this.cmp(e)},o.prototype.lten=function(e){return this.cmpn(e)<=0},o.prototype.lte=function(e){return this.cmp(e)<=0},o.prototype.eqn=function(e){return 0===this.cmpn(e)},o.prototype.eq=function(e){return 0===this.cmp(e)},o.red=function(e){return new S(e)},o.prototype.toRed=function(e){return n(!this.red,"Already a number in reduction context"),n(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},o.prototype.fromRed=function(){return n(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},o.prototype._forceRed=function(e){return this.red=e,this},o.prototype.forceRed=function(e){return n(!this.red,"Already a number in reduction context"),this._forceRed(e)},o.prototype.redAdd=function(e){return n(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},o.prototype.redIAdd=function(e){return n(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},o.prototype.redSub=function(e){return n(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},o.prototype.redISub=function(e){return n(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},o.prototype.redShl=function(e){return n(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},o.prototype.redMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},o.prototype.redIMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},o.prototype.redSqr=function(){return n(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},o.prototype.redISqr=function(){return n(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},o.prototype.redSqrt=function(){return n(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},o.prototype.redInvm=function(){return n(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},o.prototype.redNeg=function(){return n(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},o.prototype.redPow=function(e){return n(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function b(e,t){this.name=e,this.p=new o(t,16),this.n=this.p.bitLength(),this.k=new o(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){b.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){b.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function w(){b.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function _(){b.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function S(e){if("string"==typeof e){var t=o._prime(e);this.m=t.p,this.prime=t}else n(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function M(e){S.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new o(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}b.prototype._tmp=function(){var e=new o(null);return e.words=new Array(Math.ceil(this.n/13)),e},b.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var n=t0?r.isub(this.p):r.strip(),r},b.prototype.split=function(e,t){e.iushrn(this.n,0,t)},b.prototype.imulK=function(e){return e.imul(this.k)},i(v,b),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),n=0;n>>22,i=o}i>>>=22,e.words[n-10]=i,0===i&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=i,t=n}return 0!==t&&(e.words[e.length++]=t),e},o._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new w;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new _}return g[e]=t,t},S.prototype._verify1=function(e){n(0===e.negative,"red works only with positives"),n(e.red,"red works only with red numbers")},S.prototype._verify2=function(e,t){n(0==(e.negative|t.negative),"red works only with positives"),n(e.red&&e.red===t.red,"red works only with red numbers")},S.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},S.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},S.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},S.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},S.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},S.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},S.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},S.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},S.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},S.prototype.isqr=function(e){return this.imul(e,e.clone())},S.prototype.sqr=function(e){return this.mul(e,e)},S.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(n(t%2==1),3===t){var r=this.m.add(new o(1)).iushrn(2);return this.pow(e,r)}for(var i=this.m.subn(1),a=0;!i.isZero()&&0===i.andln(1);)a++,i.iushrn(1);n(!i.isZero());var s=new o(1).toRed(this),u=s.redNeg(),c=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new o(2*h*h).toRed(this);0!==this.pow(h,c).cmp(u);)h.redIAdd(u);for(var f=this.pow(h,i),l=this.pow(e,i.addn(1).iushrn(1)),d=this.pow(e,i),p=a;0!==d.cmp(s);){for(var m=d,g=0;0!==m.cmp(s);g++)m=m.redSqr();n(g=0;n--){for(var c=t.words[n],h=u-1;h>=0;h--){var f=c>>h&1;i!==r[0]&&(i=this.sqr(i)),0!==f||0!==a?(a<<=1,a|=f,(4===++s||0===n&&0===h)&&(i=this.mul(i,r[a]),s=0,a=0)):s=0}u=26}return i},S.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},S.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},o.mont=function(e){return new M(e)},i(M,S),M.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},M.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},M.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),o=i;return i.cmp(this.m)>=0?o=i.isub(this.m):i.cmpn(0)<0&&(o=i.iadd(this.m)),o._forceRed(this)},M.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new o(0)._forceRed(this);var r=e.mul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),a=i;return i.cmp(this.m)>=0?a=i.isub(this.m):i.cmpn(0)<0&&(a=i.iadd(this.m)),a._forceRed(this)},M.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(28)(e))},function(e){e.exports=JSON.parse('{"sha224WithRSAEncryption":{"sign":"rsa","hash":"sha224","id":"302d300d06096086480165030402040500041c"},"RSA-SHA224":{"sign":"ecdsa/rsa","hash":"sha224","id":"302d300d06096086480165030402040500041c"},"sha256WithRSAEncryption":{"sign":"rsa","hash":"sha256","id":"3031300d060960864801650304020105000420"},"RSA-SHA256":{"sign":"ecdsa/rsa","hash":"sha256","id":"3031300d060960864801650304020105000420"},"sha384WithRSAEncryption":{"sign":"rsa","hash":"sha384","id":"3041300d060960864801650304020205000430"},"RSA-SHA384":{"sign":"ecdsa/rsa","hash":"sha384","id":"3041300d060960864801650304020205000430"},"sha512WithRSAEncryption":{"sign":"rsa","hash":"sha512","id":"3051300d060960864801650304020305000440"},"RSA-SHA512":{"sign":"ecdsa/rsa","hash":"sha512","id":"3051300d060960864801650304020305000440"},"RSA-SHA1":{"sign":"rsa","hash":"sha1","id":"3021300906052b0e03021a05000414"},"ecdsa-with-SHA1":{"sign":"ecdsa","hash":"sha1","id":""},"sha256":{"sign":"ecdsa","hash":"sha256","id":""},"sha224":{"sign":"ecdsa","hash":"sha224","id":""},"sha384":{"sign":"ecdsa","hash":"sha384","id":""},"sha512":{"sign":"ecdsa","hash":"sha512","id":""},"DSA-SHA":{"sign":"dsa","hash":"sha1","id":""},"DSA-SHA1":{"sign":"dsa","hash":"sha1","id":""},"DSA":{"sign":"dsa","hash":"sha1","id":""},"DSA-WITH-SHA224":{"sign":"dsa","hash":"sha224","id":""},"DSA-SHA224":{"sign":"dsa","hash":"sha224","id":""},"DSA-WITH-SHA256":{"sign":"dsa","hash":"sha256","id":""},"DSA-SHA256":{"sign":"dsa","hash":"sha256","id":""},"DSA-WITH-SHA384":{"sign":"dsa","hash":"sha384","id":""},"DSA-SHA384":{"sign":"dsa","hash":"sha384","id":""},"DSA-WITH-SHA512":{"sign":"dsa","hash":"sha512","id":""},"DSA-SHA512":{"sign":"dsa","hash":"sha512","id":""},"DSA-RIPEMD160":{"sign":"dsa","hash":"rmd160","id":""},"ripemd160WithRSA":{"sign":"rsa","hash":"rmd160","id":"3021300906052b2403020105000414"},"RSA-RIPEMD160":{"sign":"rsa","hash":"rmd160","id":"3021300906052b2403020105000414"},"md5WithRSAEncryption":{"sign":"rsa","hash":"md5","id":"3020300c06082a864886f70d020505000410"},"RSA-MD5":{"sign":"rsa","hash":"md5","id":"3020300c06082a864886f70d020505000410"}}')},function(e,t,r){"use strict";t.readUInt32BE=function(e,t){return(e[0+t]<<24|e[1+t]<<16|e[2+t]<<8|e[3+t])>>>0},t.writeUInt32BE=function(e,t,r){e[0+r]=t>>>24,e[1+r]=t>>>16&255,e[2+r]=t>>>8&255,e[3+r]=255&t},t.ip=function(e,t,r,n){for(var i=0,o=0,a=6;a>=0;a-=2){for(var s=0;s<=24;s+=8)i<<=1,i|=t>>>s+a&1;for(s=0;s<=24;s+=8)i<<=1,i|=e>>>s+a&1}for(a=6;a>=0;a-=2){for(s=1;s<=25;s+=8)o<<=1,o|=t>>>s+a&1;for(s=1;s<=25;s+=8)o<<=1,o|=e>>>s+a&1}r[n+0]=i>>>0,r[n+1]=o>>>0},t.rip=function(e,t,r,n){for(var i=0,o=0,a=0;a<4;a++)for(var s=24;s>=0;s-=8)i<<=1,i|=t>>>s+a&1,i<<=1,i|=e>>>s+a&1;for(a=4;a<8;a++)for(s=24;s>=0;s-=8)o<<=1,o|=t>>>s+a&1,o<<=1,o|=e>>>s+a&1;r[n+0]=i>>>0,r[n+1]=o>>>0},t.pc1=function(e,t,r,n){for(var i=0,o=0,a=7;a>=5;a--){for(var s=0;s<=24;s+=8)i<<=1,i|=t>>s+a&1;for(s=0;s<=24;s+=8)i<<=1,i|=e>>s+a&1}for(s=0;s<=24;s+=8)i<<=1,i|=t>>s+a&1;for(a=1;a<=3;a++){for(s=0;s<=24;s+=8)o<<=1,o|=t>>s+a&1;for(s=0;s<=24;s+=8)o<<=1,o|=e>>s+a&1}for(s=0;s<=24;s+=8)o<<=1,o|=e>>s+a&1;r[n+0]=i>>>0,r[n+1]=o>>>0},t.r28shl=function(e,t){return e<>>28-t};var n=[14,11,17,4,27,23,25,0,13,22,7,18,5,9,16,24,2,20,12,21,1,8,15,26,15,4,25,19,9,1,26,16,5,11,23,8,12,7,17,0,22,3,10,14,6,20,27,24];t.pc2=function(e,t,r,i){for(var o=0,a=0,s=n.length>>>1,u=0;u>>n[u]&1;for(u=s;u>>n[u]&1;r[i+0]=o>>>0,r[i+1]=a>>>0},t.expand=function(e,t,r){var n=0,i=0;n=(1&e)<<5|e>>>27;for(var o=23;o>=15;o-=4)n<<=6,n|=e>>>o&63;for(o=11;o>=3;o-=4)i|=e>>>o&63,i<<=6;i|=(31&e)<<1|e>>>31,t[r+0]=n>>>0,t[r+1]=i>>>0};var i=[14,0,4,15,13,7,1,4,2,14,15,2,11,13,8,1,3,10,10,6,6,12,12,11,5,9,9,5,0,3,7,8,4,15,1,12,14,8,8,2,13,4,6,9,2,1,11,7,15,5,12,11,9,3,7,14,3,10,10,0,5,6,0,13,15,3,1,13,8,4,14,7,6,15,11,2,3,8,4,14,9,12,7,0,2,1,13,10,12,6,0,9,5,11,10,5,0,13,14,8,7,10,11,1,10,3,4,15,13,4,1,2,5,11,8,6,12,7,6,12,9,0,3,5,2,14,15,9,10,13,0,7,9,0,14,9,6,3,3,4,15,6,5,10,1,2,13,8,12,5,7,14,11,12,4,11,2,15,8,1,13,1,6,10,4,13,9,0,8,6,15,9,3,8,0,7,11,4,1,15,2,14,12,3,5,11,10,5,14,2,7,12,7,13,13,8,14,11,3,5,0,6,6,15,9,0,10,3,1,4,2,7,8,2,5,12,11,1,12,10,4,14,15,9,10,3,6,15,9,0,0,6,12,10,11,1,7,13,13,8,15,9,1,4,3,5,14,11,5,12,2,7,8,2,4,14,2,14,12,11,4,2,1,12,7,4,10,7,11,13,6,1,8,5,5,0,3,15,15,10,13,3,0,9,14,8,9,6,4,11,2,8,1,12,11,7,10,1,13,14,7,2,8,13,15,6,9,15,12,0,5,9,6,10,3,4,0,5,14,3,12,10,1,15,10,4,15,2,9,7,2,12,6,9,8,5,0,6,13,1,3,13,4,14,14,0,7,11,5,3,11,8,9,4,14,3,15,2,5,12,2,9,8,5,12,15,3,10,7,11,0,14,4,1,10,7,1,6,13,0,11,8,6,13,4,13,11,0,2,11,14,7,15,4,0,9,8,1,13,10,3,14,12,3,9,5,7,12,5,2,10,15,6,8,1,6,1,6,4,11,11,13,13,8,12,1,3,4,7,10,14,7,10,9,15,5,6,0,8,15,0,14,5,2,9,3,2,12,13,1,2,15,8,13,4,8,6,10,15,3,11,7,1,4,10,12,9,5,3,6,14,11,5,0,0,14,12,9,7,2,7,2,11,1,4,14,1,7,9,4,12,10,14,8,2,13,0,15,6,12,10,9,13,0,15,3,3,5,5,6,8,11];t.substitute=function(e,t){for(var r=0,n=0;n<4;n++){r<<=4,r|=i[64*n+(e>>>18-6*n&63)]}for(n=0;n<4;n++){r<<=4,r|=i[256+64*n+(t>>>18-6*n&63)]}return r>>>0};var o=[16,25,12,11,3,20,4,15,31,17,9,6,27,14,1,22,30,24,8,18,0,5,29,23,13,19,2,26,10,21,28,7];t.permute=function(e){for(var t=0,r=0;r>>o[r]&1;return t>>>0},t.padSplit=function(e,t,r){for(var n=e.toString(2);n.length>>1];r=o.r28shl(r,s),i=o.r28shl(i,s),o.pc2(r,i,e.keys,a)}},u.prototype._update=function(e,t,r,n){var i=this._desState,a=o.readUInt32BE(e,t),s=o.readUInt32BE(e,t+4);o.ip(a,s,i.tmp,0),a=i.tmp[0],s=i.tmp[1],"encrypt"===this.type?this._encrypt(i,a,s,i.tmp,0):this._decrypt(i,a,s,i.tmp,0),a=i.tmp[0],s=i.tmp[1],o.writeUInt32BE(r,a,n),o.writeUInt32BE(r,s,n+4)},u.prototype._pad=function(e,t){for(var r=e.length-t,n=t;n>>0,a=l}o.rip(s,a,n,i)},u.prototype._decrypt=function(e,t,r,n,i){for(var a=r,s=t,u=e.keys.length-2;u>=0;u-=2){var c=e.keys[u],h=e.keys[u+1];o.expand(a,e.tmp,0),c^=e.tmp[0],h^=e.tmp[1];var f=o.substitute(c,h),l=a;a=(s^o.permute(f))>>>0,s=l}o.rip(a,s,n,i)}},function(e,t,r){var n=r(46),i=r(2).Buffer,o=r(165);function a(e){var t=e._cipher.encryptBlockRaw(e._prev);return o(e._prev),t}t.encrypt=function(e,t){var r=Math.ceil(t.length/16),o=e._cache.length;e._cache=i.concat([e._cache,i.allocUnsafe(16*r)]);for(var s=0;se;)r.ishrn(1);if(r.isEven()&&r.iadd(s),r.testn(1)||r.iadd(u),t.cmp(u)){if(!t.cmp(c))for(;r.mod(h).cmp(f);)r.iadd(d)}else for(;r.mod(o).cmp(l);)r.iadd(d);if(g(p=r.shrn(1))&&g(r)&&b(p)&&b(r)&&a.test(p)&&a.test(r))return r}}},function(e,t,r){var n=r(6),i=r(81);function o(e){this.rand=e||new i.Rand}e.exports=o,o.create=function(e){return new o(e)},o.prototype._randbelow=function(e){var t=e.bitLength(),r=Math.ceil(t/8);do{var i=new n(this.rand.generate(r))}while(i.cmp(e)>=0);return i},o.prototype._randrange=function(e,t){var r=t.sub(e);return e.add(this._randbelow(r))},o.prototype.test=function(e,t,r){var i=e.bitLength(),o=n.mont(e),a=new n(1).toRed(o);t||(t=Math.max(1,i/48|0));for(var s=e.subn(1),u=0;!s.testn(u);u++);for(var c=e.shrn(u),h=s.toRed(o);t>0;t--){var f=this._randrange(new n(2),s);r&&r(f);var l=f.toRed(o).redPow(c);if(0!==l.cmp(a)&&0!==l.cmp(h)){for(var d=1;d0;t--){var h=this._randrange(new n(2),a),f=e.gcd(h);if(0!==f.cmpn(1))return f;var l=h.toRed(i).redPow(u);if(0!==l.cmp(o)&&0!==l.cmp(c)){for(var d=1;d=49&&c<=54?c-49+10:c>=17&&c<=22?c-17+10:c,a|=u}return n(!(240&a),"Invalid character in "+e),i}function u(e,t,r,i){for(var o=0,a=0,s=Math.min(e.length,r),u=t;u=49?c-49+10:c>=17?c-17+10:c,n(c>=0&&a0?e:t},o.min=function(e,t){return e.cmp(t)<0?e:t},o.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),n(t===(0|t)&&t>=2&&t<=36);var i=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&i++,16===t?this._parseHex(e,i):this._parseBase(e,t,i),"-"===e[0]&&(this.negative=1),this._strip(),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(n(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initArray=function(e,t,r){if(n("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var i=0;i=0;i-=3)a=e[i]|e[i-1]<<8|e[i-2]<<16,this.words[o]|=a<>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);else if("le"===r)for(i=0,o=0;i>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);return this._strip()},o.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)i=s(e,r,r+6),this.words[n]|=i<>>26-o&4194303,(o+=24)>=26&&(o-=26,n++);r+6!==t&&(i=s(e,t,r+6),this.words[n]|=i<>>26-o&4194303),this._strip()},o.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var n=0,i=1;i<=67108863;i*=t)n++;n--,i=i/t|0;for(var o=e.length-r,a=o%n,s=Math.min(o,o-a)+r,c=0,h=r;h1&&0===this.words[this.length-1];)this.length--;return this._normSign()},o.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},"undefined"!=typeof Symbol&&"function"==typeof Symbol.for)try{o.prototype[Symbol.for("nodejs.util.inspect.custom")]=h}catch(e){o.prototype.inspect=h}else o.prototype.inspect=h;function h(){return(this.red?""}var f=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],d=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];o.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var i=0,o=0,a=0;a>>24-i&16777215)||a!==this.length-1?f[6-u.length]+u+r:u+r,(i+=2)>=26&&(i-=26,a--)}for(0!==o&&(r=o.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var c=l[e],h=d[e];r="";var p=this.clone();for(p.negative=0;!p.isZero();){var m=p.modrn(h).toString(e);r=(p=p.idivn(h)).isZero()?m+r:f[c-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}n(!1,"Base should be between 2 and 36")},o.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&n(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},o.prototype.toJSON=function(){return this.toString(16,2)},a&&(o.prototype.toBuffer=function(e,t){return this.toArrayLike(a,e,t)}),o.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)};function p(e,t,r){r.negative=t.negative^e.negative;var n=e.length+t.length|0;r.length=n,n=n-1|0;var i=0|e.words[0],o=0|t.words[0],a=i*o,s=67108863&a,u=a/67108864|0;r.words[0]=s;for(var c=1;c>>26,f=67108863&u,l=Math.min(c,t.length-1),d=Math.max(0,c-e.length+1);d<=l;d++){var p=c-d|0;h+=(a=(i=0|e.words[p])*(o=0|t.words[d])+f)/67108864|0,f=67108863&a}r.words[c]=0|f,u=0|h}return 0!==u?r.words[c]=0|u:r.length--,r._strip()}o.prototype.toArrayLike=function(e,t,r){this._strip();var i=this.byteLength(),o=r||Math.max(1,i);n(i<=o,"byte array longer than desired length"),n(o>0,"Requested array length <= 0");var a=function(e,t){return e.allocUnsafe?e.allocUnsafe(t):new e(t)}(e,o);return this["_toArrayLike"+("le"===t?"LE":"BE")](a,i),a},o.prototype._toArrayLikeLE=function(e,t){for(var r=0,n=0,i=0,o=0;i>8&255),r>16&255),6===o?(r>24&255),n=0,o=0):(n=a>>>24,o+=2)}if(r=0&&(e[r--]=a>>8&255),r>=0&&(e[r--]=a>>16&255),6===o?(r>=0&&(e[r--]=a>>24&255),n=0,o=0):(n=a>>>24,o+=2)}if(r>=0)for(e[r--]=n;r>=0;)e[r--]=0},Math.clz32?o.prototype._countBits=function(e){return 32-Math.clz32(e)}:o.prototype._countBits=function(e){var t=e,r=0;return t>=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},o.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},o.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},o.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},o.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},o.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},o.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},o.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var n=0;ne.length?this.clone().ixor(e):e.clone().ixor(this)},o.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},o.prototype.inotn=function(e){n("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var i=0;i0&&(this.words[i]=~this.words[i]&67108863>>26-r),this._strip()},o.prototype.notn=function(e){return this.clone().inotn(e)},o.prototype.setn=function(e,t){n("number"==typeof e&&e>=0);var r=e/26|0,i=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,n=e):(r=e,n=this);for(var i=0,o=0;o>>26;for(;0!==i&&o>>26;if(this.length=r.length,0!==i)this.words[this.length]=i,this.length++;else if(r!==this)for(;oe.length?this.clone().iadd(e):e.clone().iadd(this)},o.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,n,i=this.cmp(e);if(0===i)return this.negative=0,this.length=1,this.words[0]=0,this;i>0?(r=this,n=e):(r=e,n=this);for(var o=0,a=0;a>26,this.words[a]=67108863&t;for(;0!==o&&a>26,this.words[a]=67108863&t;if(0===o&&a>>13,d=0|a[1],p=8191&d,m=d>>>13,g=0|a[2],b=8191&g,v=g>>>13,y=0|a[3],w=8191&y,_=y>>>13,S=0|a[4],M=8191&S,k=S>>>13,E=0|a[5],A=8191&E,x=E>>>13,I=0|a[6],P=8191&I,O=I>>>13,T=0|a[7],R=8191&T,B=T>>>13,N=0|a[8],C=8191&N,j=N>>>13,z=0|a[9],U=8191&z,L=z>>>13,F=0|s[0],D=8191&F,q=F>>>13,K=0|s[1],H=8191&K,V=K>>>13,G=0|s[2],W=8191&G,Y=G>>>13,Z=0|s[3],J=8191&Z,X=Z>>>13,$=0|s[4],Q=8191&$,ee=$>>>13,te=0|s[5],re=8191&te,ne=te>>>13,ie=0|s[6],oe=8191&ie,ae=ie>>>13,se=0|s[7],ue=8191&se,ce=se>>>13,he=0|s[8],fe=8191&he,le=he>>>13,de=0|s[9],pe=8191&de,me=de>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(c+(n=Math.imul(f,D))|0)+((8191&(i=(i=Math.imul(f,q))+Math.imul(l,D)|0))<<13)|0;c=((o=Math.imul(l,q))+(i>>>13)|0)+(ge>>>26)|0,ge&=67108863,n=Math.imul(p,D),i=(i=Math.imul(p,q))+Math.imul(m,D)|0,o=Math.imul(m,q);var be=(c+(n=n+Math.imul(f,H)|0)|0)+((8191&(i=(i=i+Math.imul(f,V)|0)+Math.imul(l,H)|0))<<13)|0;c=((o=o+Math.imul(l,V)|0)+(i>>>13)|0)+(be>>>26)|0,be&=67108863,n=Math.imul(b,D),i=(i=Math.imul(b,q))+Math.imul(v,D)|0,o=Math.imul(v,q),n=n+Math.imul(p,H)|0,i=(i=i+Math.imul(p,V)|0)+Math.imul(m,H)|0,o=o+Math.imul(m,V)|0;var ve=(c+(n=n+Math.imul(f,W)|0)|0)+((8191&(i=(i=i+Math.imul(f,Y)|0)+Math.imul(l,W)|0))<<13)|0;c=((o=o+Math.imul(l,Y)|0)+(i>>>13)|0)+(ve>>>26)|0,ve&=67108863,n=Math.imul(w,D),i=(i=Math.imul(w,q))+Math.imul(_,D)|0,o=Math.imul(_,q),n=n+Math.imul(b,H)|0,i=(i=i+Math.imul(b,V)|0)+Math.imul(v,H)|0,o=o+Math.imul(v,V)|0,n=n+Math.imul(p,W)|0,i=(i=i+Math.imul(p,Y)|0)+Math.imul(m,W)|0,o=o+Math.imul(m,Y)|0;var ye=(c+(n=n+Math.imul(f,J)|0)|0)+((8191&(i=(i=i+Math.imul(f,X)|0)+Math.imul(l,J)|0))<<13)|0;c=((o=o+Math.imul(l,X)|0)+(i>>>13)|0)+(ye>>>26)|0,ye&=67108863,n=Math.imul(M,D),i=(i=Math.imul(M,q))+Math.imul(k,D)|0,o=Math.imul(k,q),n=n+Math.imul(w,H)|0,i=(i=i+Math.imul(w,V)|0)+Math.imul(_,H)|0,o=o+Math.imul(_,V)|0,n=n+Math.imul(b,W)|0,i=(i=i+Math.imul(b,Y)|0)+Math.imul(v,W)|0,o=o+Math.imul(v,Y)|0,n=n+Math.imul(p,J)|0,i=(i=i+Math.imul(p,X)|0)+Math.imul(m,J)|0,o=o+Math.imul(m,X)|0;var we=(c+(n=n+Math.imul(f,Q)|0)|0)+((8191&(i=(i=i+Math.imul(f,ee)|0)+Math.imul(l,Q)|0))<<13)|0;c=((o=o+Math.imul(l,ee)|0)+(i>>>13)|0)+(we>>>26)|0,we&=67108863,n=Math.imul(A,D),i=(i=Math.imul(A,q))+Math.imul(x,D)|0,o=Math.imul(x,q),n=n+Math.imul(M,H)|0,i=(i=i+Math.imul(M,V)|0)+Math.imul(k,H)|0,o=o+Math.imul(k,V)|0,n=n+Math.imul(w,W)|0,i=(i=i+Math.imul(w,Y)|0)+Math.imul(_,W)|0,o=o+Math.imul(_,Y)|0,n=n+Math.imul(b,J)|0,i=(i=i+Math.imul(b,X)|0)+Math.imul(v,J)|0,o=o+Math.imul(v,X)|0,n=n+Math.imul(p,Q)|0,i=(i=i+Math.imul(p,ee)|0)+Math.imul(m,Q)|0,o=o+Math.imul(m,ee)|0;var _e=(c+(n=n+Math.imul(f,re)|0)|0)+((8191&(i=(i=i+Math.imul(f,ne)|0)+Math.imul(l,re)|0))<<13)|0;c=((o=o+Math.imul(l,ne)|0)+(i>>>13)|0)+(_e>>>26)|0,_e&=67108863,n=Math.imul(P,D),i=(i=Math.imul(P,q))+Math.imul(O,D)|0,o=Math.imul(O,q),n=n+Math.imul(A,H)|0,i=(i=i+Math.imul(A,V)|0)+Math.imul(x,H)|0,o=o+Math.imul(x,V)|0,n=n+Math.imul(M,W)|0,i=(i=i+Math.imul(M,Y)|0)+Math.imul(k,W)|0,o=o+Math.imul(k,Y)|0,n=n+Math.imul(w,J)|0,i=(i=i+Math.imul(w,X)|0)+Math.imul(_,J)|0,o=o+Math.imul(_,X)|0,n=n+Math.imul(b,Q)|0,i=(i=i+Math.imul(b,ee)|0)+Math.imul(v,Q)|0,o=o+Math.imul(v,ee)|0,n=n+Math.imul(p,re)|0,i=(i=i+Math.imul(p,ne)|0)+Math.imul(m,re)|0,o=o+Math.imul(m,ne)|0;var Se=(c+(n=n+Math.imul(f,oe)|0)|0)+((8191&(i=(i=i+Math.imul(f,ae)|0)+Math.imul(l,oe)|0))<<13)|0;c=((o=o+Math.imul(l,ae)|0)+(i>>>13)|0)+(Se>>>26)|0,Se&=67108863,n=Math.imul(R,D),i=(i=Math.imul(R,q))+Math.imul(B,D)|0,o=Math.imul(B,q),n=n+Math.imul(P,H)|0,i=(i=i+Math.imul(P,V)|0)+Math.imul(O,H)|0,o=o+Math.imul(O,V)|0,n=n+Math.imul(A,W)|0,i=(i=i+Math.imul(A,Y)|0)+Math.imul(x,W)|0,o=o+Math.imul(x,Y)|0,n=n+Math.imul(M,J)|0,i=(i=i+Math.imul(M,X)|0)+Math.imul(k,J)|0,o=o+Math.imul(k,X)|0,n=n+Math.imul(w,Q)|0,i=(i=i+Math.imul(w,ee)|0)+Math.imul(_,Q)|0,o=o+Math.imul(_,ee)|0,n=n+Math.imul(b,re)|0,i=(i=i+Math.imul(b,ne)|0)+Math.imul(v,re)|0,o=o+Math.imul(v,ne)|0,n=n+Math.imul(p,oe)|0,i=(i=i+Math.imul(p,ae)|0)+Math.imul(m,oe)|0,o=o+Math.imul(m,ae)|0;var Me=(c+(n=n+Math.imul(f,ue)|0)|0)+((8191&(i=(i=i+Math.imul(f,ce)|0)+Math.imul(l,ue)|0))<<13)|0;c=((o=o+Math.imul(l,ce)|0)+(i>>>13)|0)+(Me>>>26)|0,Me&=67108863,n=Math.imul(C,D),i=(i=Math.imul(C,q))+Math.imul(j,D)|0,o=Math.imul(j,q),n=n+Math.imul(R,H)|0,i=(i=i+Math.imul(R,V)|0)+Math.imul(B,H)|0,o=o+Math.imul(B,V)|0,n=n+Math.imul(P,W)|0,i=(i=i+Math.imul(P,Y)|0)+Math.imul(O,W)|0,o=o+Math.imul(O,Y)|0,n=n+Math.imul(A,J)|0,i=(i=i+Math.imul(A,X)|0)+Math.imul(x,J)|0,o=o+Math.imul(x,X)|0,n=n+Math.imul(M,Q)|0,i=(i=i+Math.imul(M,ee)|0)+Math.imul(k,Q)|0,o=o+Math.imul(k,ee)|0,n=n+Math.imul(w,re)|0,i=(i=i+Math.imul(w,ne)|0)+Math.imul(_,re)|0,o=o+Math.imul(_,ne)|0,n=n+Math.imul(b,oe)|0,i=(i=i+Math.imul(b,ae)|0)+Math.imul(v,oe)|0,o=o+Math.imul(v,ae)|0,n=n+Math.imul(p,ue)|0,i=(i=i+Math.imul(p,ce)|0)+Math.imul(m,ue)|0,o=o+Math.imul(m,ce)|0;var ke=(c+(n=n+Math.imul(f,fe)|0)|0)+((8191&(i=(i=i+Math.imul(f,le)|0)+Math.imul(l,fe)|0))<<13)|0;c=((o=o+Math.imul(l,le)|0)+(i>>>13)|0)+(ke>>>26)|0,ke&=67108863,n=Math.imul(U,D),i=(i=Math.imul(U,q))+Math.imul(L,D)|0,o=Math.imul(L,q),n=n+Math.imul(C,H)|0,i=(i=i+Math.imul(C,V)|0)+Math.imul(j,H)|0,o=o+Math.imul(j,V)|0,n=n+Math.imul(R,W)|0,i=(i=i+Math.imul(R,Y)|0)+Math.imul(B,W)|0,o=o+Math.imul(B,Y)|0,n=n+Math.imul(P,J)|0,i=(i=i+Math.imul(P,X)|0)+Math.imul(O,J)|0,o=o+Math.imul(O,X)|0,n=n+Math.imul(A,Q)|0,i=(i=i+Math.imul(A,ee)|0)+Math.imul(x,Q)|0,o=o+Math.imul(x,ee)|0,n=n+Math.imul(M,re)|0,i=(i=i+Math.imul(M,ne)|0)+Math.imul(k,re)|0,o=o+Math.imul(k,ne)|0,n=n+Math.imul(w,oe)|0,i=(i=i+Math.imul(w,ae)|0)+Math.imul(_,oe)|0,o=o+Math.imul(_,ae)|0,n=n+Math.imul(b,ue)|0,i=(i=i+Math.imul(b,ce)|0)+Math.imul(v,ue)|0,o=o+Math.imul(v,ce)|0,n=n+Math.imul(p,fe)|0,i=(i=i+Math.imul(p,le)|0)+Math.imul(m,fe)|0,o=o+Math.imul(m,le)|0;var Ee=(c+(n=n+Math.imul(f,pe)|0)|0)+((8191&(i=(i=i+Math.imul(f,me)|0)+Math.imul(l,pe)|0))<<13)|0;c=((o=o+Math.imul(l,me)|0)+(i>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,n=Math.imul(U,H),i=(i=Math.imul(U,V))+Math.imul(L,H)|0,o=Math.imul(L,V),n=n+Math.imul(C,W)|0,i=(i=i+Math.imul(C,Y)|0)+Math.imul(j,W)|0,o=o+Math.imul(j,Y)|0,n=n+Math.imul(R,J)|0,i=(i=i+Math.imul(R,X)|0)+Math.imul(B,J)|0,o=o+Math.imul(B,X)|0,n=n+Math.imul(P,Q)|0,i=(i=i+Math.imul(P,ee)|0)+Math.imul(O,Q)|0,o=o+Math.imul(O,ee)|0,n=n+Math.imul(A,re)|0,i=(i=i+Math.imul(A,ne)|0)+Math.imul(x,re)|0,o=o+Math.imul(x,ne)|0,n=n+Math.imul(M,oe)|0,i=(i=i+Math.imul(M,ae)|0)+Math.imul(k,oe)|0,o=o+Math.imul(k,ae)|0,n=n+Math.imul(w,ue)|0,i=(i=i+Math.imul(w,ce)|0)+Math.imul(_,ue)|0,o=o+Math.imul(_,ce)|0,n=n+Math.imul(b,fe)|0,i=(i=i+Math.imul(b,le)|0)+Math.imul(v,fe)|0,o=o+Math.imul(v,le)|0;var Ae=(c+(n=n+Math.imul(p,pe)|0)|0)+((8191&(i=(i=i+Math.imul(p,me)|0)+Math.imul(m,pe)|0))<<13)|0;c=((o=o+Math.imul(m,me)|0)+(i>>>13)|0)+(Ae>>>26)|0,Ae&=67108863,n=Math.imul(U,W),i=(i=Math.imul(U,Y))+Math.imul(L,W)|0,o=Math.imul(L,Y),n=n+Math.imul(C,J)|0,i=(i=i+Math.imul(C,X)|0)+Math.imul(j,J)|0,o=o+Math.imul(j,X)|0,n=n+Math.imul(R,Q)|0,i=(i=i+Math.imul(R,ee)|0)+Math.imul(B,Q)|0,o=o+Math.imul(B,ee)|0,n=n+Math.imul(P,re)|0,i=(i=i+Math.imul(P,ne)|0)+Math.imul(O,re)|0,o=o+Math.imul(O,ne)|0,n=n+Math.imul(A,oe)|0,i=(i=i+Math.imul(A,ae)|0)+Math.imul(x,oe)|0,o=o+Math.imul(x,ae)|0,n=n+Math.imul(M,ue)|0,i=(i=i+Math.imul(M,ce)|0)+Math.imul(k,ue)|0,o=o+Math.imul(k,ce)|0,n=n+Math.imul(w,fe)|0,i=(i=i+Math.imul(w,le)|0)+Math.imul(_,fe)|0,o=o+Math.imul(_,le)|0;var xe=(c+(n=n+Math.imul(b,pe)|0)|0)+((8191&(i=(i=i+Math.imul(b,me)|0)+Math.imul(v,pe)|0))<<13)|0;c=((o=o+Math.imul(v,me)|0)+(i>>>13)|0)+(xe>>>26)|0,xe&=67108863,n=Math.imul(U,J),i=(i=Math.imul(U,X))+Math.imul(L,J)|0,o=Math.imul(L,X),n=n+Math.imul(C,Q)|0,i=(i=i+Math.imul(C,ee)|0)+Math.imul(j,Q)|0,o=o+Math.imul(j,ee)|0,n=n+Math.imul(R,re)|0,i=(i=i+Math.imul(R,ne)|0)+Math.imul(B,re)|0,o=o+Math.imul(B,ne)|0,n=n+Math.imul(P,oe)|0,i=(i=i+Math.imul(P,ae)|0)+Math.imul(O,oe)|0,o=o+Math.imul(O,ae)|0,n=n+Math.imul(A,ue)|0,i=(i=i+Math.imul(A,ce)|0)+Math.imul(x,ue)|0,o=o+Math.imul(x,ce)|0,n=n+Math.imul(M,fe)|0,i=(i=i+Math.imul(M,le)|0)+Math.imul(k,fe)|0,o=o+Math.imul(k,le)|0;var Ie=(c+(n=n+Math.imul(w,pe)|0)|0)+((8191&(i=(i=i+Math.imul(w,me)|0)+Math.imul(_,pe)|0))<<13)|0;c=((o=o+Math.imul(_,me)|0)+(i>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,n=Math.imul(U,Q),i=(i=Math.imul(U,ee))+Math.imul(L,Q)|0,o=Math.imul(L,ee),n=n+Math.imul(C,re)|0,i=(i=i+Math.imul(C,ne)|0)+Math.imul(j,re)|0,o=o+Math.imul(j,ne)|0,n=n+Math.imul(R,oe)|0,i=(i=i+Math.imul(R,ae)|0)+Math.imul(B,oe)|0,o=o+Math.imul(B,ae)|0,n=n+Math.imul(P,ue)|0,i=(i=i+Math.imul(P,ce)|0)+Math.imul(O,ue)|0,o=o+Math.imul(O,ce)|0,n=n+Math.imul(A,fe)|0,i=(i=i+Math.imul(A,le)|0)+Math.imul(x,fe)|0,o=o+Math.imul(x,le)|0;var Pe=(c+(n=n+Math.imul(M,pe)|0)|0)+((8191&(i=(i=i+Math.imul(M,me)|0)+Math.imul(k,pe)|0))<<13)|0;c=((o=o+Math.imul(k,me)|0)+(i>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,n=Math.imul(U,re),i=(i=Math.imul(U,ne))+Math.imul(L,re)|0,o=Math.imul(L,ne),n=n+Math.imul(C,oe)|0,i=(i=i+Math.imul(C,ae)|0)+Math.imul(j,oe)|0,o=o+Math.imul(j,ae)|0,n=n+Math.imul(R,ue)|0,i=(i=i+Math.imul(R,ce)|0)+Math.imul(B,ue)|0,o=o+Math.imul(B,ce)|0,n=n+Math.imul(P,fe)|0,i=(i=i+Math.imul(P,le)|0)+Math.imul(O,fe)|0,o=o+Math.imul(O,le)|0;var Oe=(c+(n=n+Math.imul(A,pe)|0)|0)+((8191&(i=(i=i+Math.imul(A,me)|0)+Math.imul(x,pe)|0))<<13)|0;c=((o=o+Math.imul(x,me)|0)+(i>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,n=Math.imul(U,oe),i=(i=Math.imul(U,ae))+Math.imul(L,oe)|0,o=Math.imul(L,ae),n=n+Math.imul(C,ue)|0,i=(i=i+Math.imul(C,ce)|0)+Math.imul(j,ue)|0,o=o+Math.imul(j,ce)|0,n=n+Math.imul(R,fe)|0,i=(i=i+Math.imul(R,le)|0)+Math.imul(B,fe)|0,o=o+Math.imul(B,le)|0;var Te=(c+(n=n+Math.imul(P,pe)|0)|0)+((8191&(i=(i=i+Math.imul(P,me)|0)+Math.imul(O,pe)|0))<<13)|0;c=((o=o+Math.imul(O,me)|0)+(i>>>13)|0)+(Te>>>26)|0,Te&=67108863,n=Math.imul(U,ue),i=(i=Math.imul(U,ce))+Math.imul(L,ue)|0,o=Math.imul(L,ce),n=n+Math.imul(C,fe)|0,i=(i=i+Math.imul(C,le)|0)+Math.imul(j,fe)|0,o=o+Math.imul(j,le)|0;var Re=(c+(n=n+Math.imul(R,pe)|0)|0)+((8191&(i=(i=i+Math.imul(R,me)|0)+Math.imul(B,pe)|0))<<13)|0;c=((o=o+Math.imul(B,me)|0)+(i>>>13)|0)+(Re>>>26)|0,Re&=67108863,n=Math.imul(U,fe),i=(i=Math.imul(U,le))+Math.imul(L,fe)|0,o=Math.imul(L,le);var Be=(c+(n=n+Math.imul(C,pe)|0)|0)+((8191&(i=(i=i+Math.imul(C,me)|0)+Math.imul(j,pe)|0))<<13)|0;c=((o=o+Math.imul(j,me)|0)+(i>>>13)|0)+(Be>>>26)|0,Be&=67108863;var Ne=(c+(n=Math.imul(U,pe))|0)+((8191&(i=(i=Math.imul(U,me))+Math.imul(L,pe)|0))<<13)|0;return c=((o=Math.imul(L,me))+(i>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,u[0]=ge,u[1]=be,u[2]=ve,u[3]=ye,u[4]=we,u[5]=_e,u[6]=Se,u[7]=Me,u[8]=ke,u[9]=Ee,u[10]=Ae,u[11]=xe,u[12]=Ie,u[13]=Pe,u[14]=Oe,u[15]=Te,u[16]=Re,u[17]=Be,u[18]=Ne,0!==c&&(u[19]=c,r.length++),r};function g(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var n=0,i=0,o=0;o>>26)|0)>>>26,a&=67108863}r.words[o]=s,n=a,a=i}return 0!==n?r.words[o]=n:r.length--,r._strip()}function b(e,t,r){return g(e,t,r)}function v(e,t){this.x=e,this.y=t}Math.imul||(m=p),o.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?m(this,e,t):r<63?p(this,e,t):r<1024?g(this,e,t):b(this,e,t)},v.prototype.makeRBT=function(e){for(var t=new Array(e),r=o.prototype._countBits(e)-1,n=0;n>=1;return n},v.prototype.permute=function(e,t,r,n,i,o){for(var a=0;a>>=1)i++;return 1<>>=13,r[2*a+1]=8191&o,o>>>=13;for(a=2*t;a>=26,r+=o/67108864|0,r+=a>>>26,this.words[i]=67108863&a}return 0!==r&&(this.words[i]=r,this.length++),t?this.ineg():this},o.prototype.muln=function(e){return this.clone().imuln(e)},o.prototype.sqr=function(){return this.mul(this)},o.prototype.isqr=function(){return this.imul(this.clone())},o.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>i&1}return t}(e);if(0===t.length)return new o(1);for(var r=this,n=0;n=0);var t,r=e%26,i=(e-r)/26,o=67108863>>>26-r<<26-r;if(0!==r){var a=0;for(t=0;t>>26-r}a&&(this.words[t]=a,this.length++)}if(0!==i){for(t=this.length-1;t>=0;t--)this.words[t+i]=this.words[t];for(t=0;t=0),i=t?(t-t%26)/26:0;var o=e%26,a=Math.min((e-o)/26,this.length),s=67108863^67108863>>>o<a)for(this.length-=a,c=0;c=0&&(0!==h||c>=i);c--){var f=0|this.words[c];this.words[c]=h<<26-o|f>>>o,h=f&s}return u&&0!==h&&(u.words[u.length++]=h),0===this.length&&(this.words[0]=0,this.length=1),this._strip()},o.prototype.ishrn=function(e,t,r){return n(0===this.negative),this.iushrn(e,t,r)},o.prototype.shln=function(e){return this.clone().ishln(e)},o.prototype.ushln=function(e){return this.clone().iushln(e)},o.prototype.shrn=function(e){return this.clone().ishrn(e)},o.prototype.ushrn=function(e){return this.clone().iushrn(e)},o.prototype.testn=function(e){n("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,i=1<=0);var t=e%26,r=(e-t)/26;if(n(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var i=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},o.prototype.isubn=function(e){if(n("number"==typeof e),n(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(u/67108864|0),this.words[i+r]=67108863&o}for(;i>26,this.words[i+r]=67108863&o;if(0===s)return this._strip();for(n(-1===s),s=0,i=0;i>26,this.words[i]=67108863&o;return this.negative=1,this._strip()},o.prototype._wordDiv=function(e,t){var r=(this.length,e.length),n=this.clone(),i=e,a=0|i.words[i.length-1];0!==(r=26-this._countBits(a))&&(i=i.ushln(r),n.iushln(r),a=0|i.words[i.length-1]);var s,u=n.length-i.length;if("mod"!==t){(s=new o(null)).length=u+1,s.words=new Array(s.length);for(var c=0;c=0;f--){var l=67108864*(0|n.words[i.length+f])+(0|n.words[i.length+f-1]);for(l=Math.min(l/a|0,67108863),n._ishlnsubmul(i,l,f);0!==n.negative;)l--,n.negative=0,n._ishlnsubmul(i,1,f),n.isZero()||(n.negative^=1);s&&(s.words[f]=l)}return s&&s._strip(),n._strip(),"div"!==t&&0!==r&&n.iushrn(r),{div:s||null,mod:n}},o.prototype.divmod=function(e,t,r){return n(!e.isZero()),this.isZero()?{div:new o(0),mod:new o(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(i=s.div.neg()),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.iadd(e)),{div:i,mod:a}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(i=s.div.neg()),{div:i,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.isub(e)),{div:s.div,mod:a}):e.length>this.length||this.cmp(e)<0?{div:new o(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new o(this.modrn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new o(this.modrn(e.words[0]))}:this._wordDiv(e,t);var i,a,s},o.prototype.div=function(e){return this.divmod(e,"div",!1).div},o.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},o.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},o.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,n=e.ushrn(1),i=e.andln(1),o=r.cmp(n);return o<0||1===i&&0===o?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},o.prototype.modrn=function(e){var t=e<0;t&&(e=-e),n(e<=67108863);for(var r=(1<<26)%e,i=0,o=this.length-1;o>=0;o--)i=(r*i+(0|this.words[o]))%e;return t?-i:i},o.prototype.modn=function(e){return this.modrn(e)},o.prototype.idivn=function(e){var t=e<0;t&&(e=-e),n(e<=67108863);for(var r=0,i=this.length-1;i>=0;i--){var o=(0|this.words[i])+67108864*r;this.words[i]=o/e|0,r=o%e}return this._strip(),t?this.ineg():this},o.prototype.divn=function(e){return this.clone().idivn(e)},o.prototype.egcd=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i=new o(1),a=new o(0),s=new o(0),u=new o(1),c=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++c;for(var h=r.clone(),f=t.clone();!t.isZero();){for(var l=0,d=1;0==(t.words[0]&d)&&l<26;++l,d<<=1);if(l>0)for(t.iushrn(l);l-- >0;)(i.isOdd()||a.isOdd())&&(i.iadd(h),a.isub(f)),i.iushrn(1),a.iushrn(1);for(var p=0,m=1;0==(r.words[0]&m)&&p<26;++p,m<<=1);if(p>0)for(r.iushrn(p);p-- >0;)(s.isOdd()||u.isOdd())&&(s.iadd(h),u.isub(f)),s.iushrn(1),u.iushrn(1);t.cmp(r)>=0?(t.isub(r),i.isub(s),a.isub(u)):(r.isub(t),s.isub(i),u.isub(a))}return{a:s,b:u,gcd:r.iushln(c)}},o.prototype._invmp=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i,a=new o(1),s=new o(0),u=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var c=0,h=1;0==(t.words[0]&h)&&c<26;++c,h<<=1);if(c>0)for(t.iushrn(c);c-- >0;)a.isOdd()&&a.iadd(u),a.iushrn(1);for(var f=0,l=1;0==(r.words[0]&l)&&f<26;++f,l<<=1);if(f>0)for(r.iushrn(f);f-- >0;)s.isOdd()&&s.iadd(u),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),a.isub(s)):(r.isub(t),s.isub(a))}return(i=0===t.cmpn(1)?a:s).cmpn(0)<0&&i.iadd(e),i},o.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var n=0;t.isEven()&&r.isEven();n++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var i=t.cmp(r);if(i<0){var o=t;t=r,r=o}else if(0===i||0===r.cmpn(1))break;t.isub(r)}return r.iushln(n)},o.prototype.invm=function(e){return this.egcd(e).a.umod(e)},o.prototype.isEven=function(){return 0==(1&this.words[0])},o.prototype.isOdd=function(){return 1==(1&this.words[0])},o.prototype.andln=function(e){return this.words[0]&e},o.prototype.bincn=function(e){n("number"==typeof e);var t=e%26,r=(e-t)/26,i=1<>>26,s&=67108863,this.words[a]=s}return 0!==o&&(this.words[a]=o,this.length++),this},o.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},o.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this._strip(),this.length>1)t=1;else{r&&(e=-e),n(e<=67108863,"Number is too big");var i=0|this.words[0];t=i===e?0:ie.length)return 1;if(this.length=0;r--){var n=0|this.words[r],i=0|e.words[r];if(n!==i){ni&&(t=1);break}}return t},o.prototype.gtn=function(e){return 1===this.cmpn(e)},o.prototype.gt=function(e){return 1===this.cmp(e)},o.prototype.gten=function(e){return this.cmpn(e)>=0},o.prototype.gte=function(e){return this.cmp(e)>=0},o.prototype.ltn=function(e){return-1===this.cmpn(e)},o.prototype.lt=function(e){return-1===this.cmp(e)},o.prototype.lten=function(e){return this.cmpn(e)<=0},o.prototype.lte=function(e){return this.cmp(e)<=0},o.prototype.eqn=function(e){return 0===this.cmpn(e)},o.prototype.eq=function(e){return 0===this.cmp(e)},o.red=function(e){return new E(e)},o.prototype.toRed=function(e){return n(!this.red,"Already a number in reduction context"),n(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},o.prototype.fromRed=function(){return n(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},o.prototype._forceRed=function(e){return this.red=e,this},o.prototype.forceRed=function(e){return n(!this.red,"Already a number in reduction context"),this._forceRed(e)},o.prototype.redAdd=function(e){return n(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},o.prototype.redIAdd=function(e){return n(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},o.prototype.redSub=function(e){return n(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},o.prototype.redISub=function(e){return n(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},o.prototype.redShl=function(e){return n(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},o.prototype.redMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},o.prototype.redIMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},o.prototype.redSqr=function(){return n(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},o.prototype.redISqr=function(){return n(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},o.prototype.redSqrt=function(){return n(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},o.prototype.redInvm=function(){return n(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},o.prototype.redNeg=function(){return n(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},o.prototype.redPow=function(e){return n(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var y={k256:null,p224:null,p192:null,p25519:null};function w(e,t){this.name=e,this.p=new o(t,16),this.n=this.p.bitLength(),this.k=new o(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function _(){w.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function S(){w.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function M(){w.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function k(){w.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function E(e){if("string"==typeof e){var t=o._prime(e);this.m=t.p,this.prime=t}else n(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function A(e){E.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new o(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}w.prototype._tmp=function(){var e=new o(null);return e.words=new Array(Math.ceil(this.n/13)),e},w.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var n=t0?r.isub(this.p):void 0!==r.strip?r.strip():r._strip(),r},w.prototype.split=function(e,t){e.iushrn(this.n,0,t)},w.prototype.imulK=function(e){return e.imul(this.k)},i(_,w),_.prototype.split=function(e,t){for(var r=Math.min(e.length,9),n=0;n>>22,i=o}i>>>=22,e.words[n-10]=i,0===i&&e.length>10?e.length-=10:e.length-=9},_.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=i,t=n}return 0!==t&&(e.words[e.length++]=t),e},o._prime=function(e){if(y[e])return y[e];var t;if("k256"===e)t=new _;else if("p224"===e)t=new S;else if("p192"===e)t=new M;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new k}return y[e]=t,t},E.prototype._verify1=function(e){n(0===e.negative,"red works only with positives"),n(e.red,"red works only with red numbers")},E.prototype._verify2=function(e,t){n(0==(e.negative|t.negative),"red works only with positives"),n(e.red&&e.red===t.red,"red works only with red numbers")},E.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):(c(e,e.umod(this.m)._forceRed(this)),e)},E.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},E.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},E.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},E.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},E.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},E.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},E.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},E.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},E.prototype.isqr=function(e){return this.imul(e,e.clone())},E.prototype.sqr=function(e){return this.mul(e,e)},E.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(n(t%2==1),3===t){var r=this.m.add(new o(1)).iushrn(2);return this.pow(e,r)}for(var i=this.m.subn(1),a=0;!i.isZero()&&0===i.andln(1);)a++,i.iushrn(1);n(!i.isZero());var s=new o(1).toRed(this),u=s.redNeg(),c=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new o(2*h*h).toRed(this);0!==this.pow(h,c).cmp(u);)h.redIAdd(u);for(var f=this.pow(h,i),l=this.pow(e,i.addn(1).iushrn(1)),d=this.pow(e,i),p=a;0!==d.cmp(s);){for(var m=d,g=0;0!==m.cmp(s);g++)m=m.redSqr();n(g=0;n--){for(var c=t.words[n],h=u-1;h>=0;h--){var f=c>>h&1;i!==r[0]&&(i=this.sqr(i)),0!==f||0!==a?(a<<=1,a|=f,(4===++s||0===n&&0===h)&&(i=this.mul(i,r[a]),s=0,a=0)):s=0}u=26}return i},E.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},E.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},o.mont=function(e){return new A(e)},i(A,E),A.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},A.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},A.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),o=i;return i.cmp(this.m)>=0?o=i.isub(this.m):i.cmpn(0)<0&&(o=i.iadd(this.m)),o._forceRed(this)},A.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new o(0)._forceRed(this);var r=e.mul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),a=i;return i.cmp(this.m)>=0?a=i.isub(this.m):i.cmpn(0)<0&&(a=i.iadd(this.m)),a._forceRed(this)},A.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(28)(e))},function(e,t,r){"use strict";const n=t;n.bignum=r(6),n.define=r(352).define,n.base=r(355),n.constants=r(356),n.decoders=r(175),n.encoders=r(173)},function(e,t,r){"use strict";const n=t;n.der=r(174),n.pem=r(353)},function(e,t,r){"use strict";const n=r(1),i=r(97).Buffer,o=r(98),a=r(100);function s(e){this.enc="der",this.name=e.name,this.entity=e,this.tree=new u,this.tree._init(e.body)}function u(e){o.call(this,"der",e)}function c(e){return e<10?"0"+e:e}e.exports=s,s.prototype.encode=function(e,t){return this.tree._encode(e,t).join()},n(u,o),u.prototype._encodeComposite=function(e,t,r,n){const o=function(e,t,r,n){let i;"seqof"===e?e="seq":"setof"===e&&(e="set");if(a.tagByName.hasOwnProperty(e))i=a.tagByName[e];else{if("number"!=typeof e||(0|e)!==e)return n.error("Unknown tag: "+e);i=e}if(i>=31)return n.error("Multi-octet tag encoding unsupported");t||(i|=32);return i|=a.tagClassByName[r||"universal"]<<6,i}(e,t,r,this.reporter);if(n.length<128){const e=i.alloc(2);return e[0]=o,e[1]=n.length,this._createEncoderBuffer([e,n])}let s=1;for(let e=n.length;e>=256;e>>=8)s++;const u=i.alloc(2+s);u[0]=o,u[1]=128|s;for(let e=1+s,t=n.length;t>0;e--,t>>=8)u[e]=255&t;return this._createEncoderBuffer([u,n])},u.prototype._encodeStr=function(e,t){if("bitstr"===t)return this._createEncoderBuffer([0|e.unused,e.data]);if("bmpstr"===t){const t=i.alloc(2*e.length);for(let r=0;r=40)return this.reporter.error("Second objid identifier OOB");e.splice(0,2,40*e[0]+e[1])}let n=0;for(let t=0;t=128;r>>=7)n++}const o=i.alloc(n);let a=o.length-1;for(let t=e.length-1;t>=0;t--){let r=e[t];for(o[a--]=127&r;(r>>=7)>0;)o[a--]=128|127&r}return this._createEncoderBuffer(o)},u.prototype._encodeTime=function(e,t){let r;const n=new Date(e);return"gentime"===t?r=[c(n.getUTCFullYear()),c(n.getUTCMonth()+1),c(n.getUTCDate()),c(n.getUTCHours()),c(n.getUTCMinutes()),c(n.getUTCSeconds()),"Z"].join(""):"utctime"===t?r=[c(n.getUTCFullYear()%100),c(n.getUTCMonth()+1),c(n.getUTCDate()),c(n.getUTCHours()),c(n.getUTCMinutes()),c(n.getUTCSeconds()),"Z"].join(""):this.reporter.error("Encoding "+t+" time is not supported yet"),this._encodeStr(r,"octstr")},u.prototype._encodeNull=function(){return this._createEncoderBuffer("")},u.prototype._encodeInt=function(e,t){if("string"==typeof e){if(!t)return this.reporter.error("String int or enum given, but no values map");if(!t.hasOwnProperty(e))return this.reporter.error("Values map doesn't contain: "+JSON.stringify(e));e=t[e]}if("number"!=typeof e&&!i.isBuffer(e)){const t=e.toArray();!e.sign&&128&t[0]&&t.unshift(0),e=i.from(t)}if(i.isBuffer(e)){let t=e.length;0===e.length&&t++;const r=i.alloc(t);return e.copy(r),0===e.length&&(r[0]=0),this._createEncoderBuffer(r)}if(e<128)return this._createEncoderBuffer(e);if(e<256)return this._createEncoderBuffer([0,e]);let r=1;for(let t=e;t>=256;t>>=8)r++;const n=new Array(r);for(let t=n.length-1;t>=0;t--)n[t]=255&e,e>>=8;return 128&n[0]&&n.unshift(0),this._createEncoderBuffer(i.from(n))},u.prototype._encodeBool=function(e){return this._createEncoderBuffer(e?255:0)},u.prototype._use=function(e,t){return"function"==typeof e&&(e=e(t)),e._getEncoder("der").tree},u.prototype._skipDefault=function(e,t,r){const n=this._baseState;let i;if(null===n.default)return!1;const o=e.join();if(void 0===n.defaultBuffer&&(n.defaultBuffer=this._encodeValue(n.default,t,r).join()),o.length!==n.defaultBuffer.length)return!1;for(i=0;i>6],i=0==(32&r);if(31==(31&r)){let n=r;for(r=0;128==(128&n);){if(n=e.readUInt8(t),e.isError(n))return n;r<<=7,r|=127&n}}else r&=31;return{cls:n,primitive:i,tag:r,tagStr:s.tag[r]}}function f(e,t,r){let n=e.readUInt8(r);if(e.isError(n))return n;if(!t&&128===n)return null;if(0==(128&n))return n;const i=127&n;if(i>4)return e.error("length octect is too long");n=0;for(let t=0;t0&&a0&&a0&&(i=n?i+" "+e.buf.toString("hex"):i+" "+e.len+" 0x"+e.buf.toString("hex"));else if(void 0!==s.reverseMap[r])n?0===r?i+=" 0":79===r?i+=" -1":i=i+" "+s(r).toString():i=i+" "+s(r).toString();else{var o=r.toString(16);o.length%2!=0&&(o="0"+o),i=n?i+" "+o:i+" 0x"+o}return i},g.prototype.toASM=function(){for(var e="",t=0;t"},g.prototype.isPublicKeyHashOut=function(){return!(5!==this.chunks.length||this.chunks[0].opcodenum!==s.OP_DUP||this.chunks[1].opcodenum!==s.OP_HASH160||!this.chunks[2].buf||20!==this.chunks[2].buf.length||this.chunks[3].opcodenum!==s.OP_EQUALVERIFY||this.chunks[4].opcodenum!==s.OP_CHECKSIG)},g.prototype.isPublicKeyHashIn=function(){if(2===this.chunks.length){var e=this.chunks[0].buf,t=this.chunks[1].buf;if(e&&e.length&&48===e[0]&&t&&t.length){var r=t[0];if((4===r||6===r||7===r)&&65===t.length)return!0;if((3===r||2===r)&&33===t.length)return!0}}return!1},g.prototype.getPublicKey=function(){return f.checkState(this.isPublicKeyOut(),"Can't retrieve PublicKey from a non-PK output"),this.chunks[0].buf},g.prototype.getPublicKeyHash=function(){if(this.isPublicKeyHashOut())return this.chunks[2].buf;if(this.isWitnessPublicKeyHashOut())return this.chunks[1].buf;throw new Error("Can't retrieve PublicKeyHash from a non-PKH output")},g.prototype.isPublicKeyOut=function(){if(2===this.chunks.length&&this.chunks[0].buf&&this.chunks[0].buf.length&&this.chunks[1].opcodenum===s.OP_CHECKSIG){var e=this.chunks[0].buf,t=e[0],r=!1;if((4!==t&&6!==t&&7!==t||65!==e.length)&&(3!==t&&2!==t||33!==e.length)||(r=!0),r)return u.isValid(e)}return!1},g.prototype.isPublicKeyIn=function(){if(1===this.chunks.length){var e=this.chunks[0].buf;if(e&&e.length&&48===e[0])return!0}return!1},g.prototype.isScriptHashOut=function(){var e=this.toBuffer();return 23===e.length&&e[0]===s.OP_HASH160&&20===e[1]&&e[e.length-1]===s.OP_EQUAL},g.prototype.isWitnessScriptHashOut=function(){var e=this.toBuffer();return 34===e.length&&0===e[0]&&32===e[1]},g.prototype.isWitnessPublicKeyHashOut=function(){var e=this.toBuffer();return 22===e.length&&0===e[0]&&20===e[1]},g.prototype.isWitnessProgram=function(e){e||(e={});var t=this.toBuffer();return!(t.length<4||t.length>42)&&((t[0]===s.OP_0||t[0]>=s.OP_1&&t[0]<=s.OP_16)&&(t.length===t[1]+2&&(e.version=t[0],e.program=t.slice(2,t.length),!0)))},g.prototype.isScriptHashIn=function(){if(this.chunks.length<=1)return!1;var e,t=this.chunks[this.chunks.length-1].buf;if(!t)return!1;try{e=g.fromBuffer(t)}catch(e){if(e instanceof d.Script.InvalidBuffer)return!1;throw e}return e.classify()!==g.types.UNKNOWN},g.prototype.isMultisigOut=function(){return this.chunks.length>3&&s.isSmallIntOp(this.chunks[0].opcodenum)&&this.chunks.slice(1,this.chunks.length-2).every((function(e){return e.buf&&p.isBuffer(e.buf)}))&&s.isSmallIntOp(this.chunks[this.chunks.length-2].opcodenum)&&this.chunks[this.chunks.length-1].opcodenum===s.OP_CHECKMULTISIG},g.prototype.isMultisigIn=function(){return this.chunks.length>=2&&0===this.chunks[0].opcodenum&&this.chunks.slice(1,this.chunks.length).every((function(e){return e.buf&&p.isBuffer(e.buf)&&c.isTxDER(e.buf)}))},g.prototype.isDataOut=function(){return this.chunks.length>=1&&this.chunks[0].opcodenum===s.OP_RETURN&&(1===this.chunks.length||2===this.chunks.length&&this.chunks[1].buf&&this.chunks[1].buf.length<=g.OP_RETURN_STANDARD_SIZE&&this.chunks[1].length===this.chunks.len)},g.prototype.getData=function(){if(this.isDataOut()||this.isScriptHashOut()||this.isWitnessScriptHashOut()||this.isWitnessPublicKeyHashOut())return l.isUndefined(this.chunks[1])?t.alloc(0):t.from(this.chunks[1].buf);if(this.isPublicKeyHashOut())return t.from(this.chunks[2].buf);throw new Error("Unrecognized script type to get data from")},g.prototype.isPushOnly=function(){return l.every(this.chunks,(function(e){return e.opcodenum<=s.OP_16}))},(g.types={}).UNKNOWN="Unknown",g.types.PUBKEY_OUT="Pay to public key",g.types.PUBKEY_IN="Spend from public key",g.types.PUBKEYHASH_OUT="Pay to public key hash",g.types.PUBKEYHASH_IN="Spend from public key hash",g.types.SCRIPTHASH_OUT="Pay to script hash",g.types.SCRIPTHASH_IN="Spend from script hash",g.types.MULTISIG_OUT="Pay to multisig",g.types.MULTISIG_IN="Spend from multisig",g.types.DATA_OUT="Data push",g.OP_RETURN_STANDARD_SIZE=80,g.prototype.classify=function(){if(this._isInput)return this.classifyInput();if(this._isOutput)return this.classifyOutput();var e=this.classifyOutput();return e!=g.types.UNKNOWN?e:this.classifyInput()},(g.outputIdentifiers={}).PUBKEY_OUT=g.prototype.isPublicKeyOut,g.outputIdentifiers.PUBKEYHASH_OUT=g.prototype.isPublicKeyHashOut,g.outputIdentifiers.MULTISIG_OUT=g.prototype.isMultisigOut,g.outputIdentifiers.SCRIPTHASH_OUT=g.prototype.isScriptHashOut,g.outputIdentifiers.DATA_OUT=g.prototype.isDataOut,g.prototype.classifyOutput=function(){for(var e in g.outputIdentifiers)if(g.outputIdentifiers[e].bind(this)())return g.types[e];return g.types.UNKNOWN},(g.inputIdentifiers={}).PUBKEY_IN=g.prototype.isPublicKeyIn,g.inputIdentifiers.PUBKEYHASH_IN=g.prototype.isPublicKeyHashIn,g.inputIdentifiers.MULTISIG_IN=g.prototype.isMultisigIn,g.inputIdentifiers.SCRIPTHASH_IN=g.prototype.isScriptHashIn,g.prototype.classifyInput=function(){for(var e in g.inputIdentifiers)if(g.inputIdentifiers[e].bind(this)())return g.types[e];return g.types.UNKNOWN},g.prototype.isStandard=function(){return this.classify()!==g.types.UNKNOWN},g.prototype.prepend=function(e){return this._addByType(e,!0),this},g.prototype.equals=function(e){if(f.checkState(e instanceof g,"Must provide another script"),this.chunks.length!==e.chunks.length)return!1;var t;for(t=0;t=0&&n=1&&r[0]<=16?n===s.OP_1+(r[0]-1):1===r.length&&129===r[0]?n===s.OP_1NEGATE:r.length<=75?n===r.length:r.length<=255?n===s.OP_PUSHDATA1:!(r.length<=65535)||n===s.OP_PUSHDATA2)},g.prototype._decodeOP_N=function(e){if(e===s.OP_0)return 0;if(e>=s.OP_1&&e<=s.OP_16)return e-(s.OP_1-1);throw new Error("Invalid opcode: "+JSON.stringify(e))},g.prototype.getSignatureOperationsCount=function(e){e=!!l.isUndefined(e)||e;var t=this,r=0,n=s.OP_INVALIDOPCODE;return l.each(t.chunks,(function(i){var o=i.opcodenum;o==s.OP_CHECKSIG||o==s.OP_CHECKSIGVERIFY?r++:o!=s.OP_CHECKMULTISIG&&o!=s.OP_CHECKMULTISIGVERIFY||(e&&n>=s.OP_1&&n<=s.OP_16?r+=t._decodeOP_N(n):r+=20),n=o})),r},e.exports=g}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n=r(3),i=r(4),o=r(7),a=r(14),s=r(20),u=r(104);function c(e){if(!(this instanceof c))return new c(e);i.checkArgument(n.isObject(e),"Must provide an object from where to extract data");var t=e.address?new s(e.address):void 0,r=e.txid?e.txid:e.txId;if(!r||!o.isHexaString(r)||r.length>64)throw new Error("Invalid TXID in object",e);var h=n.isUndefined(e.vout)?e.outputIndex:e.vout;if(!n.isNumber(h))throw new Error("Invalid outputIndex, received "+h);i.checkArgument(!n.isUndefined(e.scriptPubKey)||!n.isUndefined(e.script),"Must provide the scriptPubKey for that output!");var f=new a(e.scriptPubKey||e.script);i.checkArgument(!n.isUndefined(e.amount)||!n.isUndefined(e.satoshis),"Must provide an amount for the output");var l=n.isUndefined(e.amount)?e.satoshis:new u.fromBTC(e.amount).toSatoshis();i.checkArgument(n.isNumber(l),"Amount must be a number"),o.defineImmutable(this,{address:t,txId:r,outputIndex:h,script:f,satoshis:l})}c.prototype.inspect=function(){return""},c.prototype.toString=function(){return this.txId+":"+this.outputIndex},c.fromObject=function(e){return new c(e)},c.prototype.toObject=c.prototype.toJSON=function(){return{address:this.address?this.address.toString():void 0,txid:this.txId,vout:this.outputIndex,scriptPubKey:this.script.toBuffer().toString("hex"),amount:u.fromSatoshis(this.satoshis).toBTC()}},e.exports=c},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(69),o=r(5),a=r(21),s=r(12),u=r(11),c=(r(7),r(66)),h=r(17),f=r(4);function l(e){if(!(this instanceof l))return new l(e);var t={};if(o.isBuffer(e))t=l._fromBufferReader(a(e));else{if(!n.isObject(e))throw new TypeError("Unrecognized argument for MerkleBlock");t={header:e.header instanceof i?e.header:i.fromObject(e.header),numTransactions:e.numTransactions,hashes:e.hashes,flags:e.flags}}return n.extend(this,t),this._flagBitsUsed=0,this._hashesUsed=0,this}l.fromBuffer=function(e){return l.fromBufferReader(a(e))},l.fromBufferReader=function(e){return new l(l._fromBufferReader(e))},l.prototype.toBuffer=function(){return this.toBufferWriter().concat()},l.prototype.toBufferWriter=function(e){e||(e=new s),e.write(this.header.toBuffer()),e.writeUInt32LE(this.numTransactions),e.writeVarintNum(this.hashes.length);for(var r=0;rthis.numTransactions)return!1;if(8*this.flags.lengththis.numTransactions)throw new h.MerkleBlock.InvalidMerkleTree;if(8*this.flags.length8*this.flags.length)return null;var o=this.flags[n.flagBitsUsed>>3]>>>(7&n.flagBitsUsed++)&1;if(0!==e&&o){var a=this._traverseMerkleTree(e-1,2*r,n),s=a;return 2*r+1=this.hashes.length)return null;var c=this.hashes[n.hashesUsed++];return 0===e&&o&&n.txs.push(c),t.from(c,"hex")},l.prototype._calcTreeWidth=function(e){return this.numTransactions+(1<>e},l.prototype._calcTreeHeight=function(){for(var e=0;this._calcTreeWidth(e)>1;)e++;return e},l.prototype.hasTransaction=function(e){f.checkArgument(!n.isUndefined(e),"tx cannot be undefined"),f.checkArgument(e instanceof c||"string"==typeof e,'Invalid tx given, tx must be a "string" or "Transaction"');var r=e;e instanceof c&&(r=o.reverse(t.from(e.id,"hex")).toString("hex"));var i=[],a=this._calcTreeHeight();return this._traverseMerkleTree(a,0,{txs:i}),-1!==i.indexOf(r)},l._fromBufferReader=function(e){f.checkState(!e.finished(),"No merkleblock data received");var t={};t.header=i.fromBufferReader(e),t.numTransactions=e.readUInt32LE();var r=e.readVarintNum();t.hashes=[];for(var n=0;n=0&&e=y.Hardened||r,e64)throw new g.InvalidEntropyArgument.TooMuchEntropy(e);var n=h.sha512hmac(e,t.from("Bitcoin seed"));return new y({network:f.get(r)||f.defaultNetwork,depth:0,parentFingerPrint:0,childIndex:0,privateKey:n.slice(0,32),chainCode:n.slice(32,64)})},y.prototype._calcHDPublicKey=function(){if(!this._hdPublicKey){var e=r(185);this._hdPublicKey=new e(this)}},y.prototype._buildFromBuffers=function(e){y._validateBufferArguments(e),v.defineImmutable(this,{_buffers:e});var r=[e.version,e.depth,e.parentFingerPrint,e.childIndex,e.chainCode,b.emptyBuffer(1),e.privateKey],n=i.Buffer.concat(r);if(e.checksum&&e.checksum.length){if(e.checksum.toString()!==c.checksum(n).toString())throw new m.InvalidB58Checksum(n)}else e.checksum=c.checksum(n);var o,a=f.get(b.integerFromBuffer(e.version));o=c.encode(i.Buffer.concat(r)),e.xprivkey=t.from(o);var u=new d(s.fromBuffer(e.privateKey),a),l=u.toPublicKey(),p=y.ParentFingerPrintSize,g=h.sha256ripemd160(l.toBuffer()).slice(0,p);return v.defineImmutable(this,{xprivkey:o,network:a,depth:b.integerFromSingleByteBuffer(e.depth),privateKey:u,publicKey:l,fingerPrint:g}),this._hdPublicKey=null,Object.defineProperty(this,"hdPublicKey",{configurable:!1,enumerable:!0,get:function(){return this._calcHDPublicKey(),this._hdPublicKey}}),Object.defineProperty(this,"xpubkey",{configurable:!1,enumerable:!0,get:function(){return this._calcHDPublicKey(),this._hdPublicKey.xpubkey}}),this},y._validateBufferArguments=function(e){var t=function(t,r){var i=e[t];n(b.isBuffer(i),t+" argument is not a buffer"),n(i.length===r,t+" has not the expected size: found "+i.length+", expected "+r)};t("version",y.VersionSize),t("depth",y.DepthSize),t("parentFingerPrint",y.ParentFingerPrintSize),t("childIndex",y.ChildIndexSize),t("chainCode",y.ChainCodeSize),t("privateKey",y.PrivateKeySize),e.checksum&&e.checksum.length&&t("checksum",y.CheckSumSize)},y.prototype.toString=function(){return this.xprivkey},y.prototype.inspect=function(){return""},y.prototype.toObject=y.prototype.toJSON=function(){return{network:f.get(b.integerFromBuffer(this._buffers.version),"xprivkey").name,depth:b.integerFromSingleByteBuffer(this._buffers.depth),fingerPrint:b.integerFromBuffer(this.fingerPrint),parentFingerPrint:b.integerFromBuffer(this._buffers.parentFingerPrint),childIndex:b.integerFromBuffer(this._buffers.childIndex),chainCode:b.bufferToHex(this._buffers.chainCode),privateKey:this.privateKey.toBuffer().toString("hex"),checksum:b.integerFromBuffer(this._buffers.checksum),xprivkey:this.xprivkey}},y.fromBuffer=function(e){return new y(e.toString())},y.prototype.toBuffer=function(){return b.copy(this._buffers.xprivkey)},y.DefaultDepth=0,y.DefaultFingerprint=0,y.DefaultChildIndex=0,y.Hardened=2147483648,y.MaxIndex=2*y.Hardened,y.RootElementAlias=["m","M","m'","M'"],y.VersionSize=4,y.DepthSize=1,y.ParentFingerPrintSize=4,y.ChildIndexSize=4,y.ChainCodeSize=32,y.PrivateKeySize=32,y.CheckSumSize=4,y.DataLength=78,y.SerializedByteSize=82,y.VersionStart=0,y.VersionEnd=y.VersionStart+y.VersionSize,y.DepthStart=y.VersionEnd,y.DepthEnd=y.DepthStart+y.DepthSize,y.ParentFingerPrintStart=y.DepthEnd,y.ParentFingerPrintEnd=y.ParentFingerPrintStart+y.ParentFingerPrintSize,y.ChildIndexStart=y.ParentFingerPrintEnd,y.ChildIndexEnd=y.ChildIndexStart+y.ChildIndexSize,y.ChainCodeStart=y.ChildIndexEnd,y.ChainCodeEnd=y.ChainCodeStart+y.ChainCodeSize,y.PrivateKeyStart=y.ChainCodeEnd+1,y.PrivateKeyEnd=y.PrivateKeyStart+y.PrivateKeySize,y.ChecksumStart=y.PrivateKeyEnd,y.ChecksumEnd=y.ChecksumStart+y.CheckSumSize,n(y.ChecksumEnd===y.SerializedByteSize),e.exports=y}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(4),o=r(10),a=r(65),s=r(49),u=r(11),c=r(184),h=r(32),f=r(38),l=r(19),d=r(17),p=d,m=d.HDPublicKey,g=r(45),b=r(7),v=r(5);function y(e){if(e instanceof y)return e;if(!(this instanceof y))return new y(e);if(e){if(n.isString(e)||v.isBuffer(e)){var t=y.getSerializedError(e);if(t){if(v.isBuffer(e)&&!y.getSerializedError(e.toString()))return this._buildFromSerialized(e.toString());if(t instanceof m.ArgumentIsPrivateExtended)return new c(e).hdPublicKey;throw t}return this._buildFromSerialized(e)}if(n.isObject(e))return e instanceof c?this._buildFromPrivate(e):this._buildFromObject(e);throw new m.UnrecognizedArgument(e)}throw new m.MustSupplyArgument}y.isValidPath=function(e){if(n.isString(e)){var t=c._getDerivationIndexes(e);return null!==t&&n.every(t,y.isValidPath)}return!!n.isNumber(e)&&(e>=0&&e=y.Hardened||t)throw new m.InvalidIndexCantDeriveHardened;if(e<0)throw new m.InvalidPath(e);var r,n=v.integerAsBuffer(e),i=v.concat([this.publicKey.toBuffer(),n]),a=u.sha512hmac(i,this._buffers.chainCode),s=o.fromBuffer(a.slice(0,32),{size:32}),c=a.slice(32,64);try{r=l.fromPoint(f.getG().mul(s).add(this.publicKey.point))}catch(t){return this._deriveWithNumber(e+1)}return new y({network:this.network,depth:this.depth+1,parentFingerPrint:this.fingerPrint,childIndex:e,chainCode:c,publicKey:r})},y.prototype._deriveFromString=function(e){if(n.includes(e,"'"))throw new m.InvalidIndexCantDeriveHardened;if(!y.isValidPath(e))throw new m.InvalidPath(e);return c._getDerivationIndexes(e).reduce((function(e,t){return e._deriveWithNumber(t)}),this)},y.isValidSerialized=function(e,t){return n.isNull(y.getSerializedError(e,t))},y.getSerializedError=function(e,t){if(!n.isString(e)&&!v.isBuffer(e))return new m.UnrecognizedArgument("expected buffer or string");if(!a.validCharacters(e))return new p.InvalidB58Char("(unknown)",e);try{e=s.decode(e)}catch(t){return new p.InvalidB58Checksum(e)}if(e.length!==y.DataSize)return new m.InvalidLength(e);if(!n.isUndefined(t)){var r=y._validateNetwork(e,t);if(r)return r}var i=v.integerFromBuffer(e.slice(0,4));return i===h.livenet.xprivkey||i===h.testnet.xprivkey?new m.ArgumentIsPrivateExtended:null},y._validateNetwork=function(e,t){var r=h.get(t);if(!r)return new p.InvalidNetworkArgument(t);var n=e.slice(y.VersionStart,y.VersionEnd);return v.integerFromBuffer(n)!==r.xpubkey?new p.InvalidNetwork(n):null},y.prototype._buildFromPrivate=function(e){var t=n.clone(e._buffers),r=f.getG().mul(o.fromBuffer(t.privateKey));return t.publicKey=f.pointToCompressed(r),t.version=v.integerAsBuffer(h.get(v.integerFromBuffer(t.version)).xpubkey),t.privateKey=void 0,t.checksum=void 0,t.xprivkey=void 0,this._buildFromBuffers(t)},y.prototype._buildFromObject=function(e){var r={version:e.network?v.integerAsBuffer(h.get(e.network).xpubkey):e.version,depth:n.isNumber(e.depth)?v.integerAsSingleByteBuffer(e.depth):e.depth,parentFingerPrint:n.isNumber(e.parentFingerPrint)?v.integerAsBuffer(e.parentFingerPrint):e.parentFingerPrint,childIndex:n.isNumber(e.childIndex)?v.integerAsBuffer(e.childIndex):e.childIndex,chainCode:n.isString(e.chainCode)?t.from(e.chainCode,"hex"):e.chainCode,publicKey:n.isString(e.publicKey)?t.from(e.publicKey,"hex"):v.isBuffer(e.publicKey)?e.publicKey:e.publicKey.toBuffer(),checksum:n.isNumber(e.checksum)?v.integerAsBuffer(e.checksum):e.checksum};return this._buildFromBuffers(r)},y.prototype._buildFromSerialized=function(e){var t=s.decode(e),r={version:t.slice(y.VersionStart,y.VersionEnd),depth:t.slice(y.DepthStart,y.DepthEnd),parentFingerPrint:t.slice(y.ParentFingerPrintStart,y.ParentFingerPrintEnd),childIndex:t.slice(y.ChildIndexStart,y.ChildIndexEnd),chainCode:t.slice(y.ChainCodeStart,y.ChainCodeEnd),publicKey:t.slice(y.PublicKeyStart,y.PublicKeyEnd),checksum:t.slice(y.ChecksumStart,y.ChecksumEnd),xpubkey:e};return this._buildFromBuffers(r)},y.prototype._buildFromBuffers=function(e){y._validateBufferArguments(e),b.defineImmutable(this,{_buffers:e});var r=[e.version,e.depth,e.parentFingerPrint,e.childIndex,e.chainCode,e.publicKey],n=v.concat(r),i=s.checksum(n);if(e.checksum&&e.checksum.length){if(e.checksum.toString("hex")!==i.toString("hex"))throw new p.InvalidB58Checksum(n,i)}else e.checksum=i;var o,a=h.get(v.integerFromBuffer(e.version));o=s.encode(v.concat(r)),e.xpubkey=t.from(o);var c=new l(e.publicKey,{network:a}),f=y.ParentFingerPrintSize,d=u.sha256ripemd160(c.toBuffer()).slice(0,f);return b.defineImmutable(this,{xpubkey:o,network:a,depth:v.integerFromSingleByteBuffer(e.depth),publicKey:c,fingerPrint:d}),this},y._validateBufferArguments=function(e){var t=function(t,r){var n=e[t];g(v.isBuffer(n),t+" argument is not a buffer, it's "+typeof n),g(n.length===r,t+" has not the expected size: found "+n.length+", expected "+r)};t("version",y.VersionSize),t("depth",y.DepthSize),t("parentFingerPrint",y.ParentFingerPrintSize),t("childIndex",y.ChildIndexSize),t("chainCode",y.ChainCodeSize),t("publicKey",y.PublicKeySize),e.checksum&&e.checksum.length&&t("checksum",y.CheckSumSize)},y.fromString=function(e){return i.checkArgument(n.isString(e),"No valid string was provided"),new y(e)},y.fromObject=function(e){return i.checkArgument(n.isObject(e),"No valid argument was provided"),new y(e)},y.prototype.toString=function(){return this.xpubkey},y.prototype.inspect=function(){return""},y.prototype.toObject=y.prototype.toJSON=function(){return{network:h.get(v.integerFromBuffer(this._buffers.version)).name,depth:v.integerFromSingleByteBuffer(this._buffers.depth),fingerPrint:v.integerFromBuffer(this.fingerPrint),parentFingerPrint:v.integerFromBuffer(this._buffers.parentFingerPrint),childIndex:v.integerFromBuffer(this._buffers.childIndex),chainCode:v.bufferToHex(this._buffers.chainCode),publicKey:this.publicKey.toString(),checksum:v.integerFromBuffer(this._buffers.checksum),xpubkey:this.xpubkey}},y.fromBuffer=function(e){return new y(e)},y.prototype.toBuffer=function(){return v.copy(this._buffers.xpubkey)},y.Hardened=2147483648,y.RootElementAlias=["m","M"],y.VersionSize=4,y.DepthSize=1,y.ParentFingerPrintSize=4,y.ChildIndexSize=4,y.ChainCodeSize=32,y.PublicKeySize=33,y.CheckSumSize=4,y.DataSize=78,y.SerializedByteSize=82,y.VersionStart=0,y.VersionEnd=y.VersionStart+y.VersionSize,y.DepthStart=y.VersionEnd,y.DepthEnd=y.DepthStart+y.DepthSize,y.ParentFingerPrintStart=y.DepthEnd,y.ParentFingerPrintEnd=y.ParentFingerPrintStart+y.ParentFingerPrintSize,y.ChildIndexStart=y.ParentFingerPrintEnd,y.ChildIndexEnd=y.ChildIndexStart+y.ChildIndexSize,y.ChainCodeStart=y.ChildIndexEnd,y.ChainCodeEnd=y.ChainCodeStart+y.ChainCodeSize,y.PublicKeyStart=y.ChainCodeEnd,y.PublicKeyEnd=y.PublicKeyStart+y.PublicKeySize,y.ChecksumStart=y.PublicKeyEnd,y.ChecksumEnd=y.ChecksumStart+y.CheckSumSize,g(y.PublicKeyEnd===y.DataSize),g(y.ChecksumEnd===y.SerializedByteSize),e.exports=y}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),i=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.hasOwnProperty.call(e,r)&&n(t,e,r);return i(t,e),t},a=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},s=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]t.permissionName===e)}catch(e){return console.log("Failed to obtain installed plugins",e),!1}}))}},function(e,t,r){e.exports=r(105)},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},i=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0?a-4:a;for(r=0;r>16&255,u[h++]=t>>8&255,u[h++]=255&t;2===s&&(t=i[e.charCodeAt(r)]<<2|i[e.charCodeAt(r+1)]>>4,u[h++]=255&t);1===s&&(t=i[e.charCodeAt(r)]<<10|i[e.charCodeAt(r+1)]<<4|i[e.charCodeAt(r+2)]>>2,u[h++]=t>>8&255,u[h++]=255&t);return u},t.fromByteArray=function(e){for(var t,r=e.length,i=r%3,o=[],a=0,s=r-i;as?s:a+16383));1===i?(t=e[r-1],o.push(n[t>>2]+n[t<<4&63]+"==")):2===i&&(t=(e[r-2]<<8)+e[r-1],o.push(n[t>>10]+n[t>>4&63]+n[t<<2&63]+"="));return o.join("")};for(var n=[],i=[],o="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0,u=a.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function h(e,t,r){for(var i,o,a=[],s=t;s>18&63]+n[o>>12&63]+n[o>>6&63]+n[63&o]);return a.join("")}i["-".charCodeAt(0)]=62,i["_".charCodeAt(0)]=63},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))},i=this&&this.__generator||function(e,t){var r,n,i,o,a={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function s(o){return function(s){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,n&&(i=2&o[0]?n.return:o[0]?n.throw||((i=n.return)&&i.call(n),0):n.next)&&!(i=i.call(n,o[1])).done)return i;switch(n=0,i&&(o=[2&o[0],i.value]),o[0]){case 0:case 1:i=o;break;case 4:return a.label++,{value:o[1],done:!1};case 5:a.label++,n=o[1],o=[0];continue;case 7:o=a.ops.pop(),a.trys.pop();continue;default:if(!(i=a.trys,(i=i.length>0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]c(e.toString(2),"0",8)).join("")}function l(e){const t=8*e.length/32;return f([...n("sha256").update(e).digest()]).slice(0,t)}function d(e){return"mnemonic"+(e||"")}function p(t,r){if(!(r=r||s))throw new Error(u);const n=(t||"").normalize("NFKD").split(" ");if(n.length%3!=0)throw new Error("Invalid mnemonic");const i=n.map(e=>{const t=r.indexOf(e);if(-1===t)throw new Error("Invalid mnemonic");return c(t.toString(2),"0",11)}).join(""),o=32*Math.floor(i.length/33),a=i.slice(0,o),f=i.slice(o),d=a.match(/(.{1,8})/g).map(h);if(d.length<16)throw new Error("Invalid entropy");if(d.length>32)throw new Error("Invalid entropy");if(d.length%4!=0)throw new Error("Invalid entropy");const p=e.from(d);if(l(p)!==f)throw new Error("Invalid mnemonic checksum");return p.toString("hex")}function m(t,r){if(e.isBuffer(t)||(t=e.from(t,"hex")),!(r=r||s))throw new Error(u);if(t.length<16)throw new TypeError("Invalid entropy");if(t.length>32)throw new TypeError("Invalid entropy");if(t.length%4!=0)throw new TypeError("Invalid entropy");const n=(f([...t])+l(t)).match(/(.{1,11})/g).map(e=>{const t=h(e);return r[t]});return"あいこくしん"===r[0]?n.join(" "):n.join(" ")}t.mnemonicToSeedSync=function(t,r){const n=e.from((t||"").normalize("NFKD"),"utf8"),o=e.from(d((r||"").normalize("NFKD")),"utf8");return i.pbkdf2Sync(n,o,2048,64,"sha512")},t.mnemonicToSeed=function(t,r){return new Promise((n,o)=>{try{const a=e.from((t||"").normalize("NFKD"),"utf8"),s=e.from(d((r||"").normalize("NFKD")),"utf8");i.pbkdf2(a,s,2048,64,"sha512",(e,t)=>e?o(e):n(t))}catch(e){return o(e)}})},t.mnemonicToEntropy=p,t.entropyToMnemonic=m,t.generateMnemonic=function(e,t,r){if((e=e||128)%32!=0)throw new TypeError("Invalid entropy");return m((t=t||o)(e/8),r)},t.validateMnemonic=function(e,t){try{p(e,t)}catch(e){return!1}return!0},t.setDefaultWordlist=function(e){const t=a.wordlists[e];if(!t)throw new Error('Could not find wordlist for language "'+e+'"');s=t},t.getDefaultWordlist=function(){if(!s)throw new Error("No Default Wordlist set");return Object.keys(a.wordlists).filter(e=>"JA"!==e&&"EN"!==e&&a.wordlists[e].every((e,t)=>e===s[t]))[0]};var g=r(132);t.wordlists=g.wordlists}).call(this,r(0).Buffer)},function(e,t){},function(e,t,r){"use strict";function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){for(var r=0;r0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:"unshift",value:function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length}},{key:"shift",value:function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(e){if(0===this.length)return"";for(var t=this.head,r=""+t.data;t=t.next;)r+=e+t.data;return r}},{key:"concat",value:function(e){if(0===this.length)return a.alloc(0);for(var t,r,n,i=a.allocUnsafe(e>>>0),o=this.head,s=0;o;)t=o.data,r=i,n=s,a.prototype.copy.call(t,r,n),s+=o.data.length,o=o.next;return i}},{key:"consume",value:function(e,t){var r;return ei.length?i.length:e;if(o===i.length?n+=i:n+=i.slice(0,e),0==(e-=o)){o===i.length?(++r,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=i.slice(o));break}++r}return this.length-=r,n}},{key:"_getBuffer",value:function(e){var t=a.allocUnsafe(e),r=this.head,n=1;for(r.data.copy(t),e-=r.data.length;r=r.next;){var i=r.data,o=e>i.length?i.length:e;if(i.copy(t,t.length-e,0,o),0==(e-=o)){o===i.length?(++n,r.next?this.head=r.next:this.head=this.tail=null):(this.head=r,r.data=i.slice(o));break}++n}return this.length-=n,t}},{key:u,value:function(e,t){return s(this,function(e){for(var t=1;t0,(function(e){n||(n=e),e&&a.forEach(c),o||(a.forEach(c),i(n))}))}));return t.reduce(h)}},function(e,t,r){var n=r(1),i=r(37),o=r(2).Buffer,a=[1518500249,1859775393,-1894007588,-899497514],s=new Array(80);function u(){this.init(),this._w=s,i.call(this,64,56)}function c(e){return e<<30|e>>>2}function h(e,t,r,n){return 0===e?t&r|~t&n:2===e?t&r|t&n|r&n:t^r^n}n(u,i),u.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this},u.prototype._update=function(e){for(var t,r=this._w,n=0|this._a,i=0|this._b,o=0|this._c,s=0|this._d,u=0|this._e,f=0;f<16;++f)r[f]=e.readInt32BE(4*f);for(;f<80;++f)r[f]=r[f-3]^r[f-8]^r[f-14]^r[f-16];for(var l=0;l<80;++l){var d=~~(l/20),p=0|((t=n)<<5|t>>>27)+h(d,i,o,s)+u+r[l]+a[d];u=s,s=o,o=c(i),i=n,n=p}this._a=n+this._a|0,this._b=i+this._b|0,this._c=o+this._c|0,this._d=s+this._d|0,this._e=u+this._e|0},u.prototype._hash=function(){var e=o.allocUnsafe(20);return e.writeInt32BE(0|this._a,0),e.writeInt32BE(0|this._b,4),e.writeInt32BE(0|this._c,8),e.writeInt32BE(0|this._d,12),e.writeInt32BE(0|this._e,16),e},e.exports=u},function(e,t,r){var n=r(1),i=r(37),o=r(2).Buffer,a=[1518500249,1859775393,-1894007588,-899497514],s=new Array(80);function u(){this.init(),this._w=s,i.call(this,64,56)}function c(e){return e<<5|e>>>27}function h(e){return e<<30|e>>>2}function f(e,t,r,n){return 0===e?t&r|~t&n:2===e?t&r|t&n|r&n:t^r^n}n(u,i),u.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this},u.prototype._update=function(e){for(var t,r=this._w,n=0|this._a,i=0|this._b,o=0|this._c,s=0|this._d,u=0|this._e,l=0;l<16;++l)r[l]=e.readInt32BE(4*l);for(;l<80;++l)r[l]=(t=r[l-3]^r[l-8]^r[l-14]^r[l-16])<<1|t>>>31;for(var d=0;d<80;++d){var p=~~(d/20),m=c(n)+f(p,i,o,s)+u+r[d]+a[p]|0;u=s,s=o,o=h(i),i=n,n=m}this._a=n+this._a|0,this._b=i+this._b|0,this._c=o+this._c|0,this._d=s+this._d|0,this._e=u+this._e|0},u.prototype._hash=function(){var e=o.allocUnsafe(20);return e.writeInt32BE(0|this._a,0),e.writeInt32BE(0|this._b,4),e.writeInt32BE(0|this._c,8),e.writeInt32BE(0|this._d,12),e.writeInt32BE(0|this._e,16),e},e.exports=u},function(e,t,r){var n=r(1),i=r(120),o=r(37),a=r(2).Buffer,s=new Array(64);function u(){this.init(),this._w=s,o.call(this,64,56)}n(u,i),u.prototype.init=function(){return this._a=3238371032,this._b=914150663,this._c=812702999,this._d=4144912697,this._e=4290775857,this._f=1750603025,this._g=1694076839,this._h=3204075428,this},u.prototype._hash=function(){var e=a.allocUnsafe(28);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e},e.exports=u},function(e,t,r){var n=r(1),i=r(121),o=r(37),a=r(2).Buffer,s=new Array(160);function u(){this.init(),this._w=s,o.call(this,128,112)}n(u,i),u.prototype.init=function(){return this._ah=3418070365,this._bh=1654270250,this._ch=2438529370,this._dh=355462360,this._eh=1731405415,this._fh=2394180231,this._gh=3675008525,this._hh=1203062813,this._al=3238371032,this._bl=914150663,this._cl=812702999,this._dl=4144912697,this._el=4290775857,this._fl=1750603025,this._gl=1694076839,this._hl=3204075428,this},u.prototype._hash=function(){var e=a.allocUnsafe(48);function t(t,r,n){e.writeInt32BE(t,n),e.writeInt32BE(r,n+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),e},e.exports=u},function(e,t,r){e.exports=i;var n=r(27).EventEmitter;function i(){n.call(this)}r(1)(i,n),i.Readable=r(76),i.Writable=r(227),i.Duplex=r(228),i.Transform=r(229),i.PassThrough=r(230),i.Stream=i,i.prototype.pipe=function(e,t){var r=this;function i(t){e.writable&&!1===e.write(t)&&r.pause&&r.pause()}function o(){r.readable&&r.resume&&r.resume()}r.on("data",i),e.on("drain",o),e._isStdio||t&&!1===t.end||(r.on("end",s),r.on("close",u));var a=!1;function s(){a||(a=!0,e.end())}function u(){a||(a=!0,"function"==typeof e.destroy&&e.destroy())}function c(e){if(h(),0===n.listenerCount(this,"error"))throw e}function h(){r.removeListener("data",i),e.removeListener("drain",o),r.removeListener("end",s),r.removeListener("close",u),r.removeListener("error",c),e.removeListener("error",c),r.removeListener("end",h),r.removeListener("close",h),e.removeListener("close",h)}return r.on("error",c),e.on("error",c),r.on("end",h),r.on("close",h),e.on("close",h),e.emit("pipe",r),e}},function(e,t){},function(e,t,r){"use strict";var n=r(77).Buffer,i=r(224);e.exports=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,r=""+t.data;t=t.next;)r+=e+t.data;return r},e.prototype.concat=function(e){if(0===this.length)return n.alloc(0);if(1===this.length)return this.head.data;for(var t,r,i,o=n.allocUnsafe(e>>>0),a=this.head,s=0;a;)t=a.data,r=o,i=s,t.copy(r,i),s+=a.data.length,a=a.next;return o},e}(),i&&i.inspect&&i.inspect.custom&&(e.exports.prototype[i.inspect.custom]=function(){var e=i.inspect({length:this.length});return this.constructor.name+" "+e})},function(e,t){},function(e,t,r){(function(e,t){!function(e,r){"use strict";if(!e.setImmediate){var n,i,o,a,s,u=1,c={},h=!1,f=e.document,l=Object.getPrototypeOf&&Object.getPrototypeOf(e);l=l&&l.setTimeout?l:e,"[object process]"==={}.toString.call(e.process)?n=function(e){t.nextTick((function(){p(e)}))}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,r=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=r,t}}()?e.MessageChannel?((o=new MessageChannel).port1.onmessage=function(e){p(e.data)},n=function(e){o.port2.postMessage(e)}):f&&"onreadystatechange"in f.createElement("script")?(i=f.documentElement,n=function(e){var t=f.createElement("script");t.onreadystatechange=function(){p(e),t.onreadystatechange=null,i.removeChild(t),t=null},i.appendChild(t)}):n=function(e){setTimeout(p,0,e)}:(a="setImmediate$"+Math.random()+"$",s=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(a)&&p(+t.data.slice(a.length))},e.addEventListener?e.addEventListener("message",s,!1):e.attachEvent("onmessage",s),n=function(t){e.postMessage(a+t,"*")}),l.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r=2147483648,i=e.allocUnsafe(37);if(r){if(this.isNeutered())throw new TypeError("Missing private key for hardened child key");i[0]=0,this.privateKey.copy(i,1),i.writeUInt32BE(t,33)}else this.publicKey.copy(i,0),i.writeUInt32BE(t,33);const s=n.hmacSHA512(this.chainCode,i),u=s.slice(0,32),c=s.slice(32);if(!o.isPrivate(u))return this.derive(t+1);let h;if(this.isNeutered()){const e=o.pointAddScalar(this.publicKey,u,!0);if(null===e)return this.derive(t+1);h=b(e,c,this.network,this.depth+1,t,this.fingerprint.readUInt32BE(0))}else{const e=o.privateAdd(this.privateKey,u);if(null==e)return this.derive(t+1);h=g(e,c,this.network,this.depth+1,t,this.fingerprint.readUInt32BE(0))}return h}deriveHardened(e){return a(d,e),this.derive(e+2147483648)}derivePath(e){a(l,e);let t=e.split("/");if("m"===t[0]){if(this.parentFingerprint)throw new TypeError("Expected master, got child");t=t.slice(1)}return t.reduce((e,t)=>{let r;return"'"===t.slice(-1)?(r=parseInt(t.slice(0,-1),10),e.deriveHardened(r)):(r=parseInt(t,10),e.derive(r))},this)}sign(t,r){if(!this.privateKey)throw new Error("Missing private key");if(void 0===r&&(r=this.lowR),!1===r)return o.sign(t,this.privateKey);{let r=o.sign(t,this.privateKey);const n=e.alloc(32,0);let i=0;for(;r[0]>127;)i++,n.writeUIntLE(i,0,6),r=o.signWithEntropy(t,this.privateKey,n);return r}}verify(e,t){return o.verify(e,this.publicKey,t)}}function m(e,t,r){return g(e,t,r)}function g(e,t,r,n,i,s){if(a({privateKey:u,chainCode:u},{privateKey:e,chainCode:t}),r=r||h,!o.isPrivate(e))throw new TypeError("Private key not in range [1, n)");return new p(e,void 0,t,r,n,i,s)}function b(e,t,r,n,i,s){if(a({publicKey:a.BufferN(33),chainCode:u},{publicKey:e,chainCode:t}),r=r||h,!o.isPoint(e))throw new TypeError("Point is not on the curve");return new p(void 0,e,t,r,n,i,s)}t.fromBase58=function(e,t){const r=i.decode(e);if(78!==r.length)throw new TypeError("Invalid buffer length");t=t||h;const n=r.readUInt32BE(0);if(n!==t.bip32.private&&n!==t.bip32.public)throw new TypeError("Invalid network version");const o=r[4],a=r.readUInt32BE(5);if(0===o&&0!==a)throw new TypeError("Invalid parent fingerprint");const s=r.readUInt32BE(9);if(0===o&&0!==s)throw new TypeError("Invalid index");const u=r.slice(13,45);let c;if(n===t.bip32.private){if(0!==r.readUInt8(45))throw new TypeError("Invalid private key");c=g(r.slice(46,78),u,t,o,s,a)}else{c=b(r.slice(45,78),u,t,o,s,a)}return c},t.fromPrivateKey=m,t.fromPublicKey=function(e,t,r){return b(e,t,r)},t.fromSeed=function(t,r){if(a(a.Buffer,t),t.length<16)throw new TypeError("Seed should be at least 128 bits");if(t.length>64)throw new TypeError("Seed should be at most 512 bits");r=r||h;const i=n.hmacSHA512(e.from("Bitcoin seed","utf8"),t);return m(i.slice(0,32),i.slice(32),r)}}).call(this,r(0).Buffer)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=r(24),i=r(55);t.hash160=function(e){const t=n("sha256").update(e).digest();try{return n("rmd160").update(t).digest()}catch(e){return n("ripemd160").update(t).digest()}},t.hmacSHA512=function(e,t){return i("sha512",e).update(t).digest()}},function(e,t,r){"use strict";var n=r(1),i=r(2).Buffer,o=r(25),a=i.alloc(128);function s(e,t){o.call(this,"digest"),"string"==typeof t&&(t=i.from(t)),this._alg=e,this._key=t,t.length>64?t=e(t):t.length<64&&(t=i.concat([t,a],64));for(var r=this._ipad=i.allocUnsafe(64),n=this._opad=i.allocUnsafe(64),s=0;s<64;s++)r[s]=54^t[s],n[s]=92^t[s];this._hash=[r]}n(s,o),s.prototype._update=function(e){this._hash.push(e)},s.prototype._final=function(){var e=this._alg(i.concat(this._hash));return this._alg(i.concat([this._opad,e]))},e.exports=s},function(e,t,r){"use strict";var n=r(80),i=r(2).Buffer;e.exports=function(e){function t(t){var r=t.slice(0,-4),n=t.slice(-4),i=e(r);if(!(n[0]^i[0]|n[1]^i[1]|n[2]^i[2]|n[3]^i[3]))return r}return{encode:function(t){var r=e(t);return n.encode(i.concat([t,r],t.length+4))},decode:function(e){var r=t(n.decode(e));if(!r)throw new Error("Invalid checksum");return r},decodeUnsafe:function(e){var r=n.decodeUnsafe(e);if(r)return t(r)}}}},function(e,t,r){"use strict";var n=r(2).Buffer;e.exports=function(e){if(e.length>=255)throw new TypeError("Alphabet too long");for(var t=new Uint8Array(256),r=0;r>>0,h=new Uint8Array(a);e[r];){var f=t[e.charCodeAt(r)];if(255===f)return;for(var l=0,d=a-1;(0!==f||l>>0,h[d]=f%256>>>0,f=f/256>>>0;if(0!==f)throw new Error("Non-zero carry");o=l,r++}if(" "!==e[r]){for(var p=a-o;p!==a&&0===h[p];)p++;var m=n.allocUnsafe(i+(a-p));m.fill(0,0,i);for(var g=i;p!==a;)m[g++]=h[p++];return m}}}return{encode:function(t){if((Array.isArray(t)||t instanceof Uint8Array)&&(t=n.from(t)),!n.isBuffer(t))throw new TypeError("Expected Buffer");if(0===t.length)return"";for(var r=0,i=0,o=0,a=t.length;o!==a&&0===t[o];)o++,r++;for(var c=(a-o)*h+1>>>0,f=new Uint8Array(c);o!==a;){for(var l=t[o],d=0,p=c-1;(0!==l||d>>0,f[p]=l%s>>>0,l=l/s>>>0;if(0!==l)throw new Error("Non-zero carry");i=d,o++}for(var m=c-i;m!==c&&0===f[m];)m++;for(var g=u.repeat(r);m=0)return!1;if((2===r||3===r)&&33===e.length){try{w(e)}catch(e){return!1}return!0}const i=e.slice(33);return 0!==i.compare(a)&&(!(i.compare(u)>=0)&&(4===r&&65===e.length))}function m(e){return 4!==e[0]}function g(e){return!!l(e)&&(e.compare(a)>0&&e.compare(s)<0)}function b(e,t){return void 0===e&&void 0!==t?m(t):void 0===e||e}function v(e){return new n(e)}function y(e){return e.toArrayLike(t,"be",32)}function w(e){return i.curve.decodePoint(e)}function _(e,r){return t.from(e._encode(r))}function S(e,r,n){if(!l(e))throw new TypeError("Expected Hash");if(!g(r))throw new TypeError("Expected Private");if(void 0!==n&&!l(n))throw new TypeError("Expected Extra Data (32 bytes)");const i=v(r),a=v(e);let s,u;o(e,r,(function(e){const t=v(e),r=f.mul(t);return!r.isInfinity()&&(s=r.x.umod(c),0!==s.isZero()&&(u=t.invm(c).mul(a.add(i.mul(s))).umod(c),0!==u.isZero()))}),g,n),u.cmp(h)>0&&(u=c.sub(u));const d=t.allocUnsafe(64);return y(s).copy(d,0),y(u).copy(d,32),d}e.exports={isPoint:p,isPointCompressed:function(e){return!!p(e)&&m(e)},isPrivate:g,pointAdd:function(e,t,r){if(!p(e))throw new TypeError("Expected Point");if(!p(t))throw new TypeError("Expected Point");const n=w(e),i=w(t),o=n.add(i);return o.isInfinity()?null:_(o,b(r,e))},pointAddScalar:function(e,t,r){if(!p(e))throw new TypeError("Expected Point");if(!d(t))throw new TypeError("Expected Tweak");const n=b(r,e),i=w(e);if(0===t.compare(a))return _(i,n);const o=v(t),s=f.mul(o),u=i.add(s);return u.isInfinity()?null:_(u,n)},pointCompress:function(e,t){if(!p(e))throw new TypeError("Expected Point");const r=w(e);if(r.isInfinity())throw new TypeError("Expected Point");return _(r,b(t,e))},pointFromScalar:function(e,t){if(!g(e))throw new TypeError("Expected Private");const r=v(e),n=f.mul(r);return n.isInfinity()?null:_(n,b(t))},pointMultiply:function(e,t,r){if(!p(e))throw new TypeError("Expected Point");if(!d(t))throw new TypeError("Expected Tweak");const n=b(r,e),i=w(e),o=v(t),a=i.mul(o);return a.isInfinity()?null:_(a,n)},privateAdd:function(e,t){if(!g(e))throw new TypeError("Expected Private");if(!d(t))throw new TypeError("Expected Tweak");const r=v(e),n=v(t),i=y(r.add(n).umod(c));return g(i)?i:null},privateSub:function(e,t){if(!g(e))throw new TypeError("Expected Private");if(!d(t))throw new TypeError("Expected Tweak");const r=v(e),n=v(t),i=y(r.sub(n).umod(c));return g(i)?i:null},sign:function(e,t){return S(e,t)},signWithEntropy:function(e,t,r){return S(e,t,r)},verify:function(e,r,n,i){if(!l(e))throw new TypeError("Expected Hash");if(!p(r))throw new TypeError("Expected Point");if(!function(e){const r=e.slice(0,32),n=e.slice(32,64);return t.isBuffer(e)&&64===e.length&&r.compare(s)<0&&n.compare(s)<0}(n))throw new TypeError("Expected Signature");const o=w(r),a=v(n.slice(0,32)),u=v(n.slice(32,64));if(i&&u.cmp(h)>0)return!1;if(a.gtn(0)<=0)return!1;if(u.gtn(0)<=0)return!1;const d=v(e),m=u.invm(c),g=d.mul(m).umod(c),b=a.mul(m).umod(c),y=f.mulAdd(g,o,b);return!y.isInfinity()&&y.x.umod(c).eq(a)}}}).call(this,r(0).Buffer)},function(e){e.exports=JSON.parse('{"_args":[["elliptic@6.5.3","/home/smooth-op/work/filecoin/filecoin.js"]],"_from":"elliptic@6.5.3","_id":"elliptic@6.5.3","_inBundle":false,"_integrity":"sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==","_location":"/elliptic","_phantomChildren":{},"_requested":{"type":"version","registry":true,"raw":"elliptic@6.5.3","name":"elliptic","escapedName":"elliptic","rawSpec":"6.5.3","saveSpec":null,"fetchSpec":"6.5.3"},"_requiredBy":["/bitcore-lib","/browserify-sign","/create-ecdh","/secp256k1","/tiny-secp256k1"],"_resolved":"https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz","_spec":"6.5.3","_where":"/home/smooth-op/work/filecoin/filecoin.js","author":{"name":"Fedor Indutny","email":"fedor@indutny.com"},"bugs":{"url":"https://github.com/indutny/elliptic/issues"},"dependencies":{"bn.js":"^4.4.0","brorand":"^1.0.1","hash.js":"^1.0.0","hmac-drbg":"^1.0.0","inherits":"^2.0.1","minimalistic-assert":"^1.0.0","minimalistic-crypto-utils":"^1.0.0"},"description":"EC cryptography","devDependencies":{"brfs":"^1.4.3","coveralls":"^3.0.8","grunt":"^1.0.4","grunt-browserify":"^5.0.0","grunt-cli":"^1.2.0","grunt-contrib-connect":"^1.0.0","grunt-contrib-copy":"^1.0.0","grunt-contrib-uglify":"^1.0.1","grunt-mocha-istanbul":"^3.0.1","grunt-saucelabs":"^9.0.1","istanbul":"^0.4.2","jscs":"^3.0.7","jshint":"^2.10.3","mocha":"^6.2.2"},"files":["lib"],"homepage":"https://github.com/indutny/elliptic","keywords":["EC","Elliptic","curve","Cryptography"],"license":"MIT","main":"lib/elliptic.js","name":"elliptic","repository":{"type":"git","url":"git+ssh://git@github.com/indutny/elliptic.git"},"scripts":{"jscs":"jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js","jshint":"jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js","lint":"npm run jscs && npm run jshint","test":"npm run lint && npm run unit","unit":"istanbul test _mocha --reporter=spec test/index.js","version":"grunt dist && git add dist/"},"version":"6.5.3"}')},function(e,t){},function(e,t,r){"use strict";var n=r(15),i=r(6),o=r(1),a=r(56),s=n.assert;function u(e){a.call(this,"short",e),this.a=new i(e.a,16).toRed(this.red),this.b=new i(e.b,16).toRed(this.red),this.tinv=this.two.redInvm(),this.zeroA=0===this.a.fromRed().cmpn(0),this.threeA=0===this.a.fromRed().sub(this.p).cmpn(-3),this.endo=this._getEndomorphism(e),this._endoWnafT1=new Array(4),this._endoWnafT2=new Array(4)}function c(e,t,r,n){a.BasePoint.call(this,e,"affine"),null===t&&null===r?(this.x=null,this.y=null,this.inf=!0):(this.x=new i(t,16),this.y=new i(r,16),n&&(this.x.forceRed(this.curve.red),this.y.forceRed(this.curve.red)),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.inf=!1)}function h(e,t,r,n){a.BasePoint.call(this,e,"jacobian"),null===t&&null===r&&null===n?(this.x=this.curve.one,this.y=this.curve.one,this.z=new i(0)):(this.x=new i(t,16),this.y=new i(r,16),this.z=new i(n,16)),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.zOne=this.z===this.curve.one}o(u,a),e.exports=u,u.prototype._getEndomorphism=function(e){if(this.zeroA&&this.g&&this.n&&1===this.p.modn(3)){var t,r;if(e.beta)t=new i(e.beta,16).toRed(this.red);else{var n=this._getEndoRoots(this.p);t=(t=n[0].cmp(n[1])<0?n[0]:n[1]).toRed(this.red)}if(e.lambda)r=new i(e.lambda,16);else{var o=this._getEndoRoots(this.n);0===this.g.mul(o[0]).x.cmp(this.g.x.redMul(t))?r=o[0]:(r=o[1],s(0===this.g.mul(r).x.cmp(this.g.x.redMul(t))))}return{beta:t,lambda:r,basis:e.basis?e.basis.map((function(e){return{a:new i(e.a,16),b:new i(e.b,16)}})):this._getEndoBasis(r)}}},u.prototype._getEndoRoots=function(e){var t=e===this.p?this.red:i.mont(e),r=new i(2).toRed(t).redInvm(),n=r.redNeg(),o=new i(3).toRed(t).redNeg().redSqrt().redMul(r);return[n.redAdd(o).fromRed(),n.redSub(o).fromRed()]},u.prototype._getEndoBasis=function(e){for(var t,r,n,o,a,s,u,c,h,f=this.n.ushrn(Math.floor(this.n.bitLength()/2)),l=e,d=this.n.clone(),p=new i(1),m=new i(0),g=new i(0),b=new i(1),v=0;0!==l.cmpn(0);){var y=d.div(l);c=d.sub(y.mul(l)),h=g.sub(y.mul(p));var w=b.sub(y.mul(m));if(!n&&c.cmp(f)<0)t=u.neg(),r=p,n=c.neg(),o=h;else if(n&&2==++v)break;u=c,d=l,l=c,g=p,p=h,b=m,m=w}a=c.neg(),s=h;var _=n.sqr().add(o.sqr());return a.sqr().add(s.sqr()).cmp(_)>=0&&(a=t,s=r),n.negative&&(n=n.neg(),o=o.neg()),a.negative&&(a=a.neg(),s=s.neg()),[{a:n,b:o},{a:a,b:s}]},u.prototype._endoSplit=function(e){var t=this.endo.basis,r=t[0],n=t[1],i=n.b.mul(e).divRound(this.n),o=r.b.neg().mul(e).divRound(this.n),a=i.mul(r.a),s=o.mul(n.a),u=i.mul(r.b),c=o.mul(n.b);return{k1:e.sub(a).sub(s),k2:u.add(c).neg()}},u.prototype.pointFromX=function(e,t){(e=new i(e,16)).red||(e=e.toRed(this.red));var r=e.redSqr().redMul(e).redIAdd(e.redMul(this.a)).redIAdd(this.b),n=r.redSqrt();if(0!==n.redSqr().redSub(r).cmp(this.zero))throw new Error("invalid point");var o=n.fromRed().isOdd();return(t&&!o||!t&&o)&&(n=n.redNeg()),this.point(e,n)},u.prototype.validate=function(e){if(e.inf)return!0;var t=e.x,r=e.y,n=this.a.redMul(t),i=t.redSqr().redMul(t).redIAdd(n).redIAdd(this.b);return 0===r.redSqr().redISub(i).cmpn(0)},u.prototype._endoWnafMulAdd=function(e,t,r){for(var n=this._endoWnafT1,i=this._endoWnafT2,o=0;o":""},c.prototype.isInfinity=function(){return this.inf},c.prototype.add=function(e){if(this.inf)return e;if(e.inf)return this;if(this.eq(e))return this.dbl();if(this.neg().eq(e))return this.curve.point(null,null);if(0===this.x.cmp(e.x))return this.curve.point(null,null);var t=this.y.redSub(e.y);0!==t.cmpn(0)&&(t=t.redMul(this.x.redSub(e.x).redInvm()));var r=t.redSqr().redISub(this.x).redISub(e.x),n=t.redMul(this.x.redSub(r)).redISub(this.y);return this.curve.point(r,n)},c.prototype.dbl=function(){if(this.inf)return this;var e=this.y.redAdd(this.y);if(0===e.cmpn(0))return this.curve.point(null,null);var t=this.curve.a,r=this.x.redSqr(),n=e.redInvm(),i=r.redAdd(r).redIAdd(r).redIAdd(t).redMul(n),o=i.redSqr().redISub(this.x.redAdd(this.x)),a=i.redMul(this.x.redSub(o)).redISub(this.y);return this.curve.point(o,a)},c.prototype.getX=function(){return this.x.fromRed()},c.prototype.getY=function(){return this.y.fromRed()},c.prototype.mul=function(e){return e=new i(e,16),this.isInfinity()?this:this._hasDoubles(e)?this.curve._fixedNafMul(this,e):this.curve.endo?this.curve._endoWnafMulAdd([this],[e]):this.curve._wnafMul(this,e)},c.prototype.mulAdd=function(e,t,r){var n=[this,t],i=[e,r];return this.curve.endo?this.curve._endoWnafMulAdd(n,i):this.curve._wnafMulAdd(1,n,i,2)},c.prototype.jmulAdd=function(e,t,r){var n=[this,t],i=[e,r];return this.curve.endo?this.curve._endoWnafMulAdd(n,i,!0):this.curve._wnafMulAdd(1,n,i,2,!0)},c.prototype.eq=function(e){return this===e||this.inf===e.inf&&(this.inf||0===this.x.cmp(e.x)&&0===this.y.cmp(e.y))},c.prototype.neg=function(e){if(this.inf)return this;var t=this.curve.point(this.x,this.y.redNeg());if(e&&this.precomputed){var r=this.precomputed,n=function(e){return e.neg()};t.precomputed={naf:r.naf&&{wnd:r.naf.wnd,points:r.naf.points.map(n)},doubles:r.doubles&&{step:r.doubles.step,points:r.doubles.points.map(n)}}}return t},c.prototype.toJ=function(){return this.inf?this.curve.jpoint(null,null,null):this.curve.jpoint(this.x,this.y,this.curve.one)},o(h,a.BasePoint),u.prototype.jpoint=function(e,t,r){return new h(this,e,t,r)},h.prototype.toP=function(){if(this.isInfinity())return this.curve.point(null,null);var e=this.z.redInvm(),t=e.redSqr(),r=this.x.redMul(t),n=this.y.redMul(t).redMul(e);return this.curve.point(r,n)},h.prototype.neg=function(){return this.curve.jpoint(this.x,this.y.redNeg(),this.z)},h.prototype.add=function(e){if(this.isInfinity())return e;if(e.isInfinity())return this;var t=e.z.redSqr(),r=this.z.redSqr(),n=this.x.redMul(t),i=e.x.redMul(r),o=this.y.redMul(t.redMul(e.z)),a=e.y.redMul(r.redMul(this.z)),s=n.redSub(i),u=o.redSub(a);if(0===s.cmpn(0))return 0!==u.cmpn(0)?this.curve.jpoint(null,null,null):this.dbl();var c=s.redSqr(),h=c.redMul(s),f=n.redMul(c),l=u.redSqr().redIAdd(h).redISub(f).redISub(f),d=u.redMul(f.redISub(l)).redISub(o.redMul(h)),p=this.z.redMul(e.z).redMul(s);return this.curve.jpoint(l,d,p)},h.prototype.mixedAdd=function(e){if(this.isInfinity())return e.toJ();if(e.isInfinity())return this;var t=this.z.redSqr(),r=this.x,n=e.x.redMul(t),i=this.y,o=e.y.redMul(t).redMul(this.z),a=r.redSub(n),s=i.redSub(o);if(0===a.cmpn(0))return 0!==s.cmpn(0)?this.curve.jpoint(null,null,null):this.dbl();var u=a.redSqr(),c=u.redMul(a),h=r.redMul(u),f=s.redSqr().redIAdd(c).redISub(h).redISub(h),l=s.redMul(h.redISub(f)).redISub(i.redMul(c)),d=this.z.redMul(a);return this.curve.jpoint(f,l,d)},h.prototype.dblp=function(e){if(0===e)return this;if(this.isInfinity())return this;if(!e)return this.dbl();if(this.curve.zeroA||this.curve.threeA){for(var t=this,r=0;r=0)return!1;if(r.redIAdd(i),0===this.x.cmp(r))return!0}},h.prototype.inspect=function(){return this.isInfinity()?"":""},h.prototype.isInfinity=function(){return 0===this.z.cmpn(0)}},function(e,t,r){"use strict";var n=r(6),i=r(1),o=r(56),a=r(15);function s(e){o.call(this,"mont",e),this.a=new n(e.a,16).toRed(this.red),this.b=new n(e.b,16).toRed(this.red),this.i4=new n(4).toRed(this.red).redInvm(),this.two=new n(2).toRed(this.red),this.a24=this.i4.redMul(this.a.redAdd(this.two))}function u(e,t,r){o.BasePoint.call(this,e,"projective"),null===t&&null===r?(this.x=this.curve.one,this.z=this.curve.zero):(this.x=new n(t,16),this.z=new n(r,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)))}i(s,o),e.exports=s,s.prototype.validate=function(e){var t=e.normalize().x,r=t.redSqr(),n=r.redMul(t).redAdd(r.redMul(this.a)).redAdd(t);return 0===n.redSqrt().redSqr().cmp(n)},i(u,o.BasePoint),s.prototype.decodePoint=function(e,t){return this.point(a.toArray(e,t),1)},s.prototype.point=function(e,t){return new u(this,e,t)},s.prototype.pointFromJSON=function(e){return u.fromJSON(this,e)},u.prototype.precompute=function(){},u.prototype._encode=function(){return this.getX().toArray("be",this.curve.p.byteLength())},u.fromJSON=function(e,t){return new u(e,t[0],t[1]||e.one)},u.prototype.inspect=function(){return this.isInfinity()?"":""},u.prototype.isInfinity=function(){return 0===this.z.cmpn(0)},u.prototype.dbl=function(){var e=this.x.redAdd(this.z).redSqr(),t=this.x.redSub(this.z).redSqr(),r=e.redSub(t),n=e.redMul(t),i=r.redMul(t.redAdd(this.curve.a24.redMul(r)));return this.curve.point(n,i)},u.prototype.add=function(){throw new Error("Not supported on Montgomery curve")},u.prototype.diffAdd=function(e,t){var r=this.x.redAdd(this.z),n=this.x.redSub(this.z),i=e.x.redAdd(e.z),o=e.x.redSub(e.z).redMul(r),a=i.redMul(n),s=t.z.redMul(o.redAdd(a).redSqr()),u=t.x.redMul(o.redISub(a).redSqr());return this.curve.point(s,u)},u.prototype.mul=function(e){for(var t=e.clone(),r=this,n=this.curve.point(null,null),i=[];0!==t.cmpn(0);t.iushrn(1))i.push(t.andln(1));for(var o=i.length-1;o>=0;o--)0===i[o]?(r=r.diffAdd(n,this),n=n.dbl()):(n=r.diffAdd(n,this),r=r.dbl());return n},u.prototype.mulAdd=function(){throw new Error("Not supported on Montgomery curve")},u.prototype.jumlAdd=function(){throw new Error("Not supported on Montgomery curve")},u.prototype.eq=function(e){return 0===this.getX().cmp(e.getX())},u.prototype.normalize=function(){return this.x=this.x.redMul(this.z.redInvm()),this.z=this.curve.one,this},u.prototype.getX=function(){return this.normalize(),this.x.fromRed()}},function(e,t,r){"use strict";var n=r(15),i=r(6),o=r(1),a=r(56),s=n.assert;function u(e){this.twisted=1!=(0|e.a),this.mOneA=this.twisted&&-1==(0|e.a),this.extended=this.mOneA,a.call(this,"edwards",e),this.a=new i(e.a,16).umod(this.red.m),this.a=this.a.toRed(this.red),this.c=new i(e.c,16).toRed(this.red),this.c2=this.c.redSqr(),this.d=new i(e.d,16).toRed(this.red),this.dd=this.d.redAdd(this.d),s(!this.twisted||0===this.c.fromRed().cmpn(1)),this.oneC=1==(0|e.c)}function c(e,t,r,n,o){a.BasePoint.call(this,e,"projective"),null===t&&null===r&&null===n?(this.x=this.curve.zero,this.y=this.curve.one,this.z=this.curve.one,this.t=this.curve.zero,this.zOne=!0):(this.x=new i(t,16),this.y=new i(r,16),this.z=n?new i(n,16):this.curve.one,this.t=o&&new i(o,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.t&&!this.t.red&&(this.t=this.t.toRed(this.curve.red)),this.zOne=this.z===this.curve.one,this.curve.extended&&!this.t&&(this.t=this.x.redMul(this.y),this.zOne||(this.t=this.t.redMul(this.z.redInvm()))))}o(u,a),e.exports=u,u.prototype._mulA=function(e){return this.mOneA?e.redNeg():this.a.redMul(e)},u.prototype._mulC=function(e){return this.oneC?e:this.c.redMul(e)},u.prototype.jpoint=function(e,t,r,n){return this.point(e,t,r,n)},u.prototype.pointFromX=function(e,t){(e=new i(e,16)).red||(e=e.toRed(this.red));var r=e.redSqr(),n=this.c2.redSub(this.a.redMul(r)),o=this.one.redSub(this.c2.redMul(this.d).redMul(r)),a=n.redMul(o.redInvm()),s=a.redSqrt();if(0!==s.redSqr().redSub(a).cmp(this.zero))throw new Error("invalid point");var u=s.fromRed().isOdd();return(t&&!u||!t&&u)&&(s=s.redNeg()),this.point(e,s)},u.prototype.pointFromY=function(e,t){(e=new i(e,16)).red||(e=e.toRed(this.red));var r=e.redSqr(),n=r.redSub(this.c2),o=r.redMul(this.d).redMul(this.c2).redSub(this.a),a=n.redMul(o.redInvm());if(0===a.cmp(this.zero)){if(t)throw new Error("invalid point");return this.point(this.zero,e)}var s=a.redSqrt();if(0!==s.redSqr().redSub(a).cmp(this.zero))throw new Error("invalid point");return s.fromRed().isOdd()!==t&&(s=s.redNeg()),this.point(s,e)},u.prototype.validate=function(e){if(e.isInfinity())return!0;e.normalize();var t=e.x.redSqr(),r=e.y.redSqr(),n=t.redMul(this.a).redAdd(r),i=this.c2.redMul(this.one.redAdd(this.d.redMul(t).redMul(r)));return 0===n.cmp(i)},o(c,a.BasePoint),u.prototype.pointFromJSON=function(e){return c.fromJSON(this,e)},u.prototype.point=function(e,t,r,n){return new c(this,e,t,r,n)},c.fromJSON=function(e,t){return new c(e,t[0],t[1],t[2])},c.prototype.inspect=function(){return this.isInfinity()?"":""},c.prototype.isInfinity=function(){return 0===this.x.cmpn(0)&&(0===this.y.cmp(this.z)||this.zOne&&0===this.y.cmp(this.curve.c))},c.prototype._extDbl=function(){var e=this.x.redSqr(),t=this.y.redSqr(),r=this.z.redSqr();r=r.redIAdd(r);var n=this.curve._mulA(e),i=this.x.redAdd(this.y).redSqr().redISub(e).redISub(t),o=n.redAdd(t),a=o.redSub(r),s=n.redSub(t),u=i.redMul(a),c=o.redMul(s),h=i.redMul(s),f=a.redMul(o);return this.curve.point(u,c,f,h)},c.prototype._projDbl=function(){var e,t,r,n=this.x.redAdd(this.y).redSqr(),i=this.x.redSqr(),o=this.y.redSqr();if(this.curve.twisted){var a=(c=this.curve._mulA(i)).redAdd(o);if(this.zOne)e=n.redSub(i).redSub(o).redMul(a.redSub(this.curve.two)),t=a.redMul(c.redSub(o)),r=a.redSqr().redSub(a).redSub(a);else{var s=this.z.redSqr(),u=a.redSub(s).redISub(s);e=n.redSub(i).redISub(o).redMul(u),t=a.redMul(c.redSub(o)),r=a.redMul(u)}}else{var c=i.redAdd(o);s=this.curve._mulC(this.z).redSqr(),u=c.redSub(s).redSub(s);e=this.curve._mulC(n.redISub(c)).redMul(u),t=this.curve._mulC(c).redMul(i.redISub(o)),r=c.redMul(u)}return this.curve.point(e,t,r)},c.prototype.dbl=function(){return this.isInfinity()?this:this.curve.extended?this._extDbl():this._projDbl()},c.prototype._extAdd=function(e){var t=this.y.redSub(this.x).redMul(e.y.redSub(e.x)),r=this.y.redAdd(this.x).redMul(e.y.redAdd(e.x)),n=this.t.redMul(this.curve.dd).redMul(e.t),i=this.z.redMul(e.z.redAdd(e.z)),o=r.redSub(t),a=i.redSub(n),s=i.redAdd(n),u=r.redAdd(t),c=o.redMul(a),h=s.redMul(u),f=o.redMul(u),l=a.redMul(s);return this.curve.point(c,h,l,f)},c.prototype._projAdd=function(e){var t,r,n=this.z.redMul(e.z),i=n.redSqr(),o=this.x.redMul(e.x),a=this.y.redMul(e.y),s=this.curve.d.redMul(o).redMul(a),u=i.redSub(s),c=i.redAdd(s),h=this.x.redAdd(this.y).redMul(e.x.redAdd(e.y)).redISub(o).redISub(a),f=n.redMul(u).redMul(h);return this.curve.twisted?(t=n.redMul(c).redMul(a.redSub(this.curve._mulA(o))),r=u.redMul(c)):(t=n.redMul(c).redMul(a.redSub(o)),r=this.curve._mulC(u).redMul(c)),this.curve.point(f,t,r)},c.prototype.add=function(e){return this.isInfinity()?e:e.isInfinity()?this:this.curve.extended?this._extAdd(e):this._projAdd(e)},c.prototype.mul=function(e){return this._hasDoubles(e)?this.curve._fixedNafMul(this,e):this.curve._wnafMul(this,e)},c.prototype.mulAdd=function(e,t,r){return this.curve._wnafMulAdd(1,[this,t],[e,r],2,!1)},c.prototype.jmulAdd=function(e,t,r){return this.curve._wnafMulAdd(1,[this,t],[e,r],2,!0)},c.prototype.normalize=function(){if(this.zOne)return this;var e=this.z.redInvm();return this.x=this.x.redMul(e),this.y=this.y.redMul(e),this.t&&(this.t=this.t.redMul(e)),this.z=this.curve.one,this.zOne=!0,this},c.prototype.neg=function(){return this.curve.point(this.x.redNeg(),this.y,this.z,this.t&&this.t.redNeg())},c.prototype.getX=function(){return this.normalize(),this.x.fromRed()},c.prototype.getY=function(){return this.normalize(),this.y.fromRed()},c.prototype.eq=function(e){return this===e||0===this.getX().cmp(e.getX())&&0===this.getY().cmp(e.getY())},c.prototype.eqXToP=function(e){var t=e.toRed(this.curve.red).redMul(this.z);if(0===this.x.cmp(t))return!0;for(var r=e.clone(),n=this.curve.redN.redMul(this.z);;){if(r.iadd(this.curve.n),r.cmp(this.curve.p)>=0)return!1;if(t.redIAdd(n),0===this.x.cmp(t))return!0}},c.prototype.toP=c.prototype.normalize,c.prototype.mixedAdd=c.prototype.add},function(e,t,r){"use strict";t.sha1=r(253),t.sha224=r(254),t.sha256=r(137),t.sha384=r(255),t.sha512=r(138)},function(e,t,r){"use strict";var n=r(18),i=r(41),o=r(136),a=n.rotl32,s=n.sum32,u=n.sum32_5,c=o.ft_1,h=i.BlockHash,f=[1518500249,1859775393,2400959708,3395469782];function l(){if(!(this instanceof l))return new l;h.call(this),this.h=[1732584193,4023233417,2562383102,271733878,3285377520],this.W=new Array(80)}n.inherits(l,h),e.exports=l,l.blockSize=512,l.outSize=160,l.hmacStrength=80,l.padLength=64,l.prototype._update=function(e,t){for(var r=this.W,n=0;n<16;n++)r[n]=e[t+n];for(;nthis.blockSize&&(e=(new this.Hash).update(e).digest()),i(e.length<=this.blockSize);for(var t=e.length;t0))return a.iaddn(1),this.keyFromPrivate(a)}},f.prototype._truncateToN=function(e,t){var r=8*e.byteLength()-this.n.bitLength();return r>0&&(e=e.ushrn(r)),!t&&e.cmp(this.n)>=0?e.sub(this.n):e},f.prototype.sign=function(e,t,r,o){"object"==typeof r&&(o=r,r=null),o||(o={}),t=this.keyFromPrivate(t,r),e=this._truncateToN(new n(e,16));for(var a=this.n.byteLength(),s=t.getPrivate().toArray("be",a),u=e.toArray("be",a),c=new i({hash:this.hash,entropy:s,nonce:u,pers:o.pers,persEnc:o.persEnc||"utf8"}),f=this.n.sub(new n(1)),l=0;;l++){var d=o.k?o.k(l):new n(c.generate(this.n.byteLength()));if(!((d=this._truncateToN(d,!0)).cmpn(1)<=0||d.cmp(f)>=0)){var p=this.g.mul(d);if(!p.isInfinity()){var m=p.getX(),g=m.umod(this.n);if(0!==g.cmpn(0)){var b=d.invm(this.n).mul(g.mul(t.getPrivate()).iadd(e));if(0!==(b=b.umod(this.n)).cmpn(0)){var v=(p.getY().isOdd()?1:0)|(0!==m.cmp(g)?2:0);return o.canonical&&b.cmp(this.nh)>0&&(b=this.n.sub(b),v^=1),new h({r:g,s:b,recoveryParam:v})}}}}}},f.prototype.verify=function(e,t,r,i){e=this._truncateToN(new n(e,16)),r=this.keyFromPublic(r,i);var o=(t=new h(t,"hex")).r,a=t.s;if(o.cmpn(1)<0||o.cmp(this.n)>=0)return!1;if(a.cmpn(1)<0||a.cmp(this.n)>=0)return!1;var s,u=a.invm(this.n),c=u.mul(e).umod(this.n),f=u.mul(o).umod(this.n);return this.curve._maxwellTrick?!(s=this.g.jmulAdd(c,r.getPublic(),f)).isInfinity()&&s.eqXToP(o):!(s=this.g.mulAdd(c,r.getPublic(),f)).isInfinity()&&0===s.getX().umod(this.n).cmp(o)},f.prototype.recoverPubKey=function(e,t,r,i){u((3&r)===r,"The recovery param is more than two bits"),t=new h(t,i);var o=this.n,a=new n(e),s=t.r,c=t.s,f=1&r,l=r>>1;if(s.cmp(this.curve.p.umod(this.curve.n))>=0&&l)throw new Error("Unable to find sencond key candinate");s=l?this.curve.pointFromX(s.add(this.curve.n),f):this.curve.pointFromX(s,f);var d=t.r.invm(o),p=o.sub(a).mul(d).umod(o),m=c.mul(d).umod(o);return this.g.mulAdd(p,s,m)},f.prototype.getKeyRecoveryParam=function(e,t,r,n){if(null!==(t=new h(t,n)).recoveryParam)return t.recoveryParam;for(var i=0;i<4;i++){var o;try{o=this.recoverPubKey(e,t,i)}catch(e){continue}if(o.eq(r))return i}throw new Error("Unable to find valid recovery factor")}},function(e,t,r){"use strict";var n=r(83),i=r(134),o=r(16);function a(e){if(!(this instanceof a))return new a(e);this.hash=e.hash,this.predResist=!!e.predResist,this.outLen=this.hash.outSize,this.minEntropy=e.minEntropy||this.hash.hmacStrength,this._reseed=null,this.reseedInterval=null,this.K=null,this.V=null;var t=i.toArray(e.entropy,e.entropyEnc||"hex"),r=i.toArray(e.nonce,e.nonceEnc||"hex"),n=i.toArray(e.pers,e.persEnc||"hex");o(t.length>=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._init(t,r,n)}e.exports=a,a.prototype._init=function(e,t,r){var n=e.concat(t).concat(r);this.K=new Array(this.outLen/8),this.V=new Array(this.outLen/8);for(var i=0;i=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._update(e.concat(r||[])),this._reseed=1},a.prototype.generate=function(e,t,r,n){if(this._reseed>this.reseedInterval)throw new Error("Reseed is required");"string"!=typeof t&&(n=r,r=t,t=null),r&&(r=i.toArray(r,n||"hex"),this._update(r));for(var o=[];o.length"}},function(e,t,r){"use strict";var n=r(6),i=r(15),o=i.assert;function a(e,t){if(e instanceof a)return e;this._importDER(e,t)||(o(e.r&&e.s,"Signature without r or s"),this.r=new n(e.r,16),this.s=new n(e.s,16),void 0===e.recoveryParam?this.recoveryParam=null:this.recoveryParam=e.recoveryParam)}function s(){this.place=0}function u(e,t){var r=e[t.place++];if(!(128&r))return r;var n=15&r;if(0===n||n>4)return!1;for(var i=0,o=0,a=t.place;o>>=0;return!(i<=127)&&(t.place=a,i)}function c(e){for(var t=0,r=e.length-1;!e[t]&&!(128&e[t+1])&&t>>3);for(e.push(128|r);--r;)e.push(t>>>(r<<3)&255);e.push(t)}}e.exports=a,a.prototype._importDER=function(e,t){e=i.toArray(e,t);var r=new s;if(48!==e[r.place++])return!1;var o=u(e,r);if(!1===o)return!1;if(o+r.place!==e.length)return!1;if(2!==e[r.place++])return!1;var a=u(e,r);if(!1===a)return!1;var c=e.slice(r.place,a+r.place);if(r.place+=a,2!==e[r.place++])return!1;var h=u(e,r);if(!1===h)return!1;if(e.length!==h+r.place)return!1;var f=e.slice(r.place,h+r.place);if(0===c[0]){if(!(128&c[1]))return!1;c=c.slice(1)}if(0===f[0]){if(!(128&f[1]))return!1;f=f.slice(1)}return this.r=new n(c),this.s=new n(f),this.recoveryParam=null,!0},a.prototype.toDER=function(e){var t=this.r.toArray(),r=this.s.toArray();for(128&t[0]&&(t=[0].concat(t)),128&r[0]&&(r=[0].concat(r)),t=c(t),r=c(r);!(r[0]||128&r[1]);)r=r.slice(1);var n=[2];h(n,t.length),(n=n.concat(t)).push(2),h(n,r.length);var o=n.concat(r),a=[48];return h(a,o.length),a=a.concat(o),i.encode(a,e)}},function(e,t,r){"use strict";var n=r(83),i=r(82),o=r(15),a=o.assert,s=o.parseBytes,u=r(264),c=r(265);function h(e){if(a("ed25519"===e,"only tested with ed25519 so far"),!(this instanceof h))return new h(e);e=i[e].curve;this.curve=e,this.g=e.g,this.g.precompute(e.n.bitLength()+1),this.pointClass=e.point().constructor,this.encodingLength=Math.ceil(e.n.bitLength()/8),this.hash=n.sha512}e.exports=h,h.prototype.sign=function(e,t){e=s(e);var r=this.keyFromSecret(t),n=this.hashInt(r.messagePrefix(),e),i=this.g.mul(n),o=this.encodePoint(i),a=this.hashInt(o,r.pubBytes(),e).mul(r.priv()),u=n.add(a).umod(this.curve.n);return this.makeSignature({R:i,S:u,Rencoded:o})},h.prototype.verify=function(e,t,r){e=s(e),t=this.makeSignature(t);var n=this.keyFromPublic(r),i=this.hashInt(t.Rencoded(),n.pubBytes(),e),o=this.g.mul(t.S());return t.R().add(n.pub().mul(i)).eq(o)},h.prototype.hashInt=function(){for(var e=this.hash(),t=0;tt.maxLength)&&((void 0===t.length||r.length===t.length)&&r.every((function(t,r){try{return l(e,t,n)}catch(e){throw u(e,r)}}))))))}return e=f(e),t=t||{},r.toJSON=function(){var r="["+o(e)+"]";return void 0!==t.length?r+="{"+t.length+"}":void 0===t.minLength&&void 0===t.maxLength||(r+="{"+(void 0===t.minLength?0:t.minLength)+","+(void 0===t.maxLength?1/0:t.maxLength)+"}"),r},r},maybe:function e(t){function r(r,n){return i.Nil(r)||t(r,n,e)}return t=f(t),r.toJSON=function(){return"?"+o(t)},r},map:function(e,t){function r(r,n){if(!i.Object(r))return!1;if(i.Nil(r))return!1;for(var o in r){try{t&&l(t,o,n)}catch(e){throw u(e,o,"key")}try{var a=r[o];l(e,a,n)}catch(e){throw u(e,o)}}return!0}return e=f(e),t&&(t=f(t)),r.toJSON=t?function(){return"{"+o(t)+": "+o(e)+"}"}:function(){return"{"+o(e)+"}"},r},object:function(e){var t={};for(var r in e)t[r]=f(e[r]);function n(e,r){if(!i.Object(e))return!1;if(i.Nil(e))return!1;var n;try{for(n in t){l(t[n],e[n],r)}}catch(e){throw u(e,n)}if(r)for(n in e)if(!t[n])throw new s(void 0,n);return!0}return n.toJSON=function(){return o(t)},n},anyOf:function(){var e=[].slice.call(arguments).map(f);function t(t,r){return e.some((function(e){try{return l(e,t,r)}catch(e){return!1}}))}return t.toJSON=function(){return e.map(o).join("|")},t},allOf:function(){var e=[].slice.call(arguments).map(f);function t(t,r){return e.every((function(e){try{return l(e,t,r)}catch(e){return!1}}))}return t.toJSON=function(){return e.map(o).join(" & ")},t},quacksLike:function(e){function t(t){return e===c(t)}return t.toJSON=function(){return e},t},tuple:function(){var e=[].slice.call(arguments).map(f);function t(t,r){return!i.Nil(t)&&(!i.Nil(t.length)&&((!r||t.length===e.length)&&e.every((function(e,n){try{return l(e,t[n],r)}catch(e){throw u(e,n)}}))))}return t.toJSON=function(){return"("+e.map(o).join(", ")+")"},t},value:function(e){function t(t){return t===e}return t.toJSON=function(){return e},t}};function f(e){if(i.String(e))return"?"===e[0]?h.maybe(e.slice(1)):i[e]||h.quacksLike(e);if(e&&i.Object(e)){if(i.Array(e)){if(1!==e.length)throw new TypeError("Expected compile() parameter of type Array of length 1");return h.arrayOf(e[0])}return h.object(e)}return i.Function(e)?e:h.value(e)}function l(e,t,r,n){if(i.Function(e)){if(e(t,r))return!0;throw new a(n||e,t)}return l(f(e),t,r)}for(var d in h.oneOf=h.anyOf,i)l[d]=i[d];for(d in h)l[d]=h[d];var p=r(268);for(d in p)l[d]=p[d];l.compile=f,l.TfTypeError=a,l.TfPropertyTypeError=s,e.exports=l},function(e,t,r){(function(t){var n=r(84),i=r(139);function o(e){return t.isBuffer(e)}function a(e){return"string"==typeof e&&/^([0-9a-f]{2})+$/i.test(e)}function s(e,t){var r=e.toJSON();function n(n){if(!e(n))return!1;if(n.length===t)return!0;throw i.tfCustomError(r+"(Length: "+t+")",r+"(Length: "+n.length+")")}return n.toJSON=function(){return r},n}var u=s.bind(null,n.Array),c=s.bind(null,o),h=s.bind(null,a),f=s.bind(null,n.String);var l=Math.pow(2,53)-1;var d={ArrayN:u,Buffer:o,BufferN:c,Finite:function(e){return"number"==typeof e&&isFinite(e)},Hex:a,HexN:h,Int8:function(e){return e<<24>>24===e},Int16:function(e){return e<<16>>16===e},Int32:function(e){return(0|e)===e},Int53:function(e){return"number"==typeof e&&e>=-l&&e<=l&&Math.floor(e)===e},Range:function(e,t,r){function i(n,i){return r(n,i)&&n>e&&n>>0===e},UInt53:function(e){return"number"==typeof e&&e>=0&&e<=l&&Math.floor(e)===e}};for(var p in d)d[p].toJSON=function(e){return e}.bind(null,p);e.exports=d}).call(this,r(0).Buffer)},function(e,t,r){(function(t){var n=r(133);function i(e,t){if(void 0!==t&&e[0]!==t)throw new Error("Invalid network version");if(33===e.length)return{version:e[0],privateKey:e.slice(1,33),compressed:!1};if(34!==e.length)throw new Error("Invalid WIF length");if(1!==e[33])throw new Error("Invalid compression flag");return{version:e[0],privateKey:e.slice(1,33),compressed:!0}}function o(e,r,n){var i=new t(n?34:33);return i.writeUInt8(e,0),r.copy(i,1),n&&(i[33]=1),i}e.exports={decode:function(e,t){return i(n.decode(e),t)},decodeRaw:i,encode:function(e,t,r){return"number"==typeof e?n.encode(o(e,t,r)):n.encode(o(e.version,e.privateKey,e.compressed))},encodeRaw:o}}).call(this,r(0).Buffer)},function(e,t,r){"use strict";t.Diagnose=r(271),t.Decoder=r(141),t.Encoder=r(274),t.Simple=r(142),t.Tagged=r(143),t.decodeAll=t.Decoder.decodeAll,t.decodeFirst=t.Decoder.decodeFirst,t.diagnose=t.Diagnose.diagnose,t.encode=t.Encoder.encode,t.decode=t.Decoder.decode,t.leveldb={decode:t.Decoder.decodeAll,encode:t.Encoder.encode,buffer:!0,name:"cbor"}},function(e,t,r){"use strict";const{Buffer:n}=r(0),i=r(141),o=r(85);class a extends i{createTag(e,t){return`${e}(${t})`}createInt(e){return super.createInt(e).toString()}createInt32(e,t){return super.createInt32(e,t).toString()}createInt64(e,t,r,n){return super.createInt64(e,t,r,n).toString()}createInt32Neg(e,t){return super.createInt32Neg(e,t).toString()}createInt64Neg(e,t,r,n){return super.createInt64Neg(e,t,r,n).toString()}createTrue(){return"true"}createFalse(){return"false"}createFloat(e){const t=super.createFloat(e);return o.isNegativeZero(e)?"-0_1":t+"_1"}createFloatSingle(e,t,r,n){return super.createFloatSingle(e,t,r,n)+"_2"}createFloatDouble(e,t,r,n,i,o,a,s){return super.createFloatDouble(e,t,r,n,i,o,a,s)+"_3"}createByteString(e,t){const r=e.join(", ");return-1===t?`(_ ${r})`:"h'"+r}createByteStringFromHeap(e,t){return`h'${n.from(super.createByteStringFromHeap(e,t)).toString("hex")}'`}createInfinity(){return"Infinity_1"}createInfinityNeg(){return"-Infinity_1"}createNaN(){return"NaN_1"}createNaNNeg(){return"-NaN_1"}createNull(){return"null"}createUndefined(){return"undefined"}createSimpleUnassigned(e){return`simple(${e})`}createArray(e,t){const r=super.createArray(e,t);return-1===t?`[_ ${r.join(", ")}]`:`[${r.join(", ")}]`}createMap(e,t){const r=super.createMap(e),n=Array.from(r.keys()).reduce(s(r),"");return-1===t?`{_ ${n}}`:`{${n}}`}createObject(e,t){const r=super.createObject(e),n=Object.keys(r).reduce(s(r),"");return-1===t?`{_ ${n}}`:`{${n}}`}createUtf8String(e,t){const r=e.join(", ");return-1===t?`(_ ${r})`:`"${r}"`}createUtf8StringFromHeap(e,t){return`"${n.from(super.createUtf8StringFromHeap(e,t)).toString("utf8")}"`}static diagnose(e,t){"string"==typeof e&&(e=n.from(e,t||"hex"));return(new a).decodeFirst(e)}}function s(e){return(t,r)=>t?`${t}, ${r}: ${e[r]}`:`${r}: ${e[r]}`}e.exports=a},function(e,t){e.exports=function(e,t,r){"use asm";var n=new e.Uint8Array(r);var i=t.pushInt;var o=t.pushInt32;var a=t.pushInt32Neg;var s=t.pushInt64;var u=t.pushInt64Neg;var c=t.pushFloat;var h=t.pushFloatSingle;var f=t.pushFloatDouble;var l=t.pushTrue;var d=t.pushFalse;var p=t.pushUndefined;var m=t.pushNull;var g=t.pushInfinity;var b=t.pushInfinityNeg;var v=t.pushNaN;var y=t.pushNaNNeg;var w=t.pushArrayStart;var _=t.pushArrayStartFixed;var S=t.pushArrayStartFixed32;var M=t.pushArrayStartFixed64;var k=t.pushObjectStart;var E=t.pushObjectStartFixed;var A=t.pushObjectStartFixed32;var x=t.pushObjectStartFixed64;var I=t.pushByteString;var P=t.pushByteStringStart;var O=t.pushUtf8String;var T=t.pushUtf8StringStart;var R=t.pushSimpleUnassigned;var B=t.pushTagStart;var N=t.pushTagStart4;var C=t.pushTagStart8;var j=t.pushTagUnassigned;var z=t.pushBreak;var U=e.Math.pow;var L=0;var F=0;var D=0;function q(e){e=e|0;L=0;F=e;while((L|0)<(F|0)){D=Je[n[L]&255](n[L]|0)|0;if((D|0)>0){break}}return D|0}function K(e){e=e|0;if(((L|0)+(e|0)|0)<(F|0)){return 0}return 1}function H(e){e=e|0;return n[e|0]<<8|n[e+1|0]|0}function V(e){e=e|0;return n[e|0]<<24|n[e+1|0]<<16|n[e+2|0]<<8|n[e+3|0]|0}function G(e){e=e|0;i(e|0);L=L+1|0;return 0}function W(e){e=e|0;if(K(1)|0){return 1}i(n[L+1|0]|0);L=L+2|0;return 0}function Y(e){e=e|0;if(K(2)|0){return 1}i(H(L+1|0)|0);L=L+3|0;return 0}function Z(e){e=e|0;if(K(4)|0){return 1}o(H(L+1|0)|0,H(L+3|0)|0);L=L+5|0;return 0}function J(e){e=e|0;if(K(8)|0){return 1}s(H(L+1|0)|0,H(L+3|0)|0,H(L+5|0)|0,H(L+7|0)|0);L=L+9|0;return 0}function X(e){e=e|0;i(-1-(e-32|0)|0);L=L+1|0;return 0}function $(e){e=e|0;if(K(1)|0){return 1}i(-1-(n[L+1|0]|0)|0);L=L+2|0;return 0}function Q(e){e=e|0;var t=0;if(K(2)|0){return 1}t=H(L+1|0)|0;i(-1-(t|0)|0);L=L+3|0;return 0}function ee(e){e=e|0;if(K(4)|0){return 1}a(H(L+1|0)|0,H(L+3|0)|0);L=L+5|0;return 0}function te(e){e=e|0;if(K(8)|0){return 1}u(H(L+1|0)|0,H(L+3|0)|0,H(L+5|0)|0,H(L+7|0)|0);L=L+9|0;return 0}function re(e){e=e|0;var t=0;var r=0;var n=0;n=e-64|0;if(K(n|0)|0){return 1}t=L+1|0;r=(L+1|0)+(n|0)|0;I(t|0,r|0);L=r|0;return 0}function ne(e){e=e|0;var t=0;var r=0;var i=0;if(K(1)|0){return 1}i=n[L+1|0]|0;t=L+2|0;r=(L+2|0)+(i|0)|0;if(K(i+1|0)|0){return 1}I(t|0,r|0);L=r|0;return 0}function ie(e){e=e|0;var t=0;var r=0;var n=0;if(K(2)|0){return 1}n=H(L+1|0)|0;t=L+3|0;r=(L+3|0)+(n|0)|0;if(K(n+2|0)|0){return 1}I(t|0,r|0);L=r|0;return 0}function oe(e){e=e|0;var t=0;var r=0;var n=0;if(K(4)|0){return 1}n=V(L+1|0)|0;t=L+5|0;r=(L+5|0)+(n|0)|0;if(K(n+4|0)|0){return 1}I(t|0,r|0);L=r|0;return 0}function ae(e){e=e|0;return 1}function se(e){e=e|0;P();L=L+1|0;return 0}function ue(e){e=e|0;var t=0;var r=0;var n=0;n=e-96|0;if(K(n|0)|0){return 1}t=L+1|0;r=(L+1|0)+(n|0)|0;O(t|0,r|0);L=r|0;return 0}function ce(e){e=e|0;var t=0;var r=0;var i=0;if(K(1)|0){return 1}i=n[L+1|0]|0;t=L+2|0;r=(L+2|0)+(i|0)|0;if(K(i+1|0)|0){return 1}O(t|0,r|0);L=r|0;return 0}function he(e){e=e|0;var t=0;var r=0;var n=0;if(K(2)|0){return 1}n=H(L+1|0)|0;t=L+3|0;r=(L+3|0)+(n|0)|0;if(K(n+2|0)|0){return 1}O(t|0,r|0);L=r|0;return 0}function fe(e){e=e|0;var t=0;var r=0;var n=0;if(K(4)|0){return 1}n=V(L+1|0)|0;t=L+5|0;r=(L+5|0)+(n|0)|0;if(K(n+4|0)|0){return 1}O(t|0,r|0);L=r|0;return 0}function le(e){e=e|0;return 1}function de(e){e=e|0;T();L=L+1|0;return 0}function pe(e){e=e|0;_(e-128|0);L=L+1|0;return 0}function me(e){e=e|0;if(K(1)|0){return 1}_(n[L+1|0]|0);L=L+2|0;return 0}function ge(e){e=e|0;if(K(2)|0){return 1}_(H(L+1|0)|0);L=L+3|0;return 0}function be(e){e=e|0;if(K(4)|0){return 1}S(H(L+1|0)|0,H(L+3|0)|0);L=L+5|0;return 0}function ve(e){e=e|0;if(K(8)|0){return 1}M(H(L+1|0)|0,H(L+3|0)|0,H(L+5|0)|0,H(L+7|0)|0);L=L+9|0;return 0}function ye(e){e=e|0;w();L=L+1|0;return 0}function we(e){e=e|0;var t=0;t=e-160|0;if(K(t|0)|0){return 1}E(t|0);L=L+1|0;return 0}function _e(e){e=e|0;if(K(1)|0){return 1}E(n[L+1|0]|0);L=L+2|0;return 0}function Se(e){e=e|0;if(K(2)|0){return 1}E(H(L+1|0)|0);L=L+3|0;return 0}function Me(e){e=e|0;if(K(4)|0){return 1}A(H(L+1|0)|0,H(L+3|0)|0);L=L+5|0;return 0}function ke(e){e=e|0;if(K(8)|0){return 1}x(H(L+1|0)|0,H(L+3|0)|0,H(L+5|0)|0,H(L+7|0)|0);L=L+9|0;return 0}function Ee(e){e=e|0;k();L=L+1|0;return 0}function Ae(e){e=e|0;B(e-192|0|0);L=L+1|0;return 0}function xe(e){e|0;B(e|0);L=L+1|0;return 0}function Ie(e){e|0;B(e|0);L=L+1|0;return 0}function Pe(e){e|0;B(e|0);L=L+1|0;return 0}function Oe(e){e|0;B(e|0);L=L+1|0;return 0}function Te(e){e=e|0;B(e-192|0|0);L=L+1|0;return 0}function Re(e){e|0;B(e|0);L=L+1|0;return 0}function Be(e){e|0;B(e|0);L=L+1|0;return 0}function Ne(e){e|0;B(e|0);L=L+1|0;return 0}function Ce(e){e=e|0;if(K(1)|0){return 1}B(n[L+1|0]|0);L=L+2|0;return 0}function je(e){e=e|0;if(K(2)|0){return 1}B(H(L+1|0)|0);L=L+3|0;return 0}function ze(e){e=e|0;if(K(4)|0){return 1}N(H(L+1|0)|0,H(L+3|0)|0);L=L+5|0;return 0}function Ue(e){e=e|0;if(K(8)|0){return 1}C(H(L+1|0)|0,H(L+3|0)|0,H(L+5|0)|0,H(L+7|0)|0);L=L+9|0;return 0}function Le(e){e=e|0;R((e|0)-224|0);L=L+1|0;return 0}function Fe(e){e=e|0;d();L=L+1|0;return 0}function De(e){e=e|0;l();L=L+1|0;return 0}function qe(e){e=e|0;m();L=L+1|0;return 0}function Ke(e){e=e|0;p();L=L+1|0;return 0}function He(e){e=e|0;if(K(1)|0){return 1}R(n[L+1|0]|0);L=L+2|0;return 0}function Ve(e){e=e|0;var t=0;var r=0;var i=1.0;var o=0.0;var a=0.0;var s=0.0;if(K(2)|0){return 1}t=n[L+1|0]|0;r=n[L+2|0]|0;if((t|0)&0x80){i=-1.0}o=+(((t|0)&0x7C)>>2);a=+(((t|0)&0x03)<<8|r);if(+o==0.0){c(+(+i*+5.9604644775390625e-8*+a))}else if(+o==31.0){if(+i==1.0){if(+a>0.0){v()}else{g()}}else{if(+a>0.0){y()}else{b()}}}else{c(+(+i*U(+2,+(+o-25.0))*+(1024.0+a)))}L=L+3|0;return 0}function Ge(e){e=e|0;if(K(4)|0){return 1}h(n[L+1|0]|0,n[L+2|0]|0,n[L+3|0]|0,n[L+4|0]|0);L=L+5|0;return 0}function We(e){e=e|0;if(K(8)|0){return 1}f(n[L+1|0]|0,n[L+2|0]|0,n[L+3|0]|0,n[L+4|0]|0,n[L+5|0]|0,n[L+6|0]|0,n[L+7|0]|0,n[L+8|0]|0);L=L+9|0;return 0}function Ye(e){e=e|0;return 1}function Ze(e){e=e|0;z();L=L+1|0;return 0}var Je=[G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,Y,Z,J,Ye,Ye,Ye,Ye,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,$,Q,ee,te,Ye,Ye,Ye,Ye,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,re,ne,ie,oe,ae,Ye,Ye,Ye,se,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ue,ce,he,fe,le,Ye,Ye,Ye,de,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,pe,me,ge,be,ve,Ye,Ye,Ye,ye,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,we,_e,Se,Me,ke,Ye,Ye,Ye,Ee,Ae,Ae,Ae,Ae,Ae,Ae,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Te,Ce,je,ze,Ue,Ye,Ye,Ye,Ye,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Le,Fe,De,qe,Ke,He,Ve,Ge,We,Ye,Ye,Ye,Ze];return{parse:q}}},function(e,t,r){"use strict";const{URLWithLegacySupport:n,format:i}=r(145);e.exports=(e,t={},r={},o)=>{let a,s=t.protocol?t.protocol.replace(":",""):"http";s=(r[s]||o||s)+":";try{a=new n(e)}catch(e){a={}}const u=Object.assign({},t,{protocol:s||a.protocol,host:t.host||a.host});return new n(e,i(u)).toString()}},function(e,t,r){"use strict";const{Buffer:n}=r(0),{URL:i}=r(144),o=r(23).BigNumber,a=r(85),s=r(58),u=s.MT,c=s.NUMBYTES,h=s.SHIFT32,f=s.SYMS,l=s.TAG,d=s.MT.SIMPLE_FLOAT<<5|s.NUMBYTES.TWO,p=s.MT.SIMPLE_FLOAT<<5|s.NUMBYTES.FOUR,m=s.MT.SIMPLE_FLOAT<<5|s.NUMBYTES.EIGHT,g=s.MT.SIMPLE_FLOAT<<5|s.SIMPLE.TRUE,b=s.MT.SIMPLE_FLOAT<<5|s.SIMPLE.FALSE,v=s.MT.SIMPLE_FLOAT<<5|s.SIMPLE.UNDEFINED,y=s.MT.SIMPLE_FLOAT<<5|s.SIMPLE.NULL,w=new o("0x20000000000000"),_=n.from("f97e00","hex"),S=n.from("f9fc00","hex"),M=n.from("f97c00","hex");class k{constructor(e){e=e||{},this.streaming="function"==typeof e.stream,this.onData=e.stream,this.semanticTypes=[[i,this._pushUrl],[o,this._pushBigNumber]];const t=e.genTypes||[],r=t.length;for(let e=0;e[t,e[t]]))}_pushRawMap(e,t){t=t.map((function(e){return e[0]=k.encode(e[0]),e})).sort(a.keySorter);for(var r=0;r=r;)n[i++]=255&t|128,t/=128;for(;-128&t;)n[i++]=255&t|128,t>>>=7;return n[i]=0|t,e.bytes=i-o+1,n};var r=Math.pow(2,31)},function(e,t){e.exports=function e(t,r){var n,i=0,o=0,a=r=r||0,s=t.length;do{if(a>=s)throw e.bytes=0,new RangeError("Could not decode varint");n=t[a++],i+=o<28?(127&n)<=128);return e.bytes=a-r,i}},function(e,t){var r=Math.pow(2,7),n=Math.pow(2,14),i=Math.pow(2,21),o=Math.pow(2,28),a=Math.pow(2,35),s=Math.pow(2,42),u=Math.pow(2,49),c=Math.pow(2,56),h=Math.pow(2,63);e.exports=function(e){return e=255)throw new TypeError("Alphabet too long");for(var t=new Uint8Array(256),r=0;r>>0,c=new Uint8Array(o);e[r];){var h=t[e.charCodeAt(r)];if(255===h)return;for(var f=0,l=o-1;(0!==h||f>>0,c[l]=h%256>>>0,h=h/256>>>0;if(0!==h)throw new Error("Non-zero carry");i=f,r++}if(" "!==e[r]){for(var d=o-i;d!==o&&0===c[d];)d++;for(var p=new Uint8Array(n+(o-d)),m=n;d!==o;)p[m++]=c[d++];return p}}}return{encode:function(t){if(t instanceof Uint8Array||(ArrayBuffer.isView(t)?t=new Uint8Array(t.buffer,t.byteOffset,t.byteLength):Array.isArray(t)&&(t=Uint8Array.from(t))),!(t instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(0===t.length)return"";for(var r=0,n=0,i=0,o=t.length;i!==o&&0===t[i];)i++,r++;for(var u=(o-i)*c+1>>>0,h=new Uint8Array(u);i!==o;){for(var f=t[i],l=0,d=u-1;(0!==f||l>>0,h[d]=f%a>>>0,f=f/a>>>0;if(0!==f)throw new Error("Non-zero carry");n=l,i++}for(var p=u-n;p!==u&&0===h[p];)p++;for(var m=s.repeat(r);pt=>({encode:r=>((e,t,r)=>{const n="="===t[t.length-1],i=(1<r;)a-=r,o+=t[i&s>>a];if(a&&(o+=t[i&s<((e,t,r)=>{const n={};for(let e=0;e=8&&(a-=8,o[u++]=255&s>>a)}if(a>=r||255&s<<8-a)throw new SyntaxError("Unexpected end of data");return o})(r,t,e)})},function(e,t,r){"use strict";const{names:n}=r(43),{TextEncoder:i}=r(44),o=new i;e.exports=function(e,t="utf8"){if("utf8"===t||"utf-8"===t)return o.encode(e);const r=n[t];if(!r)throw new Error("Unknown base");return r.decode(e)}},function(e,t,r){"use strict";e.exports=function(e,t){t||(t=e.reduce((e,t)=>e+t.length,0));const r=new Uint8Array(t);let n=0;for(const t of e)r.set(t,n),n+=t.length;return r}},function(e,t,r){"use strict";const n=r(42),i={};for(const[e,t]of Object.entries(n))i[e.toUpperCase().replace(/-/g,"_")]=t;e.exports=Object.freeze(i)},function(e,t,r){"use strict";const n=r(42),i={};for(const[e,t]of Object.entries(n))void 0===i[t]&&(i[t]=e);e.exports=Object.freeze(i)},function(e,t,r){"use strict";const n=r(289),i=r(59),o=r(291),a=r(151);async function s(e,t,r){const n=await s.digest(e,t,r);return i.encode(n,t,r)}s.multihash=i,s.digest=async(e,t,r)=>{const n=s.createHash(t),i=await n(e);return r?i.slice(0,r):i},s.createHash=function(e){if(!e)throw n(new Error("hash algorithm must be specified"),"ERR_HASH_ALGORITHM_NOT_SPECIFIED");if(e=i.coerceCode(e),!s.functions[e])throw n(new Error(`multihash function '${e}' not yet supported`),"ERR_HASH_ALGORITHM_NOT_SUPPORTED");return s.functions[e]},s.functions={0:o.identity,17:o.sha1,18:o.sha2256,19:o.sha2512,20:o.sha3512,21:o.sha3384,22:o.sha3256,23:o.sha3224,24:o.shake128,25:o.shake256,26:o.keccak224,27:o.keccak256,28:o.keccak384,29:o.keccak512,34:o.murmur3128,35:o.murmur332,86:o.dblSha2256},o.addBlake(s.functions),s.validate=async(e,t)=>{const r=await s(e,i.decode(t).name);return a(t,r)},e.exports=s},function(e,t,r){"use strict";function n(e,t){for(const r in t)Object.defineProperty(e,r,{value:t[r],enumerable:!0,configurable:!0});return e}e.exports=function(e,t,r){if(!e||"string"==typeof e)throw new TypeError("Please pass an Error to err-code");r||(r={}),"object"==typeof t&&(r=t,t=void 0),null!=t&&(r.code=t);try{return n(e,r)}catch(t){r.message=e.message,r.stack=e.stack;const i=function(){};return i.prototype=Object.create(Object.getPrototypeOf(e)),n(new i,r)}}},function(e,t,r){"use strict";const n=Object.freeze({identity:0,sha1:17,"sha2-256":18,"sha2-512":19,"sha3-512":20,"sha3-384":21,"sha3-256":22,"sha3-224":23,"shake-128":24,"shake-256":25,"keccak-224":26,"keccak-256":27,"keccak-384":28,"keccak-512":29,blake3:30,"murmur3-128":34,"murmur3-32":35,"dbl-sha2-256":86,md4:212,md5:213,bmt:214,"sha2-256-trunc254-padded":4114,"ripemd-128":4178,"ripemd-160":4179,"ripemd-256":4180,"ripemd-320":4181,x11:4352,"sm3-256":21325,"blake2b-8":45569,"blake2b-16":45570,"blake2b-24":45571,"blake2b-32":45572,"blake2b-40":45573,"blake2b-48":45574,"blake2b-56":45575,"blake2b-64":45576,"blake2b-72":45577,"blake2b-80":45578,"blake2b-88":45579,"blake2b-96":45580,"blake2b-104":45581,"blake2b-112":45582,"blake2b-120":45583,"blake2b-128":45584,"blake2b-136":45585,"blake2b-144":45586,"blake2b-152":45587,"blake2b-160":45588,"blake2b-168":45589,"blake2b-176":45590,"blake2b-184":45591,"blake2b-192":45592,"blake2b-200":45593,"blake2b-208":45594,"blake2b-216":45595,"blake2b-224":45596,"blake2b-232":45597,"blake2b-240":45598,"blake2b-248":45599,"blake2b-256":45600,"blake2b-264":45601,"blake2b-272":45602,"blake2b-280":45603,"blake2b-288":45604,"blake2b-296":45605,"blake2b-304":45606,"blake2b-312":45607,"blake2b-320":45608,"blake2b-328":45609,"blake2b-336":45610,"blake2b-344":45611,"blake2b-352":45612,"blake2b-360":45613,"blake2b-368":45614,"blake2b-376":45615,"blake2b-384":45616,"blake2b-392":45617,"blake2b-400":45618,"blake2b-408":45619,"blake2b-416":45620,"blake2b-424":45621,"blake2b-432":45622,"blake2b-440":45623,"blake2b-448":45624,"blake2b-456":45625,"blake2b-464":45626,"blake2b-472":45627,"blake2b-480":45628,"blake2b-488":45629,"blake2b-496":45630,"blake2b-504":45631,"blake2b-512":45632,"blake2s-8":45633,"blake2s-16":45634,"blake2s-24":45635,"blake2s-32":45636,"blake2s-40":45637,"blake2s-48":45638,"blake2s-56":45639,"blake2s-64":45640,"blake2s-72":45641,"blake2s-80":45642,"blake2s-88":45643,"blake2s-96":45644,"blake2s-104":45645,"blake2s-112":45646,"blake2s-120":45647,"blake2s-128":45648,"blake2s-136":45649,"blake2s-144":45650,"blake2s-152":45651,"blake2s-160":45652,"blake2s-168":45653,"blake2s-176":45654,"blake2s-184":45655,"blake2s-192":45656,"blake2s-200":45657,"blake2s-208":45658,"blake2s-216":45659,"blake2s-224":45660,"blake2s-232":45661,"blake2s-240":45662,"blake2s-248":45663,"blake2s-256":45664,"skein256-8":45825,"skein256-16":45826,"skein256-24":45827,"skein256-32":45828,"skein256-40":45829,"skein256-48":45830,"skein256-56":45831,"skein256-64":45832,"skein256-72":45833,"skein256-80":45834,"skein256-88":45835,"skein256-96":45836,"skein256-104":45837,"skein256-112":45838,"skein256-120":45839,"skein256-128":45840,"skein256-136":45841,"skein256-144":45842,"skein256-152":45843,"skein256-160":45844,"skein256-168":45845,"skein256-176":45846,"skein256-184":45847,"skein256-192":45848,"skein256-200":45849,"skein256-208":45850,"skein256-216":45851,"skein256-224":45852,"skein256-232":45853,"skein256-240":45854,"skein256-248":45855,"skein256-256":45856,"skein512-8":45857,"skein512-16":45858,"skein512-24":45859,"skein512-32":45860,"skein512-40":45861,"skein512-48":45862,"skein512-56":45863,"skein512-64":45864,"skein512-72":45865,"skein512-80":45866,"skein512-88":45867,"skein512-96":45868,"skein512-104":45869,"skein512-112":45870,"skein512-120":45871,"skein512-128":45872,"skein512-136":45873,"skein512-144":45874,"skein512-152":45875,"skein512-160":45876,"skein512-168":45877,"skein512-176":45878,"skein512-184":45879,"skein512-192":45880,"skein512-200":45881,"skein512-208":45882,"skein512-216":45883,"skein512-224":45884,"skein512-232":45885,"skein512-240":45886,"skein512-248":45887,"skein512-256":45888,"skein512-264":45889,"skein512-272":45890,"skein512-280":45891,"skein512-288":45892,"skein512-296":45893,"skein512-304":45894,"skein512-312":45895,"skein512-320":45896,"skein512-328":45897,"skein512-336":45898,"skein512-344":45899,"skein512-352":45900,"skein512-360":45901,"skein512-368":45902,"skein512-376":45903,"skein512-384":45904,"skein512-392":45905,"skein512-400":45906,"skein512-408":45907,"skein512-416":45908,"skein512-424":45909,"skein512-432":45910,"skein512-440":45911,"skein512-448":45912,"skein512-456":45913,"skein512-464":45914,"skein512-472":45915,"skein512-480":45916,"skein512-488":45917,"skein512-496":45918,"skein512-504":45919,"skein512-512":45920,"skein1024-8":45921,"skein1024-16":45922,"skein1024-24":45923,"skein1024-32":45924,"skein1024-40":45925,"skein1024-48":45926,"skein1024-56":45927,"skein1024-64":45928,"skein1024-72":45929,"skein1024-80":45930,"skein1024-88":45931,"skein1024-96":45932,"skein1024-104":45933,"skein1024-112":45934,"skein1024-120":45935,"skein1024-128":45936,"skein1024-136":45937,"skein1024-144":45938,"skein1024-152":45939,"skein1024-160":45940,"skein1024-168":45941,"skein1024-176":45942,"skein1024-184":45943,"skein1024-192":45944,"skein1024-200":45945,"skein1024-208":45946,"skein1024-216":45947,"skein1024-224":45948,"skein1024-232":45949,"skein1024-240":45950,"skein1024-248":45951,"skein1024-256":45952,"skein1024-264":45953,"skein1024-272":45954,"skein1024-280":45955,"skein1024-288":45956,"skein1024-296":45957,"skein1024-304":45958,"skein1024-312":45959,"skein1024-320":45960,"skein1024-328":45961,"skein1024-336":45962,"skein1024-344":45963,"skein1024-352":45964,"skein1024-360":45965,"skein1024-368":45966,"skein1024-376":45967,"skein1024-384":45968,"skein1024-392":45969,"skein1024-400":45970,"skein1024-408":45971,"skein1024-416":45972,"skein1024-424":45973,"skein1024-432":45974,"skein1024-440":45975,"skein1024-448":45976,"skein1024-456":45977,"skein1024-464":45978,"skein1024-472":45979,"skein1024-480":45980,"skein1024-488":45981,"skein1024-496":45982,"skein1024-504":45983,"skein1024-512":45984,"skein1024-520":45985,"skein1024-528":45986,"skein1024-536":45987,"skein1024-544":45988,"skein1024-552":45989,"skein1024-560":45990,"skein1024-568":45991,"skein1024-576":45992,"skein1024-584":45993,"skein1024-592":45994,"skein1024-600":45995,"skein1024-608":45996,"skein1024-616":45997,"skein1024-624":45998,"skein1024-632":45999,"skein1024-640":46e3,"skein1024-648":46001,"skein1024-656":46002,"skein1024-664":46003,"skein1024-672":46004,"skein1024-680":46005,"skein1024-688":46006,"skein1024-696":46007,"skein1024-704":46008,"skein1024-712":46009,"skein1024-720":46010,"skein1024-728":46011,"skein1024-736":46012,"skein1024-744":46013,"skein1024-752":46014,"skein1024-760":46015,"skein1024-768":46016,"skein1024-776":46017,"skein1024-784":46018,"skein1024-792":46019,"skein1024-800":46020,"skein1024-808":46021,"skein1024-816":46022,"skein1024-824":46023,"skein1024-832":46024,"skein1024-840":46025,"skein1024-848":46026,"skein1024-856":46027,"skein1024-864":46028,"skein1024-872":46029,"skein1024-880":46030,"skein1024-888":46031,"skein1024-896":46032,"skein1024-904":46033,"skein1024-912":46034,"skein1024-920":46035,"skein1024-928":46036,"skein1024-936":46037,"skein1024-944":46038,"skein1024-952":46039,"skein1024-960":46040,"skein1024-968":46041,"skein1024-976":46042,"skein1024-984":46043,"skein1024-992":46044,"skein1024-1000":46045,"skein1024-1008":46046,"skein1024-1016":46047,"skein1024-1024":46048,"poseidon-bls12_381-a2-fc1":46081,"poseidon-bls12_381-a2-fc1-sc":46082});e.exports={names:n}},function(e,t,r){"use strict";const n=r(292),i=r(294),{factory:o}=r(296),{fromNumberTo32BitBuf:a}=r(297),s=r(88),u=e=>async t=>{switch(e){case"sha3-224":return new Uint8Array(n.sha3_224.arrayBuffer(t));case"sha3-256":return new Uint8Array(n.sha3_256.arrayBuffer(t));case"sha3-384":return new Uint8Array(n.sha3_384.arrayBuffer(t));case"sha3-512":return new Uint8Array(n.sha3_512.arrayBuffer(t));case"shake-128":return new Uint8Array(n.shake128.create(128).update(t).arrayBuffer());case"shake-256":return new Uint8Array(n.shake256.create(256).update(t).arrayBuffer());case"keccak-224":return new Uint8Array(n.keccak224.arrayBuffer(t));case"keccak-256":return new Uint8Array(n.keccak256.arrayBuffer(t));case"keccak-384":return new Uint8Array(n.keccak384.arrayBuffer(t));case"keccak-512":return new Uint8Array(n.keccak512.arrayBuffer(t));case"murmur3-128":return s(i.x64.hash128(t),"base16");case"murmur3-32":return a(i.x86.hash32(t));default:throw new TypeError(e+" is not a supported algorithm")}};e.exports={identity:e=>e,sha1:o("sha1"),sha2256:o("sha2-256"),sha2512:o("sha2-512"),dblSha2256:o("dbl-sha2-256"),sha3224:u("sha3-224"),sha3256:u("sha3-256"),sha3384:u("sha3-384"),sha3512:u("sha3-512"),shake128:u("shake-128"),shake256:u("shake-256"),keccak224:u("keccak-224"),keccak256:u("keccak-256"),keccak384:u("keccak-384"),keccak512:u("keccak-512"),murmur3128:u("murmur3-128"),murmur332:u("murmur3-32"),addBlake:r(298)}},function(e,t,r){(function(n,i){var o; +/** + * [js-sha3]{@link https://github.com/emn178/js-sha3} + * + * @version 0.8.0 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2015-2018 + * @license MIT + */!function(){"use strict";var a="input is invalid type",s="object"==typeof window,u=s?window:{};u.JS_SHA3_NO_WINDOW&&(s=!1);var c=!s&&"object"==typeof self;!u.JS_SHA3_NO_NODE_JS&&"object"==typeof n&&n.versions&&n.versions.node?u=i:c&&(u=self);var h=!u.JS_SHA3_NO_COMMON_JS&&"object"==typeof e&&e.exports,f=r(293),l=!u.JS_SHA3_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,d="0123456789abcdef".split(""),p=[4,1024,262144,67108864],m=[0,8,16,24],g=[1,0,32898,0,32906,2147483648,2147516416,2147483648,32907,0,2147483649,0,2147516545,2147483648,32777,2147483648,138,0,136,0,2147516425,0,2147483658,0,2147516555,0,139,2147483648,32905,2147483648,32771,2147483648,32770,2147483648,128,2147483648,32778,0,2147483658,2147483648,2147516545,2147483648,32896,2147483648,2147483649,0,2147516424,2147483648],b=[224,256,384,512],v=[128,256],y=["hex","buffer","arrayBuffer","array","digest"],w={128:168,256:136};!u.JS_SHA3_NO_NODE_JS&&Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),!l||!u.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW&&ArrayBuffer.isView||(ArrayBuffer.isView=function(e){return"object"==typeof e&&e.buffer&&e.buffer.constructor===ArrayBuffer});for(var _=function(e,t,r){return function(n){return new j(e,t,e).update(n)[r]()}},S=function(e,t,r){return function(n,i){return new j(e,t,i).update(n)[r]()}},M=function(e,t,r){return function(t,n,i,o){return I["cshake"+e].update(t,n,i,o)[r]()}},k=function(e,t,r){return function(t,n,i,o){return I["kmac"+e].update(t,n,i,o)[r]()}},E=function(e,t,r,n){for(var i=0;i>5,this.byteCount=this.blockCount<<2,this.outputBlocks=r>>5,this.extraBytes=(31&r)>>3;for(var n=0;n<50;++n)this.s[n]=0}function z(e,t,r){j.call(this,e,t,r)}j.prototype.update=function(e){if(this.finalized)throw new Error("finalize already called");var t,r=typeof e;if("string"!==r){if("object"!==r)throw new Error(a);if(null===e)throw new Error(a);if(l&&e.constructor===ArrayBuffer)e=new Uint8Array(e);else if(!(Array.isArray(e)||l&&ArrayBuffer.isView(e)))throw new Error(a);t=!0}for(var n,i,o=this.blocks,s=this.byteCount,u=e.length,c=this.blockCount,h=0,f=this.s;h>2]|=e[h]<>2]|=i<>2]|=(192|i>>6)<>2]|=(128|63&i)<=57344?(o[n>>2]|=(224|i>>12)<>2]|=(128|i>>6&63)<>2]|=(128|63&i)<>2]|=(240|i>>18)<>2]|=(128|i>>12&63)<>2]|=(128|i>>6&63)<>2]|=(128|63&i)<=s){for(this.start=n-s,this.block=o[c],n=0;n>=8);r>0;)i.unshift(r),r=255&(e>>=8),++n;return t?i.push(n):i.unshift(n),this.update(i),i.length},j.prototype.encodeString=function(e){var t,r=typeof e;if("string"!==r){if("object"!==r)throw new Error(a);if(null===e)throw new Error(a);if(l&&e.constructor===ArrayBuffer)e=new Uint8Array(e);else if(!(Array.isArray(e)||l&&ArrayBuffer.isView(e)))throw new Error(a);t=!0}var n=0,i=e.length;if(t)n=i;else for(var o=0;o=57344?n+=3:(s=65536+((1023&s)<<10|1023&e.charCodeAt(++o)),n+=4)}return n+=this.encode(8*n),this.update(e),n},j.prototype.bytepad=function(e,t){for(var r=this.encode(t),n=0;n>2]|=this.padding[3&t],this.lastByteIndex===this.byteCount)for(e[0]=e[r],t=1;t>4&15]+d[15&e]+d[e>>12&15]+d[e>>8&15]+d[e>>20&15]+d[e>>16&15]+d[e>>28&15]+d[e>>24&15];a%t==0&&(U(r),o=0)}return i&&(e=r[o],s+=d[e>>4&15]+d[15&e],i>1&&(s+=d[e>>12&15]+d[e>>8&15]),i>2&&(s+=d[e>>20&15]+d[e>>16&15])),s},j.prototype.arrayBuffer=function(){this.finalize();var e,t=this.blockCount,r=this.s,n=this.outputBlocks,i=this.extraBytes,o=0,a=0,s=this.outputBits>>3;e=i?new ArrayBuffer(n+1<<2):new ArrayBuffer(s);for(var u=new Uint32Array(e);a>8&255,u[e+2]=t>>16&255,u[e+3]=t>>24&255;s%r==0&&U(n)}return o&&(e=s<<2,t=n[a],u[e]=255&t,o>1&&(u[e+1]=t>>8&255),o>2&&(u[e+2]=t>>16&255)),u},z.prototype=new j,z.prototype.finalize=function(){return this.encode(this.outputBits,!0),j.prototype.finalize.call(this)};var U=function(e){var t,r,n,i,o,a,s,u,c,h,f,l,d,p,m,b,v,y,w,_,S,M,k,E,A,x,I,P,O,T,R,B,N,C,j,z,U,L,F,D,q,K,H,V,G,W,Y,Z,J,X,$,Q,ee,te,re,ne,ie,oe,ae,se,ue,ce,he;for(n=0;n<48;n+=2)i=e[0]^e[10]^e[20]^e[30]^e[40],o=e[1]^e[11]^e[21]^e[31]^e[41],a=e[2]^e[12]^e[22]^e[32]^e[42],s=e[3]^e[13]^e[23]^e[33]^e[43],u=e[4]^e[14]^e[24]^e[34]^e[44],c=e[5]^e[15]^e[25]^e[35]^e[45],h=e[6]^e[16]^e[26]^e[36]^e[46],f=e[7]^e[17]^e[27]^e[37]^e[47],t=(l=e[8]^e[18]^e[28]^e[38]^e[48])^(a<<1|s>>>31),r=(d=e[9]^e[19]^e[29]^e[39]^e[49])^(s<<1|a>>>31),e[0]^=t,e[1]^=r,e[10]^=t,e[11]^=r,e[20]^=t,e[21]^=r,e[30]^=t,e[31]^=r,e[40]^=t,e[41]^=r,t=i^(u<<1|c>>>31),r=o^(c<<1|u>>>31),e[2]^=t,e[3]^=r,e[12]^=t,e[13]^=r,e[22]^=t,e[23]^=r,e[32]^=t,e[33]^=r,e[42]^=t,e[43]^=r,t=a^(h<<1|f>>>31),r=s^(f<<1|h>>>31),e[4]^=t,e[5]^=r,e[14]^=t,e[15]^=r,e[24]^=t,e[25]^=r,e[34]^=t,e[35]^=r,e[44]^=t,e[45]^=r,t=u^(l<<1|d>>>31),r=c^(d<<1|l>>>31),e[6]^=t,e[7]^=r,e[16]^=t,e[17]^=r,e[26]^=t,e[27]^=r,e[36]^=t,e[37]^=r,e[46]^=t,e[47]^=r,t=h^(i<<1|o>>>31),r=f^(o<<1|i>>>31),e[8]^=t,e[9]^=r,e[18]^=t,e[19]^=r,e[28]^=t,e[29]^=r,e[38]^=t,e[39]^=r,e[48]^=t,e[49]^=r,p=e[0],m=e[1],W=e[11]<<4|e[10]>>>28,Y=e[10]<<4|e[11]>>>28,P=e[20]<<3|e[21]>>>29,O=e[21]<<3|e[20]>>>29,se=e[31]<<9|e[30]>>>23,ue=e[30]<<9|e[31]>>>23,K=e[40]<<18|e[41]>>>14,H=e[41]<<18|e[40]>>>14,C=e[2]<<1|e[3]>>>31,j=e[3]<<1|e[2]>>>31,b=e[13]<<12|e[12]>>>20,v=e[12]<<12|e[13]>>>20,Z=e[22]<<10|e[23]>>>22,J=e[23]<<10|e[22]>>>22,T=e[33]<<13|e[32]>>>19,R=e[32]<<13|e[33]>>>19,ce=e[42]<<2|e[43]>>>30,he=e[43]<<2|e[42]>>>30,te=e[5]<<30|e[4]>>>2,re=e[4]<<30|e[5]>>>2,z=e[14]<<6|e[15]>>>26,U=e[15]<<6|e[14]>>>26,y=e[25]<<11|e[24]>>>21,w=e[24]<<11|e[25]>>>21,X=e[34]<<15|e[35]>>>17,$=e[35]<<15|e[34]>>>17,B=e[45]<<29|e[44]>>>3,N=e[44]<<29|e[45]>>>3,E=e[6]<<28|e[7]>>>4,A=e[7]<<28|e[6]>>>4,ne=e[17]<<23|e[16]>>>9,ie=e[16]<<23|e[17]>>>9,L=e[26]<<25|e[27]>>>7,F=e[27]<<25|e[26]>>>7,_=e[36]<<21|e[37]>>>11,S=e[37]<<21|e[36]>>>11,Q=e[47]<<24|e[46]>>>8,ee=e[46]<<24|e[47]>>>8,V=e[8]<<27|e[9]>>>5,G=e[9]<<27|e[8]>>>5,x=e[18]<<20|e[19]>>>12,I=e[19]<<20|e[18]>>>12,oe=e[29]<<7|e[28]>>>25,ae=e[28]<<7|e[29]>>>25,D=e[38]<<8|e[39]>>>24,q=e[39]<<8|e[38]>>>24,M=e[48]<<14|e[49]>>>18,k=e[49]<<14|e[48]>>>18,e[0]=p^~b&y,e[1]=m^~v&w,e[10]=E^~x&P,e[11]=A^~I&O,e[20]=C^~z&L,e[21]=j^~U&F,e[30]=V^~W&Z,e[31]=G^~Y&J,e[40]=te^~ne&oe,e[41]=re^~ie&ae,e[2]=b^~y&_,e[3]=v^~w&S,e[12]=x^~P&T,e[13]=I^~O&R,e[22]=z^~L&D,e[23]=U^~F&q,e[32]=W^~Z&X,e[33]=Y^~J&$,e[42]=ne^~oe&se,e[43]=ie^~ae&ue,e[4]=y^~_&M,e[5]=w^~S&k,e[14]=P^~T&B,e[15]=O^~R&N,e[24]=L^~D&K,e[25]=F^~q&H,e[34]=Z^~X&Q,e[35]=J^~$&ee,e[44]=oe^~se&ce,e[45]=ae^~ue&he,e[6]=_^~M&p,e[7]=S^~k&m,e[16]=T^~B&E,e[17]=R^~N&A,e[26]=D^~K&C,e[27]=q^~H&j,e[36]=X^~Q&V,e[37]=$^~ee&G,e[46]=se^~ce&te,e[47]=ue^~he&re,e[8]=M^~p&b,e[9]=k^~m&v,e[18]=B^~E&x,e[19]=N^~A&I,e[28]=K^~C&z,e[29]=H^~j&U,e[38]=Q^~V&W,e[39]=ee^~G&Y,e[48]=ce^~te&ne,e[49]=he^~re&ie,e[0]^=g[n],e[1]^=g[n+1]};if(h)e.exports=I;else{for(O=0;O255)return!1;return!0}function a(e,t){return(65535&e)*t+(((e>>>16)*t&65535)<<16)}function s(e,t){return e<>>32-t}function u(e){return e=a(e^=e>>>16,2246822507),e=a(e^=e>>>13,3266489909),e^=e>>>16}function c(e,t){e=[e[0]>>>16,65535&e[0],e[1]>>>16,65535&e[1]],t=[t[0]>>>16,65535&t[0],t[1]>>>16,65535&t[1]];var r=[0,0,0,0];return r[3]+=e[3]+t[3],r[2]+=r[3]>>>16,r[3]&=65535,r[2]+=e[2]+t[2],r[1]+=r[2]>>>16,r[2]&=65535,r[1]+=e[1]+t[1],r[0]+=r[1]>>>16,r[1]&=65535,r[0]+=e[0]+t[0],r[0]&=65535,[r[0]<<16|r[1],r[2]<<16|r[3]]}function h(e,t){e=[e[0]>>>16,65535&e[0],e[1]>>>16,65535&e[1]],t=[t[0]>>>16,65535&t[0],t[1]>>>16,65535&t[1]];var r=[0,0,0,0];return r[3]+=e[3]*t[3],r[2]+=r[3]>>>16,r[3]&=65535,r[2]+=e[2]*t[3],r[1]+=r[2]>>>16,r[2]&=65535,r[2]+=e[3]*t[2],r[1]+=r[2]>>>16,r[2]&=65535,r[1]+=e[1]*t[3],r[0]+=r[1]>>>16,r[1]&=65535,r[1]+=e[2]*t[2],r[0]+=r[1]>>>16,r[1]&=65535,r[1]+=e[3]*t[1],r[0]+=r[1]>>>16,r[1]&=65535,r[0]+=e[0]*t[3]+e[1]*t[2]+e[2]*t[1]+e[3]*t[0],r[0]&=65535,[r[0]<<16|r[1],r[2]<<16|r[3]]}function f(e,t){return 32===(t%=64)?[e[1],e[0]]:t<32?[e[0]<>>32-t,e[1]<>>32-t]:(t-=32,[e[1]<>>32-t,e[0]<>>32-t])}function l(e,t){return 0===(t%=64)?e:t<32?[e[0]<>>32-t,e[1]<>>1]),e=d(e=h(e,[4283543511,3981806797]),[0,e[0]>>>1]),e=d(e=h(e,[3301882366,444984403]),[0,e[0]>>>1])}i.x86.hash32=function(e,t){if(!i.inputValidation||o(e)){t=t||0;for(var r=e.length%4,n=e.length-r,c=t,h=0,f=3432918353,l=461845907,d=0;d>>0}},i.x86.hash128=function(e,t){if(!i.inputValidation||o(e)){t=t||0;for(var r=e.length%16,n=e.length-r,c=t,h=t,f=t,l=t,d=0,p=0,m=0,g=0,b=597399067,v=2869860233,y=951274213,w=2716044179,_=0;_>>0).toString(16)).slice(-8)+("00000000"+(h>>>0).toString(16)).slice(-8)+("00000000"+(f>>>0).toString(16)).slice(-8)+("00000000"+(l>>>0).toString(16)).slice(-8)}},i.x64.hash128=function(e,t){if(!i.inputValidation||o(e)){t=t||0;for(var r=e.length%16,n=e.length-r,a=[0,t],s=[0,t],u=[0,0],m=[0,0],g=[2277735313,289559509],b=[1291169091,658871167],v=0;v>>0).toString(16)).slice(-8)+("00000000"+(a[1]>>>0).toString(16)).slice(-8)+("00000000"+(s[0]>>>0).toString(16)).slice(-8)+("00000000"+(s[1]>>>0).toString(16)).slice(-8)}},e.exports&&(t=e.exports=i),t.murmurHash3=i}()},function(e,t,r){"use strict";const n=r(59),i=self.crypto||self.msCrypto,o=async(e,t)=>{if("undefined"==typeof self||!self.crypto&&!self.msCrypto)throw new Error("Please use a browser with webcrypto support and ensure the code has been delivered securely via HTTPS/TLS and run within a Secure Context");switch(t){case"sha1":return new Uint8Array(await i.subtle.digest({name:"SHA-1"},e));case"sha2-256":return new Uint8Array(await i.subtle.digest({name:"SHA-256"},e));case"sha2-512":return new Uint8Array(await i.subtle.digest({name:"SHA-512"},e));case"dbl-sha2-256":{const t=await i.subtle.digest({name:"SHA-256"},e);return new Uint8Array(await i.subtle.digest({name:"SHA-256"},t))}default:throw new Error(t+" is not a supported algorithm")}};e.exports={factory:e=>async t=>o(t,e),digest:o,multihashing:async(e,t,r)=>{const i=await o(e,t);return n.encode(i,t,r)}}},function(e,t,r){"use strict";e.exports={fromNumberTo32BitBuf:e=>{const t=new Uint8Array(4);for(let r=0;r<4;r++)t[r]=255&e,e>>=8;return t}}},function(e,t,r){"use strict";const n=r(90),i={init:n.blake2bInit,update:n.blake2bUpdate,digest:n.blake2bFinal},o={init:n.blake2sInit,update:n.blake2sUpdate,digest:n.blake2sFinal},a=(e,t)=>async r=>{const n=t.init(e,null);return t.update(n,r),t.digest(n)};e.exports=e=>{for(let t=0;t<64;t++)e[45569+t]=a(t+1,i);for(let t=0;t<32;t++)e[45633+t]=a(t+1,o)}},function(e,t,r){var n=r(150);function i(e,t,r){var n=e[t]+e[r],i=e[t+1]+e[r+1];n>=4294967296&&i++,e[t]=n,e[t+1]=i}function o(e,t,r,n){var i=e[t]+r;r<0&&(i+=4294967296);var o=e[t+1]+n;i>=4294967296&&o++,e[t]=i,e[t+1]=o}function a(e,t){return e[t]^e[t+1]<<8^e[t+2]<<16^e[t+3]<<24}function s(e,t,r,n,a,s){var u=f[a],c=f[a+1],l=f[s],d=f[s+1];i(h,e,t),o(h,e,u,c);var p=h[n]^h[e],m=h[n+1]^h[e+1];h[n]=m,h[n+1]=p,i(h,r,n),p=h[t]^h[r],m=h[t+1]^h[r+1],h[t]=p>>>24^m<<8,h[t+1]=m>>>24^p<<8,i(h,e,t),o(h,e,l,d),p=h[n]^h[e],m=h[n+1]^h[e+1],h[n]=p>>>16^m<<16,h[n+1]=m>>>16^p<<16,i(h,r,n),p=h[t]^h[r],m=h[t+1]^h[r+1],h[t]=m>>>31^p<<1,h[t+1]=p>>>31^m<<1}var u=new Uint32Array([4089235720,1779033703,2227873595,3144134277,4271175723,1013904242,1595750129,2773480762,2917565137,1359893119,725511199,2600822924,4215389547,528734635,327033209,1541459225]),c=new Uint8Array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9,12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11,13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10,6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5,10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3].map((function(e){return 2*e}))),h=new Uint32Array(32),f=new Uint32Array(32);function l(e,t){var r=0;for(r=0;r<16;r++)h[r]=e.h[r],h[r+16]=u[r];for(h[24]=h[24]^e.t,h[25]=h[25]^e.t/4294967296,t&&(h[28]=~h[28],h[29]=~h[29]),r=0;r<32;r++)f[r]=a(e.b,4*r);for(r=0;r<12;r++)s(0,8,16,24,c[16*r+0],c[16*r+1]),s(2,10,18,26,c[16*r+2],c[16*r+3]),s(4,12,20,28,c[16*r+4],c[16*r+5]),s(6,14,22,30,c[16*r+6],c[16*r+7]),s(0,10,20,30,c[16*r+8],c[16*r+9]),s(2,12,22,24,c[16*r+10],c[16*r+11]),s(4,14,16,26,c[16*r+12],c[16*r+13]),s(6,8,18,28,c[16*r+14],c[16*r+15]);for(r=0;r<16;r++)e.h[r]=e.h[r]^h[r]^h[r+16]}function d(e,t){if(0===e||e>64)throw new Error("Illegal output length, expected 0 < length <= 64");if(t&&t.length>64)throw new Error("Illegal key, expected Uint8Array with 0 < length <= 64");for(var r={b:new Uint8Array(128),h:new Uint32Array(16),t:0,c:0,outlen:e},n=0;n<16;n++)r.h[n]=u[n];var i=t?t.length:0;return r.h[0]^=16842752^i<<8^e,t&&(p(r,t),r.c=128),r}function p(e,t){for(var r=0;r>2]>>8*(3&r);return t}function g(e,t,r){r=r||64,e=n.normalizeInput(e);var i=d(r,t);return p(i,e),m(i)}e.exports={blake2b:g,blake2bHex:function(e,t,r){var i=g(e,t,r);return n.toHex(i)},blake2bInit:d,blake2bUpdate:p,blake2bFinal:m}},function(e,t,r){var n=r(150);function i(e,t){return e[t]^e[t+1]<<8^e[t+2]<<16^e[t+3]<<24}function o(e,t,r,n,i,o){c[e]=c[e]+c[t]+i,c[n]=a(c[n]^c[e],16),c[r]=c[r]+c[n],c[t]=a(c[t]^c[r],12),c[e]=c[e]+c[t]+o,c[n]=a(c[n]^c[e],8),c[r]=c[r]+c[n],c[t]=a(c[t]^c[r],7)}function a(e,t){return e>>>t^e<<32-t}var s=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),u=new Uint8Array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9,12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11,13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10,6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5,10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0]),c=new Uint32Array(16),h=new Uint32Array(16);function f(e,t){var r=0;for(r=0;r<8;r++)c[r]=e.h[r],c[r+8]=s[r];for(c[12]^=e.t,c[13]^=e.t/4294967296,t&&(c[14]=~c[14]),r=0;r<16;r++)h[r]=i(e.b,4*r);for(r=0;r<10;r++)o(0,4,8,12,h[u[16*r+0]],h[u[16*r+1]]),o(1,5,9,13,h[u[16*r+2]],h[u[16*r+3]]),o(2,6,10,14,h[u[16*r+4]],h[u[16*r+5]]),o(3,7,11,15,h[u[16*r+6]],h[u[16*r+7]]),o(0,5,10,15,h[u[16*r+8]],h[u[16*r+9]]),o(1,6,11,12,h[u[16*r+10]],h[u[16*r+11]]),o(2,7,8,13,h[u[16*r+12]],h[u[16*r+13]]),o(3,4,9,14,h[u[16*r+14]],h[u[16*r+15]]);for(r=0;r<8;r++)e.h[r]^=c[r]^c[r+8]}function l(e,t){if(!(e>0&&e<=32))throw new Error("Incorrect output length, should be in [1, 32]");var r=t?t.length:0;if(t&&!(r>0&&r<=32))throw new Error("Incorrect key length, should be in [1, 32]");var n={h:new Uint32Array(s),b:new Uint32Array(64),c:0,t:0,outlen:e};return n.h[0]^=16842752^r<<8^e,r>0&&(d(n,t),n.c=64),n}function d(e,t){for(var r=0;r>2]>>8*(3&r)&255;return t}function m(e,t,r){r=r||32,e=n.normalizeInput(e);var i=l(r,t);return d(i,e),p(i)}e.exports={blake2s:m,blake2sHex:function(e,t,r){var i=m(e,t,r);return n.toHex(i)},blake2sInit:l,blake2sUpdate:d,blake2sFinal:p}},function(e,t,r){"use strict";const n=r(59),i={checkCIDComponents:function(e){if(null==e)return"null values are not valid CIDs";if(0!==e.version&&1!==e.version)return"Invalid version, must be a number equal to 1 or 0";if("string"!=typeof e.codec)return"codec must be string";if(0===e.version){if("dag-pb"!==e.codec)return"codec must be 'dag-pb' for CIDv0";if("base58btc"!==e.multibaseName)return"multibaseName must be 'base58btc' for CIDv0"}if(!(e.multihash instanceof Uint8Array))return"multihash must be a Uint8Array";try{n.validate(e.multihash)}catch(e){let t=e.message;return t||(t="Multihash validation failed"),t}}};e.exports=i},function(e,t,r){"use strict";e.exports=function(e,{className:t,symbolName:r}){const n=Symbol.for(r),i={[t]:class extends e{constructor(...e){super(...e),Object.defineProperty(this,n,{value:!0})}get[Symbol.toStringTag](){return t}}}[t];return i["is"+t]=e=>!(!e||!e[n]),i},e.exports.proto=function(e,{className:t,symbolName:r,withoutNew:n}){const i=Symbol.for(r),o={[t]:function(...t){if(n&&!(this instanceof o))return new o(...t);const r=e.call(this,...t)||this;return r&&!r[i]&&Object.defineProperty(r,i,{value:!0}),r}}[t];return o.prototype=Object.create(e.prototype),o.prototype.constructor=o,Object.defineProperty(o.prototype,Symbol.toStringTag,{get:()=>t}),o["is"+t]=e=>!(!e||!e[i]),o}},function(e,t,r){var n=r(304);e.exports=function(e){if(!(e instanceof Object))throw new TypeError('"obj" must be an object (or inherit from it)');return function e(t,r){for(var i in r=new n(t,r),t){var o=t[i];if(o instanceof Object&&(r.contains(o)||e(o,r)))return!0}return!1}(e)}},function(e,t){function r(e,t){this.value=e,this.next=t}e.exports=r,r.prototype.contains=function(e){for(var t=this;t;){if(t.value===e)return!0;t=t.next}return!1}},function(e,t,r){"use strict";const n=r(60),i=r(140);t.resolve=(e,t)=>{let r=i.deserialize(e);const o=t.split("/").filter(Boolean);for(;o.length;){const e=o.shift();if(void 0===r[e])throw new Error(`Object has no property '${e}'`);if(r=r[e],n.isCID(r))return{value:r,remainderPath:o.join("/")}}return{value:r,remainderPath:""}};const o=function*(e,t){if(!(e instanceof Uint8Array||n.isCID(e)||"string"==typeof e||null===e))for(const r of Object.keys(e)){const n=void 0===t?r:t+"/"+r;yield n,yield*o(e[r],n)}};t.tree=function*(e){const t=i.deserialize(e);yield*o(t)}},function(e,t){const r="Impossible case. Please create issue.",n="The tweak was out of range or the resulted private key is invalid",i="The tweak was out of range or equal to zero",o="Unknow error on context randomization",a="Private Key is invalid",s="Public Key could not be parsed",u="Public Key serialization error",c="The sum of the public keys is not valid",h="Signature could not be parsed",f="The nonce generation function failed, or the private key was invalid",l="Public key could not be recover",d="Scalar was invalid (zero or overflow)";function p(e,t){if(!e)throw new Error(t)}function m(e,t,r){if(p(t instanceof Uint8Array,`Expected ${e} to be an Uint8Array`),void 0!==r)if(Array.isArray(r)){const n=`Expected ${e} to be an Uint8Array with length [${r.join(", ")}]`;p(r.includes(t.length),n)}else{const n=`Expected ${e} to be an Uint8Array with length ${r}`;p(t.length===r,n)}}function g(e){p("Boolean"===v(e),"Expected compressed to be a Boolean")}function b(e=(e=>new Uint8Array(e)),t){return"function"==typeof e&&(e=e(t)),m("output",e,t),e}function v(e){return Object.prototype.toString.call(e).slice(8,-1)}e.exports=e=>({contextRandomize(t){switch(p(null===t||t instanceof Uint8Array,"Expected seed to be an Uint8Array or null"),null!==t&&m("seed",t,32),e.contextRandomize(t)){case 1:throw new Error(o)}},privateKeyVerify:t=>(m("private key",t,32),0===e.privateKeyVerify(t)),privateKeyNegate(t){switch(m("private key",t,32),e.privateKeyNegate(t)){case 0:return t;case 1:throw new Error(r)}},privateKeyTweakAdd(t,r){switch(m("private key",t,32),m("tweak",r,32),e.privateKeyTweakAdd(t,r)){case 0:return t;case 1:throw new Error(n)}},privateKeyTweakMul(t,r){switch(m("private key",t,32),m("tweak",r,32),e.privateKeyTweakMul(t,r)){case 0:return t;case 1:throw new Error(i)}},publicKeyVerify:t=>(m("public key",t,[33,65]),0===e.publicKeyVerify(t)),publicKeyCreate(t,r=!0,n){switch(m("private key",t,32),g(r),n=b(n,r?33:65),e.publicKeyCreate(n,t)){case 0:return n;case 1:throw new Error(a);case 2:throw new Error(u)}},publicKeyConvert(t,r=!0,n){switch(m("public key",t,[33,65]),g(r),n=b(n,r?33:65),e.publicKeyConvert(n,t)){case 0:return n;case 1:throw new Error(s);case 2:throw new Error(u)}},publicKeyNegate(t,n=!0,i){switch(m("public key",t,[33,65]),g(n),i=b(i,n?33:65),e.publicKeyNegate(i,t)){case 0:return i;case 1:throw new Error(s);case 2:throw new Error(r);case 3:throw new Error(u)}},publicKeyCombine(t,r=!0,n){p(Array.isArray(t),"Expected public keys to be an Array"),p(t.length>0,"Expected public keys array will have more than zero items");for(const e of t)m("public key",e,[33,65]);switch(g(r),n=b(n,r?33:65),e.publicKeyCombine(n,t)){case 0:return n;case 1:throw new Error(s);case 2:throw new Error(c);case 3:throw new Error(u)}},publicKeyTweakAdd(t,r,i=!0,o){switch(m("public key",t,[33,65]),m("tweak",r,32),g(i),o=b(o,i?33:65),e.publicKeyTweakAdd(o,t,r)){case 0:return o;case 1:throw new Error(s);case 2:throw new Error(n)}},publicKeyTweakMul(t,r,n=!0,o){switch(m("public key",t,[33,65]),m("tweak",r,32),g(n),o=b(o,n?33:65),e.publicKeyTweakMul(o,t,r)){case 0:return o;case 1:throw new Error(s);case 2:throw new Error(i)}},signatureNormalize(t){switch(m("signature",t,64),e.signatureNormalize(t)){case 0:return t;case 1:throw new Error(h)}},signatureExport(t,n){m("signature",t,64);const i={output:n=b(n,72),outputlen:72};switch(e.signatureExport(i,t)){case 0:return n.slice(0,i.outputlen);case 1:throw new Error(h);case 2:throw new Error(r)}},signatureImport(t,n){switch(m("signature",t),n=b(n,64),e.signatureImport(n,t)){case 0:return n;case 1:throw new Error(h);case 2:throw new Error(r)}},ecdsaSign(t,n,i={},o){m("message",t,32),m("private key",n,32),p("Object"===v(i),"Expected options to be an Object"),void 0!==i.data&&m("options.data",i.data),void 0!==i.noncefn&&p("Function"===v(i.noncefn),"Expected options.noncefn to be a Function");const a={signature:o=b(o,64),recid:null};switch(e.ecdsaSign(a,t,n,i.data,i.noncefn)){case 0:return a;case 1:throw new Error(f);case 2:throw new Error(r)}},ecdsaVerify(t,r,n){switch(m("signature",t,64),m("message",r,32),m("public key",n,[33,65]),e.ecdsaVerify(t,r,n)){case 0:return!0;case 3:return!1;case 1:throw new Error(h);case 2:throw new Error(s)}},ecdsaRecover(t,n,i,o=!0,a){switch(m("signature",t,64),p("Number"===v(n)&&n>=0&&n<=3,"Expected recovery id to be a Number within interval [0, 3]"),m("message",i,32),g(o),a=b(a,o?33:65),e.ecdsaRecover(a,t,n,i)){case 0:return a;case 1:throw new Error(h);case 2:throw new Error(l);case 3:throw new Error(r)}},ecdh(t,r,n={},i){switch(m("public key",t,[33,65]),m("private key",r,32),p("Object"===v(n),"Expected options to be an Object"),void 0!==n.data&&m("options.data",n.data),void 0!==n.hashfn?(p("Function"===v(n.hashfn),"Expected options.hashfn to be a Function"),void 0!==n.xbuf&&m("options.xbuf",n.xbuf,32),void 0!==n.ybuf&&m("options.ybuf",n.ybuf,32),m("output",i)):i=b(i,32),e.ecdh(i,t,r,n.data,n.hashfn,n.xbuf,n.ybuf)){case 0:return i;case 1:throw new Error(s);case 2:throw new Error(d)}}})},function(e,t,r){const n=new(0,r(31).ec)("secp256k1"),i=n.curve,o=i.n.constructor;function a(e){const t=e[0];switch(t){case 2:case 3:return 33!==e.length?null:function(e,t){let r=new o(t);if(r.cmp(i.p)>=0)return null;r=r.toRed(i.red);let a=r.redSqr().redIMul(r).redIAdd(i.b).redSqrt();return 3===e!==a.isOdd()&&(a=a.redNeg()),n.keyPair({pub:{x:r,y:a}})}(t,e.subarray(1,33));case 4:case 6:case 7:return 65!==e.length?null:function(e,t,r){let a=new o(t),s=new o(r);if(a.cmp(i.p)>=0||s.cmp(i.p)>=0)return null;if(a=a.toRed(i.red),s=s.toRed(i.red),(6===e||7===e)&&s.isOdd()!==(7===e))return null;const u=a.redSqr().redIMul(a);return s.redSqr().redISub(u.redIAdd(i.b)).isZero()?n.keyPair({pub:{x:a,y:s}}):null}(t,e.subarray(1,33),e.subarray(33,65));default:return null}}function s(e,t){const r=t.encode(null,33===e.length);for(let t=0;t0,privateKeyVerify(e){const t=new o(e);return t.cmp(i.n)<0&&!t.isZero()?0:1},privateKeyNegate(e){const t=new o(e),r=i.n.sub(t).umod(i.n).toArrayLike(Uint8Array,"be",32);return e.set(r),0},privateKeyTweakAdd(e,t){const r=new o(t);if(r.cmp(i.n)>=0)return 1;if(r.iadd(new o(e)),r.cmp(i.n)>=0&&r.isub(i.n),r.isZero())return 1;const n=r.toArrayLike(Uint8Array,"be",32);return e.set(n),0},privateKeyTweakMul(e,t){let r=new o(t);if(r.cmp(i.n)>=0||r.isZero())return 1;r.imul(new o(e)),r.cmp(i.n)>=0&&(r=r.umod(i.n));const n=r.toArrayLike(Uint8Array,"be",32);return e.set(n),0},publicKeyVerify:e=>null===a(e)?1:0,publicKeyCreate(e,t){const r=new o(t);if(r.cmp(i.n)>=0||r.isZero())return 1;return s(e,n.keyFromPrivate(t).getPublic()),0},publicKeyConvert(e,t){const r=a(t);if(null===r)return 1;return s(e,r.getPublic()),0},publicKeyNegate(e,t){const r=a(t);if(null===r)return 1;const n=r.getPublic();return n.y=n.y.redNeg(),s(e,n),0},publicKeyCombine(e,t){const r=new Array(t.length);for(let e=0;e=0)return 2;const u=n.getPublic().add(i.g.mul(r));return u.isInfinity()?2:(s(e,u),0)},publicKeyTweakMul(e,t,r){const n=a(t);if(null===n)return 1;if((r=new o(r)).cmp(i.n)>=0||r.isZero())return 2;return s(e,n.getPublic().mul(r)),0},signatureNormalize(e){const t=new o(e.subarray(0,32)),r=new o(e.subarray(32,64));return t.cmp(i.n)>=0||r.cmp(i.n)>=0?1:(1===r.cmp(n.nh)&&e.set(i.n.sub(r).toArrayLike(Uint8Array,"be",32),32),0)},signatureExport(e,t){const r=t.subarray(0,32),n=t.subarray(32,64);if(new o(r).cmp(i.n)>=0)return 1;if(new o(n).cmp(i.n)>=0)return 1;const{output:a}=e;let s=a.subarray(4,37);s[0]=0,s.set(r,1);let u=33,c=0;for(;u>1&&0===s[c]&&!(128&s[c+1]);--u,++c);if(s=s.subarray(c),128&s[0])return 1;if(u>1&&0===s[0]&&!(128&s[1]))return 1;let h=a.subarray(39,72);h[0]=0,h.set(n,1);let f=33,l=0;for(;f>1&&0===h[l]&&!(128&h[l+1]);--f,++l);return h=h.subarray(l),128&h[0]||f>1&&0===h[0]&&!(128&h[1])?1:(e.outputlen=6+u+f,a[0]=48,a[1]=e.outputlen-2,a[2]=2,a[3]=s.length,a.set(s,4),a[4+u]=2,a[5+u]=h.length,a.set(h,6+u),0)},signatureImport(e,t){if(t.length<8)return 1;if(t.length>72)return 1;if(48!==t[0])return 1;if(t[1]!==t.length-2)return 1;if(2!==t[2])return 1;const r=t[3];if(0===r)return 1;if(5+r>=t.length)return 1;if(2!==t[4+r])return 1;const n=t[5+r];if(0===n)return 1;if(6+r+n!==t.length)return 1;if(128&t[4])return 1;if(r>1&&0===t[4]&&!(128&t[5]))return 1;if(128&t[r+6])return 1;if(n>1&&0===t[r+6]&&!(128&t[r+7]))return 1;let a=t.subarray(4,4+r);if(33===a.length&&0===a[0]&&(a=a.subarray(1)),a.length>32)return 1;let s=t.subarray(6+r);if(33===s.length&&0===s[0]&&(s=s.slice(1)),s.length>32)throw new Error("S length is too long");let u=new o(a);u.cmp(i.n)>=0&&(u=new o(0));let c=new o(t.subarray(6+r));return c.cmp(i.n)>=0&&(c=new o(0)),e.set(u.toArrayLike(Uint8Array,"be",32),0),e.set(c.toArrayLike(Uint8Array,"be",32),32),0},ecdsaSign(e,t,r,a,s){if(s){const e=s;s=n=>{const i=e(t,r,null,a,n);if(!(i instanceof Uint8Array&&32===i.length))throw new Error("This is the way");return new o(i)}}const u=new o(r);if(u.cmp(i.n)>=0||u.isZero())return 1;let c;try{c=n.sign(t,r,{canonical:!0,k:s,pers:a})}catch(e){return 1}return e.signature.set(c.r.toArrayLike(Uint8Array,"be",32),0),e.signature.set(c.s.toArrayLike(Uint8Array,"be",32),32),e.recid=c.recoveryParam,0},ecdsaVerify(e,t,r){const s={r:e.subarray(0,32),s:e.subarray(32,64)},u=new o(s.r),c=new o(s.s);if(u.cmp(i.n)>=0||c.cmp(i.n)>=0)return 1;if(1===c.cmp(n.nh)||u.isZero()||c.isZero())return 3;const h=a(r);if(null===h)return 2;const f=h.getPublic();return n.verify(t,s,f)?0:3},ecdsaRecover(e,t,r,a){const u={r:t.slice(0,32),s:t.slice(32,64)},c=new o(u.r),h=new o(u.s);if(c.cmp(i.n)>=0||h.cmp(i.n)>=0)return 1;if(c.isZero()||h.isZero())return 2;let f;try{f=n.recoverPubKey(a,u,r)}catch(e){return 2}return s(e,f),0},ecdh(e,t,r,s,u,c,h){const f=a(t);if(null===f)return 1;const l=new o(r);if(l.cmp(i.n)>=0||l.isZero())return 2;const d=f.getPublic().mul(l);if(void 0===u){const t=d.encode(null,!0),r=n.hash().update(t).digest();for(let t=0;t<32;++t)e[t]=r[t]}else{c||(c=new Uint8Array(32));const t=d.getX().toArray("be",32);for(let e=0;e<32;++e)c[e]=t[e];h||(h=new Uint8Array(32));const r=d.getY().toArray("be",32);for(let e=0;e<32;++e)h[e]=r[e];const n=u(c,h,s);if(!(n instanceof Uint8Array&&n.length===e.length))return 2;e.set(n)}return 0}}},function(e,t,r){(function(e){!function(e,t){"use strict";function n(e,t){if(!e)throw new Error(t||"Assertion failed")}function i(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function o(e,t,r){if(o.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var a;"object"==typeof e?e.exports=o:t.BN=o,o.BN=o,o.wordSize=26;try{a=r(309).Buffer}catch(e){}function s(e,t,r){for(var i=0,o=Math.min(e.length,r),a=0,s=t;s=49&&c<=54?c-49+10:c>=17&&c<=22?c-17+10:c,a|=u}return n(!(240&a),"Invalid character in "+e),i}function u(e,t,r,i){for(var o=0,a=0,s=Math.min(e.length,r),u=t;u=49?c-49+10:c>=17?c-17+10:c,n(c>=0&&a0?e:t},o.min=function(e,t){return e.cmp(t)<0?e:t},o.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),n(t===(0|t)&&t>=2&&t<=36);var i=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&i++,16===t?this._parseHex(e,i):this._parseBase(e,t,i),"-"===e[0]&&(this.negative=1),this._strip(),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(n(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},o.prototype._initArray=function(e,t,r){if(n("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var i=0;i=0;i-=3)a=e[i]|e[i-1]<<8|e[i-2]<<16,this.words[o]|=a<>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);else if("le"===r)for(i=0,o=0;i>>26-s&67108863,(s+=24)>=26&&(s-=26,o++);return this._strip()},o.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)i=s(e,r,r+6),this.words[n]|=i<>>26-o&4194303,(o+=24)>=26&&(o-=26,n++);r+6!==t&&(i=s(e,t,r+6),this.words[n]|=i<>>26-o&4194303),this._strip()},o.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var n=0,i=1;i<=67108863;i*=t)n++;n--,i=i/t|0;for(var o=e.length-r,a=o%n,s=Math.min(o,o-a)+r,c=0,h=r;h1&&0===this.words[this.length-1];)this.length--;return this._normSign()},o.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},"undefined"!=typeof Symbol&&"function"==typeof Symbol.for)try{o.prototype[Symbol.for("nodejs.util.inspect.custom")]=h}catch(e){o.prototype.inspect=h}else o.prototype.inspect=h;function h(){return(this.red?""}var f=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],d=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];o.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var i=0,o=0,a=0;a>>24-i&16777215)||a!==this.length-1?f[6-u.length]+u+r:u+r,(i+=2)>=26&&(i-=26,a--)}for(0!==o&&(r=o.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var c=l[e],h=d[e];r="";var p=this.clone();for(p.negative=0;!p.isZero();){var m=p.modrn(h).toString(e);r=(p=p.idivn(h)).isZero()?m+r:f[c-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}n(!1,"Base should be between 2 and 36")},o.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&n(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},o.prototype.toJSON=function(){return this.toString(16,2)},a&&(o.prototype.toBuffer=function(e,t){return this.toArrayLike(a,e,t)}),o.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)};function p(e,t,r){r.negative=t.negative^e.negative;var n=e.length+t.length|0;r.length=n,n=n-1|0;var i=0|e.words[0],o=0|t.words[0],a=i*o,s=67108863&a,u=a/67108864|0;r.words[0]=s;for(var c=1;c>>26,f=67108863&u,l=Math.min(c,t.length-1),d=Math.max(0,c-e.length+1);d<=l;d++){var p=c-d|0;h+=(a=(i=0|e.words[p])*(o=0|t.words[d])+f)/67108864|0,f=67108863&a}r.words[c]=0|f,u=0|h}return 0!==u?r.words[c]=0|u:r.length--,r._strip()}o.prototype.toArrayLike=function(e,t,r){this._strip();var i=this.byteLength(),o=r||Math.max(1,i);n(i<=o,"byte array longer than desired length"),n(o>0,"Requested array length <= 0");var a=function(e,t){return e.allocUnsafe?e.allocUnsafe(t):new e(t)}(e,o);return this["_toArrayLike"+("le"===t?"LE":"BE")](a,i),a},o.prototype._toArrayLikeLE=function(e,t){for(var r=0,n=0,i=0,o=0;i>8&255),r>16&255),6===o?(r>24&255),n=0,o=0):(n=a>>>24,o+=2)}if(r=0&&(e[r--]=a>>8&255),r>=0&&(e[r--]=a>>16&255),6===o?(r>=0&&(e[r--]=a>>24&255),n=0,o=0):(n=a>>>24,o+=2)}if(r>=0)for(e[r--]=n;r>=0;)e[r--]=0},Math.clz32?o.prototype._countBits=function(e){return 32-Math.clz32(e)}:o.prototype._countBits=function(e){var t=e,r=0;return t>=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},o.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},o.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},o.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},o.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},o.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},o.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},o.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var n=0;ne.length?this.clone().ixor(e):e.clone().ixor(this)},o.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},o.prototype.inotn=function(e){n("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var i=0;i0&&(this.words[i]=~this.words[i]&67108863>>26-r),this._strip()},o.prototype.notn=function(e){return this.clone().inotn(e)},o.prototype.setn=function(e,t){n("number"==typeof e&&e>=0);var r=e/26|0,i=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,n=e):(r=e,n=this);for(var i=0,o=0;o>>26;for(;0!==i&&o>>26;if(this.length=r.length,0!==i)this.words[this.length]=i,this.length++;else if(r!==this)for(;oe.length?this.clone().iadd(e):e.clone().iadd(this)},o.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,n,i=this.cmp(e);if(0===i)return this.negative=0,this.length=1,this.words[0]=0,this;i>0?(r=this,n=e):(r=e,n=this);for(var o=0,a=0;a>26,this.words[a]=67108863&t;for(;0!==o&&a>26,this.words[a]=67108863&t;if(0===o&&a>>13,d=0|a[1],p=8191&d,m=d>>>13,g=0|a[2],b=8191&g,v=g>>>13,y=0|a[3],w=8191&y,_=y>>>13,S=0|a[4],M=8191&S,k=S>>>13,E=0|a[5],A=8191&E,x=E>>>13,I=0|a[6],P=8191&I,O=I>>>13,T=0|a[7],R=8191&T,B=T>>>13,N=0|a[8],C=8191&N,j=N>>>13,z=0|a[9],U=8191&z,L=z>>>13,F=0|s[0],D=8191&F,q=F>>>13,K=0|s[1],H=8191&K,V=K>>>13,G=0|s[2],W=8191&G,Y=G>>>13,Z=0|s[3],J=8191&Z,X=Z>>>13,$=0|s[4],Q=8191&$,ee=$>>>13,te=0|s[5],re=8191&te,ne=te>>>13,ie=0|s[6],oe=8191&ie,ae=ie>>>13,se=0|s[7],ue=8191&se,ce=se>>>13,he=0|s[8],fe=8191&he,le=he>>>13,de=0|s[9],pe=8191&de,me=de>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(c+(n=Math.imul(f,D))|0)+((8191&(i=(i=Math.imul(f,q))+Math.imul(l,D)|0))<<13)|0;c=((o=Math.imul(l,q))+(i>>>13)|0)+(ge>>>26)|0,ge&=67108863,n=Math.imul(p,D),i=(i=Math.imul(p,q))+Math.imul(m,D)|0,o=Math.imul(m,q);var be=(c+(n=n+Math.imul(f,H)|0)|0)+((8191&(i=(i=i+Math.imul(f,V)|0)+Math.imul(l,H)|0))<<13)|0;c=((o=o+Math.imul(l,V)|0)+(i>>>13)|0)+(be>>>26)|0,be&=67108863,n=Math.imul(b,D),i=(i=Math.imul(b,q))+Math.imul(v,D)|0,o=Math.imul(v,q),n=n+Math.imul(p,H)|0,i=(i=i+Math.imul(p,V)|0)+Math.imul(m,H)|0,o=o+Math.imul(m,V)|0;var ve=(c+(n=n+Math.imul(f,W)|0)|0)+((8191&(i=(i=i+Math.imul(f,Y)|0)+Math.imul(l,W)|0))<<13)|0;c=((o=o+Math.imul(l,Y)|0)+(i>>>13)|0)+(ve>>>26)|0,ve&=67108863,n=Math.imul(w,D),i=(i=Math.imul(w,q))+Math.imul(_,D)|0,o=Math.imul(_,q),n=n+Math.imul(b,H)|0,i=(i=i+Math.imul(b,V)|0)+Math.imul(v,H)|0,o=o+Math.imul(v,V)|0,n=n+Math.imul(p,W)|0,i=(i=i+Math.imul(p,Y)|0)+Math.imul(m,W)|0,o=o+Math.imul(m,Y)|0;var ye=(c+(n=n+Math.imul(f,J)|0)|0)+((8191&(i=(i=i+Math.imul(f,X)|0)+Math.imul(l,J)|0))<<13)|0;c=((o=o+Math.imul(l,X)|0)+(i>>>13)|0)+(ye>>>26)|0,ye&=67108863,n=Math.imul(M,D),i=(i=Math.imul(M,q))+Math.imul(k,D)|0,o=Math.imul(k,q),n=n+Math.imul(w,H)|0,i=(i=i+Math.imul(w,V)|0)+Math.imul(_,H)|0,o=o+Math.imul(_,V)|0,n=n+Math.imul(b,W)|0,i=(i=i+Math.imul(b,Y)|0)+Math.imul(v,W)|0,o=o+Math.imul(v,Y)|0,n=n+Math.imul(p,J)|0,i=(i=i+Math.imul(p,X)|0)+Math.imul(m,J)|0,o=o+Math.imul(m,X)|0;var we=(c+(n=n+Math.imul(f,Q)|0)|0)+((8191&(i=(i=i+Math.imul(f,ee)|0)+Math.imul(l,Q)|0))<<13)|0;c=((o=o+Math.imul(l,ee)|0)+(i>>>13)|0)+(we>>>26)|0,we&=67108863,n=Math.imul(A,D),i=(i=Math.imul(A,q))+Math.imul(x,D)|0,o=Math.imul(x,q),n=n+Math.imul(M,H)|0,i=(i=i+Math.imul(M,V)|0)+Math.imul(k,H)|0,o=o+Math.imul(k,V)|0,n=n+Math.imul(w,W)|0,i=(i=i+Math.imul(w,Y)|0)+Math.imul(_,W)|0,o=o+Math.imul(_,Y)|0,n=n+Math.imul(b,J)|0,i=(i=i+Math.imul(b,X)|0)+Math.imul(v,J)|0,o=o+Math.imul(v,X)|0,n=n+Math.imul(p,Q)|0,i=(i=i+Math.imul(p,ee)|0)+Math.imul(m,Q)|0,o=o+Math.imul(m,ee)|0;var _e=(c+(n=n+Math.imul(f,re)|0)|0)+((8191&(i=(i=i+Math.imul(f,ne)|0)+Math.imul(l,re)|0))<<13)|0;c=((o=o+Math.imul(l,ne)|0)+(i>>>13)|0)+(_e>>>26)|0,_e&=67108863,n=Math.imul(P,D),i=(i=Math.imul(P,q))+Math.imul(O,D)|0,o=Math.imul(O,q),n=n+Math.imul(A,H)|0,i=(i=i+Math.imul(A,V)|0)+Math.imul(x,H)|0,o=o+Math.imul(x,V)|0,n=n+Math.imul(M,W)|0,i=(i=i+Math.imul(M,Y)|0)+Math.imul(k,W)|0,o=o+Math.imul(k,Y)|0,n=n+Math.imul(w,J)|0,i=(i=i+Math.imul(w,X)|0)+Math.imul(_,J)|0,o=o+Math.imul(_,X)|0,n=n+Math.imul(b,Q)|0,i=(i=i+Math.imul(b,ee)|0)+Math.imul(v,Q)|0,o=o+Math.imul(v,ee)|0,n=n+Math.imul(p,re)|0,i=(i=i+Math.imul(p,ne)|0)+Math.imul(m,re)|0,o=o+Math.imul(m,ne)|0;var Se=(c+(n=n+Math.imul(f,oe)|0)|0)+((8191&(i=(i=i+Math.imul(f,ae)|0)+Math.imul(l,oe)|0))<<13)|0;c=((o=o+Math.imul(l,ae)|0)+(i>>>13)|0)+(Se>>>26)|0,Se&=67108863,n=Math.imul(R,D),i=(i=Math.imul(R,q))+Math.imul(B,D)|0,o=Math.imul(B,q),n=n+Math.imul(P,H)|0,i=(i=i+Math.imul(P,V)|0)+Math.imul(O,H)|0,o=o+Math.imul(O,V)|0,n=n+Math.imul(A,W)|0,i=(i=i+Math.imul(A,Y)|0)+Math.imul(x,W)|0,o=o+Math.imul(x,Y)|0,n=n+Math.imul(M,J)|0,i=(i=i+Math.imul(M,X)|0)+Math.imul(k,J)|0,o=o+Math.imul(k,X)|0,n=n+Math.imul(w,Q)|0,i=(i=i+Math.imul(w,ee)|0)+Math.imul(_,Q)|0,o=o+Math.imul(_,ee)|0,n=n+Math.imul(b,re)|0,i=(i=i+Math.imul(b,ne)|0)+Math.imul(v,re)|0,o=o+Math.imul(v,ne)|0,n=n+Math.imul(p,oe)|0,i=(i=i+Math.imul(p,ae)|0)+Math.imul(m,oe)|0,o=o+Math.imul(m,ae)|0;var Me=(c+(n=n+Math.imul(f,ue)|0)|0)+((8191&(i=(i=i+Math.imul(f,ce)|0)+Math.imul(l,ue)|0))<<13)|0;c=((o=o+Math.imul(l,ce)|0)+(i>>>13)|0)+(Me>>>26)|0,Me&=67108863,n=Math.imul(C,D),i=(i=Math.imul(C,q))+Math.imul(j,D)|0,o=Math.imul(j,q),n=n+Math.imul(R,H)|0,i=(i=i+Math.imul(R,V)|0)+Math.imul(B,H)|0,o=o+Math.imul(B,V)|0,n=n+Math.imul(P,W)|0,i=(i=i+Math.imul(P,Y)|0)+Math.imul(O,W)|0,o=o+Math.imul(O,Y)|0,n=n+Math.imul(A,J)|0,i=(i=i+Math.imul(A,X)|0)+Math.imul(x,J)|0,o=o+Math.imul(x,X)|0,n=n+Math.imul(M,Q)|0,i=(i=i+Math.imul(M,ee)|0)+Math.imul(k,Q)|0,o=o+Math.imul(k,ee)|0,n=n+Math.imul(w,re)|0,i=(i=i+Math.imul(w,ne)|0)+Math.imul(_,re)|0,o=o+Math.imul(_,ne)|0,n=n+Math.imul(b,oe)|0,i=(i=i+Math.imul(b,ae)|0)+Math.imul(v,oe)|0,o=o+Math.imul(v,ae)|0,n=n+Math.imul(p,ue)|0,i=(i=i+Math.imul(p,ce)|0)+Math.imul(m,ue)|0,o=o+Math.imul(m,ce)|0;var ke=(c+(n=n+Math.imul(f,fe)|0)|0)+((8191&(i=(i=i+Math.imul(f,le)|0)+Math.imul(l,fe)|0))<<13)|0;c=((o=o+Math.imul(l,le)|0)+(i>>>13)|0)+(ke>>>26)|0,ke&=67108863,n=Math.imul(U,D),i=(i=Math.imul(U,q))+Math.imul(L,D)|0,o=Math.imul(L,q),n=n+Math.imul(C,H)|0,i=(i=i+Math.imul(C,V)|0)+Math.imul(j,H)|0,o=o+Math.imul(j,V)|0,n=n+Math.imul(R,W)|0,i=(i=i+Math.imul(R,Y)|0)+Math.imul(B,W)|0,o=o+Math.imul(B,Y)|0,n=n+Math.imul(P,J)|0,i=(i=i+Math.imul(P,X)|0)+Math.imul(O,J)|0,o=o+Math.imul(O,X)|0,n=n+Math.imul(A,Q)|0,i=(i=i+Math.imul(A,ee)|0)+Math.imul(x,Q)|0,o=o+Math.imul(x,ee)|0,n=n+Math.imul(M,re)|0,i=(i=i+Math.imul(M,ne)|0)+Math.imul(k,re)|0,o=o+Math.imul(k,ne)|0,n=n+Math.imul(w,oe)|0,i=(i=i+Math.imul(w,ae)|0)+Math.imul(_,oe)|0,o=o+Math.imul(_,ae)|0,n=n+Math.imul(b,ue)|0,i=(i=i+Math.imul(b,ce)|0)+Math.imul(v,ue)|0,o=o+Math.imul(v,ce)|0,n=n+Math.imul(p,fe)|0,i=(i=i+Math.imul(p,le)|0)+Math.imul(m,fe)|0,o=o+Math.imul(m,le)|0;var Ee=(c+(n=n+Math.imul(f,pe)|0)|0)+((8191&(i=(i=i+Math.imul(f,me)|0)+Math.imul(l,pe)|0))<<13)|0;c=((o=o+Math.imul(l,me)|0)+(i>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,n=Math.imul(U,H),i=(i=Math.imul(U,V))+Math.imul(L,H)|0,o=Math.imul(L,V),n=n+Math.imul(C,W)|0,i=(i=i+Math.imul(C,Y)|0)+Math.imul(j,W)|0,o=o+Math.imul(j,Y)|0,n=n+Math.imul(R,J)|0,i=(i=i+Math.imul(R,X)|0)+Math.imul(B,J)|0,o=o+Math.imul(B,X)|0,n=n+Math.imul(P,Q)|0,i=(i=i+Math.imul(P,ee)|0)+Math.imul(O,Q)|0,o=o+Math.imul(O,ee)|0,n=n+Math.imul(A,re)|0,i=(i=i+Math.imul(A,ne)|0)+Math.imul(x,re)|0,o=o+Math.imul(x,ne)|0,n=n+Math.imul(M,oe)|0,i=(i=i+Math.imul(M,ae)|0)+Math.imul(k,oe)|0,o=o+Math.imul(k,ae)|0,n=n+Math.imul(w,ue)|0,i=(i=i+Math.imul(w,ce)|0)+Math.imul(_,ue)|0,o=o+Math.imul(_,ce)|0,n=n+Math.imul(b,fe)|0,i=(i=i+Math.imul(b,le)|0)+Math.imul(v,fe)|0,o=o+Math.imul(v,le)|0;var Ae=(c+(n=n+Math.imul(p,pe)|0)|0)+((8191&(i=(i=i+Math.imul(p,me)|0)+Math.imul(m,pe)|0))<<13)|0;c=((o=o+Math.imul(m,me)|0)+(i>>>13)|0)+(Ae>>>26)|0,Ae&=67108863,n=Math.imul(U,W),i=(i=Math.imul(U,Y))+Math.imul(L,W)|0,o=Math.imul(L,Y),n=n+Math.imul(C,J)|0,i=(i=i+Math.imul(C,X)|0)+Math.imul(j,J)|0,o=o+Math.imul(j,X)|0,n=n+Math.imul(R,Q)|0,i=(i=i+Math.imul(R,ee)|0)+Math.imul(B,Q)|0,o=o+Math.imul(B,ee)|0,n=n+Math.imul(P,re)|0,i=(i=i+Math.imul(P,ne)|0)+Math.imul(O,re)|0,o=o+Math.imul(O,ne)|0,n=n+Math.imul(A,oe)|0,i=(i=i+Math.imul(A,ae)|0)+Math.imul(x,oe)|0,o=o+Math.imul(x,ae)|0,n=n+Math.imul(M,ue)|0,i=(i=i+Math.imul(M,ce)|0)+Math.imul(k,ue)|0,o=o+Math.imul(k,ce)|0,n=n+Math.imul(w,fe)|0,i=(i=i+Math.imul(w,le)|0)+Math.imul(_,fe)|0,o=o+Math.imul(_,le)|0;var xe=(c+(n=n+Math.imul(b,pe)|0)|0)+((8191&(i=(i=i+Math.imul(b,me)|0)+Math.imul(v,pe)|0))<<13)|0;c=((o=o+Math.imul(v,me)|0)+(i>>>13)|0)+(xe>>>26)|0,xe&=67108863,n=Math.imul(U,J),i=(i=Math.imul(U,X))+Math.imul(L,J)|0,o=Math.imul(L,X),n=n+Math.imul(C,Q)|0,i=(i=i+Math.imul(C,ee)|0)+Math.imul(j,Q)|0,o=o+Math.imul(j,ee)|0,n=n+Math.imul(R,re)|0,i=(i=i+Math.imul(R,ne)|0)+Math.imul(B,re)|0,o=o+Math.imul(B,ne)|0,n=n+Math.imul(P,oe)|0,i=(i=i+Math.imul(P,ae)|0)+Math.imul(O,oe)|0,o=o+Math.imul(O,ae)|0,n=n+Math.imul(A,ue)|0,i=(i=i+Math.imul(A,ce)|0)+Math.imul(x,ue)|0,o=o+Math.imul(x,ce)|0,n=n+Math.imul(M,fe)|0,i=(i=i+Math.imul(M,le)|0)+Math.imul(k,fe)|0,o=o+Math.imul(k,le)|0;var Ie=(c+(n=n+Math.imul(w,pe)|0)|0)+((8191&(i=(i=i+Math.imul(w,me)|0)+Math.imul(_,pe)|0))<<13)|0;c=((o=o+Math.imul(_,me)|0)+(i>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,n=Math.imul(U,Q),i=(i=Math.imul(U,ee))+Math.imul(L,Q)|0,o=Math.imul(L,ee),n=n+Math.imul(C,re)|0,i=(i=i+Math.imul(C,ne)|0)+Math.imul(j,re)|0,o=o+Math.imul(j,ne)|0,n=n+Math.imul(R,oe)|0,i=(i=i+Math.imul(R,ae)|0)+Math.imul(B,oe)|0,o=o+Math.imul(B,ae)|0,n=n+Math.imul(P,ue)|0,i=(i=i+Math.imul(P,ce)|0)+Math.imul(O,ue)|0,o=o+Math.imul(O,ce)|0,n=n+Math.imul(A,fe)|0,i=(i=i+Math.imul(A,le)|0)+Math.imul(x,fe)|0,o=o+Math.imul(x,le)|0;var Pe=(c+(n=n+Math.imul(M,pe)|0)|0)+((8191&(i=(i=i+Math.imul(M,me)|0)+Math.imul(k,pe)|0))<<13)|0;c=((o=o+Math.imul(k,me)|0)+(i>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,n=Math.imul(U,re),i=(i=Math.imul(U,ne))+Math.imul(L,re)|0,o=Math.imul(L,ne),n=n+Math.imul(C,oe)|0,i=(i=i+Math.imul(C,ae)|0)+Math.imul(j,oe)|0,o=o+Math.imul(j,ae)|0,n=n+Math.imul(R,ue)|0,i=(i=i+Math.imul(R,ce)|0)+Math.imul(B,ue)|0,o=o+Math.imul(B,ce)|0,n=n+Math.imul(P,fe)|0,i=(i=i+Math.imul(P,le)|0)+Math.imul(O,fe)|0,o=o+Math.imul(O,le)|0;var Oe=(c+(n=n+Math.imul(A,pe)|0)|0)+((8191&(i=(i=i+Math.imul(A,me)|0)+Math.imul(x,pe)|0))<<13)|0;c=((o=o+Math.imul(x,me)|0)+(i>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,n=Math.imul(U,oe),i=(i=Math.imul(U,ae))+Math.imul(L,oe)|0,o=Math.imul(L,ae),n=n+Math.imul(C,ue)|0,i=(i=i+Math.imul(C,ce)|0)+Math.imul(j,ue)|0,o=o+Math.imul(j,ce)|0,n=n+Math.imul(R,fe)|0,i=(i=i+Math.imul(R,le)|0)+Math.imul(B,fe)|0,o=o+Math.imul(B,le)|0;var Te=(c+(n=n+Math.imul(P,pe)|0)|0)+((8191&(i=(i=i+Math.imul(P,me)|0)+Math.imul(O,pe)|0))<<13)|0;c=((o=o+Math.imul(O,me)|0)+(i>>>13)|0)+(Te>>>26)|0,Te&=67108863,n=Math.imul(U,ue),i=(i=Math.imul(U,ce))+Math.imul(L,ue)|0,o=Math.imul(L,ce),n=n+Math.imul(C,fe)|0,i=(i=i+Math.imul(C,le)|0)+Math.imul(j,fe)|0,o=o+Math.imul(j,le)|0;var Re=(c+(n=n+Math.imul(R,pe)|0)|0)+((8191&(i=(i=i+Math.imul(R,me)|0)+Math.imul(B,pe)|0))<<13)|0;c=((o=o+Math.imul(B,me)|0)+(i>>>13)|0)+(Re>>>26)|0,Re&=67108863,n=Math.imul(U,fe),i=(i=Math.imul(U,le))+Math.imul(L,fe)|0,o=Math.imul(L,le);var Be=(c+(n=n+Math.imul(C,pe)|0)|0)+((8191&(i=(i=i+Math.imul(C,me)|0)+Math.imul(j,pe)|0))<<13)|0;c=((o=o+Math.imul(j,me)|0)+(i>>>13)|0)+(Be>>>26)|0,Be&=67108863;var Ne=(c+(n=Math.imul(U,pe))|0)+((8191&(i=(i=Math.imul(U,me))+Math.imul(L,pe)|0))<<13)|0;return c=((o=Math.imul(L,me))+(i>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,u[0]=ge,u[1]=be,u[2]=ve,u[3]=ye,u[4]=we,u[5]=_e,u[6]=Se,u[7]=Me,u[8]=ke,u[9]=Ee,u[10]=Ae,u[11]=xe,u[12]=Ie,u[13]=Pe,u[14]=Oe,u[15]=Te,u[16]=Re,u[17]=Be,u[18]=Ne,0!==c&&(u[19]=c,r.length++),r};function g(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var n=0,i=0,o=0;o>>26)|0)>>>26,a&=67108863}r.words[o]=s,n=a,a=i}return 0!==n?r.words[o]=n:r.length--,r._strip()}function b(e,t,r){return g(e,t,r)}function v(e,t){this.x=e,this.y=t}Math.imul||(m=p),o.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?m(this,e,t):r<63?p(this,e,t):r<1024?g(this,e,t):b(this,e,t)},v.prototype.makeRBT=function(e){for(var t=new Array(e),r=o.prototype._countBits(e)-1,n=0;n>=1;return n},v.prototype.permute=function(e,t,r,n,i,o){for(var a=0;a>>=1)i++;return 1<>>=13,r[2*a+1]=8191&o,o>>>=13;for(a=2*t;a>=26,r+=o/67108864|0,r+=a>>>26,this.words[i]=67108863&a}return 0!==r&&(this.words[i]=r,this.length++),t?this.ineg():this},o.prototype.muln=function(e){return this.clone().imuln(e)},o.prototype.sqr=function(){return this.mul(this)},o.prototype.isqr=function(){return this.imul(this.clone())},o.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>i&1}return t}(e);if(0===t.length)return new o(1);for(var r=this,n=0;n=0);var t,r=e%26,i=(e-r)/26,o=67108863>>>26-r<<26-r;if(0!==r){var a=0;for(t=0;t>>26-r}a&&(this.words[t]=a,this.length++)}if(0!==i){for(t=this.length-1;t>=0;t--)this.words[t+i]=this.words[t];for(t=0;t=0),i=t?(t-t%26)/26:0;var o=e%26,a=Math.min((e-o)/26,this.length),s=67108863^67108863>>>o<a)for(this.length-=a,c=0;c=0&&(0!==h||c>=i);c--){var f=0|this.words[c];this.words[c]=h<<26-o|f>>>o,h=f&s}return u&&0!==h&&(u.words[u.length++]=h),0===this.length&&(this.words[0]=0,this.length=1),this._strip()},o.prototype.ishrn=function(e,t,r){return n(0===this.negative),this.iushrn(e,t,r)},o.prototype.shln=function(e){return this.clone().ishln(e)},o.prototype.ushln=function(e){return this.clone().iushln(e)},o.prototype.shrn=function(e){return this.clone().ishrn(e)},o.prototype.ushrn=function(e){return this.clone().iushrn(e)},o.prototype.testn=function(e){n("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,i=1<=0);var t=e%26,r=(e-t)/26;if(n(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var i=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},o.prototype.isubn=function(e){if(n("number"==typeof e),n(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(u/67108864|0),this.words[i+r]=67108863&o}for(;i>26,this.words[i+r]=67108863&o;if(0===s)return this._strip();for(n(-1===s),s=0,i=0;i>26,this.words[i]=67108863&o;return this.negative=1,this._strip()},o.prototype._wordDiv=function(e,t){var r=(this.length,e.length),n=this.clone(),i=e,a=0|i.words[i.length-1];0!==(r=26-this._countBits(a))&&(i=i.ushln(r),n.iushln(r),a=0|i.words[i.length-1]);var s,u=n.length-i.length;if("mod"!==t){(s=new o(null)).length=u+1,s.words=new Array(s.length);for(var c=0;c=0;f--){var l=67108864*(0|n.words[i.length+f])+(0|n.words[i.length+f-1]);for(l=Math.min(l/a|0,67108863),n._ishlnsubmul(i,l,f);0!==n.negative;)l--,n.negative=0,n._ishlnsubmul(i,1,f),n.isZero()||(n.negative^=1);s&&(s.words[f]=l)}return s&&s._strip(),n._strip(),"div"!==t&&0!==r&&n.iushrn(r),{div:s||null,mod:n}},o.prototype.divmod=function(e,t,r){return n(!e.isZero()),this.isZero()?{div:new o(0),mod:new o(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(i=s.div.neg()),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.iadd(e)),{div:i,mod:a}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(i=s.div.neg()),{div:i,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(a=s.mod.neg(),r&&0!==a.negative&&a.isub(e)),{div:s.div,mod:a}):e.length>this.length||this.cmp(e)<0?{div:new o(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new o(this.modrn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new o(this.modrn(e.words[0]))}:this._wordDiv(e,t);var i,a,s},o.prototype.div=function(e){return this.divmod(e,"div",!1).div},o.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},o.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},o.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,n=e.ushrn(1),i=e.andln(1),o=r.cmp(n);return o<0||1===i&&0===o?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},o.prototype.modrn=function(e){var t=e<0;t&&(e=-e),n(e<=67108863);for(var r=(1<<26)%e,i=0,o=this.length-1;o>=0;o--)i=(r*i+(0|this.words[o]))%e;return t?-i:i},o.prototype.modn=function(e){return this.modrn(e)},o.prototype.idivn=function(e){var t=e<0;t&&(e=-e),n(e<=67108863);for(var r=0,i=this.length-1;i>=0;i--){var o=(0|this.words[i])+67108864*r;this.words[i]=o/e|0,r=o%e}return this._strip(),t?this.ineg():this},o.prototype.divn=function(e){return this.clone().idivn(e)},o.prototype.egcd=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i=new o(1),a=new o(0),s=new o(0),u=new o(1),c=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++c;for(var h=r.clone(),f=t.clone();!t.isZero();){for(var l=0,d=1;0==(t.words[0]&d)&&l<26;++l,d<<=1);if(l>0)for(t.iushrn(l);l-- >0;)(i.isOdd()||a.isOdd())&&(i.iadd(h),a.isub(f)),i.iushrn(1),a.iushrn(1);for(var p=0,m=1;0==(r.words[0]&m)&&p<26;++p,m<<=1);if(p>0)for(r.iushrn(p);p-- >0;)(s.isOdd()||u.isOdd())&&(s.iadd(h),u.isub(f)),s.iushrn(1),u.iushrn(1);t.cmp(r)>=0?(t.isub(r),i.isub(s),a.isub(u)):(r.isub(t),s.isub(i),u.isub(a))}return{a:s,b:u,gcd:r.iushln(c)}},o.prototype._invmp=function(e){n(0===e.negative),n(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var i,a=new o(1),s=new o(0),u=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var c=0,h=1;0==(t.words[0]&h)&&c<26;++c,h<<=1);if(c>0)for(t.iushrn(c);c-- >0;)a.isOdd()&&a.iadd(u),a.iushrn(1);for(var f=0,l=1;0==(r.words[0]&l)&&f<26;++f,l<<=1);if(f>0)for(r.iushrn(f);f-- >0;)s.isOdd()&&s.iadd(u),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),a.isub(s)):(r.isub(t),s.isub(a))}return(i=0===t.cmpn(1)?a:s).cmpn(0)<0&&i.iadd(e),i},o.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var n=0;t.isEven()&&r.isEven();n++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var i=t.cmp(r);if(i<0){var o=t;t=r,r=o}else if(0===i||0===r.cmpn(1))break;t.isub(r)}return r.iushln(n)},o.prototype.invm=function(e){return this.egcd(e).a.umod(e)},o.prototype.isEven=function(){return 0==(1&this.words[0])},o.prototype.isOdd=function(){return 1==(1&this.words[0])},o.prototype.andln=function(e){return this.words[0]&e},o.prototype.bincn=function(e){n("number"==typeof e);var t=e%26,r=(e-t)/26,i=1<>>26,s&=67108863,this.words[a]=s}return 0!==o&&(this.words[a]=o,this.length++),this},o.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},o.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this._strip(),this.length>1)t=1;else{r&&(e=-e),n(e<=67108863,"Number is too big");var i=0|this.words[0];t=i===e?0:ie.length)return 1;if(this.length=0;r--){var n=0|this.words[r],i=0|e.words[r];if(n!==i){ni&&(t=1);break}}return t},o.prototype.gtn=function(e){return 1===this.cmpn(e)},o.prototype.gt=function(e){return 1===this.cmp(e)},o.prototype.gten=function(e){return this.cmpn(e)>=0},o.prototype.gte=function(e){return this.cmp(e)>=0},o.prototype.ltn=function(e){return-1===this.cmpn(e)},o.prototype.lt=function(e){return-1===this.cmp(e)},o.prototype.lten=function(e){return this.cmpn(e)<=0},o.prototype.lte=function(e){return this.cmp(e)<=0},o.prototype.eqn=function(e){return 0===this.cmpn(e)},o.prototype.eq=function(e){return 0===this.cmp(e)},o.red=function(e){return new E(e)},o.prototype.toRed=function(e){return n(!this.red,"Already a number in reduction context"),n(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},o.prototype.fromRed=function(){return n(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},o.prototype._forceRed=function(e){return this.red=e,this},o.prototype.forceRed=function(e){return n(!this.red,"Already a number in reduction context"),this._forceRed(e)},o.prototype.redAdd=function(e){return n(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},o.prototype.redIAdd=function(e){return n(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},o.prototype.redSub=function(e){return n(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},o.prototype.redISub=function(e){return n(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},o.prototype.redShl=function(e){return n(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},o.prototype.redMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},o.prototype.redIMul=function(e){return n(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},o.prototype.redSqr=function(){return n(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},o.prototype.redISqr=function(){return n(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},o.prototype.redSqrt=function(){return n(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},o.prototype.redInvm=function(){return n(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},o.prototype.redNeg=function(){return n(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},o.prototype.redPow=function(e){return n(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var y={k256:null,p224:null,p192:null,p25519:null};function w(e,t){this.name=e,this.p=new o(t,16),this.n=this.p.bitLength(),this.k=new o(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function _(){w.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function S(){w.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function M(){w.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function k(){w.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function E(e){if("string"==typeof e){var t=o._prime(e);this.m=t.p,this.prime=t}else n(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function A(e){E.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new o(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}w.prototype._tmp=function(){var e=new o(null);return e.words=new Array(Math.ceil(this.n/13)),e},w.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var n=t0?r.isub(this.p):void 0!==r.strip?r.strip():r._strip(),r},w.prototype.split=function(e,t){e.iushrn(this.n,0,t)},w.prototype.imulK=function(e){return e.imul(this.k)},i(_,w),_.prototype.split=function(e,t){for(var r=Math.min(e.length,9),n=0;n>>22,i=o}i>>>=22,e.words[n-10]=i,0===i&&e.length>10?e.length-=10:e.length-=9},_.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=i,t=n}return 0!==t&&(e.words[e.length++]=t),e},o._prime=function(e){if(y[e])return y[e];var t;if("k256"===e)t=new _;else if("p224"===e)t=new S;else if("p192"===e)t=new M;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new k}return y[e]=t,t},E.prototype._verify1=function(e){n(0===e.negative,"red works only with positives"),n(e.red,"red works only with red numbers")},E.prototype._verify2=function(e,t){n(0==(e.negative|t.negative),"red works only with positives"),n(e.red&&e.red===t.red,"red works only with red numbers")},E.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):(c(e,e.umod(this.m)._forceRed(this)),e)},E.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},E.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},E.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},E.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},E.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},E.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},E.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},E.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},E.prototype.isqr=function(e){return this.imul(e,e.clone())},E.prototype.sqr=function(e){return this.mul(e,e)},E.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(n(t%2==1),3===t){var r=this.m.add(new o(1)).iushrn(2);return this.pow(e,r)}for(var i=this.m.subn(1),a=0;!i.isZero()&&0===i.andln(1);)a++,i.iushrn(1);n(!i.isZero());var s=new o(1).toRed(this),u=s.redNeg(),c=this.m.subn(1).iushrn(1),h=this.m.bitLength();for(h=new o(2*h*h).toRed(this);0!==this.pow(h,c).cmp(u);)h.redIAdd(u);for(var f=this.pow(h,i),l=this.pow(e,i.addn(1).iushrn(1)),d=this.pow(e,i),p=a;0!==d.cmp(s);){for(var m=d,g=0;0!==m.cmp(s);g++)m=m.redSqr();n(g=0;n--){for(var c=t.words[n],h=u-1;h>=0;h--){var f=c>>h&1;i!==r[0]&&(i=this.sqr(i)),0!==f||0!==a?(a<<=1,a|=f,(4===++s||0===n&&0===h)&&(i=this.mul(i,r[a]),s=0,a=0)):s=0}u=26}return i},E.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},E.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},o.mont=function(e){return new A(e)},i(A,E),A.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},A.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},A.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),o=i;return i.cmp(this.m)>=0?o=i.isub(this.m):i.cmpn(0)<0&&(o=i.iadd(this.m)),o._forceRed(this)},A.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new o(0)._forceRed(this);var r=e.mul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),a=i;return i.cmp(this.m)>=0?a=i.isub(this.m):i.cmpn(0)<0&&(a=i.iadd(this.m)),a._forceRed(this)},A.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(28)(e))},function(e,t){},function(e,t){e.exports={MethodInit:{Constructor:1,Exec:2},MethodMultisig:{Constructor:1,Propose:2,Approve:3,Cancel:4,AddSigner:5,RemoveSigner:6,SwapSigner:7,ChangeNumApprovalsThreshold:8},MethodPaych:{Constructor:1,UpdateChannelState:2,Settle:3,Collect:4}}},function(e,t,r){(function(t){const n=r(153),i=r(152),{getPayloadSECP256K1:o,getChecksum:a}=r(154);e.exports=class{constructor(e,r){const s=i.publicKeyCreate(e);let u=new Uint8Array(65);i.publicKeyConvert(s,!1,u),u=t.from(u);const c=o(u),h=a(t.concat([t.from("01","hex"),c]));let f="f1";r&&(f="t1");const l=f+n(t.concat([c,h]),"RFC4648",{padding:!1}).toLowerCase();this.publicKey=u,this.privateKey=e,this.address=l}get public_raw(){return new Uint8Array(this.publicKey)}get private_raw(){return new Uint8Array(this.privateKey)}get public_hexstring(){return this.publicKey.toString("hex")}get private_hexstring(){return this.privateKey.toString("hex")}get public_base64(){return this.publicKey.toString("base64")}get private_base64(){return this.privateKey.toString("base64")}}}).call(this,r(0).Buffer)},function(e,t){function r(e,t){var r=e.indexOf(t);if(-1===r)throw new Error("Invalid character found: "+t);return r}e.exports=function(e,t){var n;switch(t){case"RFC3548":case"RFC4648":n="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",e=e.replace(/=+$/,"");break;case"RFC4648-HEX":n="0123456789ABCDEFGHIJKLMNOPQRSTUV",e=e.replace(/=+$/,"");break;case"Crockford":n="0123456789ABCDEFGHJKMNPQRSTVWXYZ",e=e.toUpperCase().replace(/O/g,"0").replace(/[IL]/g,"1");break;default:throw new Error("Unknown base32 variant: "+t)}for(var i=e.length,o=0,a=0,s=0,u=new Uint8Array(5*i/8|0),c=0;c=8&&(u[s++]=a>>>o-8&255,o-=8);return u.buffer}},function(e,t,r){t.unsigned=r(314),t.signed=r(316)},function(e,t,r){const n=r(155),i=r(156);function o(e){return a(e).toString()}function a(e){const t=new n(0);let r,i=0;for(;r=e.read(1)[0],t.ior(new n(127&r).shln(i)),r>>7!=0;)i+=7;return t}function s(e,t){const r=new n(e);for(;;){const e=r.maskn(7).toNumber();if(r.ishrn(7),r.isZero()){t.write([e]);break}t.write([128|e])}}e.exports={encode:function(e){const t=new i;return s(e,t),t.buffer},decode:function(e){return o(new i(e))},read:o,readBn:a,write:s}},function(e,t){},function(e,t,r){const n=r(155),i=r(156);function o(e){return a(e).toString()}function a(e){const t=new n(0);let r,i=0;for(;r=e.read(1)[0],t.ior(new n(127&r).shln(i)),i+=7,r>>7!=0;);return 64&r&&t.setn(i),t.fromTwos(i)}function s(e,t){let r=new n(e);const i=r.isNeg();for(i&&(r=r.toTwos(r.bitLength()+8));;){const e=r.maskn(7).toNumber();if(r.ishrn(7),o(r)&&0!=(64&e)||r.isZero()&&0==(64&e)){t.write([e]);break}t.write([128|e])}function o(e){return i&&e.toString(2).indexOf("0")<0}}e.exports={encode:function(e){const t=new i;return s(e,t),t.buffer},decode:function(e){return o(new i(e))},write:s,read:o,readBn:a}},function(e,t,r){"use strict"; +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/var n=Object.getOwnPropertySymbols,i=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable;function a(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},r=0;r<10;r++)t["_"+String.fromCharCode(r)]=r;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var n={};return"abcdefghijklmnopqrst".split("").forEach((function(e){n[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},n)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var r,s,u=a(e),c=1;c=o)return e;switch(e){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch(e){return"[Circular]"}default:return e}})),u=n[r];r=3&&(n.depth=arguments[2]),arguments.length>=4&&(n.colors=arguments[3]),p(r)?n.showHidden=r:r&&t._extend(n,r),v(n.showHidden)&&(n.showHidden=!1),v(n.depth)&&(n.depth=2),v(n.colors)&&(n.colors=!1),v(n.customInspect)&&(n.customInspect=!0),n.colors&&(n.stylize=u),h(n,e,n.depth)}function u(e,t){var r=s.styles[t];return r?"["+s.colors[r][0]+"m"+e+"["+s.colors[r][1]+"m":e}function c(e,t){return e}function h(e,r,n){if(e.customInspect&&r&&M(r.inspect)&&r.inspect!==t.inspect&&(!r.constructor||r.constructor.prototype!==r)){var i=r.inspect(n,e);return b(i)||(i=h(e,i,n)),i}var o=function(e,t){if(v(t))return e.stylize("undefined","undefined");if(b(t)){var r="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(r,"string")}if(g(t))return e.stylize(""+t,"number");if(p(t))return e.stylize(""+t,"boolean");if(m(t))return e.stylize("null","null")}(e,r);if(o)return o;var a=Object.keys(r),s=function(e){var t={};return e.forEach((function(e,r){t[e]=!0})),t}(a);if(e.showHidden&&(a=Object.getOwnPropertyNames(r)),S(r)&&(a.indexOf("message")>=0||a.indexOf("description")>=0))return f(r);if(0===a.length){if(M(r)){var u=r.name?": "+r.name:"";return e.stylize("[Function"+u+"]","special")}if(y(r))return e.stylize(RegExp.prototype.toString.call(r),"regexp");if(_(r))return e.stylize(Date.prototype.toString.call(r),"date");if(S(r))return f(r)}var c,w="",k=!1,E=["{","}"];(d(r)&&(k=!0,E=["[","]"]),M(r))&&(w=" [Function"+(r.name?": "+r.name:"")+"]");return y(r)&&(w=" "+RegExp.prototype.toString.call(r)),_(r)&&(w=" "+Date.prototype.toUTCString.call(r)),S(r)&&(w=" "+f(r)),0!==a.length||k&&0!=r.length?n<0?y(r)?e.stylize(RegExp.prototype.toString.call(r),"regexp"):e.stylize("[Object]","special"):(e.seen.push(r),c=k?function(e,t,r,n,i){for(var o=[],a=0,s=t.length;a=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1}),0)>60)return r[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+r[1];return r[0]+t+" "+e.join(", ")+" "+r[1]}(c,w,E)):E[0]+w+E[1]}function f(e){return"["+Error.prototype.toString.call(e)+"]"}function l(e,t,r,n,i,o){var a,s,u;if((u=Object.getOwnPropertyDescriptor(t,i)||{value:t[i]}).get?s=u.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):u.set&&(s=e.stylize("[Setter]","special")),I(n,i)||(a="["+i+"]"),s||(e.seen.indexOf(u.value)<0?(s=m(r)?h(e,u.value,null):h(e,u.value,r-1)).indexOf("\n")>-1&&(s=o?s.split("\n").map((function(e){return" "+e})).join("\n").substr(2):"\n"+s.split("\n").map((function(e){return" "+e})).join("\n")):s=e.stylize("[Circular]","special")),v(a)){if(o&&i.match(/^\d+$/))return s;(a=JSON.stringify(""+i)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=e.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=e.stylize(a,"string"))}return a+": "+s}function d(e){return Array.isArray(e)}function p(e){return"boolean"==typeof e}function m(e){return null===e}function g(e){return"number"==typeof e}function b(e){return"string"==typeof e}function v(e){return void 0===e}function y(e){return w(e)&&"[object RegExp]"===k(e)}function w(e){return"object"==typeof e&&null!==e}function _(e){return w(e)&&"[object Date]"===k(e)}function S(e){return w(e)&&("[object Error]"===k(e)||e instanceof Error)}function M(e){return"function"==typeof e}function k(e){return Object.prototype.toString.call(e)}function E(e){return e<10?"0"+e.toString(10):e.toString(10)}t.debuglog=function(r){if(v(o)&&(o=e.env.NODE_DEBUG||""),r=r.toUpperCase(),!a[r])if(new RegExp("\\b"+r+"\\b","i").test(o)){var n=e.pid;a[r]=function(){var e=t.format.apply(t,arguments);console.error("%s %d: %s",r,n,e)}}else a[r]=function(){};return a[r]},t.inspect=s,s.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},s.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.isArray=d,t.isBoolean=p,t.isNull=m,t.isNullOrUndefined=function(e){return null==e},t.isNumber=g,t.isString=b,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=v,t.isRegExp=y,t.isObject=w,t.isDate=_,t.isError=S,t.isFunction=M,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=r(319);var A=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function x(){var e=new Date,t=[E(e.getHours()),E(e.getMinutes()),E(e.getSeconds())].join(":");return[e.getDate(),A[e.getMonth()],t].join(" ")}function I(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.log=function(){console.log("%s - %s",x(),t.format.apply(t,arguments))},t.inherits=r(320),t._extend=function(e,t){if(!t||!w(t))return e;for(var r=Object.keys(t),n=r.length;n--;)e[r[n]]=t[r[n]];return e};var P="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function O(e,t){if(!e){var r=new Error("Promise was rejected with a falsy value");r.reason=e,e=r}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(P&&e[P]){var t;if("function"!=typeof(t=e[P]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,P,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,r,n=new Promise((function(e,n){t=e,r=n})),i=[],o=0;o0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]=0?[4,this.deriveKeyFromPasswordAndSalt(t,this.salt)]:[3,5];case 1:return n=a.sent(),i=this.encPrivKeys[e],this._decryptKey(i,n)?(this.addresses[r]="",this.encPrivKeys[e]="",this.defaultAddressIndex!==r?[3,4]:[4,this.getAddresses()]):[3,4];case 2:return(o=a.sent()).length>0?[4,this.setDefaultAddress(o[0])]:[3,4];case 3:a.sent(),a.label=4;case 4:a.label=5;case 5:return[2]}}))}))},t.prototype._generatePrivKeys=function(e,t){var r=this._decryptString(this.encSeed,e);if(!r||0===r.length)throw new Error("Provided password derived key is wrong");for(var n=[],i=0;i=0&&(this.defaultAddressIndex=t),[2]}))}))},t.prototype.getAddresses=function(){return a(this,void 0,void 0,(function(){return s(this,(function(e){return[2,this.addresses.filter((function(e,t){return""!=e}))]}))}))},t.prototype.hasAddress=function(e){return a(this,void 0,void 0,(function(){return s(this,(function(t){return[2,this.addresses.indexOf(e)>=0]}))}))},t.prototype.generateRandomSeed=function(t){var r="";if(void 0===t)r=new f.default(f.default.Words.ENGLISH);else{if("string"!=typeof t)throw new Error("generateRandomSeed: extraEntropy is set but not a string.");var n=e.from(t),i=h.default.crypto.Random.getRandomBuffer(32),o=this._concatAndSha256(i,n).slice(0,16);r=new f.default(o,f.default.Words.ENGLISH)}return r.toString()},t}();t.Keystore=g}).call(this,r(0).Buffer)},function(e){e.exports=JSON.parse('{"_args":[["bitcore-lib@8.22.2","/home/smooth-op/work/filecoin/filecoin.js"]],"_from":"bitcore-lib@8.22.2","_id":"bitcore-lib@8.22.2","_inBundle":false,"_integrity":"sha512-atl/RN7x2R/JQMaIgUzX0EQZ+I/d7fTaOoS2/5k+H5POGc2vygWZ9MWpGJi3T9Yb5jM/cT5aFsrDq8s8l6lqgQ==","_location":"/bitcore-lib","_phantomChildren":{},"_requested":{"type":"version","registry":true,"raw":"bitcore-lib@8.22.2","name":"bitcore-lib","escapedName":"bitcore-lib","rawSpec":"8.22.2","saveSpec":null,"fetchSpec":"8.22.2"},"_requiredBy":["/","/bitcore-mnemonic"],"_resolved":"https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-8.22.2.tgz","_spec":"8.22.2","_where":"/home/smooth-op/work/filecoin/filecoin.js","author":{"name":"BitPay","email":"dev@bitpay.com"},"browser":{"request":"browser-request"},"dependencies":{"bech32":"=1.1.3","bn.js":"=4.11.8","bs58":"^4.0.1","buffer-compare":"=1.1.1","elliptic":"^6.5.3","inherits":"=2.0.1","lodash":"^4.17.20"},"description":"A pure and powerful JavaScript Bitcoin library.","devDependencies":{"bitcore-build":"^8.22.2","brfs":"^2.0.1","chai":"^4.2.0","gulp":"^4.0.0","sinon":"^7.1.1"},"gitHead":"012cc0216a9bc6b195035855bd17149bad41acd1","keywords":["bitcoin","transaction","address","p2p","ecies","cryptocurrency","blockchain","payment","bip21","bip32","bip37","bip69","bip70","multisig"],"license":"MIT","main":"index.js","name":"bitcore-lib","repository":{"type":"git","url":"https://github.com/bitpay/bitcore/tree/master/packages/bitcore-lib"},"scripts":{"build":"gulp","coverage":"gulp coverage","pub":"npm run build && npm publish","test":"gulp test","test:ci":"npm run test"},"version":"8.22.2"}')},function(e,t){},function(e,t,r){"use strict";e.exports=[{name:"InvalidB58Char",message:"Invalid Base58 character: {0} in {1}"},{name:"InvalidB58Checksum",message:"Invalid Base58 checksum for {0}"},{name:"InvalidNetwork",message:"Invalid version for network: got {0}"},{name:"InvalidState",message:"Invalid state: {0}"},{name:"NotImplemented",message:"Function {0} was not implemented yet"},{name:"InvalidNetworkArgument",message:'Invalid network: must be "livenet" or "testnet", got {0}'},{name:"InvalidArgument",message:function(){return"Invalid Argument"+(arguments[0]?": "+arguments[0]:"")+(arguments[1]?" Documentation: http://bitcore.io/"+arguments[1]:"")}},{name:"AbstractMethodInvoked",message:"Abstract Method Invocation: {0}"},{name:"InvalidArgumentType",message:function(){return"Invalid Argument for "+arguments[2]+", expected "+arguments[1]+" but got "+typeof arguments[0]}},{name:"Unit",message:"Internal Error on Unit {0}",errors:[{name:"UnknownCode",message:"Unrecognized unit code: {0}"},{name:"InvalidRate",message:"Invalid exchange rate: {0}"}]},{name:"MerkleBlock",message:"Internal Error on MerkleBlock {0}",errors:[{name:"InvalidMerkleTree",message:"This MerkleBlock contain an invalid Merkle Tree"}]},{name:"Transaction",message:"Internal Error on Transaction {0}",errors:[{name:"Input",message:"Internal Error on Input {0}",errors:[{name:"MissingScript",message:"Need a script to create an input"},{name:"UnsupportedScript",message:"Unsupported input script type: {0}"},{name:"MissingPreviousOutput",message:"No previous output information."},{name:"BlockHeightOutOfRange",message:"Block Height can only be between 0 and 65535"},{name:"LockTimeRange",message:"Seconds needs to be more that 0 and less that 33553920"}]},{name:"NeedMoreInfo",message:"{0}"},{name:"InvalidSorting",message:"The sorting function provided did not return the change output as one of the array elements"},{name:"InvalidOutputAmountSum",message:"{0}"},{name:"MissingSignatures",message:"Some inputs have not been fully signed"},{name:"InvalidIndex",message:"Invalid index: {0} is not between 0, {1}"},{name:"UnableToVerifySignature",message:"Unable to verify signature: {0}"},{name:"DustOutputs",message:"Dust amount detected in one output"},{name:"InvalidSatoshis",message:"Output satoshis are invalid"},{name:"FeeError",message:"Internal Error on Fee {0}",errors:[{name:"TooSmall",message:"Fee is too small: {0}"},{name:"TooLarge",message:"Fee is too large: {0}"},{name:"Different",message:"Unspent value is different from specified fee: {0}"}]},{name:"ChangeAddressMissing",message:"Change address is missing"},{name:"BlockHeightTooHigh",message:"Block Height can be at most 2^32 -1"},{name:"NLockTimeOutOfRange",message:"Block Height can only be between 0 and 499 999 999"},{name:"LockTimeTooEarly",message:"Lock Time can't be earlier than UNIX date 500 000 000"}]},{name:"Script",message:"Internal Error on Script {0}",errors:[{name:"UnrecognizedAddress",message:"Expected argument {0} to be an address"},{name:"CantDeriveAddress",message:"Can't derive address associated with script {0}, needs to be p2pkh in, p2pkh out, p2sh in, or p2sh out."},{name:"InvalidBuffer",message:"Invalid script buffer: can't parse valid script from given buffer {0}"}]},{name:"HDPrivateKey",message:"Internal Error on HDPrivateKey {0}",errors:[{name:"InvalidDerivationArgument",message:"Invalid derivation argument {0}, expected string, or number and boolean"},{name:"InvalidEntropyArgument",message:"Invalid entropy: must be an hexa string or binary buffer, got {0}",errors:[{name:"TooMuchEntropy",message:'Invalid entropy: more than 512 bits is non standard, got "{0}"'},{name:"NotEnoughEntropy",message:'Invalid entropy: at least 128 bits needed, got "{0}"'}]},{name:"InvalidLength",message:"Invalid length for xprivkey string in {0}"},{name:"InvalidPath",message:"Invalid derivation path: {0}"},{name:"UnrecognizedArgument",message:'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"'}]},{name:"HDPublicKey",message:"Internal Error on HDPublicKey {0}",errors:[{name:"ArgumentIsPrivateExtended",message:"Argument is an extended private key: {0}"},{name:"InvalidDerivationArgument",message:"Invalid derivation argument: got {0}"},{name:"InvalidLength",message:'Invalid length for xpubkey: got "{0}"'},{name:"InvalidPath",message:'Invalid derivation path, it should look like: "m/1/100", got "{0}"'},{name:"InvalidIndexCantDeriveHardened",message:"Invalid argument: creating a hardened path requires an HDPrivateKey"},{name:"MustSupplyArgument",message:"Must supply an argument to create a HDPublicKey"},{name:"UnrecognizedArgument",message:"Invalid argument for creation, must be string, json, buffer, or object"}]}]},function(e,t,r){e.exports=r(161)},function(e,t,r){var n=r(331),i=r(94),o=r(95),a=r(344),s=r(63);function u(e,t,r){if(e=e.toLowerCase(),o[e])return i.createCipheriv(e,t,r);if(a[e])return new n({key:t,iv:r,mode:e});throw new TypeError("invalid suite type")}function c(e,t,r){if(e=e.toLowerCase(),o[e])return i.createDecipheriv(e,t,r);if(a[e])return new n({key:t,iv:r,mode:e,decrypt:!0});throw new TypeError("invalid suite type")}t.createCipher=t.Cipher=function(e,t){var r,n;if(e=e.toLowerCase(),o[e])r=o[e].key,n=o[e].iv;else{if(!a[e])throw new TypeError("invalid suite type");r=8*a[e].key,n=a[e].iv}var i=s(t,!1,r,n);return u(e,i.key,i.iv)},t.createCipheriv=t.Cipheriv=u,t.createDecipher=t.Decipher=function(e,t){var r,n;if(e=e.toLowerCase(),o[e])r=o[e].key,n=o[e].iv;else{if(!a[e])throw new TypeError("invalid suite type");r=8*a[e].key,n=a[e].iv}var i=s(t,!1,r,n);return c(e,i.key,i.iv)},t.createDecipheriv=t.Decipheriv=c,t.listCiphers=t.getCiphers=function(){return Object.keys(a).concat(i.getCiphers())}},function(e,t,r){var n=r(25),i=r(332),o=r(1),a=r(2).Buffer,s={"des-ede3-cbc":i.CBC.instantiate(i.EDE),"des-ede3":i.EDE,"des-ede-cbc":i.CBC.instantiate(i.EDE),"des-ede":i.EDE,"des-cbc":i.CBC.instantiate(i.DES),"des-ecb":i.DES};function u(e){n.call(this);var t,r=e.mode.toLowerCase(),i=s[r];t=e.decrypt?"decrypt":"encrypt";var o=e.key;a.isBuffer(o)||(o=a.from(o)),"des-ede"!==r&&"des-ede-cbc"!==r||(o=a.concat([o,o.slice(0,8)]));var u=e.iv;a.isBuffer(u)||(u=a.from(u)),this._des=i.create({key:o,iv:u,type:t})}s.des=s["des-cbc"],s.des3=s["des-ede3-cbc"],e.exports=u,o(u,n),u.prototype._update=function(e){return a.from(this._des.update(e))},u.prototype._final=function(){return a.from(this._des.final())}},function(e,t,r){"use strict";t.utils=r(162),t.Cipher=r(93),t.DES=r(163),t.CBC=r(333),t.EDE=r(334)},function(e,t,r){"use strict";var n=r(16),i=r(1),o={};function a(e){n.equal(e.length,8,"Invalid IV length"),this.iv=new Array(8);for(var t=0;t15){var e=this.cache.slice(0,16);return this.cache=this.cache.slice(16),e}return null},l.prototype.flush=function(){for(var e=16-this.cache.length,t=o.allocUnsafe(e),r=-1;++r>a%8,e._prev=o(e._prev,r?n:i);return s}function o(e,t){var r=e.length,i=-1,o=n.allocUnsafe(e.length);for(e=n.concat([e,n.from([t])]);++i>7;return o}t.encrypt=function(e,t,r){for(var o=t.length,a=n.allocUnsafe(o),s=-1;++s>>0,0),t.writeUInt32BE(e[1]>>>0,4),t.writeUInt32BE(e[2]>>>0,8),t.writeUInt32BE(e[3]>>>0,12),t}function a(e){this.h=e,this.state=n.alloc(16,0),this.cache=n.allocUnsafe(0)}a.prototype.ghash=function(e){for(var t=-1;++t0;t--)n[t]=n[t]>>>1|(1&n[t-1])<<31;n[0]=n[0]>>>1,r&&(n[0]=n[0]^225<<24)}this.state=o(i)},a.prototype.update=function(e){var t;for(this.cache=n.concat([this.cache,e]);this.cache.length>=16;)t=this.cache.slice(0,16),this.cache=this.cache.slice(16),this.ghash(t)},a.prototype.final=function(e,t){return this.cache.length&&this.ghash(n.concat([this.cache,i],16)),this.ghash(o([0,e,0,t])),this.state},e.exports=a},function(e,t,r){var n=r(167),i=r(2).Buffer,o=r(95),a=r(168),s=r(25),u=r(62),c=r(63);function h(e,t,r){s.call(this),this._cache=new f,this._last=void 0,this._cipher=new u.AES(t),this._prev=i.from(r),this._mode=e,this._autopadding=!0}function f(){this.cache=i.allocUnsafe(0)}function l(e,t,r){var s=o[e.toLowerCase()];if(!s)throw new TypeError("invalid suite type");if("string"==typeof r&&(r=i.from(r)),"GCM"!==s.mode&&r.length!==s.iv)throw new TypeError("invalid iv length "+r.length);if("string"==typeof t&&(t=i.from(t)),t.length!==s.key/8)throw new TypeError("invalid key length "+t.length);return"stream"===s.type?new a(s.module,t,r,!0):"auth"===s.type?new n(s.module,t,r,!0):new h(s.module,t,r)}r(1)(h,s),h.prototype._update=function(e){var t,r;this._cache.add(e);for(var n=[];t=this._cache.get(this._autopadding);)r=this._mode.decrypt(this,t),n.push(r);return i.concat(n)},h.prototype._final=function(){var e=this._cache.flush();if(this._autopadding)return function(e){var t=e[15];if(t<1||t>16)throw new Error("unable to decrypt data");var r=-1;for(;++r16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t}else if(this.cache.length>=16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t;return null},f.prototype.flush=function(){if(this.cache.length)return this.cache},t.createDecipher=function(e,t){var r=o[e.toLowerCase()];if(!r)throw new TypeError("invalid suite type");var n=c(t,!1,r.key,r.iv);return l(e,n.key,n.iv)},t.createDecipheriv=l},function(e,t){t["des-ecb"]={key:8,iv:0},t["des-cbc"]=t.des={key:8,iv:8},t["des-ede3-cbc"]=t.des3={key:24,iv:8},t["des-ede3"]={key:24,iv:0},t["des-ede-cbc"]={key:16,iv:8},t["des-ede"]={key:16,iv:0}},function(e,t,r){(function(e){var n=r(169),i=r(346),o=r(347);var a={binary:!0,hex:!0,base64:!0};t.DiffieHellmanGroup=t.createDiffieHellmanGroup=t.getDiffieHellman=function(t){var r=new e(i[t].prime,"hex"),n=new e(i[t].gen,"hex");return new o(r,n)},t.createDiffieHellman=t.DiffieHellman=function t(r,i,s,u){return e.isBuffer(i)||void 0===a[i]?t(r,"binary",i,s):(i=i||"binary",u=u||"binary",s=s||new e([2]),e.isBuffer(s)||(s=new e(s,u)),"number"==typeof r?new o(n(r,s),s,!0):(e.isBuffer(r)||(r=new e(r,i)),new o(r,s,!0)))}}).call(this,r(0).Buffer)},function(e){e.exports=JSON.parse('{"modp1":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"},"modp2":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"},"modp5":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff"},"modp14":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff"},"modp15":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff"},"modp16":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff"},"modp17":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff"},"modp18":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff"}}')},function(e,t,r){(function(t){var n=r(6),i=new(r(170)),o=new n(24),a=new n(11),s=new n(10),u=new n(3),c=new n(7),h=r(169),f=r(30);function l(e,r){return r=r||"utf8",t.isBuffer(e)||(e=new t(e,r)),this._pub=new n(e),this}function d(e,r){return r=r||"utf8",t.isBuffer(e)||(e=new t(e,r)),this._priv=new n(e),this}e.exports=m;var p={};function m(e,t,r){this.setGenerator(t),this.__prime=new n(e),this._prime=n.mont(this.__prime),this._primeLen=e.length,this._pub=void 0,this._priv=void 0,this._primeCode=void 0,r?(this.setPublicKey=l,this.setPrivateKey=d):this._primeCode=8}function g(e,r){var n=new t(e.toArray());return r?n.toString(r):n}Object.defineProperty(m.prototype,"verifyError",{enumerable:!0,get:function(){return"number"!=typeof this._primeCode&&(this._primeCode=function(e,t){var r=t.toString("hex"),n=[r,e.toString(16)].join("_");if(n in p)return p[n];var f,l=0;if(e.isEven()||!h.simpleSieve||!h.fermatTest(e)||!i.test(e))return l+=1,l+="02"===r||"05"===r?8:4,p[n]=l,l;switch(i.test(e.shrn(1))||(l+=2),r){case"02":e.mod(o).cmp(a)&&(l+=8);break;case"05":(f=e.mod(s)).cmp(u)&&f.cmp(c)&&(l+=8);break;default:l+=4}return p[n]=l,l}(this.__prime,this.__gen)),this._primeCode}}),m.prototype.generateKeys=function(){return this._priv||(this._priv=new n(f(this._primeLen))),this._pub=this._gen.toRed(this._prime).redPow(this._priv).fromRed(),this.getPublicKey()},m.prototype.computeSecret=function(e){var r=(e=(e=new n(e)).toRed(this._prime)).redPow(this._priv).fromRed(),i=new t(r.toArray()),o=this.getPrime();if(i.length0&&r.ishrn(n),r}function l(e,t,r){var o,a;do{for(o=n.alloc(0);8*o.length=t)throw new Error("invalid sig")}e.exports=function(e,t,r,c,h){var f=a(r);if("ec"===f.type){if("ecdsa"!==c&&"ecdsa/rsa"!==c)throw new Error("wrong public key type");return function(e,t,r){var n=s[r.data.algorithm.curve.join(".")];if(!n)throw new Error("unknown curve "+r.data.algorithm.curve.join("."));var i=new o(n),a=r.data.subjectPrivateKey.data;return i.verify(t,e,a)}(e,t,f)}if("dsa"===f.type){if("dsa"!==c)throw new Error("wrong public key type");return function(e,t,r){var n=r.data.p,o=r.data.q,s=r.data.g,c=r.data.pub_key,h=a.signature.decode(e,"der"),f=h.s,l=h.r;u(f,o),u(l,o);var d=i.mont(n),p=f.invm(o);return 0===s.toRed(d).redPow(new i(t).mul(p).mod(o)).fromRed().mul(c.toRed(d).redPow(l.mul(p).mod(o)).fromRed()).mod(n).mod(o).cmp(l)}(e,t,f)}if("rsa"!==c&&"ecdsa/rsa"!==c)throw new Error("wrong public key type");t=n.concat([h,t]);for(var l=f.modulus.byteLength(),d=[1],p=0;t.length+d.length+2r-l-2)throw new Error("message too long");var d=f.alloc(r-n-l-2),p=r-h-1,m=i(h),g=s(f.concat([c,d,f.alloc(1,1),t],p),a(m,p)),b=s(m,a(g,h));return new u(f.concat([f.alloc(1),b,g],r))}(p,t);else if(1===l)d=function(e,t,r){var n,o=t.length,a=e.modulus.byteLength();if(o>a-11)throw new Error("message too long");n=r?f.alloc(a-o-3,255):function(e){var t,r=f.allocUnsafe(e),n=0,o=i(2*e),a=0;for(;n=0)throw new Error("data too long for modulus")}return r?h(d,p):c(d,p)}},function(e,t,r){var n=r(64),i=r(178),o=r(179),a=r(6),s=r(96),u=r(24),c=r(180),h=r(2).Buffer;e.exports=function(e,t,r){var f;f=e.padding?e.padding:r?1:4;var l,d=n(e),p=d.modulus.byteLength();if(t.length>p||new a(t).cmp(d.modulus)>=0)throw new Error("decryption error");l=r?c(new a(t),d):s(t,d);var m=h.alloc(p-l.length);if(l=h.concat([m,l],p),4===f)return function(e,t){var r=e.modulus.byteLength(),n=u("sha1").update(h.alloc(0)).digest(),a=n.length;if(0!==t[0])throw new Error("decryption error");var s=t.slice(1,a+1),c=t.slice(a+1),f=o(s,i(c,a)),l=o(c,i(f,r-a-1));if(function(e,t){e=h.from(e),t=h.from(t);var r=0,n=e.length;e.length!==t.length&&(r++,n=Math.min(e.length,t.length));var i=-1;for(;++i=t.length){o++;break}var a=t.slice(2,i-1);("0002"!==n.toString("hex")&&!r||"0001"!==n.toString("hex")&&r)&&o++;a.length<8&&o++;if(o)throw new Error("decryption error");return t.slice(i)}(0,l,r);if(3===f)return l;throw new Error("unknown padding")}},function(e,t,r){"use strict";(function(e,n){function i(){throw new Error("secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11")}var o=r(2),a=r(30),s=o.Buffer,u=o.kMaxLength,c=e.crypto||e.msCrypto,h=Math.pow(2,32)-1;function f(e,t){if("number"!=typeof e||e!=e)throw new TypeError("offset must be a number");if(e>h||e<0)throw new TypeError("offset must be a uint32");if(e>u||e>t)throw new RangeError("offset out of range")}function l(e,t,r){if("number"!=typeof e||e!=e)throw new TypeError("size must be a number");if(e>h||e<0)throw new TypeError("size must be a uint32");if(e+t>r||e>u)throw new RangeError("buffer too small")}function d(e,t,r,i){if(n.browser){var o=e.buffer,s=new Uint8Array(o,t,r);return c.getRandomValues(s),i?void n.nextTick((function(){i(null,e)})):e}if(!i)return a(r).copy(e,t),e;a(r,(function(r,n){if(r)return i(r);n.copy(e,t),i(null,e)}))}c&&c.getRandomValues||!n.browser?(t.randomFill=function(t,r,n,i){if(!(s.isBuffer(t)||t instanceof e.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');if("function"==typeof r)i=r,r=0,n=t.length;else if("function"==typeof n)i=n,n=t.length-r;else if("function"!=typeof i)throw new TypeError('"cb" argument must be a function');return f(r,t.length),l(n,r,t.length),d(t,r,n,i)},t.randomFillSync=function(t,r,n){void 0===r&&(r=0);if(!(s.isBuffer(t)||t instanceof e.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');f(r,t.length),void 0===n&&(n=t.length-r);return l(n,r,t.length),d(t,r,n)}):(t.randomFill=i,t.randomFillSync=i)}).call(this,r(8),r(9))},function(e,t,r){"use strict";(function(t){var n=r(367);e.exports={decode:function(e){if("string"!=typeof e)throw new Error("Input should be a string");var r=n.decode(e);return{prefix:r.prefix,data:t.from(n.fromWords(r.words.slice(1))),version:r.words[0]}},encode:function(e,t,r){if("string"!=typeof e)throw new Error("Prefix should be a string");if("number"!=typeof t)throw new Error("version should be a number");var i=n.toWords(r);return i.unshift(t),n.encode(e,i)}}}).call(this,r(0).Buffer)},function(e,t,r){"use strict";for(var n="qpzry9x8gf2tvdw0s3jn54khce6mua7l",i={},o=0;o>25;return(33554431&e)<<5^996825010&-(t>>0&1)^642813549&-(t>>1&1)^513874426&-(t>>2&1)^1027748829&-(t>>3&1)^705979059&-(t>>4&1)}function u(e){for(var t=1,r=0;r126)throw new Error("Invalid prefix ("+e+")");t=s(t)^n>>5}for(t=s(t),r=0;r=r;)o-=r,s.push(i>>o&a);if(n)o>0&&s.push(i<=t)throw new Error("Excess padding");if(i<t)throw new TypeError("Exceeds length limit");var r=e.toLowerCase(),n=e.toUpperCase();if(e!==r&&e!==n)throw new Error("Mixed-case string "+e);var o=(e=r).lastIndexOf("1");if(-1===o)throw new Error("No separator character for "+e);if(0===o)throw new Error("Missing prefix for "+e);var a=e.slice(0,o),c=e.slice(o+1);if(c.length<6)throw new Error("Data too short");for(var h=u(a),f=[],l=0;l=c.length||f.push(p)}if(1!==h)throw new Error("Invalid checksum for "+e);return{prefix:a,words:f}},encode:function(e,t,r){if(r=r||90,e.length+7+t.length>r)throw new TypeError("Exceeds length limit");for(var i=u(e=e.toLowerCase()),o=e+"1",a=0;a>5!=0)throw new Error("Non 5-bit word");i=s(i)^c,o+=n.charAt(c)}for(a=0;a<6;++a)i=s(i);for(i^=1,a=0;a<6;++a){o+=n.charAt(i>>5*(5-a)&31)}return o},toWords:function(e){return c(e,8,5,!0)},fromWords:function(e){return c(e,5,8,!1)}}},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(181),o=r(101),a=r(10),s=r(11),u=r(13),c=r(19),h=function e(t){if(!(this instanceof e))return new e(t);t?(this.initialize(),this.set(t)):this.initialize()};h.prototype.verifyWitnessProgram=function(e,t,r,n,a){var u=new i,c=[];if(0!==e)return!(a&h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)||(this.errstr="SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM",!1);if(32===t.length){if(0===r.length)return this.errstr="SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY",!1;var f=r[r.length-1];if(u=new i(f),s.sha256(f).toString("hex")!==t.toString("hex"))return this.errstr="SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH",!1;c=r.slice(0,-1)}else{if(20!==t.length)return this.errstr="SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH",!1;if(2!==r.length)return this.errstr="SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH",!1;u.add(o.OP_DUP),u.add(o.OP_HASH160),u.add(t),u.add(o.OP_EQUALVERIFY),u.add(o.OP_CHECKSIG),c=r}if(this.initialize(),this.set({script:u,stack:c,sigversion:1,satoshis:n,flags:a}),!this.evaluate())return!1;if(1!==this.stack.length)return this.errstr="SCRIPT_ERR_EVAL_FALSE",!1;var l=this.stack[this.stack.length-1];return!!h.castToBool(l)||(this.errstr="SCRIPT_ERR_EVAL_FALSE_IN_STACK",!1)},h.prototype.verify=function(e,t,o,a,s,u,c){var f,l=r(66);if(n.isUndefined(o)&&(o=new l),n.isUndefined(a)&&(a=0),n.isUndefined(s)&&(s=0),n.isUndefined(u)&&(u=null),n.isUndefined(c)&&(c=0),this.set({script:e,tx:o,nin:a,sigversion:0,satoshis:0,flags:s}),0!=(s&h.SCRIPT_VERIFY_SIGPUSHONLY)&&!e.isPushOnly())return this.errstr="SCRIPT_ERR_SIG_PUSHONLY",!1;if(!this.evaluate())return!1;s&h.SCRIPT_VERIFY_P2SH&&(f=this.stack.slice());var d=this.stack;if(this.initialize(),this.set({script:t,stack:d,tx:o,nin:a,flags:s}),!this.evaluate())return!1;if(0===this.stack.length)return this.errstr="SCRIPT_ERR_EVAL_FALSE_NO_RESULT",!1;var p=this.stack[this.stack.length-1];if(!h.castToBool(p))return this.errstr="SCRIPT_ERR_EVAL_FALSE_IN_STACK",!1;var m=!1;if(s&h.SCRIPT_VERIFY_WITNESS){var g={};if(t.isWitnessProgram(g)){if(m=!0,0!==e.toBuffer().length)return!1;if(!this.verifyWitnessProgram(g.version,g.program,u,c,this.flags))return!1}}if(s&h.SCRIPT_VERIFY_P2SH&&t.isScriptHashOut()){if(!e.isPushOnly())return this.errstr="SCRIPT_ERR_SIG_PUSHONLY",!1;if(0===f.length)throw new Error("internal error - stack copy empty");var b=f[f.length-1],v=i.fromBuffer(b);if(f.pop(),this.initialize(),this.set({script:v,stack:f,tx:o,nin:a,flags:s}),!this.evaluate())return!1;if(0===f.length)return this.errstr="SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK",!1;if(!h.castToBool(f[f.length-1]))return this.errstr="SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK",!1;if(s&h.SCRIPT_VERIFY_WITNESS){var y={};if(v.isWitnessProgram(y)){m=!0;var w=new i;if(w.add(v.toBuffer()),e.toHex()!==w.toHex())return this.errstr="SCRIPT_ERR_WITNESS_MALLEATED_P2SH",!1;if(!this.verifyWitnessProgram(y.version,y.program,u,c,this.flags))return!1;d=[d[0]]}}}if(0!=(this.flags&h.SCRIPT_VERIFY_CLEANSTACK)){if(0==(this.flags&h.SCRIPT_VERIFY_P2SH))throw"flags & SCRIPT_VERIFY_P2SH";if(1!=f.length)return this.errstr="SCRIPT_ERR_CLEANSTACK",!1}return!(this.flags&h.SCRIPT_VERIFY_WITNESS&&!m&&u.length>0)||(this.errstr="SCRIPT_ERR_WITNESS_UNEXPECTED",!1)},e.exports=h,h.prototype.initialize=function(e){this.stack=[],this.altstack=[],this.pc=0,this.satoshis=0,this.sigversion=0,this.pbegincodehash=0,this.nOpCount=0,this.vfExec=[],this.errstr="",this.flags=0},h.prototype.set=function(e){this.script=e.script||this.script,this.tx=e.tx||this.tx,this.nin=void 0!==e.nin?e.nin:this.nin,this.stack=e.stack||this.stack,this.altstack=e.altack||this.altstack,this.pc=void 0!==e.pc?e.pc:this.pc,this.pbegincodehash=void 0!==e.pbegincodehash?e.pbegincodehash:this.pbegincodehash,this.sigversion=void 0!==e.sigversion?e.sigversion:this.sigversion,this.satoshis=void 0!==e.satoshis?e.satoshis:this.satoshis,this.nOpCount=void 0!==e.nOpCount?e.nOpCount:this.nOpCount,this.vfExec=e.vfExec||this.vfExec,this.errstr=e.errstr||this.errstr,this.flags=void 0!==e.flags?e.flags:this.flags},h.true=t.from([1]),h.false=t.from([]),h.MAX_SCRIPT_ELEMENT_SIZE=520,h.LOCKTIME_THRESHOLD_BN=new a(h.LOCKTIME_THRESHOLD=5e8),h.SCRIPT_VERIFY_NONE=0,h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM=4096,h.SCRIPT_VERIFY_P2SH=1,h.SCRIPT_VERIFY_STRICTENC=2,h.SCRIPT_VERIFY_DERSIG=4,h.SCRIPT_VERIFY_LOW_S=8,h.SCRIPT_VERIFY_NULLDUMMY=16,h.SCRIPT_VERIFY_SIGPUSHONLY=32,h.SCRIPT_VERIFY_MINIMALDATA=64,h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS=128,h.SCRIPT_VERIFY_CLEANSTACK=256,h.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY=512,h.SCRIPT_VERIFY_WITNESS=1024,h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS=2048,h.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY=1024,h.SCRIPT_VERIFY_MINIMALIF=8192,h.SCRIPT_VERIFY_NULLFAIL=16384,h.SCRIPT_VERIFY_WITNESS_PUBKEYTYPE=32768,h.SCRIPT_ENABLE_SIGHASH_FORKID=65536,h.SCRIPT_ENABLE_REPLAY_PROTECTION=1<<17,h.SCRIPT_ENABLE_MONOLITH_OPCODES=1<<18,h.SEQUENCE_LOCKTIME_DISABLE_FLAG=1<<31,h.SEQUENCE_LOCKTIME_TYPE_FLAG=1<<22,h.SEQUENCE_LOCKTIME_MASK=65535,h.castToBool=function(e){for(var t=0;t1e4)return this.errstr="SCRIPT_ERR_SCRIPT_SIZE",!1;try{for(;this.pc1e3)return this.errstr="SCRIPT_ERR_STACK_SIZE",!1}catch(e){return this.errstr="SCRIPT_ERR_UNKNOWN_ERROR: "+e,!1}return!(this.vfExec.length>0)||(this.errstr="SCRIPT_ERR_UNBALANCED_CONDITIONAL",!1)},h.prototype.checkLockTime=function(e){return!!(this.tx.nLockTime=h.LOCKTIME_THRESHOLD&&e.gte(h.LOCKTIME_THRESHOLD_BN))&&(!e.gt(new a(this.tx.nLockTime))&&!!this.tx.inputs[this.nin].isFinal())},h.prototype.checkSequence=function(e){var t=this.tx.inputs[this.nin].sequenceNumber;if(this.tx.version<2)return!1;if(t&SEQUENCE_LOCKTIME_DISABLE_FLAG)return!1;var r=h.SEQUENCE_LOCKTIME_TYPE_FLAG|h.SEQUENCE_LOCKTIME_MASK,n=new a(t&r),i=e.and(r),o=new a(h.SEQUENCE_LOCKTIME_TYPE_FLAG);return!!(n.lt(o)&&i.lt(o)||n.gte(o)&&i.gte(o))&&!i.gt(n)},h.prototype.step=function(){var e,t,r,f,l,d,p,m,g,b,v,y,w,_,S,M,k,E=0!=(this.flags&h.SCRIPT_VERIFY_MINIMALDATA),A=-1===this.vfExec.indexOf(!1),x=this.script.chunks[this.pc];this.pc++;var I=x.opcodenum;if(n.isUndefined(I))return this.errstr="SCRIPT_ERR_UNDEFINED_OPCODE",!1;if(x.buf&&x.buf.length>h.MAX_SCRIPT_ELEMENT_SIZE)return this.errstr="SCRIPT_ERR_PUSH_SIZE",!1;if(I>o.OP_16&&++this.nOpCount>201)return this.errstr="SCRIPT_ERR_OP_COUNT",!1;if(I===o.OP_CAT||I===o.OP_SUBSTR||I===o.OP_LEFT||I===o.OP_RIGHT||I===o.OP_INVERT||I===o.OP_AND||I===o.OP_OR||I===o.OP_XOR||I===o.OP_2MUL||I===o.OP_2DIV||I===o.OP_MUL||I===o.OP_DIV||I===o.OP_MOD||I===o.OP_LSHIFT||I===o.OP_RSHIFT)return this.errstr="SCRIPT_ERR_DISABLED_OPCODE",!1;if(A&&0<=I&&I<=o.OP_PUSHDATA4){if(E&&!this.script.checkMinimalPush(this.pc-1))return this.errstr="SCRIPT_ERR_MINIMALDATA",!1;if(x.buf){if(x.len!==x.buf.length)throw new Error("Length of push value not equal to length of data");this.stack.push(x.buf)}else this.stack.push(h.false)}else if(A||o.OP_IF<=I&&I<=o.OP_ENDIF)switch(I){case o.OP_1NEGATE:case o.OP_1:case o.OP_2:case o.OP_3:case o.OP_4:case o.OP_5:case o.OP_6:case o.OP_7:case o.OP_8:case o.OP_9:case o.OP_10:case o.OP_11:case o.OP_12:case o.OP_13:case o.OP_14:case o.OP_15:case o.OP_16:l=I-(o.OP_1-1),e=new a(l).toScriptNumBuffer(),this.stack.push(e);break;case o.OP_NOP:break;case o.OP_NOP2:case o.OP_CHECKLOCKTIMEVERIFY:if(!(this.flags&h.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)){if(this.flags&h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)return this.errstr="SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS",!1;break}if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;var P=a.fromScriptNumBuffer(this.stack[this.stack.length-1],E,5);if(P.lt(new a(0)))return this.errstr="SCRIPT_ERR_NEGATIVE_LOCKTIME",!1;if(!this.checkLockTime(P))return this.errstr="SCRIPT_ERR_UNSATISFIED_LOCKTIME",!1;break;case o.OP_NOP3:case o.OP_CHECKSEQUENCEVERIFY:if(!(this.flags&h.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)){if(this.flags&h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)return this.errstr="SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS",!1;break}if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;var O=a.fromScriptNumBuffer(this.stack[this.stack.length-1],E,5);if(O.lt(new a(0)))return this.errstr="SCRIPT_ERR_NEGATIVE_LOCKTIME",!1;if(0!=(O&h.SEQUENCE_LOCKTIME_DISABLE_FLAG))break;if(!this.checkSequence(O))return this.errstr="SCRIPT_ERR_UNSATISFIED_LOCKTIME",!1;break;case o.OP_NOP1:case o.OP_NOP4:case o.OP_NOP5:case o.OP_NOP6:case o.OP_NOP7:case o.OP_NOP8:case o.OP_NOP9:case o.OP_NOP10:if(this.flags&h.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)return this.errstr="SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS",!1;break;case o.OP_IF:case o.OP_NOTIF:if(M=!1,A){if(this.stack.length<1)return this.errstr="SCRIPT_ERR_UNBALANCED_CONDITIONAL",!1;if(e=this.stack[this.stack.length-1],this.flags&h.SCRIPT_VERIFY_MINIMALIF){if((e=this.stack[this.stack.length-1]).length>1)return this.errstr="SCRIPT_ERR_MINIMALIF",!1;if(1==e.length&&1!=e[0])return this.errstr="SCRIPT_ERR_MINIMALIF",!1}M=h.castToBool(e),I===o.OP_NOTIF&&(M=!M),this.stack.pop()}this.vfExec.push(M);break;case o.OP_ELSE:if(0===this.vfExec.length)return this.errstr="SCRIPT_ERR_UNBALANCED_CONDITIONAL",!1;this.vfExec[this.vfExec.length-1]=!this.vfExec[this.vfExec.length-1];break;case o.OP_ENDIF:if(0===this.vfExec.length)return this.errstr="SCRIPT_ERR_UNBALANCED_CONDITIONAL",!1;this.vfExec.pop();break;case o.OP_VERIFY:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;if(e=this.stack[this.stack.length-1],!(M=h.castToBool(e)))return this.errstr="SCRIPT_ERR_VERIFY",!1;this.stack.pop();break;case o.OP_RETURN:return this.errstr="SCRIPT_ERR_OP_RETURN",!1;case o.OP_TOALTSTACK:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.altstack.push(this.stack.pop());break;case o.OP_FROMALTSTACK:if(this.altstack.length<1)return this.errstr="SCRIPT_ERR_INVALID_ALTSTACK_OPERATION",!1;this.stack.push(this.altstack.pop());break;case o.OP_2DROP:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.stack.pop(),this.stack.pop();break;case o.OP_2DUP:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;t=this.stack[this.stack.length-2],r=this.stack[this.stack.length-1],this.stack.push(t),this.stack.push(r);break;case o.OP_3DUP:if(this.stack.length<3)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;t=this.stack[this.stack.length-3],r=this.stack[this.stack.length-2];var T=this.stack[this.stack.length-1];this.stack.push(t),this.stack.push(r),this.stack.push(T);break;case o.OP_2OVER:if(this.stack.length<4)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;t=this.stack[this.stack.length-4],r=this.stack[this.stack.length-3],this.stack.push(t),this.stack.push(r);break;case o.OP_2ROT:if(this.stack.length<6)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;f=this.stack.splice(this.stack.length-6,2),this.stack.push(f[0]),this.stack.push(f[1]);break;case o.OP_2SWAP:if(this.stack.length<4)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;f=this.stack.splice(this.stack.length-4,2),this.stack.push(f[0]),this.stack.push(f[1]);break;case o.OP_IFDUP:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;e=this.stack[this.stack.length-1],(M=h.castToBool(e))&&this.stack.push(e);break;case o.OP_DEPTH:e=new a(this.stack.length).toScriptNumBuffer(),this.stack.push(e);break;case o.OP_DROP:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.stack.pop();break;case o.OP_DUP:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.stack.push(this.stack[this.stack.length-1]);break;case o.OP_NIP:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.stack.splice(this.stack.length-2,1);break;case o.OP_OVER:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.stack.push(this.stack[this.stack.length-2]);break;case o.OP_PICK:case o.OP_ROLL:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;if(e=this.stack[this.stack.length-1],l=(m=a.fromScriptNumBuffer(e,E)).toNumber(),this.stack.pop(),l<0||l>=this.stack.length)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;e=this.stack[this.stack.length-l-1],I===o.OP_ROLL&&this.stack.splice(this.stack.length-l-1,1),this.stack.push(e);break;case o.OP_ROT:if(this.stack.length<3)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;d=this.stack[this.stack.length-3],p=this.stack[this.stack.length-2];var R=this.stack[this.stack.length-1];this.stack[this.stack.length-3]=p,this.stack[this.stack.length-2]=R,this.stack[this.stack.length-1]=d;break;case o.OP_SWAP:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;d=this.stack[this.stack.length-2],p=this.stack[this.stack.length-1],this.stack[this.stack.length-2]=p,this.stack[this.stack.length-1]=d;break;case o.OP_TUCK:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;this.stack.splice(this.stack.length-2,0,this.stack[this.stack.length-1]);break;case o.OP_SIZE:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;m=new a(this.stack[this.stack.length-1].length),this.stack.push(m.toScriptNumBuffer());break;case o.OP_EQUAL:case o.OP_EQUALVERIFY:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;t=this.stack[this.stack.length-2],r=this.stack[this.stack.length-1];var B=t.toString("hex")===r.toString("hex");if(this.stack.pop(),this.stack.pop(),this.stack.push(B?h.true:h.false),I===o.OP_EQUALVERIFY){if(!B)return this.errstr="SCRIPT_ERR_EQUALVERIFY",!1;this.stack.pop()}break;case o.OP_1ADD:case o.OP_1SUB:case o.OP_NEGATE:case o.OP_ABS:case o.OP_NOT:case o.OP_0NOTEQUAL:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;switch(e=this.stack[this.stack.length-1],m=a.fromScriptNumBuffer(e,E),I){case o.OP_1ADD:m=m.add(a.One);break;case o.OP_1SUB:m=m.sub(a.One);break;case o.OP_NEGATE:m=m.neg();break;case o.OP_ABS:m.cmp(a.Zero)<0&&(m=m.neg());break;case o.OP_NOT:m=new a((0===m.cmp(a.Zero))+0);break;case o.OP_0NOTEQUAL:m=new a((0!==m.cmp(a.Zero))+0)}this.stack.pop(),this.stack.push(m.toScriptNumBuffer());break;case o.OP_ADD:case o.OP_SUB:case o.OP_BOOLAND:case o.OP_BOOLOR:case o.OP_NUMEQUAL:case o.OP_NUMEQUALVERIFY:case o.OP_NUMNOTEQUAL:case o.OP_LESSTHAN:case o.OP_GREATERTHAN:case o.OP_LESSTHANOREQUAL:case o.OP_GREATERTHANOREQUAL:case o.OP_MIN:case o.OP_MAX:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;switch(g=a.fromScriptNumBuffer(this.stack[this.stack.length-2],E),b=a.fromScriptNumBuffer(this.stack[this.stack.length-1],E),m=new a(0),I){case o.OP_ADD:m=g.add(b);break;case o.OP_SUB:m=g.sub(b);break;case o.OP_BOOLAND:m=new a((0!==g.cmp(a.Zero)&&0!==b.cmp(a.Zero))+0);break;case o.OP_BOOLOR:m=new a((0!==g.cmp(a.Zero)||0!==b.cmp(a.Zero))+0);break;case o.OP_NUMEQUAL:case o.OP_NUMEQUALVERIFY:m=new a((0===g.cmp(b))+0);break;case o.OP_NUMNOTEQUAL:m=new a((0!==g.cmp(b))+0);break;case o.OP_LESSTHAN:m=new a((g.cmp(b)<0)+0);break;case o.OP_GREATERTHAN:m=new a((g.cmp(b)>0)+0);break;case o.OP_LESSTHANOREQUAL:m=new a((g.cmp(b)<=0)+0);break;case o.OP_GREATERTHANOREQUAL:m=new a((g.cmp(b)>=0)+0);break;case o.OP_MIN:m=g.cmp(b)<0?g:b;break;case o.OP_MAX:m=g.cmp(b)>0?g:b}if(this.stack.pop(),this.stack.pop(),this.stack.push(m.toScriptNumBuffer()),I===o.OP_NUMEQUALVERIFY){if(!h.castToBool(this.stack[this.stack.length-1]))return this.errstr="SCRIPT_ERR_NUMEQUALVERIFY",!1;this.stack.pop()}break;case o.OP_WITHIN:if(this.stack.length<3)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;g=a.fromScriptNumBuffer(this.stack[this.stack.length-3],E),b=a.fromScriptNumBuffer(this.stack[this.stack.length-2],E);var N=a.fromScriptNumBuffer(this.stack[this.stack.length-1],E);M=b.cmp(g)<=0&&g.cmp(N)<0,this.stack.pop(),this.stack.pop(),this.stack.pop(),this.stack.push(M?h.true:h.false);break;case o.OP_RIPEMD160:case o.OP_SHA1:case o.OP_SHA256:case o.OP_HASH160:case o.OP_HASH256:if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;var C;e=this.stack[this.stack.length-1],I===o.OP_RIPEMD160?C=s.ripemd160(e):I===o.OP_SHA1?C=s.sha1(e):I===o.OP_SHA256?C=s.sha256(e):I===o.OP_HASH160?C=s.sha256ripemd160(e):I===o.OP_HASH256&&(C=s.sha256sha256(e)),this.stack.pop(),this.stack.push(C);break;case o.OP_CODESEPARATOR:this.pbegincodehash=this.pc;break;case o.OP_CHECKSIG:case o.OP_CHECKSIGVERIFY:if(this.stack.length<2)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;if(v=this.stack[this.stack.length-2],y=this.stack[this.stack.length-1],!this.checkSignatureEncoding(v)||!this.checkPubkeyEncoding(y))return!1;w=(new i).set({chunks:this.script.chunks.slice(this.pbegincodehash)});var j=(new i).add(v);w.findAndDelete(j);try{_=u.fromTxFormat(v),S=c.fromBuffer(y,!1),k=this.tx.verifySignature(_,S,this.nin,w,this.sigversion,this.satoshis)}catch(e){k=!1}if(!k&&this.flags&h.SCRIPT_VERIFY_NULLFAIL&&v.length)return this.errstr="SCRIPT_ERR_NULLFAIL",!1;if(this.stack.pop(),this.stack.pop(),this.stack.push(k?h.true:h.false),I===o.OP_CHECKSIGVERIFY){if(!k)return this.errstr="SCRIPT_ERR_CHECKSIGVERIFY",!1;this.stack.pop()}break;case o.OP_CHECKMULTISIG:case o.OP_CHECKMULTISIGVERIFY:var z=1;if(this.stack.length20)return this.errstr="SCRIPT_ERR_PUBKEY_COUNT",!1;if(this.nOpCount+=U,this.nOpCount>201)return this.errstr="SCRIPT_ERR_OP_COUNT",!1;var L=++z;z+=U;var F=U+2;if(this.stack.lengthU)return this.errstr="SCRIPT_ERR_SIG_COUNT",!1;var q=++z;if(z+=D,this.stack.length0;){if(v=this.stack[this.stack.length-q],y=this.stack[this.stack.length-L],!this.checkSignatureEncoding(v)||!this.checkPubkeyEncoding(y))return!1;var H;try{_=u.fromTxFormat(v),S=c.fromBuffer(y,!1),H=this.tx.verifySignature(_,S,this.nin,w,this.sigversion,this.satoshis)}catch(e){H=!1}H&&(q++,D--),L++,D>--U&&(k=!1)}for(;z-- >1;){if(!k&&this.flags&h.SCRIPT_VERIFY_NULLFAIL&&!F&&this.stack[this.stack.length-1].length)return this.errstr="SCRIPT_ERR_NULLFAIL",!1;F>0&&F--,this.stack.pop()}if(this.stack.length<1)return this.errstr="SCRIPT_ERR_INVALID_STACK_OPERATION",!1;if(this.flags&h.SCRIPT_VERIFY_NULLDUMMY&&this.stack[this.stack.length-1].length)return this.errstr="SCRIPT_ERR_SIG_NULLDUMMY",!1;if(this.stack.pop(),this.stack.push(k?h.true:h.false),I===o.OP_CHECKMULTISIGVERIFY){if(!k)return this.errstr="SCRIPT_ERR_CHECKMULTISIGVERIFY",!1;this.stack.pop()}break;default:return this.errstr="SCRIPT_ERR_BAD_OPCODE",!1}return!0}}).call(this,r(0).Buffer)},function(e,t){e.exports=function(e,t){if("function"==typeof e.compare)return e.compare(t);if(e===t)return 0;for(var r=e.length,n=t.length,i=0,o=Math.min(r,n);i1;n=Math.floor((n+1)/2)){for(var i=0;i"},l.Values={START_OF_BLOCK:8,NULL_HASH:t.from("0000000000000000000000000000000000000000000000000000000000000000","hex")},e.exports=l}).call(this,r(0).Buffer)},function(e,t,r){"use strict";(function(t){var n=r(3),i=r(48),o=r(19),a=r(20),s=r(12),u=r(61),c=r(13),h=r(11).sha256sha256,f=r(7),l=r(4);function d(e){return this instanceof d?(l.checkArgument(n.isString(e),"First argument should be a string"),this.message=e,this):new d(e)}d.MAGIC_BYTES=t.from("Bitcoin Signed Message:\n"),d.prototype.magicHash=function(){var e=s.varintBufNum(d.MAGIC_BYTES.length),r=t.from(this.message),n=s.varintBufNum(r.length),i=t.concat([e,d.MAGIC_BYTES,n,r]);return h(i)},d.prototype._sign=function(e){l.checkArgument(e instanceof i,"First argument should be an instance of PrivateKey");var t=this.magicHash(),r=new u;return r.hashbuf=t,r.privkey=e,r.pubkey=e.toPublicKey(),r.signRandomK(),r.calci(),r.sig},d.prototype.sign=function(e){return this._sign(e).toCompact().toString("base64")},d.prototype._verify=function(e,t){l.checkArgument(e instanceof o,"First argument should be an instance of PublicKey"),l.checkArgument(t instanceof c,"Second argument should be an instance of Signature");var r=this.magicHash(),n=u.verify(r,t,e);return n||(this.error="The signature was invalid"),n},d.prototype.verify=function(e,r){l.checkArgument(e),l.checkArgument(r&&n.isString(r)),n.isString(e)&&(e=a.fromString(e));var i=c.fromCompact(t.from(r,"base64")),o=new u;o.hashbuf=this.magicHash(),o.sig=i;var s=o.toPublicKey(),h=a.fromPublicKey(s,e.network);return e.toString()!==h.toString()?(this.error="The signature did not match the message digest",!1):this._verify(s,i)},d.prototype.recoverPublicKey=function(e,r){l.checkArgument(e),l.checkArgument(r&&n.isString(r)),n.isString(e)&&(e=a.fromString(e));var i=c.fromCompact(t.from(r,"base64")),o=new u;o.hashbuf=this.magicHash(),o.sig=i;var s=o.toPublicKey(),h=a.fromPublicKey(s,e.network);return e.toString()!==h.toString()&&(this.error="The signature did not match the message digest"),s.toString()},d.fromString=function(e){return new d(e)},d.fromJSON=function(e){return f.isValidJSON(e)&&(e=JSON.parse(e)),new d(e.message)},d.prototype.toObject=function(){return{message:this.message}},d.prototype.toJSON=function(){return JSON.stringify(this.toObject())},d.prototype.toString=function(){return this.message},d.prototype.inspect=function(){return""},e.exports=d;r(14)}).call(this,r(0).Buffer)},function(e,t,r){"use strict";var n=r(3),i=r(379),o=r(20),a=r(104),s=function(e,t){if(!(this instanceof s))return new s(e,t);if(this.extras={},this.knownParams=t||[],this.address=this.network=this.amount=this.message=null,"string"==typeof e){var r=s.parse(e);r.amount&&(r.amount=this._parseAmount(r.amount)),this._fromObject(r)}else{if("object"!=typeof e)throw new TypeError("Unrecognized data format.");this._fromObject(e)}};s.fromString=function(e){if("string"!=typeof e)throw new TypeError("Expected a string");return new s(e)},s.fromObject=function(e){return new s(e)},s.isValid=function(e,t){try{new s(e,t)}catch(e){return!1}return!0},s.parse=function(e){var t=i.parse(e,!0);if("bitcoin:"!==t.protocol)throw new TypeError("Invalid bitcoin URI");var r=/[^:]*:\/?\/?([^?]*)/.exec(e);return t.query.address=r&&r[1]||void 0,t.query},s.Members=["address","amount","message","label","r"],s.prototype._fromObject=function(e){if(!o.isValid(e.address))throw new TypeError("Invalid bitcoin address");for(var t in this.address=new o(e.address),this.network=this.address.network,this.amount=e.amount,e)if("address"!==t&&"amount"!==t){if(/^req-/.exec(t)&&-1===this.knownParams.indexOf(t))throw Error("Unknown required argument "+t);(s.Members.indexOf(t)>-1?this:this.extras)[t]=e[t]}},s.prototype._parseAmount=function(e){if(e=Number(e),isNaN(e))throw new TypeError("Invalid amount");return a.fromBTC(e).toSatoshis()},s.prototype.toObject=s.prototype.toJSON=function(){for(var e={},t=0;t"},e.exports=s},function(e,t,r){"use strict";var n=r(380),i=r(381);function o(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}t.parse=y,t.resolve=function(e,t){return y(e,!1,!0).resolve(t)},t.resolveObject=function(e,t){return e?y(e,!1,!0).resolveObject(t):t},t.format=function(e){i.isString(e)&&(e=y(e));return e instanceof o?e.format():o.prototype.format.call(e)},t.Url=o;var a=/^([a-z0-9.+-]+:)/i,s=/:[0-9]*$/,u=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,c=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),h=["'"].concat(c),f=["%","/","?",";","#"].concat(h),l=["/","?","#"],d=/^[+a-z0-9A-Z_-]{0,63}$/,p=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},g={javascript:!0,"javascript:":!0},b={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},v=r(382);function y(e,t,r){if(e&&i.isObject(e)&&e instanceof o)return e;var n=new o;return n.parse(e,t,r),n}o.prototype.parse=function(e,t,r){if(!i.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var o=e.indexOf("?"),s=-1!==o&&o127?B+="x":B+=R[N];if(!B.match(d)){var j=O.slice(0,x),z=O.slice(x+1),U=R.match(p);U&&(j.push(U[1]),z.unshift(U[2])),z.length&&(y="/"+z.join(".")+y),this.hostname=j.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),P||(this.hostname=n.toASCII(this.hostname));var L=this.port?":"+this.port:"",F=this.hostname||"";this.host=F+L,this.href+=this.host,P&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==y[0]&&(y="/"+y))}if(!m[S])for(x=0,T=h.length;x0)&&r.host.split("@"))&&(r.auth=P.shift(),r.host=r.hostname=P.shift());return r.search=e.search,r.query=e.query,i.isNull(r.pathname)&&i.isNull(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.href=r.format(),r}if(!M.length)return r.pathname=null,r.search?r.path="/"+r.search:r.path=null,r.href=r.format(),r;for(var E=M.slice(-1)[0],A=(r.host||e.host||M.length>1)&&("."===E||".."===E)||""===E,x=0,I=M.length;I>=0;I--)"."===(E=M[I])?M.splice(I,1):".."===E?(M.splice(I,1),x++):x&&(M.splice(I,1),x--);if(!_&&!S)for(;x--;x)M.unshift("..");!_||""===M[0]||M[0]&&"/"===M[0].charAt(0)||M.unshift(""),A&&"/"!==M.join("/").substr(-1)&&M.push("");var P,O=""===M[0]||M[0]&&"/"===M[0].charAt(0);k&&(r.hostname=r.host=O?"":M.length?M.shift():"",(P=!!(r.host&&r.host.indexOf("@")>0)&&r.host.split("@"))&&(r.auth=P.shift(),r.host=r.hostname=P.shift()));return(_=_||r.host&&M.length)&&!O&&M.unshift(""),M.length?r.pathname=M.join("/"):(r.pathname=null,r.path=null),i.isNull(r.pathname)&&i.isNull(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.auth=e.auth||r.auth,r.slashes=r.slashes||e.slashes,r.href=r.format(),r},o.prototype.parseHost=function(){var e=this.host,t=s.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},function(e,t,r){(function(e,n){var i;/*! https://mths.be/punycode v1.4.1 by @mathias */!function(o){t&&t.nodeType,e&&e.nodeType;var a="object"==typeof n&&n;a.global!==a&&a.window!==a&&a.self;var s,u=2147483647,c=/^xn--/,h=/[^\x20-\x7E]/,f=/[\x2E\u3002\uFF0E\uFF61]/g,l={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},d=Math.floor,p=String.fromCharCode;function m(e){throw new RangeError(l[e])}function g(e,t){for(var r=e.length,n=[];r--;)n[r]=t(e[r]);return n}function b(e,t){var r=e.split("@"),n="";return r.length>1&&(n=r[0]+"@",e=r[1]),n+g((e=e.replace(f,".")).split("."),t).join(".")}function v(e){for(var t,r,n=[],i=0,o=e.length;i=55296&&t<=56319&&i65535&&(t+=p((e-=65536)>>>10&1023|55296),e=56320|1023&e),t+=p(e)})).join("")}function w(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function _(e,t,r){var n=0;for(e=r?d(e/700):e>>1,e+=d(e/t);e>455;n+=36)e=d(e/35);return d(n+36*e/(e+38))}function S(e){var t,r,n,i,o,a,s,c,h,f,l,p=[],g=e.length,b=0,v=128,w=72;for((r=e.lastIndexOf("-"))<0&&(r=0),n=0;n=128&&m("not-basic"),p.push(e.charCodeAt(n));for(i=r>0?r+1:0;i=g&&m("invalid-input"),((c=(l=e.charCodeAt(i++))-48<10?l-22:l-65<26?l-65:l-97<26?l-97:36)>=36||c>d((u-b)/a))&&m("overflow"),b+=c*a,!(c<(h=s<=w?1:s>=w+26?26:s-w));s+=36)a>d(u/(f=36-h))&&m("overflow"),a*=f;w=_(b-o,t=p.length+1,0==o),d(b/t)>u-v&&m("overflow"),v+=d(b/t),b%=t,p.splice(b++,0,v)}return y(p)}function M(e){var t,r,n,i,o,a,s,c,h,f,l,g,b,y,S,M=[];for(g=(e=v(e)).length,t=128,r=0,o=72,a=0;a=t&&ld((u-r)/(b=n+1))&&m("overflow"),r+=(s-t)*b,t=s,a=0;au&&m("overflow"),l==t){for(c=r,h=36;!(c<(f=h<=o?1:h>=o+26?26:h-o));h+=36)S=c-f,y=36-f,M.push(p(w(f+S%y,0))),c=d(S/y);M.push(p(w(c,0))),o=_(r,b,n==i),r=0,++n}++r,++t}return M.join("")}s={version:"1.4.1",ucs2:{decode:v,encode:y},decode:S,encode:M,toASCII:function(e){return b(e,(function(e){return h.test(e)?"xn--"+M(e):e}))},toUnicode:function(e){return b(e,(function(e){return c.test(e)?S(e.slice(4).toLowerCase()):e}))}},void 0===(i=function(){return s}.call(t,r,t,e))||(e.exports=i)}()}).call(this,r(28)(e),r(8))},function(e,t,r){"use strict";e.exports={isString:function(e){return"string"==typeof e},isObject:function(e){return"object"==typeof e&&null!==e},isNull:function(e){return null===e},isNullOrUndefined:function(e){return null==e}}},function(e,t,r){"use strict";t.decode=t.parse=r(383),t.encode=t.stringify=r(384)},function(e,t,r){"use strict";function n(e,t){return Object.prototype.hasOwnProperty.call(e,t)}e.exports=function(e,t,r,o){t=t||"&",r=r||"=";var a={};if("string"!=typeof e||0===e.length)return a;var s=/\+/g;e=e.split(t);var u=1e3;o&&"number"==typeof o.maxKeys&&(u=o.maxKeys);var c=e.length;u>0&&c>u&&(c=u);for(var h=0;h=0?(f=m.substr(0,g),l=m.substr(g+1)):(f=m,l=""),d=decodeURIComponent(f),p=decodeURIComponent(l),n(a,d)?i(a[d])?a[d].push(p):a[d]=[a[d],p]:a[d]=p}return a};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,r){"use strict";var n=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};e.exports=function(e,t,r,s){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?o(a(e),(function(a){var s=encodeURIComponent(n(a))+r;return i(e[a])?o(e[a],(function(e){return s+encodeURIComponent(n(e))})).join(t):s+encodeURIComponent(n(e[a]))})).join(t):s?encodeURIComponent(n(s))+r+encodeURIComponent(n(e)):""};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)};function o(e,t){if(e.map)return e.map(t);for(var r=[],n=0;n256)throw new n.errors.InvalidArgument("ENT","Values must be ENT > 128 and ENT < 256 and ENT % 32 == 0");s=s||l._mnemonic(i,r),Object.defineProperty(this,"wordlist",{configurable:!1,value:r}),Object.defineProperty(this,"phrase",{configurable:!1,value:s})};l.Words=r(390),l.isValid=function(e,r){if(e=o.nfkd(e),!(r=r||l._getDictionary(e)))return!1;for(var n=e.split(" "),i="",a=0;a"},l._mnemonic=function(e,t){var r=h.getRandomBuffer(e/8);return l._entropy2mnemonic(r,t)},l._entropy2mnemonic=function(e,t){for(var r="",n=0;n>8&255]>10&&(i[t]=n),n},function(e,t,r){return r?e(t,r):new n(t,null)},function(e,t,r){var i;if(t<4352||4371<=t&&t<44032||55204=55296&&e<=56319},n.isLowSurrogate=function(e){return e>=56320&&e<=57343},n.prototype.prepFeature=function(){this.feature||(this.feature=n.fromCharCode(this.codepoint,!0).feature)},n.prototype.toString=function(){if(this.codepoint<65536)return String.fromCharCode(this.codepoint);var e=this.codepoint-65536;return String.fromCharCode(Math.floor(e/1024)+55296,e%1024+56320)},n.prototype.getDecomp=function(){return this.prepFeature(),this.feature[0]||null},n.prototype.isCompatibility=function(){return this.prepFeature(),!!this.feature[1]&&256&this.feature[1]},n.prototype.isExclude=function(){return this.prepFeature(),!!this.feature[1]&&512&this.feature[1]},n.prototype.getCanonicalClass=function(){return this.prepFeature(),this.feature[1]?255&this.feature[1]:0},n.prototype.getComposite=function(e){if(this.prepFeature(),!this.feature[2])return null;var t=this.feature[2][e.codepoint];return t?n.fromCharCode(t):null};var u=function(e){this.str=e,this.cursor=0};u.prototype.next=function(){if(this.str&&this.cursor0;--r){if(this.resBuf[r-1].getCanonicalClass()<=e)break}this.resBuf.splice(r,0,t)}while(0!==e);return this.resBuf.shift()};var f=function(e){this.it=e,this.procBuf=[],this.resBuf=[],this.lastClass=null};f.prototype.next=function(){for(;0===this.resBuf.length;){var e=this.it.next();if(!e){this.resBuf=this.procBuf,this.procBuf=[];break}if(0===this.procBuf.length)this.lastClass=e.getCanonicalClass(),this.procBuf.push(e);else{var t=this.procBuf[0].getComposite(e),r=e.getCanonicalClass();t&&(this.lastClass64*(Math.pow(2,32)-1))throw Error("Requested key length too long");if("string"!=typeof e&&!t.isBuffer(e))throw new TypeError("key must a string or Buffer");if("string"!=typeof r&&!t.isBuffer(r))throw new TypeError("salt must a string or Buffer");"string"==typeof e&&(e=t.from(e)),"string"==typeof r&&(r=t.from(r));var a=t.alloc(o),s=t.alloc(64),u=t.alloc(64),c=t.alloc(r.length+4),h=Math.ceil(o/64),f=o-64*(h-1);r.copy(c,0,0,r.length);for(var l=1;l<=h;l++){c[r.length+0]=l>>24&255,c[r.length+1]=l>>16&255,c[r.length+2]=l>>8&255,c[r.length+3]=l>>0&255,(s=n.createHmac("sha512",e).update(c).digest()).copy(u,0,0,64);for(var d=1;d>24&255,e[t+1]=r>>16&255,e[t+2]=r>>8&255,e[t+3]=255&r,e[t+4]=n>>24&255,e[t+5]=n>>16&255,e[t+6]=n>>8&255,e[t+7]=255&n}function m(e,t,r,n,i){var o,a=0;for(o=0;o>>8)-1}function g(e,t,r,n){return m(e,t,r,n,16)}function b(e,t,r,n){return m(e,t,r,n,32)}function v(e,t,r,n){!function(e,t,r,n){for(var i,o=255&n[0]|(255&n[1])<<8|(255&n[2])<<16|(255&n[3])<<24,a=255&r[0]|(255&r[1])<<8|(255&r[2])<<16|(255&r[3])<<24,s=255&r[4]|(255&r[5])<<8|(255&r[6])<<16|(255&r[7])<<24,u=255&r[8]|(255&r[9])<<8|(255&r[10])<<16|(255&r[11])<<24,c=255&r[12]|(255&r[13])<<8|(255&r[14])<<16|(255&r[15])<<24,h=255&n[4]|(255&n[5])<<8|(255&n[6])<<16|(255&n[7])<<24,f=255&t[0]|(255&t[1])<<8|(255&t[2])<<16|(255&t[3])<<24,l=255&t[4]|(255&t[5])<<8|(255&t[6])<<16|(255&t[7])<<24,d=255&t[8]|(255&t[9])<<8|(255&t[10])<<16|(255&t[11])<<24,p=255&t[12]|(255&t[13])<<8|(255&t[14])<<16|(255&t[15])<<24,m=255&n[8]|(255&n[9])<<8|(255&n[10])<<16|(255&n[11])<<24,g=255&r[16]|(255&r[17])<<8|(255&r[18])<<16|(255&r[19])<<24,b=255&r[20]|(255&r[21])<<8|(255&r[22])<<16|(255&r[23])<<24,v=255&r[24]|(255&r[25])<<8|(255&r[26])<<16|(255&r[27])<<24,y=255&r[28]|(255&r[29])<<8|(255&r[30])<<16|(255&r[31])<<24,w=255&n[12]|(255&n[13])<<8|(255&n[14])<<16|(255&n[15])<<24,_=o,S=a,M=s,k=u,E=c,A=h,x=f,I=l,P=d,O=p,T=m,R=g,B=b,N=v,C=y,j=w,z=0;z<20;z+=2)_^=(i=(B^=(i=(P^=(i=(E^=(i=_+B|0)<<7|i>>>25)+_|0)<<9|i>>>23)+E|0)<<13|i>>>19)+P|0)<<18|i>>>14,A^=(i=(S^=(i=(N^=(i=(O^=(i=A+S|0)<<7|i>>>25)+A|0)<<9|i>>>23)+O|0)<<13|i>>>19)+N|0)<<18|i>>>14,T^=(i=(x^=(i=(M^=(i=(C^=(i=T+x|0)<<7|i>>>25)+T|0)<<9|i>>>23)+C|0)<<13|i>>>19)+M|0)<<18|i>>>14,j^=(i=(R^=(i=(I^=(i=(k^=(i=j+R|0)<<7|i>>>25)+j|0)<<9|i>>>23)+k|0)<<13|i>>>19)+I|0)<<18|i>>>14,_^=(i=(k^=(i=(M^=(i=(S^=(i=_+k|0)<<7|i>>>25)+_|0)<<9|i>>>23)+S|0)<<13|i>>>19)+M|0)<<18|i>>>14,A^=(i=(E^=(i=(I^=(i=(x^=(i=A+E|0)<<7|i>>>25)+A|0)<<9|i>>>23)+x|0)<<13|i>>>19)+I|0)<<18|i>>>14,T^=(i=(O^=(i=(P^=(i=(R^=(i=T+O|0)<<7|i>>>25)+T|0)<<9|i>>>23)+R|0)<<13|i>>>19)+P|0)<<18|i>>>14,j^=(i=(C^=(i=(N^=(i=(B^=(i=j+C|0)<<7|i>>>25)+j|0)<<9|i>>>23)+B|0)<<13|i>>>19)+N|0)<<18|i>>>14;_=_+o|0,S=S+a|0,M=M+s|0,k=k+u|0,E=E+c|0,A=A+h|0,x=x+f|0,I=I+l|0,P=P+d|0,O=O+p|0,T=T+m|0,R=R+g|0,B=B+b|0,N=N+v|0,C=C+y|0,j=j+w|0,e[0]=_>>>0&255,e[1]=_>>>8&255,e[2]=_>>>16&255,e[3]=_>>>24&255,e[4]=S>>>0&255,e[5]=S>>>8&255,e[6]=S>>>16&255,e[7]=S>>>24&255,e[8]=M>>>0&255,e[9]=M>>>8&255,e[10]=M>>>16&255,e[11]=M>>>24&255,e[12]=k>>>0&255,e[13]=k>>>8&255,e[14]=k>>>16&255,e[15]=k>>>24&255,e[16]=E>>>0&255,e[17]=E>>>8&255,e[18]=E>>>16&255,e[19]=E>>>24&255,e[20]=A>>>0&255,e[21]=A>>>8&255,e[22]=A>>>16&255,e[23]=A>>>24&255,e[24]=x>>>0&255,e[25]=x>>>8&255,e[26]=x>>>16&255,e[27]=x>>>24&255,e[28]=I>>>0&255,e[29]=I>>>8&255,e[30]=I>>>16&255,e[31]=I>>>24&255,e[32]=P>>>0&255,e[33]=P>>>8&255,e[34]=P>>>16&255,e[35]=P>>>24&255,e[36]=O>>>0&255,e[37]=O>>>8&255,e[38]=O>>>16&255,e[39]=O>>>24&255,e[40]=T>>>0&255,e[41]=T>>>8&255,e[42]=T>>>16&255,e[43]=T>>>24&255,e[44]=R>>>0&255,e[45]=R>>>8&255,e[46]=R>>>16&255,e[47]=R>>>24&255,e[48]=B>>>0&255,e[49]=B>>>8&255,e[50]=B>>>16&255,e[51]=B>>>24&255,e[52]=N>>>0&255,e[53]=N>>>8&255,e[54]=N>>>16&255,e[55]=N>>>24&255,e[56]=C>>>0&255,e[57]=C>>>8&255,e[58]=C>>>16&255,e[59]=C>>>24&255,e[60]=j>>>0&255,e[61]=j>>>8&255,e[62]=j>>>16&255,e[63]=j>>>24&255}(e,t,r,n)}function y(e,t,r,n){!function(e,t,r,n){for(var i,o=255&n[0]|(255&n[1])<<8|(255&n[2])<<16|(255&n[3])<<24,a=255&r[0]|(255&r[1])<<8|(255&r[2])<<16|(255&r[3])<<24,s=255&r[4]|(255&r[5])<<8|(255&r[6])<<16|(255&r[7])<<24,u=255&r[8]|(255&r[9])<<8|(255&r[10])<<16|(255&r[11])<<24,c=255&r[12]|(255&r[13])<<8|(255&r[14])<<16|(255&r[15])<<24,h=255&n[4]|(255&n[5])<<8|(255&n[6])<<16|(255&n[7])<<24,f=255&t[0]|(255&t[1])<<8|(255&t[2])<<16|(255&t[3])<<24,l=255&t[4]|(255&t[5])<<8|(255&t[6])<<16|(255&t[7])<<24,d=255&t[8]|(255&t[9])<<8|(255&t[10])<<16|(255&t[11])<<24,p=255&t[12]|(255&t[13])<<8|(255&t[14])<<16|(255&t[15])<<24,m=255&n[8]|(255&n[9])<<8|(255&n[10])<<16|(255&n[11])<<24,g=255&r[16]|(255&r[17])<<8|(255&r[18])<<16|(255&r[19])<<24,b=255&r[20]|(255&r[21])<<8|(255&r[22])<<16|(255&r[23])<<24,v=255&r[24]|(255&r[25])<<8|(255&r[26])<<16|(255&r[27])<<24,y=255&r[28]|(255&r[29])<<8|(255&r[30])<<16|(255&r[31])<<24,w=255&n[12]|(255&n[13])<<8|(255&n[14])<<16|(255&n[15])<<24,_=0;_<20;_+=2)o^=(i=(b^=(i=(d^=(i=(c^=(i=o+b|0)<<7|i>>>25)+o|0)<<9|i>>>23)+c|0)<<13|i>>>19)+d|0)<<18|i>>>14,h^=(i=(a^=(i=(v^=(i=(p^=(i=h+a|0)<<7|i>>>25)+h|0)<<9|i>>>23)+p|0)<<13|i>>>19)+v|0)<<18|i>>>14,m^=(i=(f^=(i=(s^=(i=(y^=(i=m+f|0)<<7|i>>>25)+m|0)<<9|i>>>23)+y|0)<<13|i>>>19)+s|0)<<18|i>>>14,w^=(i=(g^=(i=(l^=(i=(u^=(i=w+g|0)<<7|i>>>25)+w|0)<<9|i>>>23)+u|0)<<13|i>>>19)+l|0)<<18|i>>>14,o^=(i=(u^=(i=(s^=(i=(a^=(i=o+u|0)<<7|i>>>25)+o|0)<<9|i>>>23)+a|0)<<13|i>>>19)+s|0)<<18|i>>>14,h^=(i=(c^=(i=(l^=(i=(f^=(i=h+c|0)<<7|i>>>25)+h|0)<<9|i>>>23)+f|0)<<13|i>>>19)+l|0)<<18|i>>>14,m^=(i=(p^=(i=(d^=(i=(g^=(i=m+p|0)<<7|i>>>25)+m|0)<<9|i>>>23)+g|0)<<13|i>>>19)+d|0)<<18|i>>>14,w^=(i=(y^=(i=(v^=(i=(b^=(i=w+y|0)<<7|i>>>25)+w|0)<<9|i>>>23)+b|0)<<13|i>>>19)+v|0)<<18|i>>>14;e[0]=o>>>0&255,e[1]=o>>>8&255,e[2]=o>>>16&255,e[3]=o>>>24&255,e[4]=h>>>0&255,e[5]=h>>>8&255,e[6]=h>>>16&255,e[7]=h>>>24&255,e[8]=m>>>0&255,e[9]=m>>>8&255,e[10]=m>>>16&255,e[11]=m>>>24&255,e[12]=w>>>0&255,e[13]=w>>>8&255,e[14]=w>>>16&255,e[15]=w>>>24&255,e[16]=f>>>0&255,e[17]=f>>>8&255,e[18]=f>>>16&255,e[19]=f>>>24&255,e[20]=l>>>0&255,e[21]=l>>>8&255,e[22]=l>>>16&255,e[23]=l>>>24&255,e[24]=d>>>0&255,e[25]=d>>>8&255,e[26]=d>>>16&255,e[27]=d>>>24&255,e[28]=p>>>0&255,e[29]=p>>>8&255,e[30]=p>>>16&255,e[31]=p>>>24&255}(e,t,r,n)}var w=new Uint8Array([101,120,112,97,110,100,32,51,50,45,98,121,116,101,32,107]);function _(e,t,r,n,i,o,a){var s,u,c=new Uint8Array(16),h=new Uint8Array(64);for(u=0;u<16;u++)c[u]=0;for(u=0;u<8;u++)c[u]=o[u];for(;i>=64;){for(v(h,c,a,w),u=0;u<64;u++)e[t+u]=r[n+u]^h[u];for(s=1,u=8;u<16;u++)s=s+(255&c[u])|0,c[u]=255&s,s>>>=8;i-=64,t+=64,n+=64}if(i>0)for(v(h,c,a,w),u=0;u=64;){for(v(u,s,i,w),a=0;a<64;a++)e[t+a]=u[a];for(o=1,a=8;a<16;a++)o=o+(255&s[a])|0,s[a]=255&o,o>>>=8;r-=64,t+=64}if(r>0)for(v(u,s,i,w),a=0;a>>13|r<<3),n=255&e[4]|(255&e[5])<<8,this.r[2]=7939&(r>>>10|n<<6),i=255&e[6]|(255&e[7])<<8,this.r[3]=8191&(n>>>7|i<<9),o=255&e[8]|(255&e[9])<<8,this.r[4]=255&(i>>>4|o<<12),this.r[5]=o>>>1&8190,a=255&e[10]|(255&e[11])<<8,this.r[6]=8191&(o>>>14|a<<2),s=255&e[12]|(255&e[13])<<8,this.r[7]=8065&(a>>>11|s<<5),u=255&e[14]|(255&e[15])<<8,this.r[8]=8191&(s>>>8|u<<8),this.r[9]=u>>>5&127,this.pad[0]=255&e[16]|(255&e[17])<<8,this.pad[1]=255&e[18]|(255&e[19])<<8,this.pad[2]=255&e[20]|(255&e[21])<<8,this.pad[3]=255&e[22]|(255&e[23])<<8,this.pad[4]=255&e[24]|(255&e[25])<<8,this.pad[5]=255&e[26]|(255&e[27])<<8,this.pad[6]=255&e[28]|(255&e[29])<<8,this.pad[7]=255&e[30]|(255&e[31])<<8};function A(e,t,r,n,i,o){var a=new E(o);return a.update(r,n,i),a.finish(e,t),0}function x(e,t,r,n,i,o){var a=new Uint8Array(16);return A(a,0,r,n,i,o),g(e,t,a,0)}function I(e,t,r,n,i){var o;if(r<32)return-1;for(k(e,0,t,0,r,n,i),A(e,16,e,32,r-32,e),o=0;o<16;o++)e[o]=0;return 0}function P(e,t,r,n,i){var o,a=new Uint8Array(32);if(r<32)return-1;if(M(a,0,32,n,i),0!==x(t,16,t,32,r-32,a))return-1;for(k(e,0,t,0,r,n,i),o=0;o<32;o++)e[o]=0;return 0}function O(e,t){var r;for(r=0;r<16;r++)e[r]=0|t[r]}function T(e){var t,r,n=1;for(t=0;t<16;t++)r=e[t]+n+65535,n=Math.floor(r/65536),e[t]=r-65536*n;e[0]+=n-1+37*(n-1)}function R(e,t,r){for(var n,i=~(r-1),o=0;o<16;o++)n=i&(e[o]^t[o]),e[o]^=n,t[o]^=n}function B(e,r){var n,i,o,a=t(),s=t();for(n=0;n<16;n++)s[n]=r[n];for(T(s),T(s),T(s),i=0;i<2;i++){for(a[0]=s[0]-65517,n=1;n<15;n++)a[n]=s[n]-65535-(a[n-1]>>16&1),a[n-1]&=65535;a[15]=s[15]-32767-(a[14]>>16&1),o=a[15]>>16&1,a[14]&=65535,R(s,a,1-o)}for(n=0;n<16;n++)e[2*n]=255&s[n],e[2*n+1]=s[n]>>8}function N(e,t){var r=new Uint8Array(32),n=new Uint8Array(32);return B(r,e),B(n,t),b(r,0,n,0)}function C(e){var t=new Uint8Array(32);return B(t,e),1&t[0]}function j(e,t){var r;for(r=0;r<16;r++)e[r]=t[2*r]+(t[2*r+1]<<8);e[15]&=32767}function z(e,t,r){for(var n=0;n<16;n++)e[n]=t[n]+r[n]}function U(e,t,r){for(var n=0;n<16;n++)e[n]=t[n]-r[n]}function L(e,t,r){var n,i,o=0,a=0,s=0,u=0,c=0,h=0,f=0,l=0,d=0,p=0,m=0,g=0,b=0,v=0,y=0,w=0,_=0,S=0,M=0,k=0,E=0,A=0,x=0,I=0,P=0,O=0,T=0,R=0,B=0,N=0,C=0,j=r[0],z=r[1],U=r[2],L=r[3],F=r[4],D=r[5],q=r[6],K=r[7],H=r[8],V=r[9],G=r[10],W=r[11],Y=r[12],Z=r[13],J=r[14],X=r[15];o+=(n=t[0])*j,a+=n*z,s+=n*U,u+=n*L,c+=n*F,h+=n*D,f+=n*q,l+=n*K,d+=n*H,p+=n*V,m+=n*G,g+=n*W,b+=n*Y,v+=n*Z,y+=n*J,w+=n*X,a+=(n=t[1])*j,s+=n*z,u+=n*U,c+=n*L,h+=n*F,f+=n*D,l+=n*q,d+=n*K,p+=n*H,m+=n*V,g+=n*G,b+=n*W,v+=n*Y,y+=n*Z,w+=n*J,_+=n*X,s+=(n=t[2])*j,u+=n*z,c+=n*U,h+=n*L,f+=n*F,l+=n*D,d+=n*q,p+=n*K,m+=n*H,g+=n*V,b+=n*G,v+=n*W,y+=n*Y,w+=n*Z,_+=n*J,S+=n*X,u+=(n=t[3])*j,c+=n*z,h+=n*U,f+=n*L,l+=n*F,d+=n*D,p+=n*q,m+=n*K,g+=n*H,b+=n*V,v+=n*G,y+=n*W,w+=n*Y,_+=n*Z,S+=n*J,M+=n*X,c+=(n=t[4])*j,h+=n*z,f+=n*U,l+=n*L,d+=n*F,p+=n*D,m+=n*q,g+=n*K,b+=n*H,v+=n*V,y+=n*G,w+=n*W,_+=n*Y,S+=n*Z,M+=n*J,k+=n*X,h+=(n=t[5])*j,f+=n*z,l+=n*U,d+=n*L,p+=n*F,m+=n*D,g+=n*q,b+=n*K,v+=n*H,y+=n*V,w+=n*G,_+=n*W,S+=n*Y,M+=n*Z,k+=n*J,E+=n*X,f+=(n=t[6])*j,l+=n*z,d+=n*U,p+=n*L,m+=n*F,g+=n*D,b+=n*q,v+=n*K,y+=n*H,w+=n*V,_+=n*G,S+=n*W,M+=n*Y,k+=n*Z,E+=n*J,A+=n*X,l+=(n=t[7])*j,d+=n*z,p+=n*U,m+=n*L,g+=n*F,b+=n*D,v+=n*q,y+=n*K,w+=n*H,_+=n*V,S+=n*G,M+=n*W,k+=n*Y,E+=n*Z,A+=n*J,x+=n*X,d+=(n=t[8])*j,p+=n*z,m+=n*U,g+=n*L,b+=n*F,v+=n*D,y+=n*q,w+=n*K,_+=n*H,S+=n*V,M+=n*G,k+=n*W,E+=n*Y,A+=n*Z,x+=n*J,I+=n*X,p+=(n=t[9])*j,m+=n*z,g+=n*U,b+=n*L,v+=n*F,y+=n*D,w+=n*q,_+=n*K,S+=n*H,M+=n*V,k+=n*G,E+=n*W,A+=n*Y,x+=n*Z,I+=n*J,P+=n*X,m+=(n=t[10])*j,g+=n*z,b+=n*U,v+=n*L,y+=n*F,w+=n*D,_+=n*q,S+=n*K,M+=n*H,k+=n*V,E+=n*G,A+=n*W,x+=n*Y,I+=n*Z,P+=n*J,O+=n*X,g+=(n=t[11])*j,b+=n*z,v+=n*U,y+=n*L,w+=n*F,_+=n*D,S+=n*q,M+=n*K,k+=n*H,E+=n*V,A+=n*G,x+=n*W,I+=n*Y,P+=n*Z,O+=n*J,T+=n*X,b+=(n=t[12])*j,v+=n*z,y+=n*U,w+=n*L,_+=n*F,S+=n*D,M+=n*q,k+=n*K,E+=n*H,A+=n*V,x+=n*G,I+=n*W,P+=n*Y,O+=n*Z,T+=n*J,R+=n*X,v+=(n=t[13])*j,y+=n*z,w+=n*U,_+=n*L,S+=n*F,M+=n*D,k+=n*q,E+=n*K,A+=n*H,x+=n*V,I+=n*G,P+=n*W,O+=n*Y,T+=n*Z,R+=n*J,B+=n*X,y+=(n=t[14])*j,w+=n*z,_+=n*U,S+=n*L,M+=n*F,k+=n*D,E+=n*q,A+=n*K,x+=n*H,I+=n*V,P+=n*G,O+=n*W,T+=n*Y,R+=n*Z,B+=n*J,N+=n*X,w+=(n=t[15])*j,a+=38*(S+=n*U),s+=38*(M+=n*L),u+=38*(k+=n*F),c+=38*(E+=n*D),h+=38*(A+=n*q),f+=38*(x+=n*K),l+=38*(I+=n*H),d+=38*(P+=n*V),p+=38*(O+=n*G),m+=38*(T+=n*W),g+=38*(R+=n*Y),b+=38*(B+=n*Z),v+=38*(N+=n*J),y+=38*(C+=n*X),o=(n=(o+=38*(_+=n*z))+(i=1)+65535)-65536*(i=Math.floor(n/65536)),a=(n=a+i+65535)-65536*(i=Math.floor(n/65536)),s=(n=s+i+65535)-65536*(i=Math.floor(n/65536)),u=(n=u+i+65535)-65536*(i=Math.floor(n/65536)),c=(n=c+i+65535)-65536*(i=Math.floor(n/65536)),h=(n=h+i+65535)-65536*(i=Math.floor(n/65536)),f=(n=f+i+65535)-65536*(i=Math.floor(n/65536)),l=(n=l+i+65535)-65536*(i=Math.floor(n/65536)),d=(n=d+i+65535)-65536*(i=Math.floor(n/65536)),p=(n=p+i+65535)-65536*(i=Math.floor(n/65536)),m=(n=m+i+65535)-65536*(i=Math.floor(n/65536)),g=(n=g+i+65535)-65536*(i=Math.floor(n/65536)),b=(n=b+i+65535)-65536*(i=Math.floor(n/65536)),v=(n=v+i+65535)-65536*(i=Math.floor(n/65536)),y=(n=y+i+65535)-65536*(i=Math.floor(n/65536)),w=(n=w+i+65535)-65536*(i=Math.floor(n/65536)),o=(n=(o+=i-1+37*(i-1))+(i=1)+65535)-65536*(i=Math.floor(n/65536)),a=(n=a+i+65535)-65536*(i=Math.floor(n/65536)),s=(n=s+i+65535)-65536*(i=Math.floor(n/65536)),u=(n=u+i+65535)-65536*(i=Math.floor(n/65536)),c=(n=c+i+65535)-65536*(i=Math.floor(n/65536)),h=(n=h+i+65535)-65536*(i=Math.floor(n/65536)),f=(n=f+i+65535)-65536*(i=Math.floor(n/65536)),l=(n=l+i+65535)-65536*(i=Math.floor(n/65536)),d=(n=d+i+65535)-65536*(i=Math.floor(n/65536)),p=(n=p+i+65535)-65536*(i=Math.floor(n/65536)),m=(n=m+i+65535)-65536*(i=Math.floor(n/65536)),g=(n=g+i+65535)-65536*(i=Math.floor(n/65536)),b=(n=b+i+65535)-65536*(i=Math.floor(n/65536)),v=(n=v+i+65535)-65536*(i=Math.floor(n/65536)),y=(n=y+i+65535)-65536*(i=Math.floor(n/65536)),w=(n=w+i+65535)-65536*(i=Math.floor(n/65536)),o+=i-1+37*(i-1),e[0]=o,e[1]=a,e[2]=s,e[3]=u,e[4]=c,e[5]=h,e[6]=f,e[7]=l,e[8]=d,e[9]=p,e[10]=m,e[11]=g,e[12]=b,e[13]=v,e[14]=y,e[15]=w}function F(e,t){L(e,t,t)}function D(e,r){var n,i=t();for(n=0;n<16;n++)i[n]=r[n];for(n=253;n>=0;n--)F(i,i),2!==n&&4!==n&&L(i,i,r);for(n=0;n<16;n++)e[n]=i[n]}function q(e,r){var n,i=t();for(n=0;n<16;n++)i[n]=r[n];for(n=250;n>=0;n--)F(i,i),1!==n&&L(i,i,r);for(n=0;n<16;n++)e[n]=i[n]}function K(e,r,n){var i,o,a=new Uint8Array(32),s=new Float64Array(80),c=t(),h=t(),f=t(),l=t(),d=t(),p=t();for(o=0;o<31;o++)a[o]=r[o];for(a[31]=127&r[31]|64,a[0]&=248,j(s,n),o=0;o<16;o++)h[o]=s[o],l[o]=c[o]=f[o]=0;for(c[0]=l[0]=1,o=254;o>=0;--o)R(c,h,i=a[o>>>3]>>>(7&o)&1),R(f,l,i),z(d,c,f),U(c,c,f),z(f,h,l),U(h,h,l),F(l,d),F(p,c),L(c,f,c),L(f,h,d),z(d,c,f),U(c,c,f),F(h,c),U(f,l,p),L(c,f,u),z(c,c,l),L(f,f,c),L(c,l,p),L(l,h,s),F(h,d),R(c,h,i),R(f,l,i);for(o=0;o<16;o++)s[o+16]=c[o],s[o+32]=f[o],s[o+48]=h[o],s[o+64]=l[o];var m=s.subarray(32),g=s.subarray(16);return D(m,m),L(g,g,m),B(e,g),0}function H(e,t){return K(e,t,o)}function V(e,t){return n(t,32),H(e,t)}function G(e,t,r){var n=new Uint8Array(32);return K(n,r,t),y(e,i,n,w)}E.prototype.blocks=function(e,t,r){for(var n,i,o,a,s,u,c,h,f,l,d,p,m,g,b,v,y,w,_,S=this.fin?0:2048,M=this.h[0],k=this.h[1],E=this.h[2],A=this.h[3],x=this.h[4],I=this.h[5],P=this.h[6],O=this.h[7],T=this.h[8],R=this.h[9],B=this.r[0],N=this.r[1],C=this.r[2],j=this.r[3],z=this.r[4],U=this.r[5],L=this.r[6],F=this.r[7],D=this.r[8],q=this.r[9];r>=16;)l=f=0,l+=(M+=8191&(n=255&e[t+0]|(255&e[t+1])<<8))*B,l+=(k+=8191&(n>>>13|(i=255&e[t+2]|(255&e[t+3])<<8)<<3))*(5*q),l+=(E+=8191&(i>>>10|(o=255&e[t+4]|(255&e[t+5])<<8)<<6))*(5*D),l+=(A+=8191&(o>>>7|(a=255&e[t+6]|(255&e[t+7])<<8)<<9))*(5*F),f=(l+=(x+=8191&(a>>>4|(s=255&e[t+8]|(255&e[t+9])<<8)<<12))*(5*L))>>>13,l&=8191,l+=(I+=s>>>1&8191)*(5*U),l+=(P+=8191&(s>>>14|(u=255&e[t+10]|(255&e[t+11])<<8)<<2))*(5*z),l+=(O+=8191&(u>>>11|(c=255&e[t+12]|(255&e[t+13])<<8)<<5))*(5*j),l+=(T+=8191&(c>>>8|(h=255&e[t+14]|(255&e[t+15])<<8)<<8))*(5*C),d=f+=(l+=(R+=h>>>5|S)*(5*N))>>>13,d+=M*N,d+=k*B,d+=E*(5*q),d+=A*(5*D),f=(d+=x*(5*F))>>>13,d&=8191,d+=I*(5*L),d+=P*(5*U),d+=O*(5*z),d+=T*(5*j),f+=(d+=R*(5*C))>>>13,d&=8191,p=f,p+=M*C,p+=k*N,p+=E*B,p+=A*(5*q),f=(p+=x*(5*D))>>>13,p&=8191,p+=I*(5*F),p+=P*(5*L),p+=O*(5*U),p+=T*(5*z),m=f+=(p+=R*(5*j))>>>13,m+=M*j,m+=k*C,m+=E*N,m+=A*B,f=(m+=x*(5*q))>>>13,m&=8191,m+=I*(5*D),m+=P*(5*F),m+=O*(5*L),m+=T*(5*U),g=f+=(m+=R*(5*z))>>>13,g+=M*z,g+=k*j,g+=E*C,g+=A*N,f=(g+=x*B)>>>13,g&=8191,g+=I*(5*q),g+=P*(5*D),g+=O*(5*F),g+=T*(5*L),b=f+=(g+=R*(5*U))>>>13,b+=M*U,b+=k*z,b+=E*j,b+=A*C,f=(b+=x*N)>>>13,b&=8191,b+=I*B,b+=P*(5*q),b+=O*(5*D),b+=T*(5*F),v=f+=(b+=R*(5*L))>>>13,v+=M*L,v+=k*U,v+=E*z,v+=A*j,f=(v+=x*C)>>>13,v&=8191,v+=I*N,v+=P*B,v+=O*(5*q),v+=T*(5*D),y=f+=(v+=R*(5*F))>>>13,y+=M*F,y+=k*L,y+=E*U,y+=A*z,f=(y+=x*j)>>>13,y&=8191,y+=I*C,y+=P*N,y+=O*B,y+=T*(5*q),w=f+=(y+=R*(5*D))>>>13,w+=M*D,w+=k*F,w+=E*L,w+=A*U,f=(w+=x*z)>>>13,w&=8191,w+=I*j,w+=P*C,w+=O*N,w+=T*B,_=f+=(w+=R*(5*q))>>>13,_+=M*q,_+=k*D,_+=E*F,_+=A*L,f=(_+=x*U)>>>13,_&=8191,_+=I*z,_+=P*j,_+=O*C,_+=T*N,M=l=8191&(f=(f=((f+=(_+=R*B)>>>13)<<2)+f|0)+(l&=8191)|0),k=d+=f>>>=13,E=p&=8191,A=m&=8191,x=g&=8191,I=b&=8191,P=v&=8191,O=y&=8191,T=w&=8191,R=_&=8191,t+=16,r-=16;this.h[0]=M,this.h[1]=k,this.h[2]=E,this.h[3]=A,this.h[4]=x,this.h[5]=I,this.h[6]=P,this.h[7]=O,this.h[8]=T,this.h[9]=R},E.prototype.finish=function(e,t){var r,n,i,o,a=new Uint16Array(10);if(this.leftover){for(o=this.leftover,this.buffer[o++]=1;o<16;o++)this.buffer[o]=0;this.fin=1,this.blocks(this.buffer,0,16)}for(r=this.h[1]>>>13,this.h[1]&=8191,o=2;o<10;o++)this.h[o]+=r,r=this.h[o]>>>13,this.h[o]&=8191;for(this.h[0]+=5*r,r=this.h[0]>>>13,this.h[0]&=8191,this.h[1]+=r,r=this.h[1]>>>13,this.h[1]&=8191,this.h[2]+=r,a[0]=this.h[0]+5,r=a[0]>>>13,a[0]&=8191,o=1;o<10;o++)a[o]=this.h[o]+r,r=a[o]>>>13,a[o]&=8191;for(a[9]-=8192,n=(1^r)-1,o=0;o<10;o++)a[o]&=n;for(n=~n,o=0;o<10;o++)this.h[o]=this.h[o]&n|a[o];for(this.h[0]=65535&(this.h[0]|this.h[1]<<13),this.h[1]=65535&(this.h[1]>>>3|this.h[2]<<10),this.h[2]=65535&(this.h[2]>>>6|this.h[3]<<7),this.h[3]=65535&(this.h[3]>>>9|this.h[4]<<4),this.h[4]=65535&(this.h[4]>>>12|this.h[5]<<1|this.h[6]<<14),this.h[5]=65535&(this.h[6]>>>2|this.h[7]<<11),this.h[6]=65535&(this.h[7]>>>5|this.h[8]<<8),this.h[7]=65535&(this.h[8]>>>8|this.h[9]<<5),i=this.h[0]+this.pad[0],this.h[0]=65535&i,o=1;o<8;o++)i=(this.h[o]+this.pad[o]|0)+(i>>>16)|0,this.h[o]=65535&i;e[t+0]=this.h[0]>>>0&255,e[t+1]=this.h[0]>>>8&255,e[t+2]=this.h[1]>>>0&255,e[t+3]=this.h[1]>>>8&255,e[t+4]=this.h[2]>>>0&255,e[t+5]=this.h[2]>>>8&255,e[t+6]=this.h[3]>>>0&255,e[t+7]=this.h[3]>>>8&255,e[t+8]=this.h[4]>>>0&255,e[t+9]=this.h[4]>>>8&255,e[t+10]=this.h[5]>>>0&255,e[t+11]=this.h[5]>>>8&255,e[t+12]=this.h[6]>>>0&255,e[t+13]=this.h[6]>>>8&255,e[t+14]=this.h[7]>>>0&255,e[t+15]=this.h[7]>>>8&255},E.prototype.update=function(e,t,r){var n,i;if(this.leftover){for((i=16-this.leftover)>r&&(i=r),n=0;n=16&&(i=r-r%16,this.blocks(e,t,i),t+=i,r-=i),r){for(n=0;n=128;){for(S=0;S<16;S++)M=8*S+Y,O[S]=r[M+0]<<24|r[M+1]<<16|r[M+2]<<8|r[M+3],T[S]=r[M+4]<<24|r[M+5]<<16|r[M+6]<<8|r[M+7];for(S=0;S<80;S++)if(i=R,o=B,a=N,s=C,u=j,c=z,h=U,L,l=F,d=D,p=q,m=K,g=H,b=V,v=G,W,A=65535&(E=W),x=E>>>16,I=65535&(k=L),P=k>>>16,A+=65535&(E=(H>>>14|j<<18)^(H>>>18|j<<14)^(j>>>9|H<<23)),x+=E>>>16,I+=65535&(k=(j>>>14|H<<18)^(j>>>18|H<<14)^(H>>>9|j<<23)),P+=k>>>16,A+=65535&(E=H&V^~H&G),x+=E>>>16,I+=65535&(k=j&z^~j&U),P+=k>>>16,A+=65535&(E=Z[2*S+1]),x+=E>>>16,I+=65535&(k=Z[2*S]),P+=k>>>16,k=O[S%16],x+=(E=T[S%16])>>>16,I+=65535&k,P+=k>>>16,I+=(x+=(A+=65535&E)>>>16)>>>16,A=65535&(E=_=65535&A|x<<16),x=E>>>16,I=65535&(k=w=65535&I|(P+=I>>>16)<<16),P=k>>>16,A+=65535&(E=(F>>>28|R<<4)^(R>>>2|F<<30)^(R>>>7|F<<25)),x+=E>>>16,I+=65535&(k=(R>>>28|F<<4)^(F>>>2|R<<30)^(F>>>7|R<<25)),P+=k>>>16,x+=(E=F&D^F&q^D&q)>>>16,I+=65535&(k=R&B^R&N^B&N),P+=k>>>16,f=65535&(I+=(x+=(A+=65535&E)>>>16)>>>16)|(P+=I>>>16)<<16,y=65535&A|x<<16,A=65535&(E=m),x=E>>>16,I=65535&(k=s),P=k>>>16,x+=(E=_)>>>16,I+=65535&(k=w),P+=k>>>16,B=i,N=o,C=a,j=s=65535&(I+=(x+=(A+=65535&E)>>>16)>>>16)|(P+=I>>>16)<<16,z=u,U=c,L=h,R=f,D=l,q=d,K=p,H=m=65535&A|x<<16,V=g,G=b,W=v,F=y,S%16==15)for(M=0;M<16;M++)k=O[M],A=65535&(E=T[M]),x=E>>>16,I=65535&k,P=k>>>16,k=O[(M+9)%16],A+=65535&(E=T[(M+9)%16]),x+=E>>>16,I+=65535&k,P+=k>>>16,w=O[(M+1)%16],A+=65535&(E=((_=T[(M+1)%16])>>>1|w<<31)^(_>>>8|w<<24)^(_>>>7|w<<25)),x+=E>>>16,I+=65535&(k=(w>>>1|_<<31)^(w>>>8|_<<24)^w>>>7),P+=k>>>16,w=O[(M+14)%16],x+=(E=((_=T[(M+14)%16])>>>19|w<<13)^(w>>>29|_<<3)^(_>>>6|w<<26))>>>16,I+=65535&(k=(w>>>19|_<<13)^(_>>>29|w<<3)^w>>>6),P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,O[M]=65535&I|P<<16,T[M]=65535&A|x<<16;A=65535&(E=F),x=E>>>16,I=65535&(k=R),P=k>>>16,k=e[0],x+=(E=t[0])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[0]=R=65535&I|P<<16,t[0]=F=65535&A|x<<16,A=65535&(E=D),x=E>>>16,I=65535&(k=B),P=k>>>16,k=e[1],x+=(E=t[1])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[1]=B=65535&I|P<<16,t[1]=D=65535&A|x<<16,A=65535&(E=q),x=E>>>16,I=65535&(k=N),P=k>>>16,k=e[2],x+=(E=t[2])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[2]=N=65535&I|P<<16,t[2]=q=65535&A|x<<16,A=65535&(E=K),x=E>>>16,I=65535&(k=C),P=k>>>16,k=e[3],x+=(E=t[3])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[3]=C=65535&I|P<<16,t[3]=K=65535&A|x<<16,A=65535&(E=H),x=E>>>16,I=65535&(k=j),P=k>>>16,k=e[4],x+=(E=t[4])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[4]=j=65535&I|P<<16,t[4]=H=65535&A|x<<16,A=65535&(E=V),x=E>>>16,I=65535&(k=z),P=k>>>16,k=e[5],x+=(E=t[5])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[5]=z=65535&I|P<<16,t[5]=V=65535&A|x<<16,A=65535&(E=G),x=E>>>16,I=65535&(k=U),P=k>>>16,k=e[6],x+=(E=t[6])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[6]=U=65535&I|P<<16,t[6]=G=65535&A|x<<16,A=65535&(E=W),x=E>>>16,I=65535&(k=L),P=k>>>16,k=e[7],x+=(E=t[7])>>>16,I+=65535&k,P+=k>>>16,P+=(I+=(x+=(A+=65535&E)>>>16)>>>16)>>>16,e[7]=L=65535&I|P<<16,t[7]=W=65535&A|x<<16,Y+=128,n-=128}return n}function X(e,t,r){var n,i=new Int32Array(8),o=new Int32Array(8),a=new Uint8Array(256),s=r;for(i[0]=1779033703,i[1]=3144134277,i[2]=1013904242,i[3]=2773480762,i[4]=1359893119,i[5]=2600822924,i[6]=528734635,i[7]=1541459225,o[0]=4089235720,o[1]=2227873595,o[2]=4271175723,o[3]=1595750129,o[4]=2917565137,o[5]=725511199,o[6]=4215389547,o[7]=327033209,J(i,o,t,r),r%=128,n=0;n=0;--i)Q(e,t,n=r[i/8|0]>>(7&i)&1),$(t,e),$(e,e),Q(e,t,n)}function re(e,r){var n=[t(),t(),t(),t()];O(n[0],f),O(n[1],l),O(n[2],s),L(n[3],f,l),te(e,n,r)}function ne(e,r,i){var o,a=new Uint8Array(64),s=[t(),t(),t(),t()];for(i||n(r,32),X(a,r,32),a[0]&=248,a[31]&=127,a[31]|=64,re(s,a),ee(e,s),o=0;o<32;o++)r[o+32]=e[o];return 0}var ie=new Float64Array([237,211,245,92,26,99,18,88,214,156,247,162,222,249,222,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16]);function oe(e,t){var r,n,i,o;for(n=63;n>=32;--n){for(r=0,i=n-32,o=n-12;i>4)*ie[i],r=t[i]>>8,t[i]&=255;for(i=0;i<32;i++)t[i]-=r*ie[i];for(n=0;n<32;n++)t[n+1]+=t[n]>>8,e[n]=255&t[n]}function ae(e){var t,r=new Float64Array(64);for(t=0;t<64;t++)r[t]=e[t];for(t=0;t<64;t++)e[t]=0;oe(e,r)}function se(e,r,n,i){var o,a,s=new Uint8Array(64),u=new Uint8Array(64),c=new Uint8Array(64),h=new Float64Array(64),f=[t(),t(),t(),t()];X(s,i,32),s[0]&=248,s[31]&=127,s[31]|=64;var l=n+64;for(o=0;o>7&&U(e[0],a,e[0]),L(e[3],e[0],e[1]),0)}(l,i))return-1;for(o=0;o=0},e.sign.keyPair=function(){var e=new Uint8Array(32),t=new Uint8Array(64);return ne(e,t),{publicKey:e,secretKey:t}},e.sign.keyPair.fromSecretKey=function(e){if(he(e),64!==e.length)throw new Error("bad secret key size");for(var t=new Uint8Array(32),r=0;r=64;){var d,p,m,g,b,v=r,y=n,w=i,_=o,S=a,M=s,k=u,E=c;for(p=0;p<16;p++)m=f+4*p,h[p]=(255&e[m])<<24|(255&e[m+1])<<16|(255&e[m+2])<<8|255&e[m+3];for(p=16;p<64;p++)g=((d=h[p-2])>>>17|d<<15)^(d>>>19|d<<13)^d>>>10,b=((d=h[p-15])>>>7|d<<25)^(d>>>18|d<<14)^d>>>3,h[p]=(g+h[p-7]|0)+(b+h[p-16]|0)|0;for(p=0;p<64;p++)g=(((S>>>6|S<<26)^(S>>>11|S<<21)^(S>>>25|S<<7))+(S&M^~S&k)|0)+(E+(t[p]+h[p]|0)|0)|0,b=((v>>>2|v<<30)^(v>>>13|v<<19)^(v>>>22|v<<10))+(v&y^v&w^y&w)|0,E=k,k=M,M=S,S=_+g|0,_=w,w=y,y=v,v=g+b|0;r=r+v|0,n=n+y|0,i=i+w|0,o=o+_|0,a=a+S|0,s=s+M|0,u=u+k|0,c=c+E|0,f+=64,l-=64}}f(e);var l,d=e.length%64,p=e.length/536870912|0,m=e.length<<3,g=d<56?56:120,b=e.slice(e.length-d,e.length);for(b.push(128),l=d+1;l>>24&255),b.push(p>>>16&255),b.push(p>>>8&255),b.push(p>>>0&255),b.push(m>>>24&255),b.push(m>>>16&255),b.push(m>>>8&255),b.push(m>>>0&255),f(b),[r>>>24&255,r>>>16&255,r>>>8&255,r>>>0&255,n>>>24&255,n>>>16&255,n>>>8&255,n>>>0&255,i>>>24&255,i>>>16&255,i>>>8&255,i>>>0&255,o>>>24&255,o>>>16&255,o>>>8&255,o>>>0&255,a>>>24&255,a>>>16&255,a>>>8&255,a>>>0&255,s>>>24&255,s>>>16&255,s>>>8&255,s>>>0&255,u>>>24&255,u>>>16&255,u>>>8&255,u>>>0&255,c>>>24&255,c>>>16&255,c>>>8&255,c>>>0&255]}function h(e,t,r){e.length>64&&(e=c(e.push?e:Array.prototype.slice.call(e,0)));var n,i=64+t.length+4,o=new Array(i),a=new Array(64),s=[];for(n=0;n<64;n++)o[n]=54;for(n=0;n=i-4;e--){if(o[e]++,o[e]<=255)return;o[e]=0}}for(;r>=32;)u(),s=s.concat(c(a.concat(c(o)))),r-=32;return r>0&&(u(),s=s.concat(c(a.concat(c(o))).slice(0,r))),s}function f(e,t,r,n){var i,o,a=e[0]^t[r++],s=e[1]^t[r++],u=e[2]^t[r++],c=e[3]^t[r++],h=e[4]^t[r++],f=e[5]^t[r++],l=e[6]^t[r++],d=e[7]^t[r++],p=e[8]^t[r++],m=e[9]^t[r++],g=e[10]^t[r++],b=e[11]^t[r++],v=e[12]^t[r++],y=e[13]^t[r++],w=e[14]^t[r++],_=e[15]^t[r++],S=a,M=s,k=u,E=c,A=h,x=f,I=l,P=d,O=p,T=m,R=g,B=b,N=v,C=y,j=w,z=_;for(o=0;o<8;o+=2)S^=(i=(N^=(i=(O^=(i=(A^=(i=S+N)<<7|i>>>25)+S)<<9|i>>>23)+A)<<13|i>>>19)+O)<<18|i>>>14,x^=(i=(M^=(i=(C^=(i=(T^=(i=x+M)<<7|i>>>25)+x)<<9|i>>>23)+T)<<13|i>>>19)+C)<<18|i>>>14,R^=(i=(I^=(i=(k^=(i=(j^=(i=R+I)<<7|i>>>25)+R)<<9|i>>>23)+j)<<13|i>>>19)+k)<<18|i>>>14,z^=(i=(B^=(i=(P^=(i=(E^=(i=z+B)<<7|i>>>25)+z)<<9|i>>>23)+E)<<13|i>>>19)+P)<<18|i>>>14,S^=(i=(E^=(i=(k^=(i=(M^=(i=S+E)<<7|i>>>25)+S)<<9|i>>>23)+M)<<13|i>>>19)+k)<<18|i>>>14,x^=(i=(A^=(i=(P^=(i=(I^=(i=x+A)<<7|i>>>25)+x)<<9|i>>>23)+I)<<13|i>>>19)+P)<<18|i>>>14,R^=(i=(T^=(i=(O^=(i=(B^=(i=R+T)<<7|i>>>25)+R)<<9|i>>>23)+B)<<13|i>>>19)+O)<<18|i>>>14,z^=(i=(j^=(i=(C^=(i=(N^=(i=z+j)<<7|i>>>25)+z)<<9|i>>>23)+N)<<13|i>>>19)+C)<<18|i>>>14;t[n++]=e[0]=S+a|0,t[n++]=e[1]=M+s|0,t[n++]=e[2]=k+u|0,t[n++]=e[3]=E+c|0,t[n++]=e[4]=A+h|0,t[n++]=e[5]=x+f|0,t[n++]=e[6]=I+l|0,t[n++]=e[7]=P+d|0,t[n++]=e[8]=O+p|0,t[n++]=e[9]=T+m|0,t[n++]=e[10]=R+g|0,t[n++]=e[11]=B+b|0,t[n++]=e[12]=N+v|0,t[n++]=e[13]=C+y|0,t[n++]=e[14]=j+w|0,t[n++]=e[15]=z+_|0}function l(e,t,r,n,i){for(;i--;)e[t++]=r[n++]}function d(e,t,r,n,i){for(;i--;)e[t++]^=r[n++]}function p(e,t,r,n,i){l(e,0,t,r+16*(2*i-1),16);for(var o=0;o<2*i;o+=2)f(e,t,r+16*o,n+8*o),f(e,t,r+16*o+16,n+8*o+16*i)}function m(e,t,r){return e[t+16*(2*r-1)]}function g(e){for(var t=[],r=0;r>6),t.push(128|63&n);else if(n<55296)t.push(224|n>>12),t.push(128|n>>6&63),t.push(128|63&n);else{if(r>=e.length-1)throw new Error("invalid string");r++,n=(1023&n)<<10,n|=1023&e.charCodeAt(r),n+=65536,t.push(240|n>>18),t.push(128|n>>12&63),t.push(128|n>>6&63),t.push(128|63&n)}}return t}function b(e){for(var t="0123456789abcdef".split(""),r=e.length,n=[],i=0;i>>4&15]),n.push(t[e[i]>>>0&15]);return n.join("")}function v(e){for(var t,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),n=e.length,i=[],o=0;o>>18&63]),i.push(r[t>>>12&63]),i.push(r[t>>>6&63]),i.push(r[t>>>0&63]);return n%3>0&&(i[i.length-1]="=",n%3==1&&(i[i.length-2]="=")),i.join("")}var y=-1>>>0,w=1;if("object"==typeof n){if(arguments.length>4)throw new Error("scrypt: incorrect number of arguments");var _=n;if(s=i,void 0===(n=_.logN)){if(void 0===_.N)throw new Error("scrypt: missing N parameter");if(_.N<2||_.N>y)throw new Error("scrypt: N is out of range");if(0!=(_.N&_.N-1))throw new Error("scrypt: N is not a power of 2");n=Math.log(_.N)/Math.LN2}w=_.p||1,i=_.r,o=_.dkLen||32,a=_.interruptStep||0,u=_.encoding}if(w<1)throw new Error("scrypt: invalid p");if(i<=0)throw new Error("scrypt: invalid r");if(n<1||n>31)throw new Error("scrypt: logN must be between 1 and 31");var S,M,k,E,A=1<>>0;if(i*w>=1<<30||i>y/128/w||i>y/256||A>y/128/i)throw new Error("scrypt: parameters are too large");"string"==typeof e&&(e=g(e)),"string"==typeof r&&(r=g(r)),"undefined"!=typeof Int32Array?(S=new Int32Array(64*i),M=new Int32Array(32*A*i),E=new Int32Array(16)):(S=[],M=[],E=new Array(16)),k=h(e,r,128*w*i);var x=0,I=32*i;function P(e){for(var t=0;t<32*i;t++){var r=e+4*t;S[x+t]=(255&k[r+3])<<24|(255&k[r+2])<<16|(255&k[r+1])<<8|(255&k[r+0])<<0}}function O(e,t){for(var r=e;r>>0&255,k[e+4*t+1]=r>>>8&255,k[e+4*t+2]=r>>>16&255,k[e+4*t+3]=r>>>24&255}}var B=void 0!==t?t:setTimeout;function N(e,t,r,n,i){!function o(){B((function(){n(e,e+r0&&i[i.length-1])||6!==o[0]&&2!==o[0])){a=0;continue}if(3===o[0]&&(!i||o[1]>i[0]&&o[1]n(this,void 0,void 0,(function*(){return{calculateGasForMessage:i.calculateGasForMessage.bind(this),configure:i.configure.bind(this),exportPrivateKey:i.exportPrivateKey.bind(this),getAddress:i.getAddress.bind(this),getBalance:i.getBalance.bind(this),getMessages:i.getMessages.bind(this),getPublicKey:i.getPublicKey.bind(this),sendMessage:i.sendMessage.bind(this),signMessage:i.signMessage.bind(this),signMessageRaw:i.signMessageRaw.bind(this)}})),this.pluginOrigin=e,this.snapId="wallet_plugin_"+this.pluginOrigin}}},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(i,o){function a(e){try{u(n.next(e))}catch(e){o(e)}}function s(e){try{u(n.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(a,s)}u((n=n.apply(e,t||[])).next())}))};function i(e,t){return n(this,void 0,void 0,(function*(){return yield window.ethereum.send({method:t,params:[e]})}))}Object.defineProperty(t,"__esModule",{value:!0}),t.calculateGasForMessage=t.getMessages=t.sendMessage=t.signMessageRaw=t.signMessage=t.configure=t.exportPrivateKey=t.getBalance=t.getPublicKey=t.getAddress=void 0,t.getAddress=function(){return n(this,void 0,void 0,(function*(){return yield i({method:"getAddress"},this.snapId)}))},t.getPublicKey=function(){return n(this,void 0,void 0,(function*(){return yield i({method:"getPublicKey"},this.snapId)}))},t.getBalance=function(e){return n(this,void 0,void 0,(function*(){return yield i({method:"getBalance",params:{denomination:e}},this.snapId)}))},t.exportPrivateKey=function(){return n(this,void 0,void 0,(function*(){return yield i({method:"exportPrivateKey"},this.snapId)}))},t.configure=function(e){return n(this,void 0,void 0,(function*(){return yield i({method:"configure",params:{configuration:e}},this.snapId)}))},t.signMessage=function(e){return n(this,void 0,void 0,(function*(){return yield i({method:"signMessage",params:{message:e}},this.snapId)}))},t.signMessageRaw=function(e){return n(this,void 0,void 0,(function*(){return yield i({method:"signMessageRaw",params:{message:e}},this.snapId)}))},t.sendMessage=function(e){return n(this,void 0,void 0,(function*(){return yield i({method:"sendMessage",params:{signedMessage:e}},this.snapId)}))},t.getMessages=function(){return n(this,void 0,void 0,(function*(){return yield i({method:"getMessages"},this.snapId)}))},t.calculateGasForMessage=function(e){return n(this,void 0,void 0,(function*(){return yield i({method:"getGasForMessage",params:{message:e}},this.snapId)}))}}])})); +//# sourceMappingURL=filecoin.js.map \ No newline at end of file diff --git a/app/src/main/assets/polyfill.js b/app/src/main/assets/polyfill.js new file mode 100644 index 00000000..f00fe424 --- /dev/null +++ b/app/src/main/assets/polyfill.js @@ -0,0 +1,134 @@ +// polyfill.js +var window = this; +var self = this; +var localStorage = { + getItem: function(key) { return null; }, + setItem: function(key, value) {}, + removeItem: function(key) {} +}; +var fetch = function() { + return Promise.reject("fetch is not implemented"); +}; + +// TextEncoder polyfill +function TextEncoder() {} +TextEncoder.prototype.encode = function(str) { + var Len = str.length, resPos = -1; + var resArr = typeof Uint8Array === "function" ? new Uint8Array(Len * 3) : []; + for (var point = 0, nextcode = 0, i = 0; i !== Len; ) { + point = str.charCodeAt(i); + i += 1; + if (point >= 0xD800 && point <= 0xDBFF) { + if (i === Len) { + resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; + resArr[resPos += 1] = 0xbd; break; + } + nextcode = str.charCodeAt(i); + if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) { + point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000; + i += 1; + if (point > 0xffff) { + resArr[resPos += 1] = (0x1e<<3) | (point>>>18); + resArr[resPos += 1] = (0x2<<6) | ((point>>>12)&0x3f); + resArr[resPos += 1] = (0x2<<6) | ((point>>>6)&0x3f); + resArr[resPos += 1] = (0x2<<6) | (point&0x3f); + continue; + } + } else { + resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; + resArr[resPos += 1] = 0xbd; continue; + } + } + if (point <= 0x007f) { + resArr[resPos += 1] = (0x0<<7) | point; + } else if (point <= 0x07ff) { + resArr[resPos += 1] = (0x6<<5) | (point>>>6); + resArr[resPos += 1] = (0x2<<6) | (point&0x3f); + } else { + resArr[resPos += 1] = (0xe<<4) | (point>>>12); + resArr[resPos += 1] = (0x2<<6) | ((point>>>6)&0x3f); + resArr[resPos += 1] = (0x2<<6) | (point&0x3f); + } + } + return resArr.subarray(0, resPos + 1); +}; + +// TextDecoder polyfill +function TextDecoder() {} +TextDecoder.prototype.decode = function(octets) { + var string = ""; + var i = 0; + while (i < octets.length) { + var octet = octets[i]; + var bytesNeeded = 0; + var codePoint = 0; + if (octet <= 0x7F) { + bytesNeeded = 0; + codePoint = octet & 0xFF; + } else if (octet <= 0xDF) { + bytesNeeded = 1; + codePoint = octet & 0x1F; + } else if (octet <= 0xEF) { + bytesNeeded = 2; + codePoint = octet & 0x0F; + } else if (octet <= 0xF4) { + bytesNeeded = 3; + codePoint = octet & 0x07; + } + if (octets.length - i - bytesNeeded > 0) { + var k = 0; + while (k < bytesNeeded) { + octet = octets[i + k + 1]; + codePoint = (codePoint << 6) | (octet & 0x3F); + k += 1; + } + } else { + codePoint = 0xFFFD; + bytesNeeded = octets.length - i; + } + string += String.fromCodePoint(codePoint); + i += bytesNeeded + 1; + } + return string; +}; + +// Add any other browser APIs that Filecoin.js might be using + +var crypto = { + getRandomValues: function(buffer) { + for (var i = 0; i < buffer.length; i++) { + buffer[i] = Math.floor(Math.random() * 256); + } + return buffer; + } +}; + +// If Filecoin.js is using the subtle crypto API, we might need to mock that too +crypto.subtle = { + digest: function(algorithm, data) { + // This is a very basic mock and won't provide actual cryptographic security + return Promise.resolve(new ArrayBuffer(32)); // returns a 32-byte buffer + } +}; + +var fetch = function(url, options) { + console.log('Fetch called with:', url, options); + return Promise.reject('fetch is not implemented'); +}; + +var XMLHttpRequest = function() { + this.open = function() {}; + this.send = function() {}; +}; + +var localStorage = { + storage: {}, + getItem: function(key) { return this.storage[key] || null; }, + setItem: function(key, value) { this.storage[key] = value.toString(); }, + removeItem: function(key) { delete this.storage[key]; } +}; + +var Worker = function() { + this.onmessage = null; + this.postMessage = function() {}; +}; \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/FolderAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/FolderAdapter.kt index da8062a1..2d7e2df5 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/FolderAdapter.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/FolderAdapter.kt @@ -2,13 +2,14 @@ package net.opendasharchive.openarchive import android.content.Context import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import net.opendasharchive.openarchive.databinding.RvSimpleRowBinding +import net.opendasharchive.openarchive.databinding.RvFoldersRowBinding import net.opendasharchive.openarchive.db.Project import java.lang.ref.WeakReference @@ -16,38 +17,23 @@ interface FolderAdapterListener { fun projectClicked(project: Project) - fun getSelectedProject(): Project? } -class FolderAdapter(listener: FolderAdapterListener?) : ListAdapter(DIFF_CALLBACK), FolderAdapterListener { +class FolderAdapter(private val context: Context, private val listener: FolderAdapterListener, private val isArchived: Boolean = false) : ListAdapter(DIFF_CALLBACK) { - class ViewHolder(private val binding: RvSimpleRowBinding) : RecyclerView.ViewHolder(binding.root) { + inner class FolderViewHolder(private val binding: RvFoldersRowBinding) : + RecyclerView.ViewHolder(binding.root) { - fun bind(listener: WeakReference?, project: Project?) { - binding.rvTitle.text = project?.description + fun bind(project: Project) { - if (listener?.get()?.getSelectedProject()?.id == project?.id) { - val icon = ContextCompat.getDrawable(binding.rvIcon.context, R.drawable.baseline_folder_white_24) - val color = ContextCompat.getColor(binding.rvIcon.context, R.color.colorPrimary) - icon?.setTint(color) - binding.rvIcon.setImageDrawable(icon) - } else { - val icon = ContextCompat.getDrawable(binding.rvIcon.context, R.drawable.outline_folder_white_24) - val color = ContextCompat.getColor(binding.rvIcon.context, R.color.colorOnBackground) - icon?.setTint(color) - binding.rvIcon.setImageDrawable(icon) - } + binding.rvTitle.text = project.description - binding.rvTitle.setTextColor(getColor(binding.rvTitle.context, - listener?.get()?.getSelectedProject()?.id == project?.id)) + val icon = ContextCompat.getDrawable(context, R.drawable.ic_folder_new) + icon?.setTint(ContextCompat.getColor(context, R.color.colorOnBackground)) + binding.rvIcon.setImageDrawable(icon) - if (project != null) { - binding.root.setOnClickListener { - listener?.get()?.projectClicked(project) - } - } - else { - binding.root.setOnClickListener(null) + itemView.setOnClickListener { + listener.projectClicked(project) } } } @@ -62,78 +48,25 @@ class FolderAdapter(listener: FolderAdapterListener?) : ListAdapter? - - private var mLastSelected: Project? = null - - init { - mListener = WeakReference(listener) - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return ViewHolder(RvSimpleRowBinding.inflate(LayoutInflater.from(parent.context), - parent, false)) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FolderViewHolder { + return FolderViewHolder( + RvFoldersRowBinding.inflate( + LayoutInflater.from(parent.context), + parent, false + ) + ) } - override fun onBindViewHolder(holder: ViewHolder, position: Int) { + override fun onBindViewHolder(holder: FolderViewHolder, position: Int) { val project = getItem(position) - holder.bind(WeakReference(this), project) + holder.bind( project) } fun update(projects: List) { - notifyItemChanged(getIndex(mLastSelected)) submitList(projects) } - - override fun projectClicked(project: Project) { - notifyItemChanged(getIndex(getSelectedProject())) - notifyItemChanged(getIndex(project)) - - mListener?.get()?.projectClicked(project) - } - - override fun getSelectedProject(): Project? { - mLastSelected = mListener?.get()?.getSelectedProject() - - return mLastSelected - } - - private fun getIndex(project: Project?): Int { - return if (project == null) { - -1 - } - else { - currentList.indexOf(project) - } - } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/SaveApp.kt b/app/src/main/java/net/opendasharchive/openarchive/SaveApp.kt index 4f729118..fd0e7d09 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/SaveApp.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/SaveApp.kt @@ -1,57 +1,83 @@ package net.opendasharchive.openarchive +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.UiModeManager import android.content.Context -import com.facebook.drawee.backends.pipeline.Fresco -import com.facebook.imagepipeline.core.ImagePipelineConfig -import com.facebook.imagepipeline.decoder.SimpleProgressiveJpegConfig +import android.os.Build +import android.util.Log +import androidx.appcompat.app.AppCompatDelegate +import coil3.ImageLoader +import coil3.PlatformContext +import coil3.SingletonImageLoader +import coil3.util.Logger import com.orm.SugarApp import info.guardianproject.netcipher.proxy.OrbotHelper import net.opendasharchive.openarchive.core.di.coreModule import net.opendasharchive.openarchive.core.di.featuresModule +import net.opendasharchive.openarchive.core.di.passcodeModule +import net.opendasharchive.openarchive.core.di.retrofitModule +import net.opendasharchive.openarchive.core.di.unixSocketModule import net.opendasharchive.openarchive.core.logger.AppLogger import net.opendasharchive.openarchive.features.settings.passcode.PasscodeManager +import net.opendasharchive.openarchive.util.Analytics import net.opendasharchive.openarchive.util.Prefs import net.opendasharchive.openarchive.util.Theme import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin import org.koin.core.logger.Level +import timber.log.Timber -class SaveApp : SugarApp() { +class SaveApp : SugarApp(), SingletonImageLoader.Factory { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) } + private fun applyTheme() { + + val useDarkMode = Prefs.getBoolean(getString(R.string.pref_key_use_dark_mode), false) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val uiModeManager = getSystemService(UI_MODE_SERVICE) as UiModeManager + val darkMode = if (useDarkMode) UiModeManager.MODE_NIGHT_YES else UiModeManager.MODE_NIGHT_NO + uiModeManager.setApplicationNightMode(darkMode) + } else { + val darkMode = if (useDarkMode) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO + AppCompatDelegate.setDefaultNightMode(darkMode) + } + } + override fun onCreate() { super.onCreate() + Analytics.init(this) AppLogger.init(applicationContext, initDebugger = true) registerActivityLifecycleCallbacks(PasscodeManager()) startKoin { androidLogger(Level.DEBUG) androidContext(this@SaveApp) - modules(coreModule, featuresModule) + modules( + coreModule, + featuresModule, + retrofitModule, + unixSocketModule, + passcodeModule + ) } - - val config = ImagePipelineConfig.newBuilder(this) - .setProgressiveJpegConfig(SimpleProgressiveJpegConfig()) - .setResizeAndRotateEnabledForNetwork(true) - .setDownsampleEnabled(true) - .build() - - Fresco.initialize(this, config) Prefs.load(this) + applyTheme() if (Prefs.useTor) initNetCipher() - Theme.set(Prefs.theme) - CleanInsightsManager.init(this) + + createSnowbirdNotificationChannel() } private fun initNetCipher() { - AppLogger.d( "Initializing NetCipher client") + AppLogger.d("Initializing NetCipher client") val oh = OrbotHelper.get(this) if (BuildConfig.DEBUG) { @@ -60,4 +86,49 @@ class SaveApp : SugarApp() { // oh.init() } + + private fun createSnowbirdNotificationChannel() { + val silentChannel = NotificationChannel( + SNOWBIRD_SERVICE_CHANNEL_SILENT, + "Raven Service", + NotificationManager.IMPORTANCE_LOW + ) + + val chimeChannel = NotificationChannel( + SNOWBIRD_SERVICE_CHANNEL_CHIME, + "Raven Service", + NotificationManager.IMPORTANCE_DEFAULT + ) + + val notificationManager: NotificationManager = + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + notificationManager.createNotificationChannel(chimeChannel) + notificationManager.createNotificationChannel(silentChannel) + } + + companion object { + const val SNOWBIRD_SERVICE_ID = 2601 + const val SNOWBIRD_SERVICE_CHANNEL_CHIME = "snowbird_service_channel_chime" + const val SNOWBIRD_SERVICE_CHANNEL_SILENT = "snowbird_service_channel_silent" + + const val TOR_SERVICE_ID = 2602 + const val TOR_SERVICE_CHANNEL = "tor_service_channel" + } + + override fun newImageLoader(context: PlatformContext): ImageLoader { + return ImageLoader.Builder(this).logger(object : Logger { + override var minLevel: Logger.Level = Logger.Level.Verbose + + override fun log( + tag: String, + level: Logger.Level, + message: String?, + throwable: Throwable? + ) { + Timber.tag("Coil3:$tag").log(level.ordinal, throwable, message) + } + }) + .build() + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/SpaceAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/SpaceAdapter.kt index b1c1b12b..a548c89c 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/SpaceAdapter.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/SpaceAdapter.kt @@ -1,12 +1,15 @@ package net.opendasharchive.openarchive +import android.content.Context +import android.graphics.Rect import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import net.opendasharchive.openarchive.databinding.RvSimpleRowBinding +import net.opendasharchive.openarchive.databinding.RvSpacesRowBinding import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.util.extensions.scaled import java.lang.ref.WeakReference @@ -15,59 +18,46 @@ interface SpaceAdapterListener { fun spaceClicked(space: Space) - fun addSpaceClicked() + fun editSpaceClicked(spaceId: Long?) fun getSelectedSpace(): Space? } -class SpaceAdapter(listener: SpaceAdapterListener?) : ListAdapter(DIFF_CALLBACK), SpaceAdapterListener { +class SpaceAdapter(private val context: Context, listener: SpaceAdapterListener?) : ListAdapter(DIFF_CALLBACK), SpaceAdapterListener { - class ViewHolder(private val binding: RvSimpleRowBinding) : RecyclerView.ViewHolder(binding.root) { + inner class ViewHolder(private val binding: RvSpacesRowBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(listener: WeakReference?, space: Space?) { - val context = binding.rvTitle.context - if (listener?.get()?.getSelectedSpace()?.id == space?.id) { - val icon = Space.current?.getAvatar(context)?.scaled(32, context) - val color = ContextCompat.getColor(binding.rvIcon.context, R.color.colorPrimary) - icon?.setTint(color) - binding.rvIcon.setImageDrawable(icon) - } - else { - val icon = space?.getAvatar(context)?.scaled(32, context) - val color = ContextCompat.getColor(binding.rvIcon.context, R.color.colorOnBackground) - icon?.setTint(color) - binding.rvIcon.setImageDrawable(icon) - } + val isSelected = listener?.get()?.getSelectedSpace()?.id == space?.id + itemView.isSelected = isSelected + val textColorRes = if (isSelected) R.color.colorTertiary else R.color.colorText + val iconColorRes = if (isSelected) R.color.colorTertiary else R.color.colorOnBackground + val backgroundRes = if (isSelected) R.drawable.item_background_selector else android.R.color.transparent - if (space?.type == ADD_SPACE_ID) { - binding.rvTitle.text = context.getText(R.string.add_another_account) + binding.root.setBackgroundResource(backgroundRes) - val icon = ContextCompat.getDrawable(binding.rvIcon.context, R.drawable.ic_add) - binding.rvIcon.setImageDrawable(icon) + val icon = space?.getAvatar(context)?.scaled(32, context) - binding.root.setOnClickListener { - listener?.get()?.addSpaceClicked() - } + icon?.setTint(ContextCompat.getColor(binding.rvIcon.context, iconColorRes)) + binding.rvIcon.setImageDrawable(icon) + + binding.rvEdit.setColorFilter(ContextCompat.getColor(binding.rvEdit.context, iconColorRes)) + + + binding.rvTitle.text = space?.friendlyName + binding.rvTitle.setTextColor(ContextCompat.getColor(binding.rvTitle.context, textColorRes)) - return - } else { - binding.rvTitle.text = space?.friendlyName - } - binding.rvTitle.setTextColor( - FolderAdapter.getColor( - binding.rvTitle.context, - listener?.get()?.getSelectedSpace()?.id == space?.id - ) - ) + binding.rvEdit.setOnClickListener { + listener?.get()?.editSpaceClicked(space?.id) + } if (space != null) { binding.root.setOnClickListener { listener?.get()?.spaceClicked(space) } - } - else { + } else { binding.root.setOnClickListener(null) } } @@ -84,7 +74,6 @@ class SpaceAdapter(listener: SpaceAdapterListener?) : ListAdapter) { notifyItemChanged(getIndex(mLastSelected)) - @Suppress("NAME_SHADOWING") - val spaces = spaces.toMutableList() - spaces.add(Space(ADD_SPACE_ID)) + //@Suppress("NAME_SHADOWING") + //val spaces = spaces.toMutableList() + //spaces.add(Space(ADD_SPACE_ID)) submitList(spaces) } override fun spaceClicked(space: Space) { - notifyItemChanged(getIndex(getSelectedSpace())) - notifyItemChanged(getIndex(space)) + // Notify previous and new selected items + val previousIndex = getIndex(getSelectedSpace()) + val newIndex = getIndex(space) + + mLastSelected = space + + notifyItemChanged(previousIndex) + notifyItemChanged(newIndex) mListener.get()?.spaceClicked(space) } - override fun addSpaceClicked() { - mListener.get()?.addSpaceClicked() + override fun editSpaceClicked(spaceId: Long?) { + mListener.get()?.editSpaceClicked(spaceId) } override fun getSelectedSpace(): Space? { @@ -137,4 +132,24 @@ class SpaceAdapter(listener: SpaceAdapterListener?) : ListAdapter { DefaultResourceProvider(androidApplication()) } + // Provide DialogStateManager and let Koin inject the ResourceProvider. + viewModel { DialogStateManager(get()) } + + viewModel { HomeViewModel() } + + viewModel { + MainViewModel() + } + + viewModel { + BrowseFoldersViewModel( + context = get() + ) + } } + + diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/di/FeaturesModule.kt b/app/src/main/java/net/opendasharchive/openarchive/core/di/FeaturesModule.kt index 8f6e196d..f15c2087 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/core/di/FeaturesModule.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/core/di/FeaturesModule.kt @@ -1,5 +1,6 @@ package net.opendasharchive.openarchive.core.di +import android.app.Application import android.content.Context import net.opendasharchive.openarchive.features.internetarchive.internetArchiveModule import net.opendasharchive.openarchive.features.settings.passcode.AppConfig @@ -9,44 +10,34 @@ import net.opendasharchive.openarchive.features.settings.passcode.PBKDF2HashingS import net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryViewModel import net.opendasharchive.openarchive.features.settings.passcode.PasscodeRepository import net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupViewModel +import net.opendasharchive.openarchive.services.snowbird.ISnowbirdFileRepository +import net.opendasharchive.openarchive.services.snowbird.ISnowbirdGroupRepository +import net.opendasharchive.openarchive.services.snowbird.ISnowbirdRepoRepository +import net.opendasharchive.openarchive.services.snowbird.SnowbirdFileRepository +import net.opendasharchive.openarchive.services.snowbird.SnowbirdFileViewModel +import net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupRepository +import net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupViewModel +import net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoRepository +import net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoViewModel import org.koin.core.module.dsl.viewModel +import org.koin.core.qualifier.named import org.koin.dsl.module val featuresModule = module { includes(internetArchiveModule) // TODO: have some registry of feature modules - single { - AppConfig( - passcodeLength = 6, - enableHapticFeedback = true, - maxRetryLimitEnabled = false, - biometricAuthEnabled = false, - maxFailedAttempts = 5 - ) - } - single { - HapticManager( - appConfig = get(), - ) - } - single { - PBKDF2HashingStrategy() - } - single { AppConfig() } +// single { SnowbirdFileRepository(get(named("retrofit"))) } +// single { SnowbirdGroupRepository(get(named("retrofit"))) } +// single { SnowbirdRepoRepository(get(named("retrofit"))) } - single { - val hashingStrategy: HashingStrategy = PBKDF2HashingStrategy() - - PasscodeRepository( - context = get(), - config = get(), - hashingStrategy = hashingStrategy - ) - } - viewModel { PasscodeEntryViewModel(get(), get()) } - viewModel { PasscodeSetupViewModel(get(), get()) } + single { SnowbirdFileRepository(get(named("unixSocket"))) } + single { SnowbirdGroupRepository(get(named("unixSocket"))) } + single { SnowbirdRepoRepository(get(named("unixSocket"))) } + viewModel { (application: Application) -> SnowbirdGroupViewModel(application, get()) } + viewModel { (application: Application) -> SnowbirdFileViewModel(application, get()) } + viewModel { (application: Application) -> SnowbirdRepoViewModel(application, get()) } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/di/PasscodeModule.kt b/app/src/main/java/net/opendasharchive/openarchive/core/di/PasscodeModule.kt new file mode 100644 index 00000000..1282bc25 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/di/PasscodeModule.kt @@ -0,0 +1,48 @@ +package net.opendasharchive.openarchive.core.di + +import android.content.Context +import net.opendasharchive.openarchive.features.settings.passcode.AppConfig +import net.opendasharchive.openarchive.features.settings.passcode.HapticManager +import net.opendasharchive.openarchive.features.settings.passcode.HashingStrategy +import net.opendasharchive.openarchive.features.settings.passcode.PBKDF2HashingStrategy +import net.opendasharchive.openarchive.features.settings.passcode.PasscodeRepository +import net.opendasharchive.openarchive.features.settings.passcode.passcode_entry.PasscodeEntryViewModel +import net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupViewModel +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module + +val passcodeModule = module { + single { + AppConfig( + passcodeLength = 6, + enableHapticFeedback = true, + maxRetryLimitEnabled = false, + biometricAuthEnabled = false, + maxFailedAttempts = 5, + isDwebEnabled = false + ) + } + + single { + HapticManager( + appConfig = get(), + ) + } + + single { + PBKDF2HashingStrategy() + } + + single { + val hashingStrategy: HashingStrategy = PBKDF2HashingStrategy() + + PasscodeRepository( + context = get(), + config = get(), + hashingStrategy = hashingStrategy + ) + } + + viewModel { PasscodeEntryViewModel(get(), get()) } + viewModel { PasscodeSetupViewModel(get(), get()) } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/di/RetrofitModule.kt b/app/src/main/java/net/opendasharchive/openarchive/core/di/RetrofitModule.kt new file mode 100644 index 00000000..4f1a1a11 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/di/RetrofitModule.kt @@ -0,0 +1,48 @@ +package net.opendasharchive.openarchive.core.di + +import android.content.Context +import net.opendasharchive.openarchive.services.snowbird.service.ISnowbirdAPI +import net.opendasharchive.openarchive.services.snowbird.service.RetrofitAPI +import net.opendasharchive.openarchive.services.snowbird.service.RetrofitClient +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import org.koin.core.qualifier.named +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit + +val retrofitModule = module { + + single { + HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + } + + single { + OkHttpClient.Builder() + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) + .addInterceptor(get()) + .build() + } + + single { + Retrofit.Builder() + .baseUrl("http://localhost:8080/api/") + .client(get()) + .addConverterFactory(GsonConverterFactory.create()) + .build() + } + + single { get().create(RetrofitClient::class.java) } + + single(named("retrofit")) { + RetrofitAPI( + context = get(), + client = get() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/di/UnixSocketModule.kt b/app/src/main/java/net/opendasharchive/openarchive/core/di/UnixSocketModule.kt new file mode 100644 index 00000000..2bd3629a --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/di/UnixSocketModule.kt @@ -0,0 +1,15 @@ +package net.opendasharchive.openarchive.core.di + +import net.opendasharchive.openarchive.features.main.UnixSocketClient +import net.opendasharchive.openarchive.services.snowbird.service.ISnowbirdAPI +import net.opendasharchive.openarchive.services.snowbird.service.UnixSocketAPI +import org.koin.core.qualifier.named +import org.koin.dsl.module + +val unixSocketModule = module { + single { + UnixSocketClient(context = get()) + } + + single(named("unixSocket")) { UnixSocketAPI(get(), get()) } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/logger/AppLogger.kt b/app/src/main/java/net/opendasharchive/openarchive/core/logger/AppLogger.kt index 923d98a7..e855a898 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/core/logger/AppLogger.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/core/logger/AppLogger.kt @@ -7,6 +7,7 @@ import com.orhanobut.logger.FormatStrategy import com.orhanobut.logger.Logger import com.orhanobut.logger.PrettyFormatStrategy import net.opendasharchive.openarchive.BuildConfig +import net.opendasharchive.openarchive.util.Analytics import timber.log.Timber @@ -37,10 +38,12 @@ object AppLogger { // Info Level Logging fun i(message: String, vararg args: Any?) { Timber.i(message + args.joinToString(" ")) + Analytics.log(Analytics.APP_LOG, mapOf("info" to message + args.joinToString(" "))) } fun i(message: String, throwable: Throwable) { Timber.i(throwable, message) + Analytics.log(Analytics.APP_LOG, mapOf("info" to message)) } // Debug Level Logging @@ -55,14 +58,17 @@ object AppLogger { // Error Level Logging fun e(message: String, vararg args: Any?) { Timber.e(message + args.joinToString(" ")) + Analytics.log(Analytics.APP_ERROR, mapOf("error" to message + args.joinToString(" "))) } fun e(message: String, throwable: Throwable) { Timber.e(throwable, message) + Analytics.log(Analytics.APP_ERROR, mapOf("error" to message)) } fun e(throwable: Throwable) { Timber.e(throwable) + Analytics.log(Analytics.APP_ERROR, mapOf("error" to throwable.message)) } // Warning Level Logging diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/CustomBottomNavBar.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/CustomBottomNavBar.kt new file mode 100644 index 00000000..d44ab5e9 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/CustomBottomNavBar.kt @@ -0,0 +1,70 @@ +package net.opendasharchive.openarchive.core.presentation.components + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.CustomBottomNavBinding + +class CustomBottomNavBar @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + var onMyMediaClick: (() -> Unit)? = null + var onSettingsClick: (() -> Unit)? = null + + var onAddClick: (() -> Unit)? = null + var onAddLongClick: (() -> Unit)? = null + + // Inflate the layout + private var binding: CustomBottomNavBinding = + CustomBottomNavBinding.inflate(LayoutInflater.from(context), this, true) + + init { + + + // Set up click listeners + binding.myMediaButton.setOnClickListener { onMyMediaClick?.invoke() } + binding.settingsButton.setOnClickListener { onSettingsClick?.invoke() } + + binding.addButton.setOnClickListener { onAddClick?.invoke() } + + + binding.myMediaLabel.setOnClickListener { + // perform click + play ripple animation + binding.myMediaButton.isPressed = true + binding.myMediaButton.isPressed = false + binding.myMediaButton.performClick() + } + + binding.settingsLabel.setOnClickListener { + // perform click + play ripple animation + binding.settingsButton.isPressed = true + binding.settingsButton.isPressed = false + binding.settingsButton.performClick() + } + } + + /** + * Updates the highlighted state of the navigation bar buttons. + */ + fun updateSelectedItem(isSettings: Boolean) { + if (isSettings) { + binding.myMediaButton.setIconResource(R.drawable.outline_perm_media_24) + binding.settingsButton.setIconResource(R.drawable.ic_settings_filled) + } else { + binding.myMediaButton.setIconResource(R.drawable.perm_media_24px) + binding.settingsButton.setIconResource(R.drawable.ic_settings) + } + } + + fun setAddButtonLongClickEnabled() { + binding.addButton.setOnLongClickListener { + onAddLongClick?.invoke() + true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/PrimaryButton.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/PrimaryButton.kt index c7e2ff25..39612410 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/PrimaryButton.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/components/PrimaryButton.kt @@ -1,9 +1,51 @@ package net.opendasharchive.openarchive.core.presentation.components -import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.core.presentation.theme.DefaultBoxPreview @Composable -fun PrimaryButton(onClick: () -> Unit, content: @Composable RowScope.() -> Unit) = - Button(onClick = onClick, content = content) +fun PrimaryButton( + modifier: Modifier = Modifier, + icon: ImageVector? = null, + text: String, + onClick: () -> Unit +) { + Button( + modifier = modifier, + shape = RoundedCornerShape(8f), + onClick = onClick + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + icon?.let { + Icon(imageVector = it, contentDescription = null) + } + + Text(text) + } + } +} + +@Preview +@Composable +private fun PrimaryButtonPreview() { + DefaultBoxPreview { + + PrimaryButton( + text = "New Folder" + ) { } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Colors.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Colors.kt index e4e8db82..a608bd4c 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Colors.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Colors.kt @@ -3,13 +3,17 @@ package net.opendasharchive.openarchive.core.presentation.theme import androidx.compose.material3.ColorScheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import net.opendasharchive.openarchive.R private val c23_nav_drawer_night = Color(0xff101010) private val c23_darker_grey = Color(0xff212021) private val c23_dark_grey = Color(0xff333333) +private val c23_darker_medium_grey = Color(0xff434343) private val c23_medium_grey = Color(0xff696666) private val c23_grey = Color(0xff9f9f9f) private val c23_grey_50 = Color(0xff777979) @@ -26,6 +30,10 @@ private val c23_teal_20 = Color(0xff003530) // v=20.6 --> private val c23_teal_10 = Color(0xff001b19) // v=10.6 --> private val c23_powder_blue = Color(0xffaae6e1) +private val inputBackgroundLight = Color(0xfffffbf0) +private val inputBackgroundDark = Color(0xff212021) +private val darkPrimary = Color(0xff000A0A) + @Immutable data class ColorTheme( val material: ColorScheme, @@ -36,21 +44,22 @@ data class ColorTheme( val onDisabledContainer: Color = c23_light_grey, ) -private val LightColorScheme = ColorTheme( +@Composable +internal fun lightColorScheme() = ColorTheme( material = lightColorScheme( - primary = c23_teal, + primary = colorResource(R.color.colorPrimary), onPrimary = Color.Black, - primaryContainer = c23_teal, - onPrimaryContainer = Color.Black, + primaryContainer = colorResource(R.color.colorPrimaryContainer), + onPrimaryContainer = colorResource(R.color.colorOnPrimaryContainer), - secondary = c23_teal, - onSecondary = Color.Black, - secondaryContainer = c23_teal_90, - onSecondaryContainer = Color.Black, + secondary = colorResource(R.color.colorSecondary), + onSecondary = colorResource(R.color.colorOnSecondary), + secondaryContainer = colorResource(R.color.colorSecondaryContainer), + onSecondaryContainer = colorResource(R.color.colorOnSecondaryContainer), - tertiary = c23_powder_blue, - onTertiary = Color.Black, + tertiary = colorResource(R.color.colorTertiary), + onTertiary = colorResource(R.color.colorSecondary), tertiaryContainer = c23_powder_blue, onTertiaryContainer = Color.Black, @@ -59,13 +68,13 @@ private val LightColorScheme = ColorTheme( errorContainer = Color.Red, onErrorContainer = Color.Black, - background = Color.White, - onBackground = Color.Black, + background = colorResource(R.color.colorBackground), + onBackground = colorResource(R.color.colorOnBackground), - surface = c23_light_grey, - onSurface = Color.Black, + surface = Color.White, + onSurface = colorResource(R.color.colorOnSurface), surfaceVariant = c23_grey, - onSurfaceVariant = c23_darker_grey, + onSurfaceVariant = c23_darker_medium_grey, outline = Color.Black, inverseOnSurface = Color.White, @@ -76,24 +85,27 @@ private val LightColorScheme = ColorTheme( scrim = c23_light_grey, surfaceBright = c23_light_grey, surfaceContainer = Color.White, + surfaceContainerHighest = inputBackgroundLight, surfaceDim = c23_light_grey ), ) -private val DarkColorScheme = ColorTheme( +@Composable +internal fun darkColorScheme() = ColorTheme( material = darkColorScheme( - primary = c23_teal, - onPrimary = Color.Black, - primaryContainer = c23_teal, - onPrimaryContainer = Color.White, - secondary = c23_teal, - onSecondary = Color.Black, - secondaryContainer = c23_teal_20, - onSecondaryContainer = Color.White, + primary = colorResource(R.color.colorPrimary), + onPrimary = Color.White, + primaryContainer = colorResource(R.color.colorPrimaryContainer), + onPrimaryContainer = colorResource(R.color.colorOnPrimaryContainer), + + secondary = colorResource(R.color.colorSecondary), + onSecondary = colorResource(R.color.colorOnSecondary), + secondaryContainer = colorResource(R.color.colorSecondaryContainer), + onSecondaryContainer = colorResource(R.color.colorOnSecondaryContainer), - tertiary = c23_powder_blue, - onTertiary = Color.Black, + tertiary = colorResource(R.color.colorTertiary), + onTertiary = colorResource(R.color.colorSecondary), tertiaryContainer = c23_powder_blue, onTertiaryContainer = Color.Black, @@ -102,8 +114,8 @@ private val DarkColorScheme = ColorTheme( errorContainer = Color.Red, onErrorContainer = Color.Black, - background = Color.Black, - onBackground = Color.White, + background = colorResource(R.color.colorBackground), + onBackground = colorResource(R.color.colorOnBackground), surface = c23_darker_grey, onSurface = Color.White, @@ -119,11 +131,11 @@ private val DarkColorScheme = ColorTheme( scrim = c23_light_grey, surfaceBright = c23_grey, surfaceContainer = c23_medium_grey, + surfaceContainerHighest = inputBackgroundDark, surfaceDim = c23_dark_grey ), ) -fun getThemeColors(isDarkTheme: Boolean) = if (isDarkTheme) DarkColorScheme else LightColorScheme - -val LocalColors = staticCompositionLocalOf { LightColorScheme } - +val LocalColors = staticCompositionLocalOf { + error("LocalColors not provided. Wrap your composables in the Theme function.") +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Preview.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Preview.kt new file mode 100644 index 00000000..598566c0 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Preview.kt @@ -0,0 +1,76 @@ +package net.opendasharchive.openarchive.core.presentation.theme + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.features.internetarchive.presentation.login.ComposeAppBar + +@Composable +fun DefaultScaffoldPreview( + content: @Composable () -> Unit +) { + + SaveAppTheme { + + Scaffold( + topBar = { + ComposeAppBar() + } + ) { paddingValues -> + + Box( + modifier = Modifier.Companion.padding(paddingValues), + contentAlignment = Alignment.Companion.Center + ) { + content() + } + } + } + +} + +@Composable +fun DefaultEmptyScaffoldPreview( + content: @Composable () -> Unit +) { + + SaveAppTheme { + + Scaffold { paddingValues -> + + Box( + modifier = Modifier.Companion.padding(paddingValues), + contentAlignment = Alignment.Companion.Center + ) { + content() + } + } + } + +} + +@Composable +fun DefaultBoxPreview( + content: @Composable () -> Unit +) { + SaveAppTheme { + Surface( + color = MaterialTheme.colorScheme.surface + ) { + Box( + modifier = Modifier.padding(12.dp), + contentAlignment = Alignment.Center + ) { + content() + } + } + + + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Shape.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Shape.kt new file mode 100644 index 00000000..a8cbe804 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Shape.kt @@ -0,0 +1,11 @@ +package net.opendasharchive.openarchive.core.presentation.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Theme.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Theme.kt index e0bfbea0..deb3a5d3 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Theme.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Theme.kt @@ -8,12 +8,12 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState @Composable -fun Theme( +fun SaveAppTheme( content: @Composable () -> Unit ) { val isDarkTheme by rememberUpdatedState(newValue = isSystemInDarkTheme()) - val colors = getThemeColors(isDarkTheme) + val colors = if (isDarkTheme) darkColorScheme() else lightColorScheme() val dimensions = getThemeDimensions(isDarkTheme) @@ -23,7 +23,9 @@ fun Theme( ) { MaterialTheme( colorScheme = colors.material, - content = content + content = content, + shapes = Shapes, + typography = Typography, ) } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Type.kt b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Type.kt new file mode 100644 index 00000000..2306459e --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/core/presentation/theme/Type.kt @@ -0,0 +1,78 @@ +package net.opendasharchive.openarchive.core.presentation.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import net.opendasharchive.openarchive.R + +// Define Montserrat FontFamily +val MontserratFontFamily = FontFamily( + Font(R.font.montserrat_thin, FontWeight.Thin), // 100 + Font(R.font.montserrat_extra_light, FontWeight.ExtraLight), // 200 + Font(R.font.montserrat_light, FontWeight.Light), // 300 + Font(R.font.montserrat_regular, FontWeight.Normal), // 400 + Font(R.font.montserrat_medium, FontWeight.Medium), // 500 + Font(R.font.montserrat_semi_bold, FontWeight.SemiBold), // 600 + Font(R.font.montserrat_bold, FontWeight.Bold), // 700 + Font(R.font.montserrat_extra_bold, FontWeight.ExtraBold), // 800 + Font(R.font.montserrat_black, FontWeight.Black) // 900 +) + +// Define Montserrat Italic FontFamily +val MontserratItalicFontFamily = FontFamily( + Font(R.font.montserrat_thin_italic, FontWeight.Thin), // 100 + Font(R.font.montserrat_extra_light_italic, FontWeight.ExtraLight), // 200 + Font(R.font.montserrat_light_italic, FontWeight.Light), // 300 + Font(R.font.montserrat_italic, FontWeight.Normal), // 400 + Font(R.font.montserrat_medium_italic, FontWeight.Medium), // 500 + Font(R.font.montserrat_semi_bold_italic, FontWeight.SemiBold), // 600 + Font(R.font.montserrat_bold_italic, FontWeight.Bold), // 700 + Font(R.font.montserrat_extra_bold_italic, FontWeight.ExtraBold), // 800 + Font(R.font.montserrat_black_italic, FontWeight.Black) // 900 +) + + +val Typography = Typography( + headlineSmall = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 18.sp, + lineHeight = 22.sp, + fontWeight = FontWeight.SemiBold // 600 + ), + bodyLarge = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 16.sp, + lineHeight = 20.sp, + fontWeight = FontWeight.SemiBold // 600 + ), + bodyMedium = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 14.sp, + lineHeight = 16.sp, + fontWeight = FontWeight.Medium // 500 + ), + bodySmall = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 11.sp, + lineHeight = 14.sp, + fontWeight = FontWeight.Medium // 500 + ), + labelMedium = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 11.sp, + fontWeight = FontWeight.Medium // 500 + ), + titleLarge = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 22.sp, // Adjust according to UI needs + fontWeight = FontWeight.Normal // Default for TitleLarge + ), + titleMedium = TextStyle( + fontFamily = MontserratFontFamily, + fontSize = 18.sp, // Adjust according to UI needs + fontWeight = FontWeight.Medium // 500 + ) +) diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/ApiError.kt b/app/src/main/java/net/opendasharchive/openarchive/db/ApiError.kt new file mode 100644 index 00000000..cc2222ff --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/ApiError.kt @@ -0,0 +1,46 @@ +package net.opendasharchive.openarchive.db + +import kotlinx.serialization.Serializable + +@Serializable +sealed class ApiError: SerializableMarker { + @Serializable + data class HttpError(val code: Int, val message: String) : ApiError() + + @Serializable + data class NetworkError(val message: String) : ApiError() + + @Serializable + data class ServerError(val message: String) : ApiError() + + @Serializable + data class ClientError(val message: String) : ApiError() + + @Serializable + data class UnexpectedError(val message: String) : ApiError() + + @Serializable + data object Unauthorized : ApiError() + + @Serializable + data object ResourceNotFound : ApiError() + + @Serializable + data object TimedOut : ApiError() + + @Serializable + data object None : ApiError() + + val friendlyMessage: String + get() = when (this) { + is HttpError -> "HTTP Error $code: $message" + is NetworkError -> message + is ServerError -> message + is ClientError -> message + is UnexpectedError -> message + Unauthorized -> "Unauthorized: Please log in and try again" + ResourceNotFound -> "The requested resource was not found" + TimedOut -> "The request timed out" + None -> "No error" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/FileUploadResult.kt b/app/src/main/java/net/opendasharchive/openarchive/db/FileUploadResult.kt new file mode 100644 index 00000000..6f296dbb --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/FileUploadResult.kt @@ -0,0 +1,10 @@ +package net.opendasharchive.openarchive.db + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class FileUploadResult ( + var name: String, + @SerialName("updated_collection_hash") var updatedCollectionHash: String +) : SerializableMarker \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/JoinGroupResponse.kt b/app/src/main/java/net/opendasharchive/openarchive/db/JoinGroupResponse.kt new file mode 100644 index 00000000..7c26ded2 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/JoinGroupResponse.kt @@ -0,0 +1,8 @@ +package net.opendasharchive.openarchive.db + +import kotlinx.serialization.Serializable + +@Serializable +data class JoinGroupResponse( + val group: SnowbirdGroup +): SerializableMarker \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/MediaViewHolder.kt b/app/src/main/java/net/opendasharchive/openarchive/db/MediaViewHolder.kt deleted file mode 100644 index 036dea04..00000000 --- a/app/src/main/java/net/opendasharchive/openarchive/db/MediaViewHolder.kt +++ /dev/null @@ -1,429 +0,0 @@ -package net.opendasharchive.openarchive.db - -import android.annotation.SuppressLint -import android.text.format.Formatter -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.RecyclerView -import androidx.swiperefreshlayout.widget.CircularProgressDrawable -import androidx.viewbinding.ViewBinding -import com.bumptech.glide.Glide -import com.github.derlio.waveform.SimpleWaveformView -import com.github.derlio.waveform.soundfile.SoundFile -import com.google.android.material.progressindicator.CircularProgressIndicator -import com.squareup.picasso.Picasso -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.launch -import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.core.logger.AppLogger -import net.opendasharchive.openarchive.databinding.RvMediaBoxBinding -import net.opendasharchive.openarchive.databinding.RvMediaRowBigBinding -import net.opendasharchive.openarchive.databinding.RvMediaRowSmallBinding -import net.opendasharchive.openarchive.fragments.VideoRequestHandler -import net.opendasharchive.openarchive.util.extensions.hide -import net.opendasharchive.openarchive.util.extensions.show -import timber.log.Timber -import java.io.InputStream - -abstract class MediaViewHolder(protected val binding: ViewBinding) : - RecyclerView.ViewHolder(binding.root) { - - class Box(parent: ViewGroup) : MediaViewHolder( - RvMediaBoxBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) { - override val image: ImageView - get() = (binding as RvMediaBoxBinding).image - - override val waveform: SimpleWaveformView - get() = (binding as RvMediaBoxBinding).waveform - - override val videoIndicator: ImageView - get() = (binding as RvMediaBoxBinding).videoIndicator - - override val overlayContainer: View - get() = (binding as RvMediaBoxBinding).overlayContainer - - override val progress: CircularProgressIndicator - get() = (binding as RvMediaBoxBinding).progress - - override val progressText: TextView - get() = (binding as RvMediaBoxBinding).progressText - - override val error: ImageView - get() = (binding as RvMediaBoxBinding).error - - override val title: TextView? - get() = null //(binding as RvMediaBoxBinding).title - - override val fileInfo: TextView? - get() = null //(binding as RvMediaBoxBinding).fileInfo - - override val locationIndicator: ImageView? - get() = null - - override val tagsIndicator: ImageView? - get() = null - - override val descIndicator: ImageView? - get() = null - - override val flagIndicator: ImageView? - get() = null - - override val selectedIndicator: View - get() = (binding as RvMediaBoxBinding).selectedIndicator - - override val handle: ImageView? - get() = null - } - - class BigRow(parent: ViewGroup) : MediaViewHolder( - RvMediaRowBigBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) { - override val image: ImageView - get() = (binding as RvMediaRowBigBinding).image - - override val waveform: SimpleWaveformView - get() = (binding as RvMediaRowBigBinding).waveform - - override val videoIndicator: ImageView - get() = (binding as RvMediaRowBigBinding).videoIndicator - - override val overlayContainer: View? - get() = null - - override val progress: CircularProgressIndicator? - get() = null - - override val progressText: TextView? - get() = null - - override val error: ImageView? - get() = null - - override val title: TextView - get() = (binding as RvMediaRowBigBinding).title - - override val fileInfo: TextView - get() = (binding as RvMediaRowBigBinding).fileInfo - - override val locationIndicator: ImageView - get() = (binding as RvMediaRowBigBinding).locationIndicator - - override val tagsIndicator: ImageView - get() = (binding as RvMediaRowBigBinding).tagsIndicator - - override val descIndicator: ImageView - get() = (binding as RvMediaRowBigBinding).descIndicator - - override val flagIndicator: ImageView - get() = (binding as RvMediaRowBigBinding).flagIndicator - - override val selectedIndicator: View? - get() = null - - override val handle: ImageView? - get() = null - } - - class SmallRow(parent: ViewGroup) : MediaViewHolder( - RvMediaRowSmallBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) { - override val image: ImageView - get() = (binding as RvMediaRowSmallBinding).image - - override val waveform: SimpleWaveformView - get() = (binding as RvMediaRowSmallBinding).waveform - - override val videoIndicator: ImageView? - get() = null - - override val overlayContainer: View - get() = (binding as RvMediaRowSmallBinding).overlayContainer - - override val progress: CircularProgressIndicator - get() = (binding as RvMediaRowSmallBinding).progress - - override val progressText: TextView - get() = (binding as RvMediaRowSmallBinding).progressText - - override val error: ImageView - get() = (binding as RvMediaRowSmallBinding).error - - override val title: TextView - get() = (binding as RvMediaRowSmallBinding).title - - override val fileInfo: TextView - get() = (binding as RvMediaRowSmallBinding).fileInfo - - override val locationIndicator: ImageView? - get() = null - - override val tagsIndicator: ImageView? - get() = null - - override val descIndicator: ImageView? - get() = null - - override val flagIndicator: ImageView? - get() = null - - override val selectedIndicator: View? - get() = null - - override val handle: ImageView - get() = (binding as RvMediaRowSmallBinding).handle - } - - - companion object { - val soundCache = HashMap() - } - - - abstract val image: ImageView - abstract val waveform: SimpleWaveformView - abstract val videoIndicator: ImageView? - abstract val overlayContainer: View? - abstract val progress: CircularProgressIndicator? - abstract val progressText: TextView? - abstract val error: ImageView? - abstract val title: TextView? - abstract val fileInfo: TextView? - abstract val locationIndicator: ImageView? - abstract val tagsIndicator: ImageView? - abstract val descIndicator: ImageView? - abstract val flagIndicator: ImageView? - abstract val selectedIndicator: View? - abstract val handle: ImageView? - - private val mContext = itemView.context - - private val mPicasso = Picasso.Builder(mContext) - .addRequestHandler(VideoRequestHandler(mContext)) - .build() - - - @SuppressLint("SetTextI18n") - fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) { - AppLogger.i("Binding media item ${media?.id} with status ${media?.sStatus} and progress ${media?.uploadPercentage}") - itemView.tag = media?.id - - if (batchMode && media?.selected == true) { - itemView.setBackgroundResource(R.color.colorPrimary) - selectedIndicator?.show() - } else { - itemView.setBackgroundResource(R.color.transparent) - selectedIndicator?.hide() - } - - image.alpha = if (media?.sStatus == Media.Status.Uploaded || !doImageFade) 1f else 0.5f - - if (media?.mimeType?.startsWith("image") == true) { - val progress = CircularProgressDrawable(mContext) - progress.strokeWidth = 5f - progress.centerRadius = 30f - progress.start() - - Glide.with(mContext) - .load(media.fileUri) - .placeholder(progress) - .fitCenter() - .into(image) - - image.show() - waveform.hide() - videoIndicator?.hide() - } else if (media?.mimeType?.startsWith("video") == true) { - mPicasso.load(VideoRequestHandler.SCHEME_VIDEO + ":" + media.originalFilePath) - .fit() - .centerCrop() - .into(image) - - image.show() - waveform.hide() - videoIndicator?.show() - } else if (media?.mimeType?.startsWith("audio") == true) { - videoIndicator?.hide() - - val soundFile = soundCache[media.originalFilePath] - - if (soundFile != null) { - image.hide() - waveform.setAudioFile(soundFile) - waveform.show() - } else { - image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.no_thumbnail)) - image.show() - waveform.hide() - - CoroutineScope(Dispatchers.IO).launch { - @Suppress("NAME_SHADOWING") - val soundFile = try { - SoundFile.create(media.originalFilePath) { - return@create true - } - } catch (e: Throwable) { - Timber.d(e) - - null - } - - if (soundFile != null) { - soundCache[media.originalFilePath] = soundFile - - MainScope().launch { - waveform.setAudioFile(soundFile) - image.hide() - waveform.show() - } - } - } - } - } else { - image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.no_thumbnail)) - image.show() - waveform.hide() - videoIndicator?.hide() - } - - if (media != null) { - val file = media.file - - if (file.exists()) { - fileInfo?.text = Formatter.formatShortFileSize(mContext, file.length()) - } else { - if (media.contentLength == -1L) { - var iStream: InputStream? = null - try { - iStream = mContext.contentResolver.openInputStream(media.fileUri) - - if (iStream != null) { - media.contentLength = iStream.available().toLong() - media.save() - } - } catch (e: Throwable) { - Timber.e(e) - } finally { - iStream?.close() - } - } - - fileInfo?.text = if (media.contentLength > 0) { - Formatter.formatShortFileSize(mContext, media.contentLength) - } else { - media.formattedCreateDate - } - } - - fileInfo?.show() - } else { - fileInfo?.hide() - } - - val sbTitle = StringBuffer() - - if (media?.sStatus == Media.Status.Error) { - AppLogger.i("Media Item ${media.id} is error") - sbTitle.append(mContext.getString(R.string.error)) - - overlayContainer?.show() - progress?.hide() - progressText?.hide() - error?.show() - - if (media.statusMessage.isNotBlank()) { - fileInfo?.text = media.statusMessage - fileInfo?.show() - } - } else if (media?.sStatus == Media.Status.Queued) { - AppLogger.i("Media Item ${media.id} is queued") - overlayContainer?.show() - progress?.isIndeterminate = true - progress?.show() - progressText?.hide() - error?.hide() - } else if (media?.sStatus == Media.Status.Uploading) { -// val progressValue = if (media.contentLength > 0) { -// (media.progress.toFloat() / media.contentLength.toFloat() * 100f).roundToInt() -// } else 0 - progress?.isIndeterminate = false - val progressValue = media.uploadPercentage ?: 0 - AppLogger.i("Media Item ${media.id} is uploading") - - overlayContainer?.show() - progress?.show() - progressText?.show() - - // Make sure to keep spinning until the upload has made some noteworthy progress. - if (progressValue > 2) { - progress?.setProgressCompat(progressValue, true) - } -// else { -// progress?.isIndeterminate = true -// } - - progressText?.text = "${progressValue}%" - - error?.hide() - } else { - overlayContainer?.hide() - progress?.hide() - progressText?.hide() - error?.hide() - } - - if (sbTitle.isNotEmpty()) sbTitle.append(": ") - sbTitle.append(media?.title) - - if (sbTitle.isNotBlank()) { - title?.text = sbTitle.toString() - title?.show() - } else { - title?.hide() - } - - locationIndicator?.setImageResource( - if (media?.location.isNullOrBlank()) R.drawable.ic_location_unselected - else R.drawable.ic_location_selected - ) - - tagsIndicator?.setImageResource( - if (media?.tags.isNullOrBlank()) R.drawable.ic_tag_unselected - else R.drawable.ic_tag_selected - ) - - descIndicator?.setImageResource( - if (media?.description.isNullOrBlank()) R.drawable.ic_edit_unselected - else R.drawable.ic_edit_selected - ) - - flagIndicator?.setImageResource( - if (media?.flag == true) R.drawable.ic_flag_selected - else R.drawable.ic_flag_unselected - ) - } - - fun updateProgress(progressValue: Int) { - if (progressValue > 2) { - progress?.isIndeterminate = false - progress?.setProgressCompat(progressValue, true) - } else { - progress?.isIndeterminate = true - } - - AppLogger.i("Updating progressText to $progressValue%") - if (progressText == null) { - AppLogger.e("progressText is null") - } else { - progressText?.show(animate = true) - progressText?.text = "$progressValue%" - } - } -} diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/RequestNameDTO.kt b/app/src/main/java/net/opendasharchive/openarchive/db/RequestNameDTO.kt new file mode 100644 index 00000000..08146df3 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/RequestNameDTO.kt @@ -0,0 +1,9 @@ +package net.opendasharchive.openarchive.db + +import kotlinx.serialization.Serializable + +@Serializable +data class RequestName(val name: String): SerializableMarker + +@Serializable +data class MembershipRequest(val uri: String): SerializableMarker \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/SerializableMarker.kt b/app/src/main/java/net/opendasharchive/openarchive/db/SerializableMarker.kt new file mode 100644 index 00000000..a71d32d6 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/SerializableMarker.kt @@ -0,0 +1,9 @@ +package net.opendasharchive.openarchive.db + +import kotlinx.serialization.Serializable + +@Serializable +sealed interface SerializableMarker + +@Serializable +data object EmptyRequest : SerializableMarker \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdError.kt b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdError.kt new file mode 100644 index 00000000..354bbc2e --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdError.kt @@ -0,0 +1,14 @@ +package net.opendasharchive.openarchive.db + +sealed class SnowbirdError: SerializableMarker { + data class NetworkError(val code: Int, val message: String) : SnowbirdError() + data class GeneralError(val message: String) : SnowbirdError() + data object TimedOut : SnowbirdError() + + val friendlyMessage: String + get() = when (this) { + is GeneralError -> message + is NetworkError -> message + is TimedOut -> "The current operation took too long." + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdFileItem.kt b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdFileItem.kt new file mode 100644 index 00000000..c27bbe70 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdFileItem.kt @@ -0,0 +1,54 @@ +package net.opendasharchive.openarchive.db + +import android.database.sqlite.SQLiteException +import com.orm.SugarRecord +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient + +@Serializable +data class SnowbirdFileList( + var files: List +) : SerializableMarker + +@Serializable +data class SnowbirdFileItem( + var hash: String = "", + var name: String = "", + @Transient var groupKey: String = "", + @Transient var repoKey: String = "", + @SerialName("is_downloaded") var isDownloaded: Boolean = false +): SugarRecord(), SerializableMarker { + companion object { + fun clear() { + try { + deleteAll(SnowbirdFileItem::class.java) + } catch (e: SQLiteException) { + // Probably because table doesn't exist. Ignore. + } + } + + fun findBy(groupKey: String, repoKey: String): List { + val whereClause = "GROUP_KEY = ? AND REPO_KEY = ?" + val whereArgs = mutableListOf(groupKey, repoKey) + + val items = find( + SnowbirdFileItem::class.java, + whereClause, + whereArgs.toTypedArray(), + null, + null, + null) + + return items + } + } + + fun saveWith(groupKey: String, repoKey: String) { + this.groupKey = groupKey + this.repoKey = repoKey + save() + } +} + + diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdGroup.kt b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdGroup.kt new file mode 100644 index 00000000..c12a385b --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdGroup.kt @@ -0,0 +1,57 @@ +package net.opendasharchive.openarchive.db + +import android.database.sqlite.SQLiteException +import com.orm.SugarRecord +import kotlinx.serialization.Serializable + +@Serializable +data class SnowbirdGroupList( + var groups: List +) : SerializableMarker + +@Serializable +data class SnowbirdGroup( + var key: String = "", + var name: String? = null, + var uri: String? = null +) : SugarRecord(), SerializableMarker { + companion object { + fun clear() { + try { + deleteAll(SnowbirdGroup::class.java) + } catch (e: SQLiteException) { + // Probably because table doesn't exist. Ignore. + } + } + + fun getAll(): List { + return findAll(SnowbirdGroup::class.java).asSequence().toList() + } + + fun exists(name: String): Boolean { + val whereClause = "name = ?" + val whereArgs = mutableListOf(name) + + return find( + SnowbirdGroup::class.java, whereClause, whereArgs.toTypedArray(), + null, + null, + null).isNotEmpty() + } + + fun get(key: String): SnowbirdGroup? { + val whereClause = "key = ?" + val whereArgs = mutableListOf(key) + + return find( + SnowbirdGroup::class.java, whereClause, whereArgs.toTypedArray(), + null, + null, + null).firstOrNull() + } + } +} + +fun SnowbirdGroup.shortHash(): String { + return key.take(10) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdRepo.kt b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdRepo.kt new file mode 100644 index 00000000..09085fc5 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/SnowbirdRepo.kt @@ -0,0 +1,46 @@ +package net.opendasharchive.openarchive.db + +import com.orm.SugarRecord +import kotlinx.serialization.Serializable + +@Serializable +data class SnowbirdRepoList( + var repos: List +) : SerializableMarker + +@Serializable +data class SnowbirdRepo( + var key: String = "", + var name: String? = null, + var groupKey: String = "", + var permissions: String = "READ_ONLY" +) : SugarRecord(), SerializableMarker { + companion object { + fun clear(groupKey: String) { + val whereClause = "GROUP_KEY = ?" + + deleteAll(SnowbirdRepo::class.java, whereClause, groupKey) + } + + fun getAll(): List { + return findAll(SnowbirdRepo::class.java).asSequence().toList() + } + + fun getAllFor(group: SnowbirdGroup?): List { + if (group == null) return emptyList() + + val whereClause = "GROUP_KEY = ?" + val whereArgs = mutableListOf(group.key) + + return find( + SnowbirdRepo::class.java, whereClause, whereArgs.toTypedArray(), + null, + null, + null) + } + } +} + +fun SnowbirdRepo.shortHash(): String { + return key.take(10) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/Space.kt b/app/src/main/java/net/opendasharchive/openarchive/db/Space.kt index db17a30b..562c287f 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/db/Space.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/db/Space.kt @@ -6,10 +6,17 @@ import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.core.content.ContextCompat import com.github.abdularis.civ.AvatarImageView import com.orm.SugarRecord import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger import net.opendasharchive.openarchive.features.onboarding.SpaceSetupActivity import net.opendasharchive.openarchive.services.gdrive.GDriveConduit import net.opendasharchive.openarchive.services.internetarchive.IaConduit @@ -53,16 +60,20 @@ data class Space( name = IaConduit.NAME host = IaConduit.ARCHIVE_API_ENDPOINT } + Type.GDRIVE -> { name = GDriveConduit.NAME } + + Type.RAVEN -> "Raven" } } enum class Type(val id: Int, val friendlyName: String) { - WEBDAV(0, "WebDAV"), + WEBDAV(0, "Private Server"), INTERNET_ARCHIVE(1, IaConduit.NAME), GDRIVE(4, GDriveConduit.NAME), + RAVEN(5, "DWeb Service"), } enum class IconStyle { @@ -88,8 +99,10 @@ data class Space( whereArgs.add(username) } - return find(Space::class.java, whereClause, whereArgs.toTypedArray(), - null, null, null) + return find( + Space::class.java, whereClause, whereArgs.toTypedArray(), + null, null, null + ) } fun has(type: Type, host: String? = null, username: String? = null): Boolean { @@ -97,8 +110,12 @@ data class Space( } var current: Space? - get() = get(Prefs.currentSpaceId) ?: first(Space::class.java) + get() { + AppLogger.i("getting current space....") + return get(Prefs.currentSpaceId) ?: first(Space::class.java) + } set(value) { + AppLogger.i("setting current space... ${value?.displayname}") Prefs.currentSpaceId = value?.id ?: -1 } @@ -109,8 +126,7 @@ data class Space( fun navigate(activity: AppCompatActivity) { if (getAll().hasNext()) { activity.finish() - } - else { + } else { activity.finishAffinity() activity.startActivity(Intent(activity, SpaceSetupActivity::class.java)) } @@ -132,8 +148,8 @@ data class Space( val hostUrl: HttpUrl? get() = host.toHttpUrlOrNull() - var tType: Type? - get() = Type.values().firstOrNull { it.id == type } + var tType: Type + get() = Type.entries.first { it.id == type } set(value) { type = (value ?: Type.WEBDAV).id } @@ -157,28 +173,85 @@ data class Space( // } val projects: List - get() = find(Project::class.java, "space_id = ? AND NOT archived", arrayOf(id.toString()), null, "id DESC", null) + get() = find( + Project::class.java, + "space_id = ? AND NOT archived", + arrayOf(id.toString()), + null, + "id DESC", + null + ) val archivedProjects: List - get() = find(Project::class.java, "space_id = ? AND archived", arrayOf(id.toString()), null, "id DESC", null) + get() = find( + Project::class.java, + "space_id = ? AND archived", + arrayOf(id.toString()), + null, + "id DESC", + null + ) fun hasProject(description: String): Boolean { // Cannot use `count` from Kotlin due to strange in method signature. - return find(Project::class.java, "space_id = ? AND description = ?", id.toString(), description).size > 0 + return find( + Project::class.java, + "space_id = ? AND description = ?", + id.toString(), + description + ).size > 0 } fun getAvatar(context: Context, style: IconStyle = IconStyle.SOLID): Drawable? { - val color = ContextCompat.getColor(context, R.color.colorOnBackground) + return when (tType) { - Type.WEBDAV -> ContextCompat.getDrawable(context, R.drawable.ic_private_server) // ?.tint(color) + Type.WEBDAV -> ContextCompat.getDrawable( + context, + R.drawable.ic_private_server + ) // ?.tint(color) + + Type.INTERNET_ARCHIVE -> ContextCompat.getDrawable( + context, + R.drawable.ic_internet_archive + ) // ?.tint(color) + + Type.GDRIVE -> ContextCompat.getDrawable( + context, + R.drawable.logo_gdrive_outline + ) // ?.tint(color) + + Type.RAVEN -> ContextCompat.getDrawable(context, R.drawable.snowbird) // ?.tint(color) + + else -> { + val color = ContextCompat.getColor(context, R.color.colorOnBackground) + BitmapDrawable( + context.resources, + DrawableUtil.createCircularTextDrawable(initial, color) + ) + } - Type.INTERNET_ARCHIVE -> ContextCompat.getDrawable(context, R.drawable.ic_internet_archive) // ?.tint(color) + } + } - Type.GDRIVE -> ContextCompat.getDrawable(context, R.drawable.logo_gdrive_outline) // ?.tint(color) + @Composable + fun getAvatar(): Painter { - else -> BitmapDrawable(context.resources, DrawableUtil.createCircularTextDrawable(initial, color)) + return when (tType) { + Type.WEBDAV -> painterResource(R.drawable.ic_space_private_server) + Type.INTERNET_ARCHIVE -> painterResource(R.drawable.ic_space_interent_archive) + + Type.GDRIVE -> painterResource(R.drawable.logo_gdrive_outline) + + Type.RAVEN -> painterResource(R.drawable.ic_space_dweb) + null -> { + val context = LocalContext.current + val color = ContextCompat.getColor(context, R.color.colorOnBackground) + val bitmap = DrawableUtil.createCircularTextDrawable(initial, color) + val imageBitmap = bitmap.asImageBitmap() + BitmapPainter(imageBitmap) + } } } @@ -196,9 +269,9 @@ data class Space( if (view is AvatarImageView) { view.state = AvatarImageView.SHOW_INITIAL view.setText(initial) - view.avatarBackgroundColor = ContextCompat.getColor(view.context, R.color.colorPrimary) - } - else { + view.avatarBackgroundColor = + ContextCompat.getColor(view.context, R.color.colorPrimary) + } else { view.setImageDrawable(getAvatar(view.context)) } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/MediaAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/db/UploadMediaAdapter.kt similarity index 51% rename from app/src/main/java/net/opendasharchive/openarchive/db/MediaAdapter.kt rename to app/src/main/java/net/opendasharchive/openarchive/db/UploadMediaAdapter.kt index 4d1b82fd..367bd881 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/db/MediaAdapter.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/db/UploadMediaAdapter.kt @@ -1,8 +1,7 @@ package net.opendasharchive.openarchive.db -import android.annotation.SuppressLint import android.app.Activity -import android.content.Intent +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil @@ -10,38 +9,23 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.core.logger.AppLogger -import net.opendasharchive.openarchive.features.media.PreviewActivity +import net.opendasharchive.openarchive.databinding.RvMediaRowSmallBinding import net.opendasharchive.openarchive.upload.BroadcastManager -import net.opendasharchive.openarchive.upload.UploadManagerActivity -import net.opendasharchive.openarchive.upload.UploadService -import net.opendasharchive.openarchive.util.AlertHelper -import net.opendasharchive.openarchive.util.Prefs -import net.opendasharchive.openarchive.util.extensions.toggle import java.lang.ref.WeakReference -class MediaAdapter( +class UploadMediaAdapter( activity: Activity?, - private val generator: (parent: ViewGroup) -> MediaViewHolder, - data: List, + mediaItems: List, private val recyclerView: RecyclerView, - private val supportedStatuses: List = listOf( - Media.Status.Local, - Media.Status.Uploading, - Media.Status.Error - ), - private val checkSelecting: (() -> Unit)? = null -) : RecyclerView.Adapter() { - - var media: ArrayList = ArrayList(data) + private val checkSelecting: (() -> Unit)? = null, + private val onDeleteClick: (Media, Int) -> Unit, +) : RecyclerView.Adapter() { + + var media: ArrayList = ArrayList(mediaItems) private set var doImageFade = true - var isEditMode = false - - var selecting = false - private set - private var mActivity = WeakReference(activity) init { @@ -49,68 +33,25 @@ class MediaAdapter( } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaViewHolder { - val mvh = generator(parent) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UploadMediaViewHolder { + val binding = + RvMediaRowSmallBinding.inflate(LayoutInflater.from(parent.context), parent, false) + val mvh = UploadMediaViewHolder( + binding = binding, + onDeleteClick = { position -> + deleteItem(position) + } + ) mvh.itemView.setOnClickListener { v -> - if (selecting && checkSelecting != null) { - selectView(v) - } else { - val pos = recyclerView.getChildLayoutPosition(v) - - when (media[pos].sStatus) { - Media.Status.Local -> { - if (supportedStatuses.contains(Media.Status.Local)) { - mActivity.get()?.let { - PreviewActivity.start(it, media[pos].projectId) - } - } - } + val position = recyclerView.getChildLayoutPosition(v) + val item = media[position] - Media.Status.Queued, Media.Status.Uploading -> { - if (supportedStatuses.contains(Media.Status.Uploading)) { - mActivity.get()?.let { - it.startActivity( - Intent(it, UploadManagerActivity::class.java) - ) - } - } - } - - Media.Status.Error -> { - if (supportedStatuses.contains(Media.Status.Error)) { - //CleanInsightsManager.measureEvent("backend", "upload-error", media[pos].space?.friendlyName) - mActivity.get()?.let { - AlertHelper.show( - it, it.getString(R.string.upload_unsuccessful_description), - R.string.upload_unsuccessful, R.drawable.ic_error, listOf( - AlertHelper.positiveButton(R.string.retry) { _, _ -> - - media[pos].apply { - sStatus = Media.Status.Queued - statusMessage = "" - save() - - BroadcastManager.postChange(it, collectionId, id) - } - - UploadService.startUploadService(it) - }, - AlertHelper.negativeButton(R.string.remove) { _, _ -> - deleteItem(pos) - }, - AlertHelper.neutralButton() - ) - ) - } - } - } - - else -> { - if (checkSelecting != null) { - selectView(v) - } - } + if (item.sStatus == Media.Status.Error) { + onDeleteClick.invoke(item, position) + } else { + if (checkSelecting != null) { + selectView(v) } } } @@ -123,19 +64,6 @@ class MediaAdapter( } } - mvh.flagIndicator?.setOnClickListener { - showFirstTimeFlag() - - // Toggle flag - val mediaId = mvh.itemView.tag as? Long ?: return@setOnClickListener - - val item = media.firstOrNull { it.id == mediaId } ?: return@setOnClickListener - item.flag = !item.flag - item.save() - - notifyItemChanged(media.indexOf(item)) - } - return mvh } @@ -145,46 +73,50 @@ class MediaAdapter( return media[position].id } - @SuppressLint("ClickableViewAccessibility") - override fun onBindViewHolder(holder: MediaViewHolder, position: Int) { + override fun onBindViewHolder(holder: UploadMediaViewHolder, position: Int) { AppLogger.i("onBindViewHolder called for position $position") - holder.bind(media[position], selecting, doImageFade) - holder.handle?.toggle(isEditMode) + holder.bind(media[position], doImageFade) } - override fun onBindViewHolder(holder: MediaViewHolder, position: Int, payloads: MutableList) { + override fun onBindViewHolder( + holder: UploadMediaViewHolder, + position: Int, + payloads: MutableList + ) { if (payloads.isNotEmpty()) { val payload = payloads[0] when (payload) { "progress" -> { holder.updateProgress(media[position].uploadPercentage ?: 0) } + "full" -> { - holder.bind(media[position], selecting, doImageFade) - holder.handle?.toggle(isEditMode) + holder.bind(media[position], doImageFade) } } } else { - holder.bind(media[position], selecting, doImageFade) - holder.handle?.toggle(isEditMode) + holder.bind(media[position], doImageFade) } } fun updateItem(mediaId: Long, progress: Int, isUploaded: Boolean = false): Boolean { - val idx = media.indexOfFirst { it.id == mediaId } - AppLogger.i("updateItem: mediaId=$mediaId idx=$idx") - if (idx < 0) return false + val mediaIndex = media.indexOfFirst { it.id == mediaId } + AppLogger.i("updateItem: mediaId=$mediaId idx=$mediaIndex") + if (mediaIndex < 0) return false - val item = media[idx] + val item = media[mediaIndex] if (isUploaded) { item.status = Media.Status.Uploaded.id - AppLogger.i("Media item $mediaId uploaded, notifying item changed at position $idx") - notifyItemChanged(idx, "full") + AppLogger.i("Media item $mediaId uploaded, notifying item changed at position $mediaIndex") + notifyItemChanged(mediaIndex, "full") } else if (progress >= 0) { item.uploadPercentage = progress item.status = Media.Status.Uploading.id - notifyItemChanged(idx, "progress") + notifyItemChanged(mediaIndex, "progress") + } else { + item.status = Media.Status.Queued.id + notifyItemChanged(mediaIndex, "full") } return true @@ -213,15 +145,6 @@ class MediaAdapter( diffResult.dispatchUpdatesTo(this) } - private fun showFirstTimeFlag() { - if (Prefs.flagHintShown) return - val activity = mActivity.get() ?: return - - AlertHelper.show(activity, R.string.popup_flag_desc, R.string.popup_flag_title) - - Prefs.flagHintShown = true - } - private fun selectView(view: View) { val mediaId = view.tag as? Long ?: return @@ -231,12 +154,10 @@ class MediaAdapter( notifyItemChanged(media.indexOf(m)) - selecting = media.firstOrNull { it.selected } != null checkSelecting?.invoke() } fun onItemMove(oldPos: Int, newPos: Int) { - if (!isEditMode) return val mediaToMov = media.removeAt(oldPos) media.add(newPos, mediaToMov) @@ -310,8 +231,6 @@ class MediaAdapter( hasDeleted = true } - selecting = false - checkSelecting?.invoke() return hasDeleted diff --git a/app/src/main/java/net/opendasharchive/openarchive/db/UploadMediaViewHolder.kt b/app/src/main/java/net/opendasharchive/openarchive/db/UploadMediaViewHolder.kt new file mode 100644 index 00000000..f771e34b --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/db/UploadMediaViewHolder.kt @@ -0,0 +1,241 @@ +package net.opendasharchive.openarchive.db + +import android.text.format.Formatter +import android.widget.ImageView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import androidx.swiperefreshlayout.widget.CircularProgressDrawable +import com.bumptech.glide.Glide +import com.github.derlio.waveform.soundfile.SoundFile +import com.squareup.picasso.Picasso +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger +import net.opendasharchive.openarchive.databinding.RvMediaRowSmallBinding +import net.opendasharchive.openarchive.fragments.VideoRequestHandler +import net.opendasharchive.openarchive.util.extensions.hide +import net.opendasharchive.openarchive.util.extensions.show +import timber.log.Timber +import java.io.InputStream + +class UploadMediaViewHolder( + private val binding: RvMediaRowSmallBinding, + private val onDeleteClick: (Int) -> Unit +) : RecyclerView.ViewHolder(binding.root) { + + + companion object { + val soundCache = HashMap() + } + + + private val mContext = itemView.context + + private val mPicasso = Picasso.Builder(mContext) + .addRequestHandler(VideoRequestHandler(mContext)) + .build() + + init { + binding.btnDelete.setOnClickListener { + val position = bindingAdapterPosition + if (position != RecyclerView.NO_POSITION) { + onDeleteClick(position) + } + } + } + + fun bind(media: Media? = null, doImageFade: Boolean = true) { + AppLogger.i("Binding media item ${media?.id} with status ${media?.sStatus} and progress ${media?.uploadPercentage}") + itemView.tag = media?.id + + binding.image.alpha = + if (media?.sStatus == Media.Status.Uploaded || !doImageFade) 1f else 0.5f + + if (media?.mimeType?.startsWith("image") == true) { + val progress = CircularProgressDrawable(mContext) + progress.strokeWidth = 5f + progress.centerRadius = 30f + progress.start() + + Glide.with(mContext) + .load(media.fileUri) + .placeholder(progress) + .fitCenter() + .into(binding.image) + binding.image.scaleType = ImageView.ScaleType.CENTER_CROP + binding.image.show() + binding.waveform.hide() + } else if (media?.mimeType?.startsWith("video") == true) { + mPicasso.load(VideoRequestHandler.SCHEME_VIDEO + ":" + media.originalFilePath) + .fit() + .centerCrop() + .into(binding.image) + binding.image.scaleType = ImageView.ScaleType.CENTER_CROP + binding.image.show() + binding.waveform.hide() + } else if (media?.mimeType?.startsWith("audio") == true) { + + val soundFile = soundCache[media.originalFilePath] + + if (soundFile != null) { + binding.image.hide() + binding.waveform.setAudioFile(soundFile) + binding.waveform.show() + } else { + binding.image.setImageDrawable( + ContextCompat.getDrawable( + mContext, + R.drawable.no_thumbnail + ) + ) + binding.image.scaleType = ImageView.ScaleType.CENTER_CROP + binding.image.show() + binding.waveform.hide() + + CoroutineScope(Dispatchers.IO).launch { + @Suppress("NAME_SHADOWING") + val soundFile = try { + SoundFile.create(media.originalFilePath) { + return@create true + } + } catch (e: Throwable) { + Timber.d(e) + + null + } + + if (soundFile != null) { + soundCache[media.originalFilePath] = soundFile + + MainScope().launch { + binding.waveform.setAudioFile(soundFile) + binding.image.hide() + binding.waveform.show() + } + } + } + } + } else { + binding.image.setImageDrawable( + ContextCompat.getDrawable( + mContext, + R.drawable.ic_unknown_file + ) + ) + binding.image.scaleType = ImageView.ScaleType.CENTER_INSIDE + binding.image.show() + binding.waveform.hide() + } + + if (media != null) { + val file = media.file + + if (file.exists()) { + binding.fileInfo.text = Formatter.formatShortFileSize(mContext, file.length()) + } else { + if (media.contentLength == -1L) { + var iStream: InputStream? = null + try { + iStream = mContext.contentResolver.openInputStream(media.fileUri) + + if (iStream != null) { + media.contentLength = iStream.available().toLong() + media.save() + } + } catch (e: Throwable) { + Timber.e(e) + } finally { + iStream?.close() + } + } + + binding.fileInfo.text = if (media.contentLength > 0) { + Formatter.formatShortFileSize(mContext, media.contentLength) + } else { + media.formattedCreateDate + } + } + + binding.fileInfo.show() + } else { + binding.fileInfo.hide() + } + + val sbTitle = StringBuffer() + + if (media?.sStatus == Media.Status.Error) { + AppLogger.i("Media Item ${media.id} is error") + sbTitle.append(mContext.getString(R.string.error)) + + binding.overlayContainer.show() + binding.progress.hide() + binding.progressText.hide() + binding.error.show() + + if (media.statusMessage.isNotBlank()) { + binding.fileInfo.text = media.statusMessage + binding.fileInfo.show() + } + } else if (media?.sStatus == Media.Status.Queued) { + AppLogger.i("Media Item ${media.id} is queued") + binding.overlayContainer.show() + binding.progress.isIndeterminate = true + binding.progress.show() + binding.progressText.hide() + binding.error.hide() + } else if (media?.sStatus == Media.Status.Uploading) { +// val progressValue = if (media.contentLength > 0) { +// (media.progress.toFloat() / media.contentLength.toFloat() * 100f).roundToInt() +// } else 0 + binding.progress.isIndeterminate = false + val progressValue = media.uploadPercentage ?: 0 + AppLogger.i("Media Item ${media.id} is uploading") + + binding.overlayContainer.show() + binding.progress.show() + binding.progressText.show() + + // Make sure to keep spinning until the upload has made some noteworthy progress. + if (progressValue > 2) { + binding.progress.setProgressCompat(progressValue, true) + } +// else { +// progress?.isIndeterminate = true +// } + + binding.progressText.text = "${progressValue}%" + + binding.error.hide() + } else { + binding.overlayContainer.hide() + binding.progress.hide() + binding.progressText.hide() + binding.error.hide() + } + + if (sbTitle.isNotEmpty()) sbTitle.append(": ") + sbTitle.append(media?.title) + + if (sbTitle.isNotBlank()) { + binding.title.text = sbTitle.toString() + binding.title.show() + } else { + binding.title.hide() + } + } + + fun updateProgress(progressValue: Int) { + if (progressValue > 2) { + binding.progress.isIndeterminate = false + binding.progress.setProgressCompat(progressValue, true) + } else { + binding.progress.isIndeterminate = true + } + + binding.progressText.show(animate = true) + binding.progressText.text = "$progressValue%" + } +} diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/ActivityExtension.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/ActivityExtension.kt new file mode 100644 index 00000000..9a5985d0 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/ActivityExtension.kt @@ -0,0 +1,23 @@ +package net.opendasharchive.openarchive.extensions + +import android.app.Activity +import androidx.activity.OnBackPressedCallback +import androidx.fragment.app.FragmentActivity + +fun Activity.onBackButtonPressed(callback: () -> Boolean) { + (this as? FragmentActivity)?.onBackPressedDispatcher?.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + // If callback() returns false, we let the system handle back + // If callback() returns true, we override it (and do nothing else) + if (!callback()) { + remove() + this@onBackButtonPressed + .onBackPressedDispatcher + .onBackPressed() + } + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/ApplicationExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/ApplicationExtensions.kt new file mode 100644 index 00000000..b61c1b29 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/ApplicationExtensions.kt @@ -0,0 +1,22 @@ +package net.opendasharchive.openarchive.extensions + +import android.app.Application +import androidx.activity.ComponentActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.ViewModel +import org.koin.android.ext.android.getKoin +import org.koin.core.parameter.parametersOf +import org.koin.androidx.viewmodel.ext.android.viewModel + +inline fun Application.getViewModel(vararg parameters: Any): T { + return getKoin().get { parametersOf(*parameters) } +} + +inline fun Fragment.androidViewModel(): Lazy { + return viewModel { parametersOf(requireActivity().application) } +} + +inline fun ComponentActivity.androidViewModel(): Lazy { + return viewModel { parametersOf(application) } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/BottomSheetExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/BottomSheetExtensions.kt new file mode 100644 index 00000000..6a9f4f18 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/BottomSheetExtensions.kt @@ -0,0 +1,57 @@ +package net.opendasharchive.openarchive.extensions + +import android.annotation.SuppressLint +import android.content.res.Resources +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.IdRes +import androidx.annotation.LayoutRes +import androidx.fragment.app.Fragment +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import net.opendasharchive.openarchive.R + +fun Fragment.showBottomSheetDialog( + @LayoutRes layout: Int, + @IdRes textViewToSet: Int? = null, + textToSet: String? = null, + fullScreen: Boolean = true, + expand: Boolean = true +) { + val dialog = BottomSheetDialog(context!!) + dialog.setOnShowListener { + val bottomSheet: FrameLayout = dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet) ?: return@setOnShowListener + val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet) + if (fullScreen && bottomSheet.layoutParams != null) { showFullScreenBottomSheet(bottomSheet) } + + if (!expand) return@setOnShowListener + + bottomSheet.setBackgroundResource(android.R.color.transparent) + expandBottomSheet(bottomSheetBehavior) + } + + @SuppressLint("InflateParams") // dialog does not need a root view here + val sheetView = layoutInflater.inflate(layout, null) + textViewToSet?.also { + sheetView.findViewById(it).text = textToSet + } + +// sheetView.findViewById(R.id.closeButton)?.setOnClickListener { +// dialog.dismiss() +// } + + dialog.setContentView(sheetView) + dialog.show() +} + +private fun showFullScreenBottomSheet(bottomSheet: FrameLayout) { + val layoutParams = bottomSheet.layoutParams + layoutParams.height = Resources.getSystem().displayMetrics.heightPixels + bottomSheet.layoutParams = layoutParams +} + +private fun expandBottomSheet(bottomSheetBehavior: BottomSheetBehavior) { + bottomSheetBehavior.skipCollapsed = true + bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/DrawableExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/DrawableExtensions.kt new file mode 100644 index 00000000..f213f778 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/DrawableExtensions.kt @@ -0,0 +1,49 @@ +package net.opendasharchive.openarchive.extensions + +import android.content.Context +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.os.Build +import android.util.TypedValue +import androidx.core.graphics.drawable.toBitmap +import kotlin.math.max +import kotlin.math.roundToInt + +fun Drawable.scaled(biggerSideDipLength: Int, context: Context): Drawable { + val length = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + biggerSideDipLength.toFloat(), context.resources.displayMetrics) + + return scaled(length.toDouble() / max(intrinsicWidth, intrinsicHeight), context) +} + +fun Drawable.scaled(factor: Double, context: Context): Drawable { + if (factor == 1.0) return this + + return scaled((intrinsicWidth * factor).roundToInt(), + (intrinsicHeight * factor).roundToInt(), + context) +} + +fun Drawable.scaled(width: Int, height: Int, context: Context): Drawable { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + LayerDrawable(arrayOf(this)).also { + it.setLayerSize(0, width, height) + } + } + else { + BitmapDrawable(context.resources, toBitmap(width, height)) + } +} + +fun Drawable.tint(color: Int): Drawable { + colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN) + + return this +} + +fun Drawable.clone(): Drawable? { + return constantState?.newDrawable()?.mutate() +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/DurationExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/DurationExtensions.kt new file mode 100644 index 00000000..b72f01d9 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/DurationExtensions.kt @@ -0,0 +1,21 @@ +package net.opendasharchive.openarchive.extensions + +import kotlin.math.pow +import kotlin.math.round +import kotlin.time.Duration + +/** + * Formats a Duration to a string with a specified number of decimal places. + * + * @param decimals The number of decimal places to round to (default is 1). + * @return A formatted string representation of the duration in seconds, rounded to the specified number of decimal places. + */ +fun Duration.formatToDecimalPlaces(decimals: Int = 1): String { + require(decimals >= 0) { "Number of decimal places must be non-negative" } + + val seconds = this.inWholeNanoseconds / 1e9 + val factor = 10.0.pow(decimals) + val roundedSeconds = round(seconds * factor) / factor + + return "%.${decimals}f".format(roundedSeconds) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/StringExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/StringExtensions.kt new file mode 100644 index 00000000..58724054 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/StringExtensions.kt @@ -0,0 +1,71 @@ +package net.opendasharchive.openarchive.extensions + +import android.graphics.Bitmap +import android.graphics.Color +import android.util.Patterns +//import com.google.zxing.BarcodeFormat +//import com.google.zxing.EncodeHintType +//import com.google.zxing.qrcode.QRCodeWriter +import timber.log.Timber +import java.io.File +import java.io.InputStream +import java.net.URI +import java.net.URLDecoder +import java.net.URLEncoder +import java.nio.charset.StandardCharsets + +/** + * Generates a QR code bitmap from a given string. + * + * @param size The width and height of the resulting bitmap. + * @param quietZone The size of the quiet zone around the QR code (optional, default is 4). + * @return A Bitmap containing the generated QR code. + */ +fun String.asQRCode(size: Int = 512, quietZone: Int = 4): Bitmap { +// val hints = hashMapOf().apply { +// put(EncodeHintType.MARGIN, quietZone) +// } + +// val bits = QRCodeWriter().encode(this, BarcodeFormat.QR_CODE, size, size, hints) + + return Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565).also { bitmap -> + for (x in 0 until size) { + for (y in 0 until size) { + //bitmap.setPixel(x, y, if (bits[x, y]) Color.BLACK else Color.WHITE) + } + } + } +} + +fun String.createInputStream(): InputStream? { + return try { + File(this).inputStream() + } catch (e: Exception) { + Timber.e(e, "Failed to create InputStream from path: $this") + null + } +} + +fun String.getQueryParameter(paramName: String): String? { + val queryStart = this.indexOf('?') + if (queryStart == -1) return null + + val queryString = this.substring(queryStart + 1) + + return queryString.split('&') + .map { it.split('=', limit = 2) } + .find { it.size == 2 && URLDecoder.decode(it[0], StandardCharsets.UTF_8.toString()) == paramName } + ?.getOrNull(1) + ?.let { URLDecoder.decode(it, StandardCharsets.UTF_8.toString()) } +} + +fun String.isValidUrl() = Patterns.WEB_URL.matcher(this).matches() + +fun String.urlEncode(): String { + return URLEncoder.encode(this, StandardCharsets.UTF_8.toString()) +} + +fun String.uriToPath(): String { + val uri = URI(this) + return uri.path +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/SuspendableExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/SuspendableExtensions.kt new file mode 100644 index 00000000..43ebb787 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/SuspendableExtensions.kt @@ -0,0 +1,101 @@ +package net.opendasharchive.openarchive.extensions + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.services.snowbird.service.BackoffStrategy +import net.opendasharchive.openarchive.services.snowbird.service.RetryConfig +import kotlin.coroutines.cancellation.CancellationException +import kotlin.math.pow + +// Syntactic sugar +// +fun suspendToRetry(block: suspend () -> T): suspend () -> T = block + +/** + * Extension function to add retry capability to any suspend function + */ +fun (suspend () -> T).withRetry( + config: RetryConfig, + shouldRetry: (Throwable) -> Boolean = { true } +): Flow> = flow { + var attempt = 1 + + while (true) { + try { + val result: T = this@withRetry() + emit(RetryAttempt.Success(result, attempt)) + break + } catch (e: Throwable) { + if (!shouldRetry(e) || (config.maxAttempts != null && attempt >= config.maxAttempts)) { + emit(RetryAttempt.Failure(e, attempt)) + break + } + + emit(RetryAttempt.Retry(e, attempt)) + + val delay = when (val strategy = config.backoffStrategy) { + is BackoffStrategy.Linear -> { + strategy.baseDelay * attempt + } + is BackoffStrategy.Exponential -> { + (strategy.baseDelay * strategy.multiplier.pow(attempt - 1)) + .coerceAtMost(strategy.maxDelay) + } + } + + delay(delay) + attempt++ + } + } +} + +/** + * Extension function to add retry capability with lifecycle awareness + * @param scope The CoroutineScope to run within (e.g., viewModelScope) + * @param config Retry configuration + * @param shouldRetry Predicate to determine if an exception should trigger a retry + * @param onEach Optional callback for each attempt + * @return Job that can be cancelled + */ +fun (suspend () -> T).retryWithScope( + scope: CoroutineScope, + config: RetryConfig, + shouldRetry: (Throwable) -> Boolean = { true }, + onEach: (RetryAttempt) -> Unit +): Job = scope.launch(config.context ?: scope.coroutineContext) { + withRetry(config, shouldRetry) + .catch { throwable -> + // Handle cancellation explicitly + if (throwable is CancellationException) { + throw throwable + } + emit(RetryAttempt.Failure(throwable, 0)) + } + .collect { attempt -> + onEach(attempt) + } +} + +/** + * Interface to ensure type safety for successful results + */ +interface RetryResult { + val result: T + val attempt: Int +} + +/** + * Represents the state of a retry attempt + */ +sealed interface RetryAttempt { + val attempt: Int + + data class Success(override val result: T, override val attempt: Int) : RetryAttempt, RetryResult + data class Failure(val error: Throwable, override val attempt: Int) : RetryAttempt + data class Retry(val error: Throwable, override val attempt: Int) : RetryAttempt +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/ThrowableExceptions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/ThrowableExceptions.kt new file mode 100644 index 00000000..34fb9a23 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/ThrowableExceptions.kt @@ -0,0 +1,16 @@ +package net.opendasharchive.openarchive.extensions + +import net.opendasharchive.openarchive.db.SnowbirdError +import retrofit2.HttpException +import java.net.SocketTimeoutException + +fun Throwable.toSnowbirdError(): SnowbirdError { + return when (this) { + is HttpException -> SnowbirdError.NetworkError( + code = response()?.code() ?: 0, + message = message() ?: "HTTP Error" + ) + is SocketTimeoutException -> SnowbirdError.TimedOut + else -> SnowbirdError.GeneralError(message ?: "Unknown error occurred") + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/UriExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/UriExtensions.kt new file mode 100644 index 00000000..f3e17391 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/UriExtensions.kt @@ -0,0 +1,33 @@ +package net.opendasharchive.openarchive.extensions + +import android.content.Context +import android.net.Uri +import android.provider.OpenableColumns +import java.io.InputStream + +fun Uri.createInputStream(applicationContext: Context): InputStream? { + return applicationContext.contentResolver.openInputStream(this) +} + +fun Uri.getFilename(applicationContext: Context): String? { + var result: String? = null + if (this.scheme == "content") { + val cr = applicationContext.contentResolver.query(this, null, null, null, null) + cr.use { cursor -> + if (cursor != null && cursor.moveToFirst()) { + val columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (columnIndex != -1) { + result = cursor.getString(columnIndex) + } + } + } + } + if (result == null) { + result = this.path + val cut = result?.lastIndexOf('/') + if (cut != -1) { + result = result?.substring(cut!! + 1) + } + } + return result +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/extensions/ViewExtension.kt b/app/src/main/java/net/opendasharchive/openarchive/extensions/ViewExtension.kt index fe485e35..fe359428 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/extensions/ViewExtension.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/extensions/ViewExtension.kt @@ -1,10 +1,103 @@ package net.opendasharchive.openarchive.extensions +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.content.Context import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import com.google.android.material.snackbar.Snackbar +private object ViewHelper { + const val ANIMATION_DURATION: Long = 250 // ms + + fun hide(view: View, visibility: Int, animate: Boolean) { + if (animate && view.isVisible) { + view.animate() + .alpha(0f) + .setDuration(ANIMATION_DURATION) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + view.visibility = visibility + view.alpha = 1f + + view.animate().setListener(null) + } + }) + } + else { + view.visibility = visibility + } + } +} + + +fun View.show(animate: Boolean = false) { + if (isVisible) return + + if (animate) { + alpha = 0f + visibility = View.VISIBLE + + animate().alpha(1f).duration = ViewHelper.ANIMATION_DURATION + } + else { + visibility = View.VISIBLE + } +} + +fun View.hide(animate: Boolean = false) { + ViewHelper.hide(this, View.GONE, animate) +} + +fun View.cloak(animate: Boolean = false) { + ViewHelper.hide(this, View.INVISIBLE, animate) +} + +fun View.toggle(state: Boolean? = null, animate: Boolean = false) { + if (state ?: !isVisible) { + show(animate) + } + else { + hide(animate) + } +} + +fun View.disableAnimation(around: () -> Unit) { + val p = parent as? ViewGroup + + val original = p?.layoutTransition + p?.layoutTransition = null + + around() + + p?.layoutTransition = original +} + +val View.isVisible: Boolean + get() = visibility == View.VISIBLE + +fun View.makeSnackBar(message: CharSequence, duration: Int = Snackbar.LENGTH_INDEFINITE): Snackbar { + return Snackbar.make(this, message, duration) +} fun View.getMeasurments(): Pair { measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) val width = measuredWidth val height = measuredHeight return width to height +} + +fun View.propagateClickToParent() { + var parent = this.parent as? View + while (parent != null && !parent.isClickable) { + parent = parent.parent as? View + } + parent?.performClick() +} + +fun View.showKeyboard() { + if (requestFocus()) { + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager + imm?.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/Accordion.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/Accordion.kt new file mode 100644 index 00000000..3037a3da --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/Accordion.kt @@ -0,0 +1,171 @@ +package net.opendasharchive.openarchive.features.core + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.EnterExitState +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.expandVertically +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.ripple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription + +@Composable +fun Accordion( + modifier: Modifier = Modifier, + headerModifier: Modifier = Modifier, + state: AccordionState = rememberAccordionState(), + animate: Boolean = true, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + headerContent: @Composable () -> Unit, + bodyContent: @Composable () -> Unit, +) { + val expanded = state.expanded + + val clickableModifier = + if (state.clickable) { + Modifier.clickable( + enabled = state.enabled, + interactionSource = interactionSource, + indication = ripple(), + onClick = { state.toggle() }, + ) + } else { + Modifier + } + + Column(modifier = modifier) { + Box( + modifier = + Modifier + .fillMaxWidth() + .semantics { + role = Role.Button + stateDescription = if (expanded) "Expanded" else "Collapsed" + } + .then(headerModifier) + .then(clickableModifier), + ) { + headerContent() + } + + if (animate) { + AnimatedVisibility( + visible = expanded, + enter = expandVertically(), + exit = shrinkVertically(), + ) { + val progress by transition.animateFloat(label = "accordion transition") { state -> + if (state == EnterExitState.Visible) 1f else 0f + } + + state.updateProgress(progress) + + bodyContent() + } + } else { + if (expanded) { + bodyContent() + } + } + } +} + +@Composable +fun rememberAccordionState( + expanded: Boolean = false, + enabled: Boolean = true, + clickable: Boolean = true, + onExpandedChange: ((Boolean) -> Unit)? = null, +) = remember { + AccordionState(expanded, enabled, clickable, onExpandedChange) +} + +class AccordionState( + expanded: Boolean = false, + var enabled: Boolean = true, + var clickable: Boolean = true, + var onExpandedChange: ((Boolean) -> Unit)? = null, +) { + var expanded by mutableStateOf(expanded) + private set + + var animationProgress by mutableFloatStateOf(0f) + private set + + fun toggle() { + if (!enabled) return + expanded = !expanded + onExpandedChange?.invoke(expanded) + } + + fun updateProgress(progress: Float) { + animationProgress = progress + } + + fun collapse() { + expanded = false + } +} + +@Composable +fun rememberAccordionGroupState( + count: Int, + allowMultipleOpen: Boolean = false, +): AccordionGroupState { + return remember { AccordionGroupState(count, allowMultipleOpen) } +} + +class AccordionGroupState( + count: Int, + private val allowMultipleOpen: Boolean, +) { + private val states = List(count) { AccordionState() } + private var openedIndex by mutableIntStateOf(-1) + + fun getState(index: Int): AccordionState { + val state = states[index] + state.onExpandedChange = { isExpanded -> + if (allowMultipleOpen) { + if (!isExpanded && openedIndex == index) { + openedIndex = -1 + } + } else { + if (isExpanded) { + openedIndex = index + states.forEachIndexed { i, otherState -> + if (i != index) otherState.collapse() + } + } else if (openedIndex == index) { + openedIndex = -1 + } + } + } + return state + } + + fun collapseAll() { + states.forEach { it.collapse() } + openedIndex = -1 + } + + fun expand(index: Int) { + if (index in states.indices) { + states[index].toggle() + } + } +} diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseActivity.kt index cafc804b..260e885c 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseActivity.kt @@ -1,16 +1,64 @@ package net.opendasharchive.openarchive.features.core import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity +import androidx.compose.ui.platform.ComposeView +import com.google.android.material.appbar.MaterialToolbar +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme +import net.opendasharchive.openarchive.features.core.dialog.DialogHost +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager import net.opendasharchive.openarchive.util.Prefs +import org.koin.androidx.compose.koinViewModel +import org.koin.androidx.viewmodel.ext.android.viewModel abstract class BaseActivity : AppCompatActivity() { + val dialogManager: DialogStateManager by viewModel() + companion object { const val EXTRA_DATA_SPACE = "space" } + override fun setContentView(layoutResID: Int) { + super.setContentView(layoutResID) + ensureComposeDialogHost() + } + + override fun setContentView(view: View?) { + super.setContentView(view) + ensureComposeDialogHost() + } + + fun ensureComposeDialogHost() { + // Get root view of the window + val rootView = findViewById(android.R.id.content) + + // Add ComposeView if not already present + if (rootView.findViewById(R.id.compose_dialog_host) == null) { + ComposeView(this).apply { + id = R.id.compose_dialog_host + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + + rootView.addView(this) + + setContent { + SaveAppTheme { + // Get ViewModel scoped to this activity + val dialogManager: DialogStateManager = koinViewModel() + DialogHost(dialogStateManager = dialogManager) + } + } + } + } + } + override fun dispatchTouchEvent(event: MotionEvent?): Boolean { if (event != null) { val obscuredTouch = event.flags and MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED != 0 @@ -39,4 +87,26 @@ abstract class BaseActivity : AppCompatActivity() { window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) } } + + fun setupToolbar( + title: String = "", + subtitle: String? = null, + showBackButton: Boolean = true + ) { + val toolbar: MaterialToolbar = findViewById(R.id.common_toolbar) + setSupportActionBar(toolbar) + supportActionBar?.title = title + + if (subtitle != null) { + supportActionBar?.subtitle = subtitle + } + + if (showBackButton) { + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_ios) + toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } + } else { + supportActionBar?.setDisplayHomeAsUpEnabled(false) + } + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseButton.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseButton.kt new file mode 100644 index 00000000..c5d78c22 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseButton.kt @@ -0,0 +1,150 @@ +package net.opendasharchive.openarchive.features.core + +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import net.opendasharchive.openarchive.core.presentation.theme.DefaultBoxPreview + +@Composable +fun BaseButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + backgroundColor: Color = MaterialTheme.colorScheme.tertiary, + textColor: Color = MaterialTheme.colorScheme.onPrimary, + cornerRadius: Dp = 12.dp, +) { + + Button( + modifier = modifier, + onClick = onClick, + colors = ButtonDefaults.buttonColors( + containerColor = backgroundColor, + contentColor = textColor + ), + shape = RoundedCornerShape(cornerRadius), + contentPadding = PaddingValues(horizontal = 12.dp, vertical = 12.dp) + ) { + ButtonText(text, color = textColor) + } +} + +@Composable +fun BaseNeutralButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + textColor: Color = MaterialTheme.colorScheme.onPrimary, +) { + + TextButton( + modifier = modifier, + onClick = onClick, + ) { + ButtonText(text, color = textColor) + } +} + +@Composable +fun BaseDestructiveButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + borderColor: Color = MaterialTheme.colorScheme.error, + textColor: Color = MaterialTheme.colorScheme.error, + cornerRadius: Dp = 12.dp, +) { + + OutlinedButton( + modifier = modifier, + onClick = onClick, + shape = RoundedCornerShape(cornerRadius), + border = BorderStroke( + width = 1.dp, + color = borderColor + ), + ) { + ButtonText( + text, + color = textColor + ) + } +} + + +@Composable +fun ButtonText( + text: String, + modifier: Modifier = Modifier, + fontSize: TextUnit = 16.sp, + fontWeight: FontWeight = FontWeight.SemiBold, + color: Color = MaterialTheme.colorScheme.onPrimary +) { + Text( + modifier = modifier, + text = text, + style = MaterialTheme.typography.bodyLarge.copy( + fontSize = fontSize, + fontWeight = fontWeight, + color = color + )) +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun CustomButtonPreview() { + DefaultBoxPreview { + + BaseButton( + text = "Submit", + onClick = {}, + modifier = Modifier.fillMaxWidth(), + ) + } +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun CustomNeutralButtonPreview() { + DefaultBoxPreview { + + BaseNeutralButton( + text = "Cancel", + onClick = {}, + modifier = Modifier.fillMaxWidth(), + ) + } +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun CustomDestructiveButtonPreview() { + DefaultBoxPreview { + + BaseDestructiveButton( + text = "Delete", + onClick = {}, + modifier = Modifier.fillMaxWidth(), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseComposeActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseComposeActivity.kt new file mode 100644 index 00000000..ad69572e --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseComposeActivity.kt @@ -0,0 +1,56 @@ +package net.opendasharchive.openarchive.features.core + +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.ui.platform.ComposeView +import com.google.android.material.appbar.MaterialToolbar +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme +import net.opendasharchive.openarchive.features.core.dialog.DialogHost +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager +import net.opendasharchive.openarchive.util.Prefs +import org.koin.androidx.compose.koinViewModel +import org.koin.androidx.viewmodel.ext.android.viewModel + +abstract class BaseComposeActivity : AppCompatActivity() { + + val dialogManager: DialogStateManager by viewModel() + + companion object { + const val EXTRA_DATA_SPACE = "space" + } + + + + override fun dispatchTouchEvent(event: MotionEvent?): Boolean { + if (event != null) { + val obscuredTouch = event.flags and MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED != 0 + if (obscuredTouch) return false + } + + return super.dispatchTouchEvent(event) + } + + override fun onResume() { + super.onResume() + + // updating this in onResume (previously was in onCreate) to make sure setting changes get + // applied instantly instead after the next app restart + updateScreenshotPrevention() + } + + fun updateScreenshotPrevention() { + if (Prefs.passcodeEnabled || Prefs.prohibitScreenshots) { + // Prevent screenshots and recent apps preview + window.setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE + ) + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseFragment.kt new file mode 100644 index 00000000..18a80906 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/BaseFragment.kt @@ -0,0 +1,68 @@ +package net.opendasharchive.openarchive.features.core + +import android.content.Context +import android.os.Bundle +import android.view.View +import android.view.inputmethod.InputMethodManager +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.extensions.androidViewModel +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.onboarding.SpaceSetupActivity +import net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupViewModel +import net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoViewModel +import net.opendasharchive.openarchive.util.FullScreenOverlayManager + +abstract class BaseFragment : Fragment(), ToolbarConfigurable { + + protected val dialogManager: DialogStateManager by activityViewModels() + + val snowbirdGroupViewModel: SnowbirdGroupViewModel by androidViewModel() + val snowbirdRepoViewModel: SnowbirdRepoViewModel by androidViewModel() + + val isJetpackNavigation: Boolean + get() { + val parentFragmentManager = parentFragmentManager + return parentFragmentManager.findFragmentById(R.id.space_nav_host_fragment) != null + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ensureComposeDialogHost() + } + + private fun ensureComposeDialogHost() { + (requireActivity() as? BaseActivity)?.ensureComposeDialogHost() + } + + open fun dismissKeyboard(view: View) { + val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, 0) + } + + open fun handleError(error: SnowbirdError) { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + title = UiText.DynamicString("Oops") + message = UiText.DynamicString(error.friendlyMessage) + positiveButton { + text = UiText.StringResource(R.string.lbl_ok) + } + } + } + + open fun handleLoadingStatus(isLoading: Boolean) { + if (isLoading) { + FullScreenOverlayManager.show(this@BaseFragment) + } else { + FullScreenOverlayManager.hide() + } + } + + override fun onResume() { + super.onResume() + (activity as? SpaceSetupActivity)?.updateToolbarFromFragment(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/ToolbarConfigurable.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/ToolbarConfigurable.kt new file mode 100644 index 00000000..403a6750 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/ToolbarConfigurable.kt @@ -0,0 +1,7 @@ +package net.opendasharchive.openarchive.features.core + +interface ToolbarConfigurable { + fun getToolbarTitle(): String + fun getToolbarSubtitle(): String? = null + fun shouldShowBackButton(): Boolean = true +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/UiImage.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/UiImage.kt new file mode 100644 index 00000000..04e5a5f4 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/UiImage.kt @@ -0,0 +1,54 @@ +package net.opendasharchive.openarchive.features.core + +import androidx.annotation.DrawableRes +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource + +sealed class UiImage { + data class DynamicVector(val vector: ImageVector) : UiImage() + data class DrawableResource(@DrawableRes val resId: Int) : UiImage() + + + /** + * Resolve UiImage into a Composable function that returns an Icon/Image + * Instead of directly rendering inside, this provides flexibility for additional customizations. + */ + @Composable + fun asIcon( + contentDescription: String? = null, + tint: Color? = null, + modifier: Modifier = Modifier + ): @Composable () -> Unit { + return { + when (this) { + is DynamicVector -> Icon( + imageVector = vector, + contentDescription = contentDescription, + modifier = modifier, + tint = tint ?: Color.Unspecified + ) + + is DrawableResource -> Icon( + painter = painterResource(id = resId), + contentDescription = contentDescription, + modifier = modifier, + tint = tint ?: Color.Unspecified + ) + } + } + } + +} + + +fun @receiver:DrawableRes Int.asUiImage(): UiImage.DrawableResource { + return UiImage.DrawableResource(this) +} + +fun ImageVector.asUiImage(): UiImage { + return UiImage.DynamicVector(this) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/UiText.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/UiText.kt new file mode 100644 index 00000000..68bf024f --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/UiText.kt @@ -0,0 +1,34 @@ +package net.opendasharchive.openarchive.features.core + +import androidx.annotation.StringRes +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource + +sealed class UiText { + + data class DynamicString(val value: String) : UiText() + data class StringResource(@StringRes val resId: Int) : UiText() + + fun asString(context: android.content.Context): String { + return when (this) { + is DynamicString -> value + is StringResource -> context.getString(resId) + } + } + + @Composable + fun asString(): String { + return when (this) { + is DynamicString -> value + is StringResource -> stringResource(resId) + } + } +} + +fun @receiver:StringRes Int.asUiText(): UiText { + return UiText.StringResource(this) +} + +fun String.asUiText(): UiText { + return UiText.DynamicString(this) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/dialog/BaseDialog.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/dialog/BaseDialog.kt new file mode 100644 index 00000000..b5ffaf2c --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/dialog/BaseDialog.kt @@ -0,0 +1,311 @@ +package net.opendasharchive.openarchive.features.core.dialog + +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.ErrorOutline +import androidx.compose.material.icons.filled.Warning +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Checkbox +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.lifecycle.ViewModel +import net.opendasharchive.openarchive.core.presentation.theme.DefaultBoxPreview +import net.opendasharchive.openarchive.features.core.BaseButton +import net.opendasharchive.openarchive.features.core.BaseDestructiveButton +import net.opendasharchive.openarchive.features.core.BaseNeutralButton +import net.opendasharchive.openarchive.features.core.UiImage +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.asUiImage + +@Composable +fun BaseDialog( + onDismiss: () -> Unit, + icon: UiImage? = null, + iconColor: Color? = null, + title: String, + message: String, + hasCheckbox: Boolean = false, + onCheckBoxStateChanged: (Boolean) -> Unit = {}, + checkBoxHint: String = "Do not show me this again", + positiveButton: ButtonData? = null, + neutralButton: ButtonData? = null, + destructiveButton: ButtonData? = null, + backgroundColor: Color = MaterialTheme.colorScheme.surface +) { + + val (isCheckedState, setCheckedState) = remember { mutableStateOf(false) } + + Dialog( + onDismissRequest = { onDismiss.invoke() }, + properties = DialogProperties( + dismissOnBackPress = true, + dismissOnClickOutside = true, + usePlatformDefaultWidth = true + ) + ) { + Card( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp), + elevation = CardDefaults.cardElevation( + defaultElevation = 4.dp + ), + colors = CardDefaults.cardColors( + containerColor = backgroundColor + ) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, top = 18.dp, bottom = 12.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + + icon?.let { icon -> + icon.asIcon( + contentDescription = null, + modifier = Modifier.size(30.dp), + tint = iconColor ?: Color.Unspecified + ).invoke() + + Spacer(modifier = Modifier.height(8.dp)) + } + + BaseDialogTitle(title) + + Spacer(Modifier.height(4.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + BaseDialogMessage(message) + } + + if (hasCheckbox) { + Spacer(Modifier.height(8.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = isCheckedState, + onCheckedChange = { isChecked -> + setCheckedState(isChecked) + onCheckBoxStateChanged.invoke(isChecked) + } + ) + + BaseDialogMessage(checkBoxHint) + } + + } + + Spacer(Modifier.height(24.dp)) + + positiveButton?.let { btn -> + Spacer(Modifier.height(4.dp)) + BaseButton( + modifier = Modifier.fillMaxWidth(), + text = btn.text.asString(), + onClick = { + btn.action() + onDismiss() + }) + } + + destructiveButton?.let { btn -> + Spacer(modifier = Modifier.height(4.dp)) + BaseDestructiveButton( + modifier = Modifier.fillMaxWidth(), + onClick = { + btn.action() + onDismiss() + }, + text = btn.text.asString() + ) + } + + neutralButton?.let { btn -> + Spacer(modifier = Modifier.height(4.dp)) + BaseNeutralButton( + modifier = Modifier.fillMaxWidth(), + text = btn.text.asString(), + onClick = { + btn.action() + onDismiss() + }) + } + } + + } + + + + } +} + +@Composable +fun BaseDialogTitle( + text: String, + modifier: Modifier = Modifier +) { + Text( + text = text, + style = MaterialTheme.typography.headlineSmall.copy( + fontSize = 18.sp, + fontWeight = FontWeight.Bold + ), + modifier = modifier + ) +} + +@Composable +fun BaseDialogMessage( + text: String, + modifier: Modifier = Modifier +) { + Text( + text = text, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.bodyMedium.copy( + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + ), + modifier = modifier + ) +} + + +class DialogStateManager(private val resourceProvider: ResourceProvider) : ViewModel() { + private val _dialogConfig = mutableStateOf(null) + val dialogConfig: State = _dialogConfig + + fun showDialog(config: DialogConfig) { + _dialogConfig.value = config + } + + fun dismissDialog() { + _dialogConfig.value = null + } + + /** + * Helper to get the ResourceProvider. This will throw if one wasn’t provided. + */ + fun requireResourceProvider(): ResourceProvider = + resourceProvider + + + override fun onCleared() { + super.onCleared() + } +} + +@Composable +fun DialogHost(dialogStateManager: DialogStateManager) { + val currentDialog by dialogStateManager.dialogConfig + + currentDialog?.let { config -> + BaseDialog( + onDismiss = { + dialogStateManager.dismissDialog() + }, + icon = config.icon, + iconColor = config.iconColor, + title = config.title.asString(), + message = config.message.asString(), + positiveButton = config.positiveButton, + neutralButton = config.neutralButton, + destructiveButton = config.destructiveButton, + hasCheckbox = config.showCheckbox, + onCheckBoxStateChanged = { config.onCheckboxChanged(it) }, + checkBoxHint = config.checkboxText?.asString() ?: "", + ) + } +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun BaseDialogPreview() { + DefaultBoxPreview { + + BaseDialog( + onDismiss = {}, + icon = Icons.Filled.Check.asUiImage(), + iconColor = MaterialTheme.colorScheme.tertiary, + title = "Success", + message = "You have added a folder successfully", + positiveButton = ButtonData(UiText.DynamicString("OK")), + ) + + } +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun WarningDialogPreview() { + DefaultBoxPreview { + + BaseDialog( + onDismiss = {}, + icon = Icons.Default.Warning.asUiImage(), + iconColor = MaterialTheme.colorScheme.tertiary, + title = "Warning", + message = "Once uploaded, you will not be able to edit media", + positiveButton = ButtonData(UiText.DynamicString("OK")), + neutralButton = ButtonData(UiText.DynamicString("Cancel")), + hasCheckbox = true, + checkBoxHint = "Do not show me this again", + onCheckBoxStateChanged = { }, + ) + } +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun ErrorDialogPreview() { + DefaultBoxPreview { + + BaseDialog( + onDismiss = {}, + icon = Icons.Default.ErrorOutline.asUiImage(), + iconColor = MaterialTheme.colorScheme.error, + title = "Image upload unsuccessful", + message = "Give a reason here? Lorem Ipsum text can go here if needed", + positiveButton = ButtonData(UiText.DynamicString("Retry")), + destructiveButton = ButtonData(UiText.DynamicString("Remove Image")), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/core/dialog/DialogConfigBuilder.kt b/app/src/main/java/net/opendasharchive/openarchive/features/core/dialog/DialogConfigBuilder.kt new file mode 100644 index 00000000..f02f6e45 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/core/dialog/DialogConfigBuilder.kt @@ -0,0 +1,416 @@ +package net.opendasharchive.openarchive.features.core.dialog + +import android.content.Context +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.Warning +import androidx.compose.material.icons.outlined.Error +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.features.core.UiImage +import net.opendasharchive.openarchive.features.core.UiText + +// -------------------------------------------------------------------- +// 1. Dialog Types +// -------------------------------------------------------------------- +enum class DialogType { + Success, Error, Warning, Info, Custom +} + +// -------------------------------------------------------------------- +// 2. The unified dialog configuration model. +// -------------------------------------------------------------------- +data class DialogConfig( + val type: DialogType, + val title: UiText, + val message: UiText, + val icon: UiImage? = null, + val iconColor: Color? = null, + val positiveButton: ButtonData? = null, + val neutralButton: ButtonData? = null, + val destructiveButton: ButtonData? = null, + val showCheckbox: Boolean = false, + val checkboxText: UiText? = null, + val onCheckboxChanged: (Boolean) -> Unit = {}, + val backgroundColor: Color? = null, + val cornerRadius: Dp? = null, + val onDismissAction: (() -> Unit)? = null, +) + +// -------------------------------------------------------------------- +// 3. Button configuration +// -------------------------------------------------------------------- +data class ButtonData( + val text: UiText, + val action: () -> Unit = {}, +) + +// -------------------------------------------------------------------- +// 4. DSL marker and ButtonBuilder DSL +// -------------------------------------------------------------------- +@DslMarker +annotation class DialogDsl + +@DialogDsl +class ButtonBuilder { + var text: UiText? = null + var action: () -> Unit = {} + + fun build(defaultText: UiText): ButtonData = + ButtonData(text = text ?: defaultText, action = action) +} + +// -------------------------------------------------------------------- +// 5. DSL Builder for DialogConfig +// -------------------------------------------------------------------- +@DialogDsl +class DialogBuilder { + // Basic settings + var type: DialogType = DialogType.Info + var icon: UiImage? = null + var title: UiText? = null + var message: UiText? = null + var iconColor: Color? = null + var backgroundColor: Color? = null + var cornerRadius: Dp? = null + + // Buttons (initially null) + private var _positiveButton: ButtonData? = null + private var _neutralButton: ButtonData? = null + private var _destructiveButton: ButtonData? = null + + // Checkbox options + var showCheckbox: Boolean = false + var checkboxText: UiText? = null + var onCheckboxChanged: (Boolean) -> Unit = {} + + private var _onDismissAction: (() -> Unit)? = null + + // Button DSL functions – simple and concise + fun positiveButton(block: ButtonBuilder.() -> Unit) { + _positiveButton = ButtonBuilder().apply(block) + .build(defaultText = defaultPositiveTextFor(type)) + } + + fun neutralButton(block: ButtonBuilder.() -> Unit) { + _neutralButton = ButtonBuilder().apply(block) + .build(defaultText = defaultNeutralText()) + } + + fun destructiveButton(block: ButtonBuilder.() -> Unit) { + _destructiveButton = ButtonBuilder().apply(block) + .build(defaultText = defaultDestructiveText()) + } + + // Default texts based on type. + private fun defaultPositiveTextFor(type: DialogType): UiText = when (type) { + DialogType.Success -> UiText.StringResource(R.string.lbl_ok) + DialogType.Error -> UiText.StringResource(R.string.retry) + DialogType.Warning -> UiText.StringResource(R.string.lbl_ok) + DialogType.Info -> UiText.StringResource(R.string.lbl_got_it) + DialogType.Custom -> UiText.StringResource(R.string.lbl_ok) + } + private fun defaultNeutralText(): UiText = UiText.StringResource(R.string.lbl_Cancel) + private fun defaultDestructiveText(): UiText = UiText.StringResource(R.string.lbl_Cancel) + + // ------------------------------- + // 5a. Compose build() – use MaterialTheme defaults. + // ------------------------------- + @Composable + fun build(): DialogConfig { + + if (icon == null) { + icon = when (type) { + DialogType.Success -> UiImage.DrawableResource(R.drawable.ic_done) + DialogType.Error -> UiImage.DynamicVector(Icons.Outlined.Error) + DialogType.Warning -> UiImage.DynamicVector(Icons.Default.Warning) + DialogType.Info -> UiImage.DynamicVector(Icons.Filled.Info) + DialogType.Custom -> null + } + } + + val finalIconColor = iconColor ?: when (type) { + DialogType.Error -> MaterialTheme.colorScheme.error + else -> MaterialTheme.colorScheme.primary + } + val finalBackgroundColor = backgroundColor ?: MaterialTheme.colorScheme.surfaceVariant + val finalCornerRadius = cornerRadius ?: 12.dp + val finalTitle = title ?: when (type) { + DialogType.Success -> UiText.StringResource(R.string.label_success_title) + DialogType.Error -> UiText.StringResource(R.string.error) + DialogType.Warning -> UiText.StringResource(R.string.label_warning_title) + DialogType.Info -> UiText.StringResource(R.string.label_info_title) + DialogType.Custom -> UiText.DynamicString("") + } + + return DialogConfig( + type = type, + title = finalTitle, + message = message ?: UiText.DynamicString(""), + icon = icon, + iconColor = finalIconColor, + positiveButton = _positiveButton, //?: ButtonData(defaultPositiveTextFor(type)), + neutralButton = _neutralButton, + destructiveButton = _destructiveButton, + showCheckbox = showCheckbox, + checkboxText = checkboxText, + onCheckboxChanged = onCheckboxChanged, + backgroundColor = finalBackgroundColor, + cornerRadius = finalCornerRadius, + onDismissAction = _onDismissAction + ) + } + + // ------------------------------- + // 5b. View build() – use ContextCompat to get resource colors. + // ------------------------------- + fun build(resourceProvider: ResourceProvider): DialogConfig { + + if (icon == null) { + + icon = when (type) { + DialogType.Success -> UiImage.DrawableResource(R.drawable.ic_done) + DialogType.Error -> UiImage.DynamicVector(Icons.Outlined.Error) + DialogType.Warning -> UiImage.DynamicVector(Icons.Default.Warning) + DialogType.Info -> UiImage.DynamicVector(Icons.Filled.Info) + DialogType.Custom -> null + } + } + + // Convert resource colors (ints) to Compose Colors. + val finalIconColor = iconColor ?: when (type) { + DialogType.Error -> resourceProvider.getColor(R.color.colorError) + else -> resourceProvider.getColor(R.color.colorPrimary) + } + val finalBackgroundColor = backgroundColor ?: resourceProvider.getColor(R.color.colorSurface) + val finalCornerRadius = cornerRadius ?: 12.dp + val finalTitle = title ?: when (type) { + DialogType.Success -> UiText.StringResource(R.string.label_success_title) + DialogType.Error -> UiText.StringResource(R.string.error) + DialogType.Warning -> UiText.StringResource(R.string.label_warning_title) + DialogType.Info -> UiText.StringResource(R.string.label_info_title) + DialogType.Custom -> UiText.DynamicString("") + } + + return DialogConfig( + type = type, + title = finalTitle, + message = message ?: UiText.DynamicString(""), + icon = icon, + iconColor = finalIconColor, + positiveButton = _positiveButton, //?: ButtonData(defaultPositiveTextFor(type)), + neutralButton = _neutralButton, + destructiveButton = _destructiveButton, + showCheckbox = showCheckbox, + checkboxText = checkboxText, + onCheckboxChanged = onCheckboxChanged, + backgroundColor = finalBackgroundColor, + cornerRadius = finalCornerRadius + ) + } +} + +// -------------------------------------------------------------------- +// 6. Extension functions on DialogStateManager for showing dialogs +// -------------------------------------------------------------------- + +// --- Compose extension: allows calling showDialog { ... } in a @Composable block. +@Composable +fun DialogStateManager.showDialog(block: DialogBuilder.() -> Unit) { + val config = DialogBuilder().apply(block).build() + showDialog(config) +} + +// --- View extension: pass a Context so that resource colors are used. +fun DialogStateManager.showDialog(resourceProvider: ResourceProvider = this.requireResourceProvider(), block: DialogBuilder.() -> Unit) { + val config = DialogBuilder().apply(block).build(resourceProvider) + showDialog(config) +} + + +// -------------------------------------------------------------------- +// 7. Helper functions for common dialog types +// -------------------------------------------------------------------- + +// Compose helper for a success dialog. +@Composable +fun DialogStateManager.showSuccessDialog( + message: String, + title: String = "", // if empty, default title is used + onPositive: () -> Unit = {} +) { + showDialog { + type = DialogType.Success + this.message = UiText.DynamicString(message) + if (title.isNotEmpty()) this.title = UiText.DynamicString(title) + positiveButton { + text = UiText.StringResource(R.string.lbl_ok) + action = onPositive + } + } +} + +// View helper for an info/hint dialog. +fun DialogStateManager.showSuccessDialog( + @StringRes title: Int?, + @StringRes message: Int, + @StringRes positiveButtonText: Int? = null, + icon: UiImage? = null, + onDone: () -> Unit = {}, +) { + val resourceProvider = this.requireResourceProvider() + + showDialog(resourceProvider) { + type = DialogType.Success + if (icon != null) this.icon = icon + this.iconColor = resourceProvider.getColor(R.color.colorTertiary) + if (title != null) this.title = UiText.StringResource(title) + this.message = UiText.StringResource(message) + positiveButton { + text = UiText.StringResource(positiveButtonText ?: R.string.lbl_got_it) + action = onDone + } + } +} + +// View helper for an error dialog. +fun DialogStateManager.showErrorDialog( + message: String, + title: String = "", + onRetry: () -> Unit = {}, + onCancel: () -> Unit = {} +) { + val resourceProvider = this.requireResourceProvider() + + showDialog(resourceProvider) { + type = DialogType.Error + this.message = UiText.DynamicString(message) + if (title.isNotEmpty()) this.title = UiText.DynamicString(title) + positiveButton { + text = UiText.StringResource(R.string.retry) + action = onRetry + } + + neutralButton { + text = UiText.StringResource(R.string.lbl_Cancel) + action = onCancel + } + } +} + +// View helper for an info/hint dialog. +fun DialogStateManager.showInfoDialog( + message: UiText, + title: UiText?, + icon: UiImage? = null, + onDone: () -> Unit = {}, +) { + val resourceProvider = this.requireResourceProvider() + + showDialog(resourceProvider) { + type = DialogType.Info + this.icon = icon + this.iconColor = resourceProvider.getColor(R.color.colorTertiary) + this.title = title + this.message = message + positiveButton { + text = UiText.StringResource(R.string.lbl_got_it) + action = onDone + } + } +} + +// View helper for an info/hint dialog. +fun DialogStateManager.showWarningDialog( + title: UiText?, + message: UiText, + icon: UiImage? = null, + positiveButtonText: UiText? = null, + onDone: () -> Unit = {}, + onCancel: () -> Unit = {} +) { + val resourceProvider = this.requireResourceProvider() + + showDialog(resourceProvider) { + type = DialogType.Warning + this.title = title + this.icon = icon + this.message = message + positiveButton { + text = positiveButtonText ?: UiText.StringResource(R.string.lbl_got_it) + action = onDone + } + destructiveButton { + text = UiText.StringResource(R.string.lbl_Cancel) + action = onCancel + } + } +} + +// For Destructive Actions confirmation (Removing folder or server etc) +fun DialogStateManager.showDestructiveDialog( + title: UiText?, + message: UiText, + icon: UiImage? = null, + positiveButtonText: UiText? = null, + onDone: () -> Unit = {}, + onCancel: () -> Unit = {} +) { + val resourceProvider = this.requireResourceProvider() + + showDialog(resourceProvider) { + type = DialogType.Warning + this.title = title + this.icon = icon + this.message = message + positiveButton { + text = positiveButtonText ?: UiText.StringResource(R.string.lbl_got_it) + action = onDone + } + destructiveButton { + text = UiText.StringResource(R.string.lbl_Cancel) + action = onCancel + } + } +} + + +/** + * ResourceProvider is an abstraction that lets you look up colors and vector icons + * without passing a Context every time. + */ +interface ResourceProvider { + fun getColor(@ColorRes colorRes: Int): Color + fun getVector(@DrawableRes drawableRes: Int): ImageVector? +} + +/** + * A simple implementation that uses an Android Context. + * You can instantiate this once (for example in your BaseActivity) and pass it + * to your DialogStateManager. + */ +class DefaultResourceProvider(private val context: Context) : ResourceProvider { + override fun getColor(@ColorRes colorRes: Int): Color { + // ContextCompat.getColor returns an int (the ARGB value); we wrap it in Compose’s Color. + return Color(ContextCompat.getColor(context, colorRes)) + } + + override fun getVector(@DrawableRes drawableRes: Int): ImageVector? { + // For a real application you might have a more elaborate mapping. + // In this simple example, if the drawable resource equals R.drawable.ic_info, + // we return Icons.Filled.Info; otherwise, return null. + return when (drawableRes) { + R.drawable.ic_info -> Icons.Filled.Info + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderActivity.kt index eb23d402..f04c5ee0 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderActivity.kt @@ -3,18 +3,13 @@ package net.opendasharchive.openarchive.features.folders import android.content.Intent import android.os.Bundle import android.view.MenuItem +import androidx.activity.compose.setContent import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts -import androidx.core.content.ContextCompat -import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.databinding.ActivityAddFolderBinding +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.core.BaseActivity import net.opendasharchive.openarchive.features.onboarding.SpaceSetupActivity -import net.opendasharchive.openarchive.util.extensions.Position -import net.opendasharchive.openarchive.util.extensions.hide -import net.opendasharchive.openarchive.util.extensions.setDrawable -import net.opendasharchive.openarchive.util.extensions.tint class AddFolderActivity : BaseActivity() { @@ -23,54 +18,57 @@ class AddFolderActivity : BaseActivity() { const val EXTRA_FOLDER_NAME = "folder_name" } - private lateinit var mBinding: ActivityAddFolderBinding private lateinit var mResultLauncher: ActivityResultLauncher override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == RESULT_OK) { - setResult(RESULT_OK, it.data) - finish() - } - else { - val name = it.data?.getStringExtra(EXTRA_FOLDER_NAME) + mResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == RESULT_OK) { + setResult(RESULT_OK, it.data) + finish() + } else { + val name = it.data?.getStringExtra(EXTRA_FOLDER_NAME) - if (!name.isNullOrBlank()) { - val i = Intent(this, CreateNewFolderActivity::class.java) - i.putExtra(EXTRA_FOLDER_NAME, name) + if (!name.isNullOrBlank()) { + val i = Intent(this, CreateNewFolderFragment::class.java) + i.putExtra(EXTRA_FOLDER_NAME, name) - mResultLauncher.launch(i) + mResultLauncher.launch(i) + } } } - } - mBinding = ActivityAddFolderBinding.inflate(layoutInflater) - setContentView(mBinding.root) + //mBinding = ActivityAddFolderBinding.inflate(layoutInflater) + //setContentView(mBinding.root) - mBinding.newFolder.setOnClickListener { - setFolder(false) - } - mBinding.browseFolders.setOnClickListener { - setFolder(true) + setContent { + + SaveAppTheme { + + AddFolderScreen( +// onCreateFolder = { +// setFolder(browse = false) +// }, +// onBrowseFolders = { +// setFolder(browse = true) +// }, +// onNavigateBack = { +// finish() +// } + ) + } } - val arrow = ContextCompat.getDrawable(this, R.drawable.ic_arrow_right) - arrow?.tint(ContextCompat.getColor(this, R.color.colorPrimary)) - mBinding.newFolderText.setDrawable(arrow, Position.End, tint = false) - mBinding.browseFoldersText.setDrawable(arrow, Position.End, tint = false) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.title = "" - supportActionBar?.setDisplayHomeAsUpEnabled(true) // We cannot browse the Internet Archive. Directly forward to creating a project, // as it doesn't make sense to show a one-option menu. if (Space.current?.tType == Space.Type.INTERNET_ARCHIVE) { - mBinding.browseFolders.hide() + //mBinding.browseFolderContainer.hide() finish() setFolder(false) @@ -97,7 +95,11 @@ class AddFolderActivity : BaseActivity() { return } - mResultLauncher.launch(Intent(this, - if (browse) BrowseFoldersActivity::class.java else CreateNewFolderActivity::class.java)) + mResultLauncher.launch( + Intent( + this, + if (browse) BrowseFoldersFragment::class.java else CreateNewFolderFragment::class.java + ) + ) } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderScreen.kt new file mode 100644 index 00000000..6444a253 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/AddFolderScreen.kt @@ -0,0 +1,164 @@ +package net.opendasharchive.openarchive.features.folders + +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowForward +import androidx.compose.material.icons.filled.ArrowForward +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.findNavController +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme + +@Composable +fun AddFolderScreen() { + + val navController = LocalView.current.findNavController() + + SaveAppTheme { + AddFolderScreenContent( + onCreateFolder = { + navController.navigate(R.id.fragment_add_folder_to_fragment_create_new_folder) + }, + onBrowseFolders = { + navController.navigate(R.id.fragment_add_folder_to_fragment_browse_folders) + } + ) + } + +} + + +@Composable +fun AddFolderScreenContent( + onCreateFolder: () -> Unit, + onBrowseFolders: () -> Unit +) { + + + Column( + modifier = Modifier + .fillMaxSize() + .padding() + .padding(vertical = 24.dp) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(32.dp)) + + Text( + text = stringResource(id = R.string.select_where_to_store_your_media), + fontSize = 18.sp, + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = 64.dp) + ) + + Spacer(modifier = Modifier.height(32.dp)) + + FolderOption( + iconRes = R.drawable.ic_create_new_folder, + text = stringResource(id = R.string.create_a_new_folder), + onClick = onCreateFolder + ) + + Spacer(modifier = Modifier.height(8.dp)) + + FolderOption( + iconRes = R.drawable.ic_browse_existing_folders, + text = stringResource(id = R.string.browse_existing_folders), + onClick = onBrowseFolders + ) + } +} + + +@Composable +fun FolderOption(iconRes: Int, text: String, onClick: () -> Unit) { + + Card( + modifier = Modifier.padding(horizontal = 24.dp, vertical = 12.dp), + onClick = onClick, + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.background + ), + shape = RoundedCornerShape(8.dp), + border = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.onBackground) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 24.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painterResource(id = iconRes), + contentDescription = null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.tertiary + ) + + Spacer(modifier = Modifier.width(12.dp)) + + Text( + text = text, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + modifier = Modifier.weight(1f) + ) + + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowForward, + contentDescription = null, + modifier = Modifier.size(24.dp) + ) + } + } +} + + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun AddFolderScreenPreview() { + DefaultScaffoldPreview { + AddFolderScreenContent( + onCreateFolder = {}, + onBrowseFolders = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFolderScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFolderScreen.kt new file mode 100644 index 00000000..67dd1470 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFolderScreen.kt @@ -0,0 +1,103 @@ +package net.opendasharchive.openarchive.features.folders + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Card +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.findNavController +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview +import org.koin.androidx.compose.koinViewModel +import java.util.Date + +@Composable +fun BrowseFolderScreen( + viewModel: BrowseFoldersViewModel = koinViewModel() +) { + + val navController = LocalView.current.findNavController() + + + val folders by viewModel.folders.observeAsState() + + + BrowseFolderScreenContent( + folders = folders ?: emptyList() + ) +} + + +@Composable +fun BrowseFolderScreenContent( + folders: List +) { + + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(vertical = 24.dp, horizontal = 16.dp), + contentPadding = PaddingValues(16.dp) + ) { + + items(folders) { folder -> + BrowseFolderItem(folder) { } + } + } + +} + +@Composable +fun BrowseFolderItem( + folder: Folder, + onClick: () -> Unit +) { + + Card( + modifier = Modifier.fillMaxWidth() + ) { + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + + Icon(painter = painterResource(R.drawable.ic_folder_new), contentDescription = null) + Text(folder.name) + } + } +} + +@Preview +@Composable +private fun BrowseFolderScreenPreview() { + DefaultScaffoldPreview { + BrowseFolderScreenContent( + folders = listOf( + Folder(name = "Elelan", modified = Date()), + Folder(name = "Save", modified = Date()), + Folder(name = "Downloads", modified = Date()), + Folder(name = "Trip", modified = Date()), + Folder(name = "Wedding", modified = Date()), + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersActivity.kt deleted file mode 100644 index 3de2283a..00000000 --- a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersActivity.kt +++ /dev/null @@ -1,105 +0,0 @@ -package net.opendasharchive.openarchive.features.folders - -import android.content.Intent -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import androidx.recyclerview.widget.LinearLayoutManager -import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.databinding.ActivityBrowseFoldersBinding -import net.opendasharchive.openarchive.db.Project -import net.opendasharchive.openarchive.db.Space -import net.opendasharchive.openarchive.features.core.BaseActivity -import net.opendasharchive.openarchive.util.extensions.toggle -import java.util.Date - - -class BrowseFoldersActivity : BaseActivity() { - - private lateinit var mBinding: ActivityBrowseFoldersBinding - private lateinit var mViewModel: BrowseFoldersViewModel - - private var mSelected: BrowseFoldersViewModel.Folder? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - mBinding = ActivityBrowseFoldersBinding.inflate(layoutInflater) - setContentView(mBinding.root) - - mViewModel = BrowseFoldersViewModel() - - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - - title = getString(R.string.browse_existing) - - mBinding.rvFolderList.layoutManager = LinearLayoutManager(this) - - val space = Space.current - if (space != null) mViewModel.getFiles(this, space) - - mViewModel.folders.observe(this) { - mBinding.projectsEmpty.toggle(it.isEmpty()) - - mBinding.rvFolderList.adapter = BrowseFoldersAdapter(it) { name -> - mSelected = name - } - } - - mViewModel.progressBarFlag.observe(this) { - mBinding.progressBar.toggle(it) - } - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_browse_folder, menu) - - return super.onCreateOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> { - finish() - - return true - } - R.id.action_add -> { - addFolder(mSelected) - - return true - } - } - - return super.onOptionsItemSelected(item) - } - - private fun addFolder(folder: BrowseFoldersViewModel.Folder?) { - if (folder == null) return - val space = Space.current ?: return - - // This should not happen. These should have been filtered on display. - if (space.hasProject(folder.name)) return - - val license = space.license - -// if (license.isNullOrBlank()) { -// val i = Intent() -// i.putExtra(AddFolderActivity.EXTRA_FOLDER_NAME, folder.name) -// -// setResult(RESULT_CANCELED, i) -// } -// else { - val project = Project(folder.name, Date(), space.id, licenseUrl = license) - project.save() - - val i = Intent() - i.putExtra(AddFolderActivity.EXTRA_FOLDER_ID, project.id) - - setResult(RESULT_OK, i) -// } - - finish() - } -} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersAdapter.kt index 580859f7..1fd1ec01 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersAdapter.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersAdapter.kt @@ -1,69 +1,66 @@ package net.opendasharchive.openarchive.features.folders -import android.graphics.drawable.Drawable import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.FolderRowBinding -import net.opendasharchive.openarchive.util.extensions.clone -import net.opendasharchive.openarchive.util.extensions.scaled -import net.opendasharchive.openarchive.util.extensions.tint import java.text.SimpleDateFormat class BrowseFoldersAdapter( - private val folders: List = emptyList(), - private val onClick: (folder: BrowseFoldersViewModel.Folder) -> Unit + private val folders: List = emptyList(), + private val onClick: (folder: Folder) -> Unit ) : RecyclerView.Adapter() { companion object { - private var sOriginalColor = 0 - private var sHighlightColor = 0 - private var sIcon: Drawable? = null private val formatter = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.MEDIUM) } - private var mSelected = -1 + private var mSelected: Folder? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FolderViewHolder { val binding = FolderRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) - val context = binding.root.context - - if (sOriginalColor == 0) sOriginalColor = binding.name.currentTextColor - if (sHighlightColor == 0) sHighlightColor = ContextCompat.getColor(context, R.color.colorPrimary) - if (sIcon == null) sIcon = ContextCompat.getDrawable(context, R.drawable.ic_folder)?.scaled(0.75, context) return FolderViewHolder(binding, onClick) } override fun onBindViewHolder(holder: FolderViewHolder, position: Int) { - holder.onBindView(position, mSelected == position) + holder.bind(folders[position]) } - override fun getItemCount(): Int { - return folders.size - } + override fun getItemCount(): Int = folders.size + + inner class FolderViewHolder(private val binding: FolderRowBinding, private val onClick: (folder: Folder) -> Unit) : RecyclerView.ViewHolder(binding.root) { + + fun bind(folder: Folder) { + + val isSelected = mSelected == folder - inner class FolderViewHolder( - private val binding: FolderRowBinding, - private val onClick: (folder: BrowseFoldersViewModel.Folder) -> Unit - ) : RecyclerView.ViewHolder(binding.root) - { - fun onBindView(position: Int, selected: Boolean) { - val color = if (selected) sHighlightColor else sOriginalColor + itemView.isSelected = isSelected - binding.icon.setImageDrawable(sIcon?.clone()?.tint(color)) - binding.name.setTextColor(color) - binding.name.text = folders[position].name - binding.timestamp.text = formatter.format(folders[position].modified) + val icon = ContextCompat.getDrawable(binding.icon.context, R.drawable.ic_folder_new) + icon?.setTint(ContextCompat.getColor(binding.icon.context, R.color.colorOnBackground)) + binding.icon.setImageDrawable(icon) + + binding.name.text = folder.name + binding.timestamp.text = formatter.format(folder.modified) + + binding.rvTick.visibility = if (isSelected) View.VISIBLE else View.INVISIBLE binding.root.setOnClickListener { - mSelected = position - this@BrowseFoldersAdapter.notifyDataSetChanged() + if (mSelected == folder) return@setOnClickListener + + val previousSelected = mSelected + mSelected = folder + + // Notify changes for previous and current selection + notifyItemChanged(folders.indexOf(previousSelected)) + notifyItemChanged(folders.indexOf(mSelected)) - onClick.invoke(folders[position]) + onClick.invoke(folder) } } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersFragment.kt new file mode 100644 index 00000000..042c8a81 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersFragment.kt @@ -0,0 +1,126 @@ +package net.opendasharchive.openarchive.features.folders + +import android.app.Activity +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle +import androidx.recyclerview.widget.LinearLayoutManager +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.FragmentBrowseFoldersBinding +import net.opendasharchive.openarchive.db.Project +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.dialog.showSuccessDialog +import net.opendasharchive.openarchive.util.extensions.toggle +import org.koin.androidx.viewmodel.ext.android.viewModel +import java.util.Date + + +class BrowseFoldersFragment : BaseFragment(), MenuProvider { + + private lateinit var mBinding: FragmentBrowseFoldersBinding + private val mViewModel: BrowseFoldersViewModel by viewModel() + + private var mSelected: Folder? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + mBinding = FragmentBrowseFoldersBinding.inflate(layoutInflater) + + mBinding.rvFolderList.layoutManager = LinearLayoutManager(requireContext()) + + return mBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + activity?.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + + val space = Space.current + if (space != null) mViewModel.getFiles(space) + + mViewModel.folders.observe(viewLifecycleOwner) { + mBinding.projectsEmpty.toggle(it.isEmpty()) + + mBinding.rvFolderList.adapter = BrowseFoldersAdapter(it) { folder -> + this.mSelected = folder + activity?.invalidateOptionsMenu() + } + } + + mViewModel.progressBarFlag.observe(viewLifecycleOwner) { + mBinding.progressBar.toggle(it) + } + } + + + override fun getToolbarTitle(): String = getString(R.string.browse_existing) + + private fun addFolder(folder: Folder?) { + if (folder == null) return + val space = Space.current ?: return + + // This should not happen. These should have been filtered on display. + if (space.hasProject(folder.name)) return + + val license = space.license + + + val project = Project(folder.name, Date(), space.id, licenseUrl = license) + project.save() + + showFolderCreated(project.id) + } + + private fun showFolderCreated(projectId: Long) { + + dialogManager.showSuccessDialog( + title = R.string.label_success_title, + message = R.string.create_folder_ok_message, + positiveButtonText = R.string.label_got_it, + onDone = { + navigateBackWithResult(projectId) + } + ) + } + + private fun navigateBackWithResult(projectId: Long) { + requireActivity().setResult(RESULT_OK, Intent().apply { + putExtra(AddFolderActivity.EXTRA_FOLDER_ID, projectId) + }) + requireActivity().finish() + } + + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_browse_folder, menu) + } + + override fun onPrepareMenu(menu: Menu) { + super.onPrepareMenu(menu) + val addMenuItem = menu.findItem(R.id.action_add) + addMenuItem?.isVisible = mSelected != null + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.action_add -> { + addFolder(mSelected) + true + } + + else -> false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersViewModel.kt index 1ec74006..0f1055df 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersViewModel.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/BrowseFoldersViewModel.kt @@ -15,9 +15,11 @@ import timber.log.Timber import java.io.IOException import java.util.Date -class BrowseFoldersViewModel : ViewModel() { - data class Folder(val name: String, val modified: Date) + +data class Folder(val name: String, val modified: Date) + +class BrowseFoldersViewModel(private val context: Context) : ViewModel() { private val mFolders = MutableLiveData>() @@ -26,7 +28,7 @@ class BrowseFoldersViewModel : ViewModel() { val progressBarFlag = MutableLiveData(false) - fun getFiles(context: Context, space: Space) { + fun getFiles(space: Space) { viewModelScope.launch { progressBarFlag.value = true diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/CreateNewFolderActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/CreateNewFolderActivity.kt deleted file mode 100644 index bf00aa97..00000000 --- a/app/src/main/java/net/opendasharchive/openarchive/features/folders/CreateNewFolderActivity.kt +++ /dev/null @@ -1,107 +0,0 @@ -package net.opendasharchive.openarchive.features.folders - -import android.content.Intent -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.inputmethod.EditorInfo -import android.widget.Toast -import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.databinding.ActivityCreateNewFolderBinding -import net.opendasharchive.openarchive.db.Project -import net.opendasharchive.openarchive.db.Space -import net.opendasharchive.openarchive.features.core.BaseActivity -import net.opendasharchive.openarchive.features.settings.CcSelector -import net.opendasharchive.openarchive.util.extensions.hide -import java.util.Date - -class CreateNewFolderActivity : BaseActivity() { - - companion object { - private const val SPECIAL_CHARS = ".*[\\\\/*\\s]" - } - - private lateinit var mBinding: ActivityCreateNewFolderBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - mBinding = ActivityCreateNewFolderBinding.inflate(layoutInflater) - setContentView(mBinding.root) - - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - supportActionBar?.title = getString(R.string.new_folder) - - mBinding.newFolder.setText(intent.getStringExtra(AddFolderActivity.EXTRA_FOLDER_NAME)) - - mBinding.newFolder.setOnEditorActionListener { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - store() - } - - false - } - - if (Space.current?.license != null) { - mBinding.cc.root.hide() - } - else { - CcSelector.init(mBinding.cc) - } - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_new_folder, menu) - - return super.onCreateOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> { - finish() - return true - } - R.id.action_done -> { - store() - return true - } - } - return super.onOptionsItemSelected(item) - } - - private fun store() { - val name = mBinding.newFolder.text.toString() - - if (name.isBlank()) return - - if (name.matches(SPECIAL_CHARS.toRegex())) { - Toast.makeText(this, - getString(R.string.please_do_not_include_special_characters_in_the_name), - Toast.LENGTH_SHORT).show() - - return - } - - val space = Space.current ?: return - - if (space.hasProject(name)) { - Toast.makeText(this, getString(R.string.folder_name_already_exists), - Toast.LENGTH_LONG).show() - - return - } - - val license = space.license ?: CcSelector.get(mBinding.cc) - - val project = Project(name, Date(), space.id, licenseUrl = license) - project.save() - - val i = Intent() - i.putExtra(AddFolderActivity.EXTRA_FOLDER_ID, project.id) - - setResult(RESULT_OK, i) - finish() - } -} diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/folders/CreateNewFolderFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/folders/CreateNewFolderFragment.kt new file mode 100644 index 00000000..7386f33b --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/folders/CreateNewFolderFragment.kt @@ -0,0 +1,150 @@ +package net.opendasharchive.openarchive.features.folders + +import android.app.Activity.RESULT_CANCELED +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import android.widget.Toast +import androidx.core.view.MenuProvider +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.FragmentCreateNewFolderBinding +import net.opendasharchive.openarchive.db.Project +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.dialog.showSuccessDialog +import net.opendasharchive.openarchive.features.settings.CreativeCommonsLicenseManager +import net.opendasharchive.openarchive.util.extensions.hide +import java.util.Date + +class CreateNewFolderFragment : BaseFragment() { + + companion object { + private const val SPECIAL_CHARS = ".*[\\\\/*\\s]" + } + + private lateinit var binding: FragmentCreateNewFolderBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentCreateNewFolderBinding.inflate(layoutInflater) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val intent = requireActivity().intent + + binding.newFolder.setText(intent.getStringExtra(AddFolderActivity.EXTRA_FOLDER_NAME)) + + binding.newFolder.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + store() + } + + false + } + + binding.btnSubmit.setOnClickListener { + store() + } + + binding.btnCancel.setOnClickListener { + requireActivity().setResult(RESULT_CANCELED) + requireActivity().finish() + } + + setupTextWatchers() + } + + private fun setupTextWatchers() { + // Create a common TextWatcher for all three fields + val textWatcher = object : android.text.TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + updateAuthenticateButtonState() + } + + override fun afterTextChanged(s: android.text.Editable?) {} + } + + binding.newFolder.addTextChangedListener(textWatcher) + } + + private fun updateAuthenticateButtonState() { + val folderName = binding.newFolder.text?.toString()?.trim().orEmpty() + + // Enable the button only if none of the fields are empty + binding.btnSubmit.isEnabled = folderName.isNotEmpty() + } + + override fun getToolbarTitle(): String = getString(R.string.create_a_new_folder) + + private fun store() { + val name = binding.newFolder.text.toString() + + if (name.isBlank()) return + + if (name.matches(SPECIAL_CHARS.toRegex())) { + Toast.makeText( + requireContext(), + getString(R.string.please_do_not_include_special_characters_in_the_name), + Toast.LENGTH_SHORT + ).show() + + return + } + + val space = Space.current ?: return + + if (space.hasProject(name)) { + Toast.makeText( + requireContext(), getString(R.string.folder_name_already_exists), + Toast.LENGTH_LONG + ).show() + + return + } + + val license = + space.license ?: CreativeCommonsLicenseManager.getSelectedLicenseUrl(binding.cc) + + val project = Project(name, Date(), space.id, licenseUrl = license) + project.save() + + showFolderCreated(project.id) + + + } + + private fun showFolderCreated(projectId: Long) { + + dialogManager.showSuccessDialog( + title = R.string.label_success_title, + message = R.string.create_folder_ok_message, + positiveButtonText = R.string.label_got_it, + onDone = { + navigateBackWithResult(projectId) + } + ) + } + + private fun navigateBackWithResult(projectId: Long) { + val i = Intent() + i.putExtra(AddFolderActivity.EXTRA_FOLDER_ID, projectId) + + requireActivity().setResult(RESULT_OK, i) + requireActivity().finish() + } +} diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveActivity.kt index be5500f7..87c6aef3 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveActivity.kt @@ -1,31 +1,65 @@ package net.opendasharchive.openarchive.features.internetarchive.presentation -import android.app.Activity import android.content.Intent import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity -import net.opendasharchive.openarchive.CleanInsightsManager +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.dialog.DialogHost +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager import net.opendasharchive.openarchive.features.internetarchive.presentation.components.IAResult import net.opendasharchive.openarchive.features.internetarchive.presentation.components.getSpace +import net.opendasharchive.openarchive.features.internetarchive.presentation.login.ComposeAppBar import net.opendasharchive.openarchive.features.main.MainActivity +import org.koin.androidx.viewmodel.ext.android.viewModel @Deprecated("use jetpack compose") class InternetArchiveActivity : AppCompatActivity() { + + val dialogManager: DialogStateManager by viewModel() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val (space, isNewSpace) = intent.extras.getSpace(Space.Type.INTERNET_ARCHIVE) setContent { - InternetArchiveScreen(space, isNewSpace) { - finish(it) + + SaveAppTheme { + + DialogHost(dialogManager) + + Scaffold( + topBar = { + ComposeAppBar( + title = stringResource(R.string.internet_archive), + onNavigationAction = { onComplete(IAResult.Cancelled) } + ) + } + ) { paddingValues -> + Box(modifier = Modifier + .fillMaxSize() + .padding(paddingValues)) { + InternetArchiveScreen(space, isNewSpace) { + onComplete(it) + } + } + } } + + } } - private fun finish(result: IAResult) { + private fun onComplete(result: IAResult) { when (result) { IAResult.Saved -> { startActivity(Intent(this, MainActivity::class.java)) @@ -33,7 +67,7 @@ class InternetArchiveActivity : AppCompatActivity() { } IAResult.Deleted -> Space.navigate(this) - else -> Unit + IAResult.Cancelled -> onBackPressed() } } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveFragment.kt index 6c934e1f..950267db 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveFragment.kt @@ -6,16 +6,19 @@ import android.view.View import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResult +import androidx.navigation.fragment.findNavController +import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.internetarchive.presentation.components.IAResult import net.opendasharchive.openarchive.features.internetarchive.presentation.components.bundleWithNewSpace import net.opendasharchive.openarchive.features.internetarchive.presentation.components.bundleWithSpaceId import net.opendasharchive.openarchive.features.internetarchive.presentation.components.getSpace +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.ToolbarConfigurable @Deprecated("only used for backward compatibility") -class InternetArchiveFragment : Fragment() { +class InternetArchiveFragment : BaseFragment(), ToolbarConfigurable { override fun onCreateView( inflater: LayoutInflater, @@ -35,10 +38,22 @@ class InternetArchiveFragment : Fragment() { } private fun finish(result: IAResult) { - setFragmentResult(result.value, bundleOf()) + if (isJetpackNavigation) { + when (result) { + IAResult.Saved -> { + val message = getString(R.string.you_have_successfully_connected_to_the_internet_archive) + val action = InternetArchiveFragmentDirections.actionFragmentInternetArchiveToFragmentSpaceSetupSuccess(message) + findNavController().navigate(action) + } + IAResult.Deleted -> TODO() + IAResult.Cancelled -> findNavController().popBackStack() + } + } else { + setFragmentResult(result.value, bundleOf()) - if (result == IAResult.Saved) { - // activity?.measureNewBackend(Space.Type.INTERNET_ARCHIVE) + if (result == IAResult.Saved) { + // activity?.measureNewBackend(Space.Type.INTERNET_ARCHIVE) + } } } @@ -58,4 +73,7 @@ class InternetArchiveFragment : Fragment() { @JvmStatic fun newInstance() = newInstance(args = bundleWithNewSpace()) } + + override fun getToolbarTitle() = "Internet Archive" + override fun shouldShowBackButton() = true } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveScreen.kt index 36338e8d..4429b4cd 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveScreen.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/InternetArchiveScreen.kt @@ -1,14 +1,14 @@ package net.opendasharchive.openarchive.features.internetarchive.presentation import androidx.compose.runtime.Composable -import net.opendasharchive.openarchive.core.presentation.theme.Theme +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.internetarchive.presentation.components.IAResult import net.opendasharchive.openarchive.features.internetarchive.presentation.details.InternetArchiveDetailsScreen import net.opendasharchive.openarchive.features.internetarchive.presentation.login.InternetArchiveLoginScreen @Composable -fun InternetArchiveScreen(space: Space, isNewSpace: Boolean, onFinish: (IAResult) -> Unit) = Theme { +fun InternetArchiveScreen(space: Space, isNewSpace: Boolean, onFinish: (IAResult) -> Unit) = SaveAppTheme { if (isNewSpace) { InternetArchiveLoginScreen(space) { onFinish(it) diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/BundleExt.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/BundleExt.kt index 177d5615..8a955ad7 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/BundleExt.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/BundleExt.kt @@ -8,7 +8,7 @@ import net.opendasharchive.openarchive.db.Space private const val ARG_VAL_NEW_SPACE = -1L @Deprecated("only for use with fragments and activities") -private const val ARG_SPACE = "space" +private const val ARG_SPACE = "space_id" @Deprecated("only for use with fragments and activities") enum class IAResult( @@ -25,7 +25,7 @@ fun bundleWithNewSpace() = bundleOf(ARG_SPACE to ARG_VAL_NEW_SPACE) @Deprecated("only for use with fragments and activities") fun Bundle?.getSpace(type: Space.Type): Pair { - val mSpaceId = this?.getLong(ARG_SPACE, ARG_VAL_NEW_SPACE) ?: ARG_VAL_NEW_SPACE + val mSpaceId = this?.getLong(ARG_SPACE) ?: ARG_VAL_NEW_SPACE val isNewSpace = ARG_VAL_NEW_SPACE == mSpaceId diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/InternetArchiveHeader.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/InternetArchiveHeader.kt index 2f6d1a07..3885aec2 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/InternetArchiveHeader.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/components/InternetArchiveHeader.kt @@ -24,11 +24,12 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.core.presentation.theme.ThemeColors import net.opendasharchive.openarchive.core.presentation.theme.ThemeDimensions @Composable -fun InternetArchiveHeader(modifier: Modifier = Modifier, titleSize: TextUnit = 18.sp) { +fun InternetArchiveHeader(modifier: Modifier = Modifier) { Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically, @@ -36,34 +37,28 @@ fun InternetArchiveHeader(modifier: Modifier = Modifier, titleSize: TextUnit = 1 ) { Box( modifier = Modifier - .size(ThemeDimensions.touchable) - .background( - color = ThemeColors.material.surface, - shape = CircleShape - ) + .size(50.dp) .clip(CircleShape) + .background(ThemeColors.material.surfaceDim,) + .padding(8.dp), + contentAlignment = Alignment.Center ) { Image( - modifier = Modifier - .matchParentSize() - .padding(11.dp), + modifier = Modifier.size(30.dp), painter = painterResource(id = R.drawable.ic_internet_archive), - contentDescription = stringResource( - id = R.string.internet_archive - ), - colorFilter = tint(colorResource(id = R.color.colorPrimary)) + contentDescription = stringResource(R.string.internet_archive), + colorFilter = tint(colorResource(id = R.color.colorTertiary)) ) } - Column(modifier = Modifier.padding(start = ThemeDimensions.spacing.medium)) { - Text( - text = stringResource(id = R.string.internet_archive), - fontSize = titleSize, - fontWeight = FontWeight.Bold, - color = ThemeColors.material.onSurface - ) + + Column( + modifier = Modifier.padding(start = ThemeDimensions.spacing.medium, end = ThemeDimensions.spacing.xlarge) + ) { Text( text = stringResource(id = R.string.internet_archive_description), - color = ThemeColors.material.onSurfaceVariant + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = ThemeColors.material.onSurfaceVariant, ) } } @@ -71,6 +66,9 @@ fun InternetArchiveHeader(modifier: Modifier = Modifier, titleSize: TextUnit = 1 @Composable @Preview(showBackground = true) +@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveHeaderPreview() { - InternetArchiveHeader() + SaveAppTheme { + InternetArchiveHeader() + } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/details/InternetArchiveDetailsScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/details/InternetArchiveDetailsScreen.kt index c851cde5..b006feb4 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/details/InternetArchiveDetailsScreen.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/details/InternetArchiveDetailsScreen.kt @@ -1,38 +1,39 @@ package net.opendasharchive.openarchive.features.internetarchive.presentation.details +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.core.presentation.theme.ThemeColors +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview import net.opendasharchive.openarchive.core.presentation.theme.ThemeDimensions import net.opendasharchive.openarchive.core.state.Dispatch import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.UiImage +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager +import net.opendasharchive.openarchive.features.core.dialog.showDialog import net.opendasharchive.openarchive.features.internetarchive.presentation.components.IAResult -import net.opendasharchive.openarchive.features.internetarchive.presentation.components.InternetArchiveHeader import net.opendasharchive.openarchive.features.internetarchive.presentation.details.InternetArchiveDetailsViewModel.Action +import net.opendasharchive.openarchive.features.internetarchive.presentation.login.CustomTextField import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf @@ -60,11 +61,10 @@ fun InternetArchiveDetailsScreen(space: Space, onResult: (IAResult) -> Unit) { @Composable private fun InternetArchiveDetailsContent( state: InternetArchiveDetailsState, - dispatch: Dispatch + dispatch: Dispatch, + dialogManager: DialogStateManager = koinViewModel() ) { - var isRemoving by remember { mutableStateOf(false) } - Box( modifier = Modifier .fillMaxSize() @@ -73,113 +73,96 @@ private fun InternetArchiveDetailsContent( Column { - InternetArchiveHeader() + //InternetArchiveHeader() Spacer(Modifier.height(ThemeDimensions.spacing.large)) - Text( - text = stringResource(id = R.string.label_username), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onBackground - ) - Text( - text = state.userName, - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground + CustomTextField( + label = stringResource(R.string.label_username), + value = state.userName, + onValueChange = {}, + enabled = false, ) - Text( - modifier = Modifier.padding(top = 16.dp), - text = stringResource(id = R.string.label_screen_name), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onBackground - ) + Spacer(Modifier.height(ThemeDimensions.spacing.medium)) - Text( - text = state.screenName, - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground + CustomTextField( + label = stringResource(R.string.label_screen_name), + value = state.screenName, + onValueChange = {}, + enabled = false, ) - Text( - modifier = Modifier.padding(top = 16.dp), - text = stringResource(id = R.string.label_email), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onBackground - ) + Spacer(Modifier.height(ThemeDimensions.spacing.medium)) + - Text( - text = state.email, - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground + CustomTextField( + label = stringResource(R.string.label_email), + value = state.email, + onValueChange = {}, + enabled = false, ) - } - Button( - modifier = Modifier - .padding(top = 12.dp) - .align(Alignment.BottomCenter), - shape = RoundedCornerShape(ThemeDimensions.roundedCorner), - onClick = { - isRemoving = true - }, - colors = ButtonDefaults.buttonColors(containerColor = ThemeColors.material.error) - ) { - Text(stringResource(id = R.string.menu_delete)) - } - } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 24.dp), + horizontalArrangement = Arrangement.Center + ) { + TextButton( + onClick = { + //isRemoving = true + + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + title = UiText.StringResource(R.string.remove_from_app) + message = UiText.StringResource(R.string.are_you_sure_you_want_to_remove_this_server_from_the_app) + icon = UiImage.DrawableResource(R.drawable.ic_trash) + destructiveButton { + text = UiText.StringResource(R.string.remove) + action = { + dispatch(Action.Remove) + } + } + + neutralButton { + text = UiText.StringResource(R.string.action_cancel) + action = { + //dismiss + } + } + } + }, + colors = ButtonDefaults.textButtonColors( + contentColor = MaterialTheme.colorScheme.error + ) + ) { + Text( + stringResource(id = R.string.remove_from_app), + fontSize = 18.sp + ) + } + } + - if (isRemoving) { - RemoveInternetArchiveDialog(onDismiss = { isRemoving = false }) { - isRemoving = false - dispatch(Action.Remove) } - } -} -@Composable -private fun RemoveInternetArchiveDialog(onDismiss: () -> Unit, onRemove: () -> Unit) { - AlertDialog( - onDismissRequest = onDismiss, - containerColor = ThemeColors.material.surface, - titleContentColor = ThemeColors.material.onSurface, - textContentColor = ThemeColors.material.onSurfaceVariant, - title = { - Text(text = stringResource(id = R.string.remove_from_app)) - }, - text = { Text(stringResource(id = R.string.are_you_sure_you_want_to_remove_this_server_from_the_app)) }, - dismissButton = { - OutlinedButton( - onClick = onDismiss, - shape = RoundedCornerShape(ThemeDimensions.roundedCorner) - ) { - Text(stringResource(id = R.string.action_cancel)) - } - }, confirmButton = { - Button( - onClick = onRemove, - shape = RoundedCornerShape(ThemeDimensions.roundedCorner), - colors = ButtonDefaults.buttonColors(containerColor = ThemeColors.material.error) - ) { - Text(stringResource(id = R.string.remove)) - } - }) + + } } @Composable @Preview(showBackground = true) +@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveScreenPreview() { - InternetArchiveDetailsContent( - state = InternetArchiveDetailsState( - email = "abc@example.com", - userName = "@abc_name", - screenName = "ABC Name" + DefaultScaffoldPreview { + InternetArchiveDetailsContent( + state = InternetArchiveDetailsState( + email = "abc@example.com", + userName = "@abc_name", + screenName = "ABC Name" + ), + dispatch = {} ) - ) {} + } } -@Composable -@Preview(showBackground = true) -private fun RemoveInternetArchiveDialogPreview() { - RemoveInternetArchiveDialog(onDismiss = { }) {} -} diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/login/InternetArchiveLoginScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/login/InternetArchiveLoginScreen.kt index 65267de5..b23aa36f 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/login/InternetArchiveLoginScreen.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/internetarchive/presentation/login/InternetArchiveLoginScreen.kt @@ -1,13 +1,13 @@ package net.opendasharchive.openarchive.features.internetarchive.presentation.login import android.content.Intent -import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -23,31 +23,45 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.PlatformImeOptions import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.net.toUri +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.delay import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview import net.opendasharchive.openarchive.core.presentation.theme.ThemeColors import net.opendasharchive.openarchive.core.presentation.theme.ThemeDimensions import net.opendasharchive.openarchive.core.state.Dispatch @@ -68,10 +82,11 @@ fun InternetArchiveLoginScreen(space: Space, onResult: (IAResult) -> Unit) { parametersOf(space) } - val state by viewModel.state.collectAsState() + val state by viewModel.state.collectAsStateWithLifecycle() val launcher = - rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult(), + rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult(), onResult = {}) LaunchedEffect(Unit) { @@ -79,7 +94,7 @@ fun InternetArchiveLoginScreen(space: Space, onResult: (IAResult) -> Unit) { when (action) { is CreateLogin -> launcher.launch( Intent( - Intent.ACTION_VIEW, Uri.parse(CreateLogin.URI) + Intent.ACTION_VIEW, CreateLogin.URI.toUri() ) ) @@ -100,12 +115,6 @@ private fun InternetArchiveLoginContent( state: InternetArchiveLoginState, dispatch: Dispatch ) { - // If extra paranoid could pre-hash password in memory - // and use the store/dispatcher - var showPassword by rememberSaveable { - mutableStateOf(false) - } - LaunchedEffect(state.isLoginError) { while (state.isLoginError) { delay(3000) @@ -116,91 +125,97 @@ private fun InternetArchiveLoginContent( Column( modifier = Modifier .fillMaxSize() - .padding(ThemeDimensions.spacing.medium), + .padding(top = 32.dp, bottom = 16.dp) + .padding(horizontal = 24.dp), horizontalAlignment = Alignment.CenterHorizontally ) { InternetArchiveHeader( - modifier = Modifier.padding(bottom = ThemeDimensions.spacing.large) + modifier = Modifier + .padding(vertical = 48.dp) + .padding(end = 24.dp) ) - OutlinedTextField( + + + Box { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp, bottom = 16.dp) + ) { + Text( + stringResource(R.string.account), + color = MaterialTheme.colorScheme.onBackground, + fontWeight = FontWeight.SemiBold, + fontSize = 18.sp + ) + } + } + + CustomTextField( value = state.username, - enabled = !state.isBusy, onValueChange = { dispatch(UpdateUsername(it)) }, - label = { - Text(stringResource(R.string.label_username)) - }, - placeholder = { - Text(stringResource(R.string.placeholder_email_or_username)) - }, - singleLine = true, - shape = RoundedCornerShape(ThemeDimensions.roundedCorner), - keyboardOptions = KeyboardOptions( - imeAction = ImeAction.Next, - autoCorrect = false, - keyboardType = KeyboardType.Email - ), + label = stringResource(R.string.label_username), + placeholder = stringResource(R.string.prompt_email), isError = state.isUsernameError, + isLoading = state.isBusy, + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Next, ) Spacer(Modifier.height(ThemeDimensions.spacing.large)) - OutlinedTextField( + CustomSecureField( value = state.password, - enabled = !state.isBusy, onValueChange = { dispatch(UpdatePassword(it)) }, - label = { - Text(stringResource(R.string.label_password)) - }, - placeholder = { - Text(stringResource(R.string.placeholder_password)) - }, - singleLine = true, - trailingIcon = { - IconButton(modifier = Modifier.sizeIn(ThemeDimensions.touchable), onClick = { showPassword = !showPassword }) { - Icon( - imageVector = if (showPassword) Icons.Default.Visibility else Icons.Default.VisibilityOff, - contentDescription = "show password" - ) - } - }, - shape = RoundedCornerShape(ThemeDimensions.roundedCorner), - visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), - keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Password, - autoCorrect = false, - imeAction = ImeAction.Go - ), + label = stringResource(R.string.label_password), + placeholder = stringResource(R.string.prompt_password), isError = state.isPasswordError, + isLoading = state.isBusy, + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Done, ) - AnimatedVisibility( - visible = state.isLoginError, - enter = fadeIn(), - exit = fadeOut() + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Start ) { - Text( - text = stringResource(R.string.error_incorrect_username_or_password), - color = MaterialTheme.colorScheme.error - ) + AnimatedVisibility( + visible = state.isLoginError, + enter = fadeIn(), + exit = fadeOut() + ) { + Text( + text = stringResource(R.string.error_incorrect_username_or_password), + color = MaterialTheme.colorScheme.error + ) + } } + + Spacer(Modifier.height(ThemeDimensions.spacing.large)) Row( modifier = Modifier - .padding(top = ThemeDimensions.spacing.small) - .weight(1f), + .padding(top = ThemeDimensions.spacing.small), verticalAlignment = Alignment.CenterVertically ) { Text( text = stringResource(R.string.prompt_no_account), - color = ThemeColors.material.onBackground + color = ThemeColors.material.onBackground, + fontWeight = FontWeight.SemiBold, + fontSize = 16.sp ) TextButton( modifier = Modifier.heightIn(ThemeDimensions.touchable), - onClick = { dispatch(CreateLogin) }) { + colors = ButtonDefaults.textButtonColors( + contentColor = MaterialTheme.colorScheme.tertiary + ), + onClick = { dispatch(CreateLogin) } + ) { Text( text = stringResource(R.string.label_create_login), - fontWeight = FontWeight.Bold, + fontWeight = FontWeight.SemiBold, + fontSize = 16.sp, style = MaterialTheme.typography.bodyLarge ) } @@ -209,21 +224,26 @@ private fun InternetArchiveLoginContent( Row( modifier = Modifier .fillMaxWidth() - .padding(top = ThemeDimensions.spacing.medium), - verticalAlignment = Alignment.CenterVertically, + .weight(1f), + verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.SpaceEvenly ) { TextButton( modifier = Modifier - .weight(1f) + .padding(8.dp) .heightIn(ThemeDimensions.touchable) - .padding(ThemeDimensions.spacing.small), + .weight(1f), + colors = ButtonDefaults.textButtonColors( + contentColor = colorResource(R.color.colorOnBackground) + ), + enabled = !state.isBusy, shape = RoundedCornerShape(ThemeDimensions.roundedCorner), onClick = { dispatch(Action.Cancel) }) { - Text(stringResource(R.string.action_cancel)) + Text(stringResource(R.string.back)) } Button( modifier = Modifier + .padding(8.dp) .heightIn(ThemeDimensions.touchable) .weight(1f), enabled = !state.isBusy && state.isValid, @@ -233,7 +253,7 @@ private fun InternetArchiveLoginContent( if (state.isBusy) { CircularProgressIndicator(color = ThemeColors.material.primary) } else { - Text(stringResource(R.string.label_login)) + Text(stringResource(R.string.next)) } } } @@ -241,11 +261,142 @@ private fun InternetArchiveLoginContent( } @Composable -@Preview(showBackground = true) +@Preview +@Preview(showBackground = true, uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES) private fun InternetArchiveLoginPreview() { - InternetArchiveLoginContent( - state = InternetArchiveLoginState( - username = "user@example.org", password = "abc123" + DefaultScaffoldPreview { + InternetArchiveLoginContent( + state = InternetArchiveLoginState( + username = "user@example.org", password = "abc123" + ) + ) {} + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ComposeAppBar( + title: String = "Save App", + onNavigationAction: () -> Unit = {} +) { + TopAppBar( + title = { + Text(title) + }, + navigationIcon = { + IconButton(onClick = onNavigationAction) { + Icon(painter = painterResource(R.drawable.ic_arrow_back), contentDescription = null) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + navigationIconContentColor = Color.White, + titleContentColor = Color.White, + actionIconContentColor = Color.White ) - ) {} + ) +} + +@Composable +fun CustomTextField( + modifier: Modifier = Modifier, + value: String, + onValueChange: (String) -> Unit, + label: String, + enabled: Boolean = true, + placeholder: String? = null, + isError: Boolean = false, + isLoading: Boolean = false, + keyboardType: KeyboardType = KeyboardType.Text, + imeAction: ImeAction = ImeAction.Next, +) { + + OutlinedTextField( + modifier = modifier.fillMaxWidth(), + value = value, + enabled = !isLoading, + onValueChange = onValueChange, + placeholder = { + placeholder?.let { + Text(placeholder) + } + }, + singleLine = true, + shape = RoundedCornerShape(ThemeDimensions.roundedCorner), + keyboardOptions = KeyboardOptions( + capitalization = KeyboardCapitalization.None, + autoCorrectEnabled = false, + keyboardType = keyboardType, + imeAction = imeAction, + platformImeOptions = PlatformImeOptions(), + showKeyboardOnFocus = true, + hintLocales = null + ), + isError = isError, + colors = OutlinedTextFieldDefaults.colors( + focusedContainerColor = MaterialTheme.colorScheme.background, + unfocusedContainerColor = MaterialTheme.colorScheme.background, + focusedBorderColor = MaterialTheme.colorScheme.tertiary + //focusedIndicatorColor = Color.Transparent, + //unfocusedIndicatorColor = Color.Transparent, + ), + ) +} + +@Composable +fun CustomSecureField( + modifier: Modifier = Modifier, + value: String, + onValueChange: (String) -> Unit, + label: String, + placeholder: String, + isError: Boolean = false, + isLoading: Boolean = false, + keyboardType: KeyboardType, + imeAction: ImeAction, +) { + + var showPassword by rememberSaveable { + mutableStateOf(false) + } + + OutlinedTextField( + modifier = modifier.fillMaxWidth(), + value = value, + enabled = !isLoading, + onValueChange = onValueChange, + placeholder = { + Text(placeholder) + }, + singleLine = true, + shape = RoundedCornerShape(ThemeDimensions.roundedCorner), + keyboardOptions = KeyboardOptions( + capitalization = KeyboardCapitalization.None, + autoCorrectEnabled = false, + keyboardType = keyboardType, + imeAction = imeAction, + platformImeOptions = PlatformImeOptions(), + showKeyboardOnFocus = true, + hintLocales = null + ), + visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), + isError = isError, + colors = OutlinedTextFieldDefaults.colors( + focusedContainerColor = MaterialTheme.colorScheme.background, + unfocusedContainerColor = MaterialTheme.colorScheme.background, + focusedBorderColor = MaterialTheme.colorScheme.tertiary + //focusedIndicatorColor = Color.Transparent, + //unfocusedIndicatorColor = Color.Transparent, + ), + trailingIcon = { + IconButton( + modifier = Modifier.sizeIn(ThemeDimensions.touchable), + onClick = { showPassword = !showPassword }) { + Icon( + imageVector = if (showPassword) Icons.Default.Visibility else Icons.Default.VisibilityOff, + contentDescription = "show password" + ) + } + }, + ) } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/HomeActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/HomeActivity.kt new file mode 100644 index 00000000..4a619799 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/HomeActivity.kt @@ -0,0 +1,220 @@ +package net.opendasharchive.openarchive.features.main + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.view.View +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.fragment.app.FragmentActivity +import net.opendasharchive.openarchive.db.Project +import net.opendasharchive.openarchive.features.main.ui.HomeScreen +import net.opendasharchive.openarchive.features.main.ui.HomeViewModel +import net.opendasharchive.openarchive.features.main.ui.SaveNavGraph +import net.opendasharchive.openarchive.features.media.AddMediaType +import net.opendasharchive.openarchive.features.media.MediaLaunchers +import net.opendasharchive.openarchive.features.media.Picker +import org.koin.androidx.viewmodel.ext.android.viewModel +import timber.log.Timber + +class HomeActivity: FragmentActivity() { + + private val viewModel by viewModel() + + // We'll hold a reference to the media launchers registered with Picker. + private lateinit var mediaLaunchers: MediaLaunchers + + private val mNewFolderResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == RESULT_OK) { + //TODO: Refresh projects in MainViewModel + } + } + + private val folderResultLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val selectedFolderId:Long? = result.data?.getLongExtra("SELECTED_FOLDER_ID", -1) + if (selectedFolderId != null && selectedFolderId > -1) { + navigateToFolder(selectedFolderId) + } + } + } + + private val requestPermissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestPermission() + ) { isGranted: Boolean -> + if (isGranted) { + Timber.d("Able to post notifications") + } else { + Timber.d("Need to explain") + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + installSplashScreen() + + // Perform any intent processing (e.g. deep-links or shared media) + handleIntent(intent) + + // Check notification permission (for Android 13+) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + checkNotificationPermissions() + } + + // Get a reference to a view to serve as the root for Snackbars, etc. + val rootView: View = findViewById(android.R.id.content) + + // Register media launchers via Picker. + // The lambda for 'project' should return the currently selected project. + // For now, this stub returns null—you should wire it to your actual selection. + mediaLaunchers = Picker.register( + activity = this, + root = rootView, + project = { getCurrentProject() }, + completed = { media -> + // For example, refresh the current project UI and preview media. + refreshCurrentProject() + if (media.isNotEmpty()) { + previewMedia() + } + } + ) + + // Set up your Compose UI and pass callbacks. + setContent { + SaveNavGraph( + context = this@HomeActivity, + onExit = { + finish() + }, + viewModel = viewModel, + onNewFolder = { launchNewFolder() }, + onFolderSelected = { folderId -> navigateToFolder(folderId) }, + onAddMedia = { mediaType -> addMediaClicked(mediaType) } + ) + } + } + + /** + * Returns the currently selected project. + * Replace this stub with your actual project–retrieval logic. + */ + private fun getCurrentProject(): Project? { + // TODO: Return your current project from a ViewModel or other state. + return null + } + + /** + * Refresh UI details for the current project. + */ + private fun refreshCurrentProject() { + // TODO: Update your UI state, refresh fragment content, etc. + } + + /** + * Launch a preview after media import. + */ + private fun previewMedia() { + // TODO: Launch your preview activity or update the UI as needed. + } + + /** + * Launch the AddFolderActivity using your folder launcher. + */ + private fun launchNewFolder() { + // Example: startActivity(Intent(this, AddFolderActivity::class.java)) + // Or, if you have a registered launcher, use it here. + } + + /** + * Navigate to a folder after selection. + */ + private fun navigateToFolder(folderId: Long) { + // TODO: Update your navigation or fragment state to display the selected folder. + } + + /** + * Handle "Add Media" events from the Compose UI. + */ + private fun addMediaClicked(mediaType: AddMediaType) { + if (getCurrentProject() != null) { + // If you wish to show hints or dialogs before picking media, + // insert that logic here (e.g., check Prefs.addMediaHint). + when (mediaType) { + AddMediaType.CAMERA -> { + // Launch the camera using Picker. + Picker.takePhoto(this, mediaLaunchers.cameraLauncher) + } + AddMediaType.GALLERY -> { + // Launch the gallery/image picker. + Picker.pickMedia(mediaLaunchers.imagePickerLauncher) + } + AddMediaType.FILES -> { + // Launch the file picker. + Picker.pickFiles(mediaLaunchers.filePickerLauncher) + } + } + } else { + // If no project is selected, prompt the user to create one (e.g. add a folder). + launchNewFolder() + } + } + + /** + * Check for POST_NOTIFICATIONS permission on Android 13+. + */ + private fun checkNotificationPermissions() { + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) == PackageManager.PERMISSION_GRANTED + ) { + Timber.d("Notification permission already granted") + } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { + showNotificationPermissionRationale() + } else { + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } + + /** + * Show a rationale for notification permission. + */ + private fun showNotificationPermissionRationale() { + // TODO: Display a dialog or Snackbar explaining why notifications are needed. + Timber.d("Showing notification permission rationale") + } + + /** + * Handle incoming intents for deep-linking, shared media, etc. + */ + private fun handleIntent(intent: Intent?) { + intent?.let { receivedIntent -> + when (receivedIntent.action) { + Intent.ACTION_VIEW -> { + val uri = receivedIntent.data + if (uri?.scheme == "save-veilid") { + processUri(uri) + } + } + // Optionally handle other actions (like ACTION_SEND) here. + } + } + } + + private fun processUri(uri: Uri) { + // Process the URI similarly to your original logic. + Timber.d("Processing URI: $uri") + // TODO: Extract path, query parameters, etc. + } + + +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/MainActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/MainActivity.kt index 0d41a854..e6520c7c 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/main/MainActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/MainActivity.kt @@ -1,77 +1,125 @@ package net.opendasharchive.openarchive.features.main +import android.content.Context import android.content.Intent +import android.graphics.Point +import android.graphics.drawable.ColorDrawable +import android.net.Uri import android.os.Build import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager +import android.widget.LinearLayout +import android.widget.PopupWindow import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.drawerlayout.widget.DrawerLayout +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import net.opendasharchive.openarchive.FolderAdapter -import net.opendasharchive.openarchive.FolderAdapterListener +import net.opendasharchive.openarchive.BuildConfig import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.SpaceAdapter -import net.opendasharchive.openarchive.SpaceAdapterListener +import net.opendasharchive.openarchive.core.logger.AppLogger import net.opendasharchive.openarchive.databinding.ActivityMainBinding +import net.opendasharchive.openarchive.databinding.PopupFolderOptionsBinding +import net.opendasharchive.openarchive.db.Media import net.opendasharchive.openarchive.db.Project import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.extensions.getMeasurments import net.opendasharchive.openarchive.features.core.BaseActivity +import net.opendasharchive.openarchive.features.core.UiImage +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.asUiImage +import net.opendasharchive.openarchive.features.core.asUiText +import net.opendasharchive.openarchive.features.core.dialog.ButtonData +import net.opendasharchive.openarchive.features.core.dialog.DialogConfig +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.core.dialog.showInfoDialog import net.opendasharchive.openarchive.features.folders.AddFolderActivity +import net.opendasharchive.openarchive.features.main.adapters.FolderDrawerAdapter +import net.opendasharchive.openarchive.features.main.adapters.FolderDrawerAdapterListener +import net.opendasharchive.openarchive.features.main.adapters.SpaceDrawerAdapter +import net.opendasharchive.openarchive.features.main.adapters.SpaceDrawerAdapterListener import net.opendasharchive.openarchive.features.media.AddMediaDialogFragment import net.opendasharchive.openarchive.features.media.AddMediaType +import net.opendasharchive.openarchive.features.media.ContentPickerFragment import net.opendasharchive.openarchive.features.media.MediaLaunchers import net.opendasharchive.openarchive.features.media.Picker import net.opendasharchive.openarchive.features.media.PreviewActivity import net.opendasharchive.openarchive.features.onboarding.Onboarding23Activity import net.opendasharchive.openarchive.features.onboarding.SpaceSetupActivity +import net.opendasharchive.openarchive.features.onboarding.StartDestination +import net.opendasharchive.openarchive.features.settings.passcode.AppConfig +import net.opendasharchive.openarchive.services.snowbird.SnowbirdBridge +import net.opendasharchive.openarchive.services.snowbird.service.SnowbirdService +import net.opendasharchive.openarchive.upload.UploadManagerFragment import net.opendasharchive.openarchive.upload.UploadService -import net.opendasharchive.openarchive.util.AlertHelper +import net.opendasharchive.openarchive.util.PermissionManager import net.opendasharchive.openarchive.util.Prefs import net.opendasharchive.openarchive.util.ProofModeHelper import net.opendasharchive.openarchive.util.extensions.Position import net.opendasharchive.openarchive.util.extensions.cloak import net.opendasharchive.openarchive.util.extensions.hide import net.opendasharchive.openarchive.util.extensions.scaleAndTintDrawable -import net.opendasharchive.openarchive.util.extensions.scaled -import net.opendasharchive.openarchive.util.extensions.setDrawable import net.opendasharchive.openarchive.util.extensions.show +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.viewModel import java.text.NumberFormat -import kotlin.math.roundToInt -class MainActivity : BaseActivity(), FolderAdapterListener, SpaceAdapterListener { +class MainActivity : BaseActivity(), SpaceDrawerAdapterListener, FolderDrawerAdapterListener { + + private val appConfig by inject() + private val viewModel by viewModel() private var mMenuDelete: MenuItem? = null private var mSnackBar: Snackbar? = null - private lateinit var mBinding: ActivityMainBinding + var uploadManagerFragment: UploadManagerFragment? = null + + private lateinit var binding: ActivityMainBinding private lateinit var mPagerAdapter: ProjectAdapter - private lateinit var mSpaceAdapter: SpaceAdapter - private lateinit var mFolderAdapter: FolderAdapter + private lateinit var mSpaceAdapter: SpaceDrawerAdapter + private lateinit var mFolderAdapter: FolderDrawerAdapter private lateinit var mediaLaunchers: MediaLaunchers - private var mLastItem: Int = 0 - private var mLastMediaItem: Int = 0 + private var mSelectedPageIndex: Int = 0 + private var mSelectedMediaPageIndex: Int = 0 private var serverListOffset: Float = 0F private var serverListCurOffset: Float = 0F - private var mCurrentItem - get() = mBinding.pager.currentItem + private var selectModeToggle: Boolean = false + private var currentSelectionCount = 0 + + private enum class FolderBarMode { INFO, SELECTION, EDIT } + + // Hold the current mode (default to INFO) + private var folderBarMode = FolderBarMode.INFO + + // Current page getter/setter (updates bottom navbar accordingly) + private var mCurrentPagerItem + get() = binding.contentMain.pager.currentItem set(value) { - mBinding.pager.currentItem = value + binding.contentMain.pager.currentItem = value updateBottomNavbar(value) } + // ----- Activity Result Launchers ----- private val mNewFolderResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { @@ -79,281 +127,598 @@ class MainActivity : BaseActivity(), FolderAdapterListener, SpaceAdapterListener } } + private lateinit var permissionManager: PermissionManager + + override fun onCreate(savedInstanceState: Bundle?) { + ///enableEdgeToEdge() + super.onCreate(savedInstanceState) + installSplashScreen() + +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { +// window.insetsController?.let { +// it.hide(WindowInsets.Type.statusBars()) +// it.hide(WindowInsets.Type.systemBars()) +// it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE +// } +// } else { +// // For older versions, use the deprecated approach +// window.setFlags( +// WindowManager.LayoutParams.FLAG_FULLSCREEN, +// WindowManager.LayoutParams.FLAG_FULLSCREEN +// ) +// } + +// window.apply { +// clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) +// addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) +// statusBarColor = ContextCompat.getColor(this@MainActivity, R.color.colorPrimary) +// // optional. if you want the icons to be light. +// decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR +// } + + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + // Initialize the permission manager with this activity and its dialogManager. + permissionManager = PermissionManager(this, dialogManager) + + initMediaLaunchers() + setupToolbarAndPager() + setupNavigationDrawer() + setupBottomNavBar() + setupFolderBar() + setupBottomSheetObserver() + + + if (appConfig.isDwebEnabled) { + permissionManager.checkNotificationPermission { + AppLogger.i("Notification permission granted") + } + SnowbirdBridge.getInstance().initialize() + startForegroundService(Intent(this, SnowbirdService::class.java)) + handleIntent(intent) + } + + + if (BuildConfig.DEBUG) { + binding.contentMain.imgLogo.setOnLongClickListener { + startActivity(Intent(this, HomeActivity::class.java)) + true + } + } + + supportFragmentManager.setFragmentResultListener("uploadRetry", this) { key, bundle -> + val mediaId = bundle.getLong("mediaId") + // Now you know which media item is being retried. + // You can start the upload service or update the UI accordingly. + UploadService.startUploadService(this) + } + } + + override fun onResume() { + super.onResume() + if (!Prefs.didCompleteOnboarding) { + startActivity(Intent(this, Onboarding23Activity::class.java)) + } + AppLogger.i("MainActivity onResume is called.......") + refreshSpace() + mCurrentPagerItem = mSelectedPageIndex + importSharedMedia(intent) + if (serverListOffset == 0F) { + val dims = binding.spaces.getMeasurments() + serverListOffset = -dims.second.toFloat() + serverListCurOffset = serverListOffset + } + } + + @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + override fun onStart() { + super.onStart() - mBinding = ActivityMainBinding.inflate(layoutInflater) - setContentView(mBinding.root) + if (Prefs.useProofMode) { + Prefs.proofModeLocation = true + Prefs.proofModeNetwork = true + } else { + Prefs.proofModeLocation = false + Prefs.proofModeNetwork = false + } + ProofModeHelper.init(this) { + // Check for any queued uploads and restart, only after ProofMode is correctly initialized. + UploadService.startUploadService(this) + } + } + + // ----- Initialization Methods ----- + private fun initMediaLaunchers() { mediaLaunchers = Picker.register( activity = this, - root = mBinding.root, + root = binding.root, project = { getSelectedProject() }, completed = { media -> refreshCurrentProject() + if (media.isNotEmpty()) navigateToPreview() + } + ) + } - if (media.isNotEmpty()) { - preview() - } - }) - - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(false) - supportActionBar?.title = null + private fun setupToolbarAndPager() { + setSupportActionBar(binding.contentMain.toolbar) + supportActionBar?.apply { + setDisplayHomeAsUpEnabled(false) + title = null + } mPagerAdapter = ProjectAdapter(supportFragmentManager, lifecycle) - mBinding.pager.adapter = mPagerAdapter - - mBinding.pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { - override fun onPageScrolled( - position: Int, positionOffset: Float, - positionOffsetPixels: Int - ) { - } + binding.contentMain.pager.adapter = mPagerAdapter + binding.contentMain.pager.registerOnPageChangeCallback(object : + ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { - mLastItem = position + mSelectedPageIndex = position if (position < mPagerAdapter.settingsIndex) { - mLastMediaItem = position + mSelectedMediaPageIndex = position + val selectedProject = getSelectedProject() + mFolderAdapter.updateSelectedProject(selectedProject) + } + if (!appConfig.multipleProjectSelectionMode) { + getCurrentMediaFragment()?.cancelSelection() } - updateBottomNavbar(position) - refreshCurrentProject() } - - override fun onPageScrollStateChanged(state: Int) {} }) + } - mBinding.spaceName.setOnClickListener { - var newAlpha = 0F + private fun setupNavigationDrawer() { + // Drawer listener resets state on close + binding.root.addDrawerListener(object : DrawerLayout.DrawerListener { + override fun onDrawerClosed(drawerView: View) { + collapseSpacesList() + } - if (serverListCurOffset != serverListOffset) { - serverListCurOffset = serverListOffset - mBinding.spaceName.setDrawable(R.drawable.ic_expand_more, Position.End, 0.75) - } else { - newAlpha = 1F - serverListCurOffset = 0F - mBinding.spaceName.setDrawable(R.drawable.ic_expand_less, Position.End, 0.75) + override fun onDrawerOpened(drawerView: View) { + // } - mBinding.spaces.visibility = View.VISIBLE - mBinding.currentSpaceName.visibility = View.VISIBLE - mBinding.newFolder.visibility = View.VISIBLE - mBinding.folders.visibility = View.VISIBLE + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { + // + } - mBinding.spaces.animate().translationY(serverListCurOffset).alpha(newAlpha) - .withEndAction { - run { - if (newAlpha == 0F) { - mBinding.spaces.hide(false) - } - } - } - mBinding.currentSpaceName.animate().alpha(1 - newAlpha) - mBinding.newFolder.animate().alpha(1 - newAlpha) - mBinding.folders.animate().alpha(1 - newAlpha) + override fun onDrawerStateChanged(newState: Int) { + // + } + }) + + binding.navigationDrawerHeader.setOnClickListener { toggleSpacesList() } + binding.dimOverlay.setOnClickListener { collapseSpacesList() } + + mSpaceAdapter = SpaceDrawerAdapter(this) + binding.spaces.layoutManager = LinearLayoutManager(this) + binding.spaces.adapter = mSpaceAdapter + + mFolderAdapter = FolderDrawerAdapter(this) + binding.folders.layoutManager = LinearLayoutManager(this) + binding.folders.adapter = mFolderAdapter + + binding.btnAddFolder.scaleAndTintDrawable(Position.Start, 0.75) + binding.btnAddFolder.setOnClickListener { + closeDrawer() + navigateToAddFolder() } updateCurrentSpaceAtDrawer() + } - mSpaceAdapter = SpaceAdapter(this) - mBinding.spaces.layoutManager = LinearLayoutManager(this) - mBinding.spaces.adapter = mSpaceAdapter - - mFolderAdapter = FolderAdapter(this) - mBinding.folders.layoutManager = LinearLayoutManager(this) - mBinding.folders.adapter = mFolderAdapter + private fun setupBottomNavBar() { + with(binding.contentMain.bottomNavBar) { + onMyMediaClick = { + mCurrentPagerItem = mSelectedMediaPageIndex + } + onAddClick = { addClicked(AddMediaType.GALLERY) } + onSettingsClick = { + mCurrentPagerItem = mPagerAdapter.settingsIndex + } - mBinding.newFolder.scaleAndTintDrawable(Position.Start, 0.75) - mBinding.newFolder.setOnClickListener { - addFolder() + if (Picker.canPickFiles(this@MainActivity)) { + setAddButtonLongClickEnabled() + onAddLongClick = { + if (Space.current == null) { + navigateToAddServer() + } else if (getSelectedProject() == null) { + navigateToAddFolder() + } else { + val addMediaBottomSheet = + ContentPickerFragment { actionType -> addClicked(actionType) } + addMediaBottomSheet.show(supportFragmentManager, ContentPickerFragment.TAG) + } + } + supportFragmentManager.setFragmentResultListener( + AddMediaDialogFragment.RESP_TAKE_PHOTO, this@MainActivity + ) { _, _ -> addClicked(AddMediaType.CAMERA) } + supportFragmentManager.setFragmentResultListener( + AddMediaDialogFragment.RESP_PHOTO_GALLERY, this@MainActivity + ) { _, _ -> addClicked(AddMediaType.GALLERY) } + supportFragmentManager.setFragmentResultListener( + AddMediaDialogFragment.RESP_FILES, this@MainActivity + ) { _, _ -> addClicked(AddMediaType.FILES) } + } } + } - mBinding.myMediaButton.setOnClickListener { - mCurrentItem = mLastMediaItem + private fun setupFolderBar() { + // Tapping the edit button shows the folder options popup. + binding.contentMain.btnEdit.setOnClickListener { btnView -> + val location = IntArray(2) + binding.contentMain.btnEdit.getLocationOnScreen(location) + val point = Point(location[0], location[1]) + showFolderOptionsPopup(point) + } + // In selection mode, cancel selection reverts to INFO mode. + binding.contentMain.btnCancelSelection.setOnClickListener { + setFolderBarMode(FolderBarMode.INFO) + getCurrentMediaFragment()?.cancelSelection() } - mBinding.myMediaLabel.setOnClickListener { - // perform click + play ripple animation - mBinding.myMediaButton.isPressed = true - mBinding.myMediaButton.isPressed = false - mBinding.myMediaButton.performClick() + // In the edit (rename) container, cancel button reverts to INFO mode. + binding.contentMain.btnCancelEdit.setOnClickListener { + setFolderBarMode(FolderBarMode.INFO) } + // Listen for the "done" action to commit a rename. + binding.contentMain.etFolderName.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + val newName = binding.contentMain.etFolderName.text.toString().trim() + if (newName.isNotEmpty()) { + renameCurrentFolder(newName) + setFolderBarMode(FolderBarMode.INFO) + } else { + Snackbar.make( + binding.root, + getString(R.string.folder_empty_warning), + Snackbar.LENGTH_SHORT + ).show() + } + // Hide the keyboard + val imm = + binding.contentMain.etFolderName.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.contentMain.etFolderName.windowToken, 0) - mBinding.addButton.setOnClickListener { - addClicked(AddMediaType.GALLERY) + // Remove focus from the EditText + binding.contentMain.etFolderName.clearFocus() + + true + } else false } - mBinding.settingsButton.setOnClickListener { - mCurrentItem = mPagerAdapter.settingsIndex + binding.contentMain.btnRemoveSelected.setOnClickListener { + showDeleteSelectedMediaConfirmDialog() } - mBinding.settingsLabel.setOnClickListener { - // perform click + play ripple animation - mBinding.settingsButton.isPressed = true - mBinding.settingsButton.isPressed = false - mBinding.settingsButton.performClick() + } + + // Called when a new folder name is confirmed. (Adjust as needed to update your data store.) + private fun renameCurrentFolder(newName: String) { + val project = getSelectedProject() + project?.let { + it.description = newName + it.save() + refreshCurrentProject() + Snackbar.make(binding.root, getString(R.string.folder_rename_success), Snackbar.LENGTH_SHORT).show() } + } - if (Picker.canPickFiles(this)) { - mBinding.addButton.setOnLongClickListener { - val addMediaDialogFragment = AddMediaDialogFragment() - addMediaDialogFragment.show(supportFragmentManager, addMediaDialogFragment.tag) + private fun showFolderOptionsPopup(p: Point) { + val layoutInflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater + val popupBinding = PopupFolderOptionsBinding.inflate(layoutInflater) + val popup = PopupWindow(this).apply { + contentView = popupBinding.root + width = LinearLayout.LayoutParams.WRAP_CONTENT + height = LinearLayout.LayoutParams.WRAP_CONTENT + isFocusable = true + setBackgroundDrawable(ColorDrawable()) + animationStyle = R.style.popup_window_animation + } - true - } + // Option to toggle selection mode + popupBinding.menuFolderBarSelectMedia.setOnClickListener { + popup.dismiss() + setFolderBarMode(FolderBarMode.SELECTION) + } + // Rename folder + popupBinding.menuFolderBarRenameFolder.setOnClickListener { + popup.dismiss() + setFolderBarMode(FolderBarMode.EDIT) + } - supportFragmentManager.setFragmentResultListener( - AddMediaDialogFragment.RESP_TAKE_PHOTO, - this - ) { _, _ -> - addClicked(AddMediaType.CAMERA) - } - supportFragmentManager.setFragmentResultListener( - AddMediaDialogFragment.RESP_PHOTO_GALLERY, - this - ) { _, _ -> - addClicked(AddMediaType.GALLERY) - } - supportFragmentManager.setFragmentResultListener( - AddMediaDialogFragment.RESP_FILES, - this - ) { _, _ -> - addClicked(AddMediaType.FILES) + // Remove folder + popupBinding.menuFolderBarRemove.setOnClickListener { + popup.dismiss() + if (getSelectedProject() != null) { + showDeleteFolderConfirmDialog() + } else { + Snackbar.make(binding.root, getString(R.string.folder_not_found), Snackbar.LENGTH_LONG).show() } } - } - @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) - override fun onStart() { - super.onStart() + // Adjust popup position if needed + val x = 200 + val y = 60 + popup.showAtLocation(binding.root, Gravity.NO_GRAVITY, p.x + x, p.y + y) + } - ProofModeHelper.init(this) { - // Check for any queued uploads and restart, only after ProofMode is correctly initialized. - UploadService.startUploadService(this) + fun setSelectionMode(isSelecting: Boolean) { + if (isSelecting) { + setFolderBarMode(FolderBarMode.SELECTION) + } else { + setFolderBarMode(FolderBarMode.INFO) } } - override fun onResume() { - super.onResume() + // New helper: update the cancel selection TextView to show the number of selected items. + fun updateSelectedCount(count: Int) { + // For example, if count > 0 display “Selected: X”; otherwise, revert to “Select Media”. + //binding.contentMain.tvSelectedCount.text = if (count > 0) "Selected: $count" else "Select Media" + } - refreshSpace() + private fun showDeleteSelectedMediaConfirmDialog() { + dialogManager.showDialog( + config = DialogConfig( + type = DialogType.Warning, + title = R.string.menu_delete.asUiText(), + message = R.string.menu_delete_desc.asUiText(), + icon = UiImage.DrawableResource(R.drawable.ic_trash), + positiveButton = ButtonData( + text = R.string.lbl_ok.asUiText(), + action = { + getCurrentMediaFragment()?.deleteSelected() + updateSelectedCount(0) + refreshCurrentFolderCount() + } + ), + neutralButton = + ButtonData( + text = UiText.StringResource(R.string.lbl_Cancel), + action = { - mCurrentItem = mLastItem + } + ) + ) + ) + } - if (!Prefs.didCompleteOnboarding) { - startActivity(Intent(this, Onboarding23Activity::class.java)) + private fun showDeleteFolderConfirmDialog() { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Error + icon = UiImage.DrawableResource(R.drawable.ic_trash) + title = UiText.StringResource(R.string.remove_from_app) + message = UiText.StringResource(R.string.action_remove_project) + destructiveButton { + text = UiText.StringResource(R.string.remove) + action = { + getSelectedProject()?.delete() + refreshProjects() + updateCurrentFolderVisibility() + refreshCurrentProject() + Snackbar.make(binding.root, getString(R.string.folder_removed), Snackbar.LENGTH_SHORT).show() + } + } + neutralButton { + text = UiText.StringResource(R.string.lbl_Cancel) + action = { + dialogManager.dismissDialog() + } + } } + } - importSharedMedia(intent) + private fun getCurrentMediaFragment(): MainMediaFragment? { + val currentItem = binding.contentMain.pager.currentItem + return supportFragmentManager.findFragmentByTag("f$currentItem") as? MainMediaFragment + } - if (serverListOffset == 0F) { - val dims = mBinding.spaces.getMeasurments() - serverListOffset = -dims.second.toFloat() - serverListCurOffset = serverListOffset - mBinding.spaces.visibility = View.GONE - mBinding.spaces.animate().translationY(serverListOffset) - mBinding.spaceName.setDrawable(R.drawable.ic_expand_more, Position.End, 0.75) + + // ----- Drawer Helpers ----- + private fun toggleDrawerState() { + if (binding.root.isDrawerOpen(binding.drawerContent)) { + closeDrawer() + } else { + openDrawer() } } - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_main, menu) - mMenuDelete = menu.findItem(R.id.menu_delete) + private fun openDrawer() { + binding.root.openDrawer(binding.drawerContent) + } - return super.onCreateOptionsMenu(menu) + private fun closeDrawer() { + binding.root.closeDrawer(binding.drawerContent) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.menu_folders -> { + private fun toggleSpacesList() { + if (serverListCurOffset == serverListOffset) { + expandSpacesList() + } else { + collapseSpacesList() + } + } - if (mBinding.root.isDrawerOpen(mBinding.folderBar)) { - mBinding.root.closeDrawer(mBinding.folderBar) - } else { - mBinding.root.openDrawer(mBinding.folderBar) - } - true + private fun expandSpacesList() { + serverListCurOffset = 0f + binding.spaceListMore.setImageDrawable( + ContextCompat.getDrawable(this, R.drawable.ic_expand_less) + ) + binding.spaces.visibility = View.VISIBLE + binding.dimOverlay.visibility = View.VISIBLE + binding.spaces.bringToFront() + binding.dimOverlay.bringToFront() + binding.spaces.animate() + .translationY(0f).alpha(1f).setDuration(200) + .withStartAction { + binding.spacesHeaderSeparator.alpha = 0.3f + binding.folders.alpha = 0.3f + binding.btnAddFolder.alpha = 0.3f } + binding.dimOverlay.animate().alpha(1f).setDuration(200) + binding.navigationDrawerHeader.elevation = 8f + } - else -> super.onOptionsItemSelected(item) - } + private fun collapseSpacesList() { + serverListCurOffset = serverListOffset + binding.spaceListMore.setImageDrawable( + ContextCompat.getDrawable(this, R.drawable.ic_expand_more) + ) + + binding.spaces.animate() + .translationY(serverListOffset).alpha(0f).setDuration(200) + .withEndAction { + binding.spaces.visibility = View.GONE + binding.dimOverlay.visibility = View.GONE + binding.spacesHeaderSeparator.alpha = 1f + binding.folders.alpha = 1f + binding.btnAddFolder.alpha = 1f + } + binding.dimOverlay.animate().alpha(0f).setDuration(200) + binding.navigationDrawerHeader.elevation = 0f } private fun updateCurrentSpaceAtDrawer() { - mBinding.currentSpaceName.text = Space.current?.friendlyName - mBinding.currentSpaceName.setDrawable( - Space.current?.getAvatar(applicationContext)?.scaled(R.dimen.avatar_size, applicationContext), - Position.Start, tint = true - ) - mBinding.currentSpaceName.compoundDrawablePadding = - applicationContext.resources.getDimension(R.dimen.padding_small).roundToInt() + Space.current?.setAvatar(binding.currentSpaceIcon) + mSpaceAdapter.notifyDataSetChanged() + + if (Space.current == null) { + binding.btnAddFolder.visibility = View.INVISIBLE + } else { + binding.btnAddFolder.visibility = View.VISIBLE + } } - fun updateAfterDelete(done: Boolean) { - mMenuDelete?.isVisible = !done + // ----- Refresh & Update Methods ----- + /** + * Updates the visibility of the current folder container. + * The container is only visible if: + * 1. We are not on the settings page AND + * 2. There is a current space with at least one project. + */ + // Central function to update folder bar state + private fun setFolderBarMode(mode: FolderBarMode) { + folderBarMode = mode + when (mode) { + FolderBarMode.INFO -> { + binding.contentMain.folderInfoContainer.visibility = View.VISIBLE + binding.contentMain.folderSelectionContainer.visibility = View.GONE + binding.contentMain.folderEditContainer.visibility = View.GONE + + if (Space.current != null) { + if (Space.current?.projects?.isNotEmpty() == true) { + binding.contentMain.folderInfoContainerRight.visibility = View.VISIBLE + } else { + binding.contentMain.folderInfoContainerRight.visibility = View.INVISIBLE + } + } else { + binding.contentMain.folderInfoContainerRight.visibility = View.INVISIBLE + } + } + + FolderBarMode.SELECTION -> { + binding.contentMain.folderInfoContainer.visibility = View.GONE + binding.contentMain.folderSelectionContainer.visibility = View.VISIBLE + binding.contentMain.folderEditContainer.visibility = View.GONE + } - if (done) refreshCurrentFolderCount() + FolderBarMode.EDIT -> { + binding.contentMain.folderInfoContainer.visibility = View.GONE + binding.contentMain.folderSelectionContainer.visibility = View.GONE + binding.contentMain.folderEditContainer.visibility = View.VISIBLE + // Prepopulate the rename field with the current folder name + binding.contentMain.etFolderName.setText(getSelectedProject()?.description ?: "") + binding.contentMain.etFolderName.requestFocus() + + // Show the keyboard + val imm = + binding.contentMain.etFolderName.context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput( + binding.contentMain.etFolderName, + InputMethodManager.SHOW_IMPLICIT + ) + } + } } - private fun addFolder() { - mNewFolderResultLauncher.launch(Intent(this, AddFolderActivity::class.java)) + private fun updateCurrentFolderVisibility() { + val currentPagerIndex = binding.contentMain.pager.currentItem + val settingsIndex = mPagerAdapter.settingsIndex + if (currentPagerIndex == settingsIndex) { + binding.contentMain.folderBar.hide() + // Reset to default mode + setFolderBarMode(FolderBarMode.INFO) + + // Force ViewPager2 to re-measure its layout after visibility change + binding.contentMain.pager.post { + binding.contentMain.pager.requestLayout() + } + } else { + binding.contentMain.folderBar.show() + setFolderBarMode(FolderBarMode.INFO) + } - mBinding.root.closeDrawer(mBinding.folderBar) + mFolderAdapter.notifyDataSetChanged() } - private fun refreshSpace() { -// val currentSpace = Space.current + private fun updateBottomNavbar(position: Int) { + val isSettings = position == mPagerAdapter.settingsIndex + binding.contentMain.bottomNavBar.updateSelectedItem(isSettings = isSettings) + updateCurrentFolderVisibility() + invalidateOptionsMenu() + } -// if (currentSpace != null) { -// mBinding.space.setDrawable( -// currentSpace.getAvatar(this@MainActivity) -// ?.scaled(32, this@MainActivity), Position.Start, tint = false -// ) - mBinding.spaceName.text = getString(R.string.servers) // currentSpace.friendlyName -// } else { -// mBinding.space.setDrawable(R.drawable.avatar_default, Position.Start, tint = false) -// mBinding.space.text = getString(R.string.app_name) -// } + private fun refreshSpace() { + val currentSpace = Space.current + if (currentSpace != null) { + binding.spaceNameLayout.visibility = View.VISIBLE + binding.currentSpaceName.text = currentSpace.friendlyName + updateCurrentSpaceAtDrawer() + currentSpace.setAvatar(binding.contentMain.spaceIcon) + } else { + binding.contentMain.spaceIcon.visibility = View.INVISIBLE + binding.spaceNameLayout.visibility = View.INVISIBLE + } mSpaceAdapter.update(Space.getAll().asSequence().toList()) - + updateCurrentSpaceAtDrawer() refreshProjects() + refreshCurrentProject() + updateCurrentFolderVisibility() } private fun refreshProjects(setProjectId: Long? = null) { val projects = Space.current?.projects ?: emptyList() - mPagerAdapter.updateData(projects) - - mBinding.pager.adapter = mPagerAdapter + binding.contentMain.pager.adapter = mPagerAdapter setProjectId?.let { - mCurrentItem = mPagerAdapter.getProjectIndexById(it, default = 0) + mCurrentPagerItem = mPagerAdapter.getProjectIndexById(it, default = 0) } - mFolderAdapter.update(projects) - - refreshCurrentProject() } private fun refreshCurrentProject() { val project = getSelectedProject() if (project != null) { - mBinding.pager.post { + binding.contentMain.pager.post { mPagerAdapter.notifyProjectChanged(project) } - - project.space?.setAvatar(mBinding.currentFolderIcon) - mBinding.currentFolderIcon.show() - - mBinding.currentFolderName.text = project.description - mBinding.currentFolderName.show() + binding.contentMain.folderInfoContainer.visibility = View.VISIBLE + project.space?.setAvatar(binding.contentMain.spaceIcon) + binding.contentMain.folderName.text = project.description + binding.contentMain.folderNameArrow.visibility = View.VISIBLE + binding.contentMain.folderName.visibility = View.VISIBLE } else { - mBinding.currentFolderIcon.cloak() - mBinding.currentFolderName.cloak() + binding.contentMain.folderNameArrow.visibility = View.INVISIBLE + binding.contentMain.folderName.visibility = View.INVISIBLE } - + updateCurrentFolderVisibility() refreshCurrentFolderCount() } @@ -361,151 +726,223 @@ class MainActivity : BaseActivity(), FolderAdapterListener, SpaceAdapterListener val project = getSelectedProject() if (project != null) { - mBinding.currentFolderCount.text = NumberFormat.getInstance().format( - project.collections.map { it.size } - .reduceOrNull { acc, count -> acc + count } ?: 0) - mBinding.currentFolderCount.show() + val count = project.collections.map { it.size } + .reduceOrNull { acc, count -> acc + count } ?: 0 + binding.contentMain.itemCount.text = NumberFormat.getInstance().format(count) + if (!selectModeToggle) { + binding.contentMain.itemCount.show() + } + } else { + binding.contentMain.itemCount.cloak() + } + } -// mBinding.uploadEditButton.toggle(project.isUploading) + // ----- Navigation & Media Handling ----- + private fun navigateToAddServer() { + closeDrawer() + startActivity(Intent(this, SpaceSetupActivity::class.java)) + } + + private fun navigateToAddFolder() { + val intent = Intent(this, SpaceSetupActivity::class.java) + if (Space.current?.tType == Space.Type.INTERNET_ARCHIVE) { + // We cannot browse the Internet Archive. Directly forward to creating a project, + // as it doesn't make sense to show a one-option menu. + intent.putExtra("start_destination", StartDestination.ADD_NEW_FOLDER.name) } else { - mBinding.currentFolderCount.cloak() -// mBinding.uploadEditButton.hide() + intent.putExtra("start_destination", StartDestination.ADD_FOLDER.name) } + mNewFolderResultLauncher.launch(intent) +// mNewFolderResultLauncher.launch(Intent(this, AddFolderActivity::class.java)) } - private fun importSharedMedia(data: Intent?) { - if (data?.action != Intent.ACTION_SEND) return + private fun addClicked(mediaType: AddMediaType) { - val uri = data.data ?: if ((data.clipData?.itemCount - ?: 0) > 0 - ) data.clipData?.getItemAt(0)?.uri else null - val path = uri?.path ?: return + when { + getSelectedProject() != null -> { + if (Prefs.addMediaHint) { + when (mediaType) { + AddMediaType.CAMERA -> { + //permissionManager.checkCameraPermission { + Picker.takePhoto(this@MainActivity, mediaLaunchers.cameraLauncher) + //} + } + + AddMediaType.GALLERY -> { + permissionManager.checkMediaPermissions { + Picker.pickMedia(mediaLaunchers.imagePickerLauncher) + } + } + AddMediaType.FILES -> Picker.pickFiles(mediaLaunchers.filePickerLauncher) + } + } else { + dialogManager.showInfoDialog( + icon = R.drawable.perm_media_24px.asUiImage(), + title = R.string.press_and_hold_options_media_screen_title.asUiText(), + message = R.string.press_and_hold_options_media_screen_message.asUiText(), + onDone = { + Prefs.addMediaHint = true + addClicked(mediaType) + } + ) + } + } + + Space.current == null -> navigateToAddServer() + else -> { + navigateToAddFolder() + } + } + } + + private fun importSharedMedia(imageIntent: Intent?) { + if (imageIntent?.action != Intent.ACTION_SEND) return + val uri = + imageIntent.data ?: imageIntent.clipData?.takeIf { it.itemCount > 0 }?.getItemAt(0)?.uri + val path = uri?.path ?: return if (path.contains(packageName)) return mSnackBar?.show() - lifecycleScope.launch(Dispatchers.IO) { val media = Picker.import(this@MainActivity, getSelectedProject(), uri) - lifecycleScope.launch(Dispatchers.Main) { mSnackBar?.dismiss() intent = null - if (media != null) { - preview() + navigateToPreview() } } } } - private fun preview() { + private fun navigateToPreview() { val projectId = getSelectedProject()?.id ?: return - PreviewActivity.start(this, projectId) } - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - - when (requestCode) { - 2 -> Picker.pickMedia(this, mediaLaunchers.imagePickerLauncher) + // ----- Permissions & Intent Handling ----- + private fun handleIntent(intent: Intent) { + if (intent.action == Intent.ACTION_VIEW) { + intent.data?.takeIf { it.scheme == "save-veilid" }?.let { processUri(it) } } } -// private fun showAlertIcon() { -// mBinding.alertIcon.show() -// TooltipCompat.setTooltipText( -// mBinding.alertIcon, -// getString(R.string.unsecured_internet_connection) -// ) -// } + private fun processUri(uri: Uri) { + val path = uri.path + val queryParams = uri.queryParameterNames.associateWith { uri.getQueryParameter(it) } + AppLogger.d("Path: $path, QueryParams: $queryParams") + } - override fun projectClicked(project: Project) { - mCurrentItem = mPagerAdapter.projects.indexOf(project) + // ----- Overrides ----- + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.menu_main, menu) + return super.onCreateOptionsMenu(menu) + } -// mBinding.root.closeDrawer(mBinding.folderBar) + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + val shouldShowSideMenu = + Space.current != null && mCurrentPagerItem != mPagerAdapter.settingsIndex + menu?.findItem(R.id.menu_folders)?.apply { + isVisible = shouldShowSideMenu + } + return super.onPrepareOptionsMenu(menu) + } -// mBinding.spacesCard.disableAnimation { -// mBinding.spacesCard.hide() -// } + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.menu_folders -> { + toggleDrawerState() + true + } - // make sure that even when navigating to settings and picking a folder there - // the dataset will get update correctly - mFolderAdapter.notifyDataSetChanged() + else -> super.onOptionsItemSelected(item) + } + } + + // ----- Adapter Listeners ----- + override fun onProjectSelected(project: Project) { + binding.root.closeDrawer(binding.drawerContent) + mCurrentPagerItem = mPagerAdapter.projects.indexOf(project) } override fun getSelectedProject(): Project? { - return mPagerAdapter.getProject(mCurrentItem) + return mPagerAdapter.getProject(mCurrentPagerItem) } - override fun spaceClicked(space: Space) { + override fun onSpaceSelected(space: Space) { Space.current = space - refreshSpace() - - mBinding.root.closeDrawer(mBinding.folderBar) - -// mBinding.spacesCard.disableAnimation { -// mBinding.spacesCard.hide() -// } - updateCurrentSpaceAtDrawer() + collapseSpacesList() + binding.root.closeDrawer(binding.drawerContent) } - override fun addSpaceClicked() { - mBinding.root.closeDrawer(mBinding.folderBar) - - startActivity(Intent(this, SpaceSetupActivity::class.java)) + override fun onAddNewSpace() { + collapseSpacesList() + closeDrawer() + val intent = Intent(this, SpaceSetupActivity::class.java) + startActivity(intent) } override fun getSelectedSpace(): Space? { + val currentSpace = Space.current + AppLogger.i("current space requested by adapter... = $currentSpace") return Space.current } - private fun addClicked(mediaType: AddMediaType) { + /** + * Show the UploadManagerFragment as a Bottom Sheet. + * Ensures we only show one instance. + */ + fun showUploadManagerFragment() { + if (uploadManagerFragment == null) { + uploadManagerFragment = UploadManagerFragment() + uploadManagerFragment?.show(supportFragmentManager, UploadManagerFragment.TAG) + + // Stop the upload service when the bottom sheet is shown + UploadService.stopUploadService(this) + } + } - if (getSelectedProject() != null) { - when(mediaType) { - AddMediaType.CAMERA -> Picker.takePhoto(this@MainActivity, mediaLaunchers.cameraLauncher) - AddMediaType.GALLERY -> Picker.pickMedia(this, mediaLaunchers.imagePickerLauncher) - AddMediaType.FILES -> Picker.pickFiles(mediaLaunchers.filePickerLauncher) + /** + * Setup a listener to detect when the UploadManagerFragment is dismissed. + * If there are pending uploads, restart the UploadService. + */ + private fun setupBottomSheetObserver() { + supportFragmentManager.addFragmentOnAttachListener { _, fragment -> + if (fragment is UploadManagerFragment) { + uploadManagerFragment = fragment + + // Observe when it gets dismissed + fragment.lifecycle.addObserver(object : DefaultLifecycleObserver { + override fun onDestroy(owner: LifecycleOwner) { + uploadManagerFragment = null // Clear reference + + // Check if there are pending uploads + if (Media.getByStatus( + listOf(Media.Status.Queued, Media.Status.Uploading), + Media.ORDER_PRIORITY + ).isNotEmpty() + ) { + UploadService.startUploadService(this@MainActivity) + } + } + }) } + } + } - } else { + override fun onDestroy() { + super.onDestroy() - if (!Prefs.addFolderHintShown) { - AlertHelper.show( - this, - R.string.before_adding_media_create_a_new_folder_first, - R.string.to_get_started_please_create_a_folder, - R.drawable.ic_folder, - buttons = listOf( - AlertHelper.positiveButton(R.string.add_a_folder) { _, _ -> - Prefs.addFolderHintShown = true - - addFolder() - }, - AlertHelper.negativeButton(R.string.lbl_Cancel) - ) - ) - } else { - addFolder() - } - } + // Clear pending callbacks/messages + window?.decorView?.handler?.removeCallbacksAndMessages(null) } - private fun updateBottomNavbar(position: Int) { - if (position == mPagerAdapter.settingsIndex) { - mBinding.myMediaButton.setIconResource(R.drawable.outline_perm_media_24) - mBinding.settingsButton.setIconResource(R.drawable.ic_settings_filled) - } else { - mBinding.myMediaButton.setIconResource(R.drawable.perm_media_24px) - mBinding.settingsButton.setIconResource(R.drawable.ic_settings) - } + companion object { + // Define request codes + const val REQUEST_CAMERA_PERMISSION = 100 + const val REQUEST_FILE_MEDIA = 101 } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/MainMediaFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/MainMediaFragment.kt index 2e6e6293..ff206b88 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/main/MainMediaFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/MainMediaFragment.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import android.view.LayoutInflater -import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment @@ -22,17 +21,24 @@ import net.opendasharchive.openarchive.databinding.FragmentMainMediaBinding import net.opendasharchive.openarchive.databinding.ViewSectionBinding import net.opendasharchive.openarchive.db.Collection import net.opendasharchive.openarchive.db.Media -import net.opendasharchive.openarchive.db.MediaAdapter -import net.opendasharchive.openarchive.db.MediaViewHolder +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.main.adapters.MainMediaAdapter import net.opendasharchive.openarchive.upload.BroadcastManager +import net.opendasharchive.openarchive.upload.UploadService import net.opendasharchive.openarchive.util.AlertHelper +import net.opendasharchive.openarchive.util.extensions.Position import net.opendasharchive.openarchive.util.extensions.toggle +import org.koin.androidx.viewmodel.ext.android.activityViewModel import kotlin.collections.set -class MainMediaFragment : Fragment() { +class MainMediaFragment : BaseFragment() { companion object { - private const val COLUMN_COUNT = 4 + private const val COLUMN_COUNT = 3 private const val ARG_PROJECT_ID = "project_id" fun newInstance(projectId: Long): MainMediaFragment { @@ -46,11 +52,16 @@ class MainMediaFragment : Fragment() { } } - private var mAdapters = HashMap() + private val viewModel by activityViewModel() + + private var mAdapters = HashMap() private var mSection = HashMap() private var mProjectId = -1L private var mCollections = mutableMapOf() + private var selectedMediaIds = mutableSetOf() + private var isSelecting = false + private lateinit var binding: FragmentMainMediaBinding private val mMessageReceiver: BroadcastReceiver = object : BroadcastReceiver() { @@ -79,11 +90,6 @@ class MainMediaFragment : Fragment() { } } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - override fun onStart() { super.onStart() BroadcastManager.register(requireContext(), mMessageReceiver) @@ -94,23 +100,9 @@ class MainMediaFragment : Fragment() { BroadcastManager.unregister(requireContext(), mMessageReceiver) } - @Deprecated("Deprecated in Java") - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.menu_delete -> { - AlertHelper.show( - requireContext(), R.string.confirm_remove_media, null, buttons = listOf( - AlertHelper.positiveButton(R.string.remove) { _, _ -> - deleteSelected() - }, - AlertHelper.negativeButton() - ) - ) - true - } - - else -> super.onOptionsItemSelected(item) - } + override fun onPause() { + cancelSelection() + super.onPause() } override fun onCreateView( @@ -127,6 +119,28 @@ class MainMediaFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel.log("MainMediaFragment onCreateView called for project Id $mProjectId") + + val space = Space.current + val text: String = if (space != null) { + val projects = space.projects + if (projects.isNotEmpty()) { + getString(R.string.tap_to_add) + } else { + getString(R.string.tap_to_add_folder) + } + } else { + getString(R.string.tap_to_add_server) + } + + binding.tvWelcomeDescr.text = text + + if (space != null) { + binding.tvWelcome.visibility = View.INVISIBLE + } else { + binding.tvWelcome.visibility = View.VISIBLE + } + refresh() } @@ -134,7 +148,6 @@ class MainMediaFragment : Fragment() { fun updateProjectItem(collectionId: Long, mediaId: Long, progress: Int, isUploaded: Boolean) { AppLogger.i("Current progress for $collectionId: ", progress) mAdapters[collectionId]?.apply { - viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) { updateItem(mediaId, progress, isUploaded) if (progress == -1) { @@ -192,6 +205,13 @@ class MainMediaFragment : Fragment() { binding.addMediaHint.toggle(mCollections.isEmpty()) } + fun cancelSelection() { + isSelecting = false + selectedMediaIds.clear() + mAdapters.values.forEach { it.clearSelections() } + updateSelectionCount() + } + fun deleteSelected() { val toDelete = ArrayList() @@ -212,20 +232,24 @@ class MainMediaFragment : Fragment() { private fun createMediaList(collection: Collection, media: List): View { val holder = SectionViewHolder(ViewSectionBinding.inflate(layoutInflater)) - holder.recyclerView.setHasFixedSize(true) holder.recyclerView.layoutManager = GridLayoutManager(activity, COLUMN_COUNT) holder.setHeader(collection, media) - val mediaAdapter = MediaAdapter( - requireActivity(), - { MediaViewHolder.Box(it) }, - media, - holder.recyclerView - ) { - (activity as? MainActivity)?.updateAfterDelete(mAdapters.values.firstOrNull { it.selecting } == null) - } + val mediaAdapter = MainMediaAdapter( + activity = requireActivity(), + mediaList = media, + recyclerView = holder.recyclerView, + checkSelecting = { updateSelectionState() }, + onDeleteClick = { mediaItem, itemPosition -> + showDeleteConfirmationDialog( + mediaItem = mediaItem, + itemPosition = itemPosition + ) + + } + ) holder.recyclerView.adapter = mediaAdapter mAdapters[collection.id] = mediaAdapter @@ -234,6 +258,50 @@ class MainMediaFragment : Fragment() { return holder.root } + private fun showDeleteConfirmationDialog(mediaItem: Media, itemPosition: Int) { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Error + title = UiText.StringResource(R.string.upload_unsuccessful) + message = UiText.StringResource(R.string.upload_unsuccessful_description) + positiveButton { + text = UiText.StringResource(R.string.retry) + action = { + mediaItem.apply { + sStatus = Media.Status.Queued + statusMessage = "" + save() + BroadcastManager.postChange( + requireActivity(), + mediaItem.collectionId, + mediaItem.id + ) + } + UploadService.startUploadService(requireActivity()) + } + } + destructiveButton { + text = UiText.StringResource(R.string.btn_lbl_remove_media) + action = { + val adapter = mAdapters[mediaItem.collectionId] + adapter?.deleteItem(itemPosition) + } + } + } + } + + //update selection UI by summing selected counts from all adapters. + fun updateSelectionState() { + val isSelecting = mAdapters.values.any { it.selecting } + (activity as? MainActivity)?.setSelectionMode(isSelecting) + val totalSelected = mAdapters.values.sumOf { it.getSelectedCount() } + (activity as? MainActivity)?.updateSelectedCount(totalSelected) + } + + + private fun updateSelectionCount() { + (activity as? MainActivity)?.updateSelectedCount(selectedMediaIds.size) + } + private fun deleteCollections(collectionIds: List, cleanup: Boolean) { collectionIds.forEach { collectionId -> mAdapters.remove(collectionId) @@ -249,4 +317,10 @@ class MainMediaFragment : Fragment() { } } } + + fun showUploadManager() { + (activity as? MainActivity)?.showUploadManagerFragment() + } + + override fun getToolbarTitle(): String = "" } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/MainViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/MainViewModel.kt new file mode 100644 index 00000000..fba870c1 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/MainViewModel.kt @@ -0,0 +1,38 @@ +package net.opendasharchive.openarchive.features.main + +import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import net.opendasharchive.openarchive.core.logger.AppLogger + +class MainViewModel : ViewModel() { + + private val _uiState = MutableStateFlow( + MainUiState( + currentPagerItem = 0 + ) + ) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + + AppLogger.i("MainViewModel initialized....") + } + + + fun log(msg: String) { + AppLogger.i("MainViewModel: $msg") + } + + fun updateCurrentPagerItem(page: Int) { + _uiState.update { it.copy(currentPagerItem = page) } + } + + fun getCurrentPagerItem(): Int = _uiState.value.currentPagerItem +} + +data class MainUiState( + val currentPagerItem: Int +) \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/QRScannerActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/QRScannerActivity.kt new file mode 100644 index 00000000..5495f775 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/QRScannerActivity.kt @@ -0,0 +1,13 @@ +package net.opendasharchive.openarchive.features.main + +import android.os.Bundle +//import com.journeyapps.barcodescanner.CaptureActivity +import timber.log.Timber + +//class QRScannerActivity : CaptureActivity() { +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// +// Timber.d("Starting QR scanner") +// } +//} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/SectionViewHolder.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/SectionViewHolder.kt index 78402f26..60f34bff 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/main/SectionViewHolder.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/SectionViewHolder.kt @@ -6,6 +6,9 @@ import net.opendasharchive.openarchive.db.Collection import net.opendasharchive.openarchive.db.Media import java.text.DateFormat import java.text.NumberFormat +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale data class SectionViewHolder( private val binding: ViewSectionBinding @@ -13,11 +16,16 @@ data class SectionViewHolder( companion object { - private val mNf - get() = NumberFormat.getIntegerInstance() + private val mNf = NumberFormat.getIntegerInstance() - private val mDf - get() = DateFormat.getDateTimeInstance() + private val mDf = DateFormat.getDateTimeInstance() + + private val dateFormat = SimpleDateFormat("MMM dd, yyyy | h:mma", Locale.ENGLISH) + + fun formatWithLowercaseAmPm(date: Date): String { + val formatted = dateFormat.format(date) + return formatted.replace("AM", "am").replace("PM", "pm") + } } @@ -33,25 +41,15 @@ data class SectionViewHolder( val recyclerView get() = binding.recyclerView - fun setHeader( - collection: Collection, - media: List - ) { - if (media.any { it.isUploading }) - { + fun setHeader(collection: Collection, media: List) { + if (media.any { it.isUploading }) { timestamp.setText(R.string.uploading) - val uploaded = media.filter { it.sStatus == Media.Status.Uploaded }.size - count.text = count.context.getString(R.string.counter, uploaded, media.size) - return } - count.text = mNf.format(media.size) - val uploadDate = collection.uploadDate - - timestamp.text = if (uploadDate != null) mDf.format(uploadDate) else "Ready to upload" + timestamp.text = if (uploadDate != null) formatWithLowercaseAmPm(uploadDate) else "Ready to upload" } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClient.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClient.kt new file mode 100644 index 00000000..b9ce6e83 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClient.kt @@ -0,0 +1,130 @@ +package net.opendasharchive.openarchive.features.main + +import android.content.Context +import android.net.LocalSocket +import android.net.LocalSocketAddress +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import net.opendasharchive.openarchive.db.SerializableMarker +import net.opendasharchive.openarchive.services.snowbird.service.HttpLikeException +import timber.log.Timber +import java.io.BufferedReader +import java.io.File +import java.io.IOException +import java.io.InputStream +import java.io.InputStreamReader +import java.net.SocketTimeoutException + +enum class HttpMethod(val value: String) { + GET("GET"), POST("POST"), PUT("PUT"), DELETE("DELETE"), PATCH("PATCH"), + HEAD("HEAD"), OPTIONS("OPTIONS"), TRACE("TRACE"); + + override fun toString() = value + + companion object { + fun fromString(method: String) = entries.find { it.value.equals(method, ignoreCase = true) } + } +} + +//sealed class ClientResponse { +// data class SuccessResponse(val data: T) : ClientResponse() +// data class ErrorResponse(val error: ApiError) : ClientResponse() +//} + +class UnixSocketClient(context: Context) { + val socketPath: String = File(context.filesDir, "rust_server.sock").absolutePath + val json = Json { ignoreUnknownKeys = true } + + suspend inline fun sendRequest( + endpoint: String, + method: HttpMethod, + body: REQUEST? = null + ): RESPONSE = withContext(Dispatchers.IO) { + Timber.d("$method $endpoint") + sendRequestInternal(endpoint, method, body, { json.encodeToString(it) }, { json.decodeFromString(it) }) + } + + fun sendRequestInternal( + endpoint: String, + method: HttpMethod, + body: REQUEST?, + serialize: (REQUEST) -> String, + deserialize: (String) -> RESPONSE + ): RESPONSE { + return try { + LocalSocket().use { socket -> + socket.connect(LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM)) + + val (responseCode, _, responseBody) = sendJsonRequestAndGetResponse(socket, endpoint, method, body, serialize) + + Timber.d("response body = $responseBody") + + when (responseCode) { + in 200..299 -> parseSuccessResponse(responseBody, deserialize) + else -> throw HttpLikeException(responseCode) + } + } + } catch (e: SocketTimeoutException) { + e.printStackTrace() + throw e + } catch (e: IOException) { + e.printStackTrace() + throw e + } catch (e: Exception) { + e.printStackTrace() + throw IOException("Unexpected error during Unix socket communication: ${e.message}") + } + } + + private fun sendJsonRequestAndGetResponse( + socket: LocalSocket, + endpoint: String, + method: HttpMethod, + body: REQUEST?, + serialize: (REQUEST) -> String + ): Triple, String> { + val output = socket.outputStream + val jsonBody = body?.let { serialize(it) } ?: "" + + val requestHeaders = buildString { + append("$method $endpoint HTTP/1.1\r\n") + append("Content-Type: application/json\r\n") + append("Content-Length: ${jsonBody.length}\r\n") + append("\r\n") + } + + output.write(requestHeaders.toByteArray()) + output.write(jsonBody.toByteArray()) + output.flush() + + return readResponse(socket.inputStream) + } + + fun readResponse(inputStream: InputStream): Triple, String> { + val reader = BufferedReader(InputStreamReader(inputStream)) + val statusLine = reader.readLine() + val (_, statusCode, _) = statusLine.split(" ", limit = 3) + + val headers = mutableMapOf() + var line: String? + while (reader.readLine().also { line = it } != null) { + if (line.isNullOrBlank()) break + val (key, value) = line!!.split(": ", limit = 2) + headers[key] = value + } + + val responseBody = reader.readText() + + return Triple(statusCode.toInt(), headers, responseBody) + } + + fun parseSuccessResponse(responseBody: String, deserialize: (String) -> T): T { + return try { + deserialize(responseBody) + } catch (e: Exception) { + Timber.e("error = $e") + throw e + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClientFileExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClientFileExtensions.kt new file mode 100644 index 00000000..67b4e4a7 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClientFileExtensions.kt @@ -0,0 +1,94 @@ +package net.opendasharchive.openarchive.features.main + +import android.net.LocalSocket +import android.net.LocalSocketAddress +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import net.opendasharchive.openarchive.db.SerializableMarker +import net.opendasharchive.openarchive.services.snowbird.service.HttpLikeException +import timber.log.Timber +import java.io.IOException +import java.io.InputStream +import java.net.SocketTimeoutException + +suspend fun UnixSocketClient.downloadFile(endpoint: String): ByteArray = withContext(Dispatchers.IO) { + LocalSocket().use { socket -> + socket.connect(LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM)) + + val requestHeaders = buildString { + append("${HttpMethod.GET} $endpoint HTTP/1.1\r\n") + append("Accept: image/*\r\n") + append("\r\n") + } + + socket.outputStream.apply { + write(requestHeaders.toByteArray()) + flush() + } + + try { + val (responseCode, _, bytes) = readBinaryResponseWithCancellation(socket.inputStream) + + Timber.d("File download response code: $responseCode") + + when (responseCode) { + in 200..299 -> bytes + else -> throw HttpLikeException(responseCode) + } + } catch (e: SocketTimeoutException) { + throw e + } catch (e: IOException) { + throw e + } catch (e: Exception) { + throw IOException("Unexpected error during Unix socket communication: ${e.message}") + } + } +} + +suspend inline fun UnixSocketClient.uploadFile( + endpoint: String, + imageData: ByteArray +): RESPONSE = withContext(Dispatchers.IO) { + try { + LocalSocket().use { socket -> + socket.connect(LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM)) + + val requestHeaders = buildString { + append("${HttpMethod.POST} $endpoint HTTP/1.1\r\n") + append("Content-Type: application/octet-stream\r\n") + append("Content-Length: ${imageData.size}\r\n") + append("\r\n") + } + + socket.outputStream.apply { + write(requestHeaders.toByteArray()) + write(imageData) + flush() + } + + val (responseCode, _, responseBody) = readResponse(socket.inputStream) + + Timber.d("Image upload response code: $responseCode") + + when (responseCode) { + in 200..299 -> parseSuccessResponse(responseBody) { json.decodeFromString(it) } + else -> throw HttpLikeException(responseCode) + } + } + } catch (e: SocketTimeoutException) { + throw e + } catch (e: IOException) { + throw e + } catch (e: Exception) { + throw IOException("Unexpected error during Unix socket communication: ${e.message}") + } +} + +suspend inline fun UnixSocketClient.uploadFile( + endpoint: String, + inputStream: InputStream, +): RESPONSE { + inputStream.use { stream -> + return uploadFile(endpoint, stream.readBytes()) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClientUtilityExtensions.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClientUtilityExtensions.kt new file mode 100644 index 00000000..2f60be63 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/UnixSocketClientUtilityExtensions.kt @@ -0,0 +1,90 @@ +package net.opendasharchive.openarchive.features.main + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.isActive +import kotlinx.coroutines.withContext +import java.io.BufferedReader +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.io.InputStream +import java.io.InputStreamReader +import kotlin.coroutines.cancellation.CancellationException + +suspend fun UnixSocketClient.readBinaryResponseWithCancellation( + inputStream: InputStream, + onProgress: ((Long) -> Unit)? = null +): Triple, ByteArray> = withContext(Dispatchers.IO) { + val reader = BufferedReader(InputStreamReader(inputStream)) + + // Read status line + val statusLine = reader.readLine() ?: throw IOException("Empty response") + val (_, statusCode, _) = statusLine.split(" ", limit = 3) + + // Read headers + val headers = mutableMapOf() + var line: String? + while (reader.readLine().also { line = it } != null) { + if (line.isNullOrBlank()) break + val (key, value) = line!!.split(": ", limit = 2) + headers[key] = value + } + + val outputStream = ByteArrayOutputStream() + var totalBytesRead = 0L + + val isChunked = headers["Transfer-Encoding"]?.equals("chunked", ignoreCase = true) ?: false + val contentLength = headers["Content-Length"]?.toLongOrNull() + + try { + if (isChunked) { + // Handle chunked transfer encoding + while (isActive) { + ensureActive() + val chunkSizeLine = reader.readLine() ?: break + val chunkSize = chunkSizeLine.trim().toInt(16) + if (chunkSize == 0) break + + val buffer = ByteArray(chunkSize) + var bytesRead = 0 + while (bytesRead < chunkSize) { + ensureActive() + val count = inputStream.read(buffer, bytesRead, chunkSize - bytesRead) + if (count == -1) break + bytesRead += count + } + outputStream.write(buffer, 0, bytesRead) + totalBytesRead += bytesRead + onProgress?.invoke(totalBytesRead) + + reader.readLine() // Read the CRLF after the chunk + } + } else if (contentLength != null) { + // Handle Content-Length specified + val buffer = ByteArray(8192) // 8KB buffer + var bytesRead = 0 + while (totalBytesRead < contentLength && inputStream.read(buffer).also { bytesRead = it } != -1) { + ensureActive() + outputStream.write(buffer, 0, bytesRead) + totalBytesRead += bytesRead + onProgress?.invoke(totalBytesRead) + } + } else { + // Handle case where neither chunked nor Content-Length is specified + val buffer = ByteArray(8192) // 8KB buffer + var bytesRead: Int + while (inputStream.read(buffer).also { bytesRead = it } != -1) { + ensureActive() + outputStream.write(buffer, 0, bytesRead) + totalBytesRead += bytesRead + onProgress?.invoke(totalBytesRead) + } + } + } catch (e: CancellationException) { + throw e + } finally { + inputStream.close() + } + + Triple(statusCode.toInt(), headers, outputStream.toByteArray()) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/FolderDrawerAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/FolderDrawerAdapter.kt new file mode 100644 index 00000000..6e068676 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/FolderDrawerAdapter.kt @@ -0,0 +1,104 @@ +package net.opendasharchive.openarchive.features.main.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.RvDrawerRowBinding +import net.opendasharchive.openarchive.db.Project + + +interface FolderDrawerAdapterListener { + fun onProjectSelected(project: Project) + fun getSelectedProject(): Project? +} + +class FolderDrawerAdapter( + private val listener: FolderDrawerAdapterListener +) : ListAdapter(DIFF_CALLBACK) { + + private var selectedProject: Project? = listener.getSelectedProject() + + inner class FolderViewHolder( + private val binding: RvDrawerRowBinding, + private val listener: FolderDrawerAdapterListener + ) : RecyclerView.ViewHolder(binding.root) { + + fun bind(project: Project) { + + binding.rvTitle.text = project.description + + val isSelected = project.id == selectedProject?.id + val iconRes = if (isSelected) R.drawable.baseline_folder_white_24 else R.drawable.outline_folder_white_24 + val iconColor = if (isSelected) R.color.colorTertiary else R.color.colorOnBackground + val textColor = if (isSelected) R.color.colorOnBackground else R.color.colorText + + val icon = ContextCompat.getDrawable(binding.rvIcon.context, iconRes) + icon?.setTint(ContextCompat.getColor(binding.rvIcon.context, iconColor)) + binding.rvIcon.setImageDrawable(icon) + + binding.rvTitle.setTextColor(ContextCompat.getColor(binding.rvTitle.context, textColor)) + + binding.root.setOnClickListener { + onItemSelected(project) + } + } + + private fun onItemSelected(project: Project) { + val previousIndex = currentList.indexOf(selectedProject) + val newIndex = currentList.indexOf(project) + + selectedProject = project + + if (previousIndex != -1) notifyItemChanged(previousIndex) + if (newIndex != -1) notifyItemChanged(newIndex) + + listener.onProjectSelected(project) + } + } + + companion object { + private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Project, newItem: Project): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: Project, newItem: Project): Boolean { + return oldItem.description == newItem.description + } + } + } + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FolderViewHolder { + val binding = RvDrawerRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return FolderViewHolder(binding, listener = listener) + } + + override fun onBindViewHolder(holder: FolderViewHolder, position: Int) { + val project = getItem(position) + + holder.bind(project) + } + + fun update(projects: List) { + // Preserve selection if the selected project is still present + val previouslySelectedId = selectedProject?.id + selectedProject = projects.find { it.id == previouslySelectedId } + + submitList(projects) + } + + fun updateSelectedProject(project: Project?) { + val previousIndex = currentList.indexOf(selectedProject) + val newIndex = currentList.indexOf(project) + + selectedProject = project + + if (previousIndex != -1) notifyItemChanged(previousIndex) + if (newIndex != -1) notifyItemChanged(newIndex) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/MainMediaAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/MainMediaAdapter.kt new file mode 100644 index 00000000..257d59ff --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/MainMediaAdapter.kt @@ -0,0 +1,319 @@ +package net.opendasharchive.openarchive.features.main.adapters + +import android.app.Activity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.snackbar.Snackbar +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger +import net.opendasharchive.openarchive.databinding.RvMediaBoxBinding +import net.opendasharchive.openarchive.db.Media +import net.opendasharchive.openarchive.features.main.MainActivity +import net.opendasharchive.openarchive.features.media.PreviewActivity +import net.opendasharchive.openarchive.upload.BroadcastManager +import java.lang.ref.WeakReference + +class MainMediaAdapter( + private val activity: Activity?, + private val mediaList: List, + private val recyclerView: RecyclerView, + private val checkSelecting: () -> Unit, + private val allowMultiProjectSelection: Boolean = false, + private val onDeleteClick: (Media, Int) -> Unit, +) : RecyclerView.Adapter() { + + companion object { + private const val PAYLOAD_SELECTION = "selection" + private const val PAYLOAD_PROGRESS = "progress" + + private val supportedStatuses: List = listOf( + Media.Status.Local, Media.Status.Uploading, Media.Status.Error + ) + } + + var media: ArrayList = ArrayList(mediaList) + private set + + var doImageFade = true + + var isEditMode = false + + var selecting = false + + private var mActivity = WeakReference(activity) + + private val selectedItems = mutableSetOf() + + init { + setHasStableIds(true) + } + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainMediaViewHolder { + val binding = RvMediaBoxBinding.inflate(LayoutInflater.from(parent.context), parent, false) + val mvh = MainMediaViewHolder(binding) + + // Normal click: either toggle selection if already in selection mode or perform normal action. + mvh.itemView.setOnClickListener { v -> + val pos = recyclerView.getChildLayoutPosition(v) + if (pos == RecyclerView.NO_POSITION) return@setOnClickListener + if (selecting) { + toggleSelection(pos) + } else { + handleNormalClick(pos) + } + } + + // Long-click: enable selection mode (if not already enabled) and toggle selection. + mvh.itemView.setOnLongClickListener { v -> + val pos = recyclerView.getChildLayoutPosition(v) + if (pos == RecyclerView.NO_POSITION) return@setOnLongClickListener true + if (!selecting) { + selecting = true + // If multi-project selection is allowed, the parent fragment may already have enabled selection + // on other adapters. Otherwise, we are only enabling it here. + checkSelecting.invoke() + } + toggleSelection(pos) + true + } + + return mvh + } + + override fun getItemCount(): Int = media.size + + override fun getItemId(position: Int): Long = media[position].id + + override fun onBindViewHolder(holder: MainMediaViewHolder, position: Int) { + AppLogger.i("onBindViewHolder called for position $position") + holder.bind(media[position], selecting, doImageFade) + } + + override fun onBindViewHolder( + holder: MainMediaViewHolder, position: Int, payloads: MutableList + ) { + if (payloads.isNotEmpty()) { + val payload = payloads[0] + when (payload) { + "progress" -> { + holder.updateProgress(media[position].uploadPercentage ?: 0) + } + + "full" -> { + holder.bind(media[position], selecting, doImageFade) + } + } + } else { + holder.bind(media[position], selecting, doImageFade) + } + } + + // --- Helper functions for selection handling --- + private fun toggleSelection(position: Int) { + val item = media[position] + item.selected = !item.selected + item.save() + notifyItemChanged(position) + // Update the adapter’s overall selecting flag. + selecting = media.any { it.selected } + checkSelecting.invoke() + } + + private fun handleNormalClick(position: Int) { + val item = media[position] + val mediaStatus = item.sStatus + // Default behavior if needed. + if (mediaStatus == Media.Status.Local) { + if (supportedStatuses.contains(Media.Status.Local)) { + mActivity.get()?.let { + PreviewActivity.start(it, item.projectId) + } + } + } else if (mediaStatus == Media.Status.Queued || mediaStatus == Media.Status.Uploading) { + if (supportedStatuses.contains(Media.Status.Uploading)) { + (mActivity.get() as? MainActivity)?.showUploadManagerFragment() + } + } else if (mediaStatus == Media.Status.Error) { + if (supportedStatuses.contains(Media.Status.Error)) { + onDeleteClick.invoke(item, position) + } + } + } + + fun updateItem(mediaId: Long, progress: Int, isUploaded: Boolean = false): Boolean { + val mediaIndex = media.indexOfFirst { it.id == mediaId } + AppLogger.i("updateItem: mediaId=$mediaId idx=$mediaIndex") + if (mediaIndex < 0) return false + + val item = media[mediaIndex] + + if (isUploaded) { + item.status = Media.Status.Uploaded.id + AppLogger.i("Media item $mediaId uploaded, notifying item changed at position $mediaIndex") + notifyItemChanged(mediaIndex, "full") + } else if (progress >= 0) { + item.uploadPercentage = progress + item.status = Media.Status.Uploading.id + notifyItemChanged(mediaIndex, "progress") + } else { + item.status = Media.Status.Queued.id + notifyItemChanged(mediaIndex, "full") + } + + return true + } + + fun removeItem(mediaId: Long): Boolean { + val idx = media.indexOfFirst { it.id == mediaId } + if (idx < 0) return false + media.removeAt(idx) + notifyItemRemoved(idx) + checkSelecting.invoke() + return true + } + + fun updateData(newMediaList: List) { + val diffCallback = MediaDiffCallback(this.media, newMediaList) + val diffResult = DiffUtil.calculateDiff(diffCallback) + media.clear() + media.addAll(newMediaList) + diffResult.dispatchUpdatesTo(this) + } + + fun clearSelections() { + selectedItems.clear() + media.forEach { it.selected = false } + notifyDataSetChanged() + } + + private fun selectView(view: View) { + if (!selecting) return + + val mediaId = view.tag as? Long ?: return + val wasSelected = selectedItems.contains(mediaId) + + if (wasSelected) { + selectedItems.remove(mediaId) + } else { + if (!allowMultiProjectSelection) { + selectedItems.clear() + media.forEach { it.selected = false } + } + selectedItems.add(mediaId) + } + + media.firstOrNull { it.id == mediaId }?.selected = !wasSelected + checkSelecting.invoke() + notifyItemChanged(media.indexOfFirst { it.id == mediaId }) + } + + fun onItemMove(oldPos: Int, newPos: Int) { + if (!isEditMode) return + + val mediaToMov = media.removeAt(oldPos) + media.add(newPos, mediaToMov) + + var priority = media.size + + for (item in media) { + item.priority = priority-- + item.save() + } + + notifyItemMoved(oldPos, newPos) + } + + fun deleteItem(pos: Int) { + if (pos < 0 || pos >= media.size) return + + val item = media[pos] + var undone = false + + val snackbar = + Snackbar.make(recyclerView, R.string.confirm_remove_media, Snackbar.LENGTH_LONG) + snackbar.setAction(R.string.undo) { _ -> + undone = true + media.add(pos, item) + + notifyItemInserted(pos) + } + + snackbar.addCallback(object : Snackbar.Callback() { + override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { + if (!undone) { + val collection = item.collection + + // Delete collection along with the item, if the collection + // would become empty. + if ((collection?.size ?: 0) < 2) { + collection?.delete() + } else { + item.delete() + } + + BroadcastManager.postDelete(recyclerView.context, item.id) + } + + super.onDismissed(transientBottomBar, event) + } + }) + + snackbar.show() + + removeItem(item.id) + + mActivity.get()?.let { + BroadcastManager.postDelete(it, item.id) + } + } + + fun getSelectedCount(): Int = media.count { it.selected } + + fun deleteSelected(): Boolean { + var hasDeleted = false + // Copy list to avoid concurrent modification. + val selectedItems = media.filter { it.selected } + selectedItems.forEach { item -> + val idx = media.indexOf(item) + if (idx != -1) { + media.removeAt(idx) + notifyItemRemoved(idx) + item.delete() + hasDeleted = true + } + } + selecting = false + checkSelecting.invoke() + return hasDeleted + } +} + +private class MediaDiffCallback( + private val oldList: List, private val newList: List +) : DiffUtil.Callback() { + + override fun getOldListSize() = oldList.size + + override fun getNewListSize() = newList.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldList[oldItemPosition].id == newList[newItemPosition].id + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + // Compare only the fields that affect the UI + + val oldItem = oldList[oldItemPosition] + val newItem = newList[newItemPosition] + + return oldItem.status == newItem.status && oldItem.uploadPercentage == newItem.uploadPercentage && oldItem.selected == newItem.selected && oldItem.title == newItem.title + } + + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + return super.getChangePayload(oldItemPosition, newItemPosition) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/MainMediaViewHolder.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/MainMediaViewHolder.kt new file mode 100644 index 00000000..51440f9c --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/MainMediaViewHolder.kt @@ -0,0 +1,202 @@ +package net.opendasharchive.openarchive.features.main.adapters + +import android.widget.ImageView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import androidx.swiperefreshlayout.widget.CircularProgressDrawable +import coil3.ImageLoader +import coil3.load +import coil3.request.crossfade +import coil3.request.placeholder +import coil3.video.VideoFrameDecoder +import coil3.video.videoFrameMillis +import com.github.derlio.waveform.soundfile.SoundFile +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger +import net.opendasharchive.openarchive.databinding.RvMediaBoxBinding +import net.opendasharchive.openarchive.db.Media +import net.opendasharchive.openarchive.util.extensions.hide +import net.opendasharchive.openarchive.util.extensions.show +import timber.log.Timber + +class MainMediaViewHolder(val binding: RvMediaBoxBinding) : RecyclerView.ViewHolder(binding.root) { + + companion object { + val soundCache = HashMap() + } + + private val mContext = itemView.context + + private val imageLoader = ImageLoader.Builder(mContext) + .components { + add(VideoFrameDecoder.Factory()) + } + .build() + + + fun bind(media: Media? = null, isInSelectionMode: Boolean = false, doImageFade: Boolean = true) { + + itemView.tag = media?.id + + // Update selection visuals. + if (isInSelectionMode && media?.selected == true) { + itemView.setBackgroundResource(R.color.colorTertiary) + binding.selectedIndicator.show() + } else { + itemView.setBackgroundResource(R.color.transparent) + binding.selectedIndicator.hide() + } + + binding.image.alpha = if (media?.sStatus == Media.Status.Uploaded || !doImageFade) 1f else 0.5f + + if (media?.mimeType?.startsWith("image") == true) { + val progress = CircularProgressDrawable(mContext) + progress.strokeWidth = 5f + progress.centerRadius = 30f + progress.start() + + binding.image.load(media.fileUri, imageLoader) { + placeholder(progress) + crossfade(true) + crossfade(300) + listener(onError = { req, res -> + AppLogger.e(res.throwable) + }) + } + + binding.image.scaleType = ImageView.ScaleType.CENTER_CROP + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.hide() + } else if (media?.mimeType?.startsWith("video") == true) { + + binding.image.load(media.originalFilePath, imageLoader) { + val progress = CircularProgressDrawable(mContext) + progress.strokeWidth = 5f + progress.centerRadius = 30f + progress.start() + videoFrameMillis(1000) // Extracts the frame at 1 second (1000ms) + placeholder(progress) + crossfade(true) + crossfade(300) + listener(onError = { req, res -> AppLogger.e(res.throwable) }) + } + + binding.image.scaleType = ImageView.ScaleType.CENTER_CROP + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.show() + } else if (media?.mimeType?.startsWith("audio") == true) { + binding.videoIndicator.hide() + + val soundFile = soundCache[media.originalFilePath] + + if (soundFile != null) { + binding.image.hide() + binding.waveform.setAudioFile(soundFile) + binding.waveform.show() + } else { + binding.image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.no_thumbnail)) + binding.image.scaleType = ImageView.ScaleType.CENTER_CROP + binding.image.show() + binding.waveform.hide() + + CoroutineScope(Dispatchers.IO).launch { + @Suppress("NAME_SHADOWING") + val soundFile = try { + SoundFile.create(media.originalFilePath) { + return@create true + } + } catch (e: Throwable) { + Timber.d(e) + + null + } + + if (soundFile != null) { + soundCache[media.originalFilePath] = soundFile + + MainScope().launch { + binding.waveform.setAudioFile(soundFile) + binding.image.hide() + binding.waveform.show() + } + } + } + } + } else if (media?.mimeType?.startsWith("application") == true) { + binding.image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_unknown_file)) + binding.image.scaleType = ImageView.ScaleType.CENTER_INSIDE + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.hide() + } else { + binding.image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_unknown_file)) + binding.image.scaleType = ImageView.ScaleType.CENTER_INSIDE + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.hide() + } + + // Update overlay based on media status. + when (media?.sStatus) { + Media.Status.Error -> { + AppLogger.i("Media Item ${media.id} is error") + + binding.overlayContainer.show() + binding.progress.hide() + binding.progressText.hide() + binding.error.show() + + } + Media.Status.Queued -> { + AppLogger.i("Media Item ${media.id} is queued") + binding.overlayContainer.show() + binding.progress.isIndeterminate = true + binding.progress.show() + binding.progressText.hide() + binding.error.hide() + } + Media.Status.Uploading -> { + binding.progress.isIndeterminate = false + val progressValue = media.uploadPercentage ?: 0 + AppLogger.i("Media Item ${media.id} is uploading") + + binding.overlayContainer.show() + binding.progress.show() + binding.progressText.show() + + // Make sure to keep spinning until the upload has made some noteworthy progress. + if (progressValue > 2) { + binding.progress.setProgressCompat(progressValue, true) + } + binding.progressText.text = "${progressValue}%" + binding.error.hide() + } + else -> { + binding.overlayContainer.hide() + binding.progress.hide() + binding.progressText.hide() + binding.error.hide() + } + } + + } + + fun updateProgress(progressValue: Int) { + if (progressValue > 2) { + binding.progress.isIndeterminate = false + binding.progress.setProgressCompat(progressValue, true) + } else { + binding.progress.isIndeterminate = true + } + + AppLogger.i("Updating progressText to $progressValue%") + binding.progressText.show(animate = true) + binding.progressText.text = "$progressValue%" + } +} diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/SpaceDrawerAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/SpaceDrawerAdapter.kt new file mode 100644 index 00000000..9abcddc4 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/adapters/SpaceDrawerAdapter.kt @@ -0,0 +1,157 @@ +package net.opendasharchive.openarchive.features.main.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.RvDrawerRowBinding +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.util.extensions.scaled + +interface SpaceDrawerAdapterListener { + fun onSpaceSelected(space: Space) + fun onAddNewSpace() + fun getSelectedSpace(): Space? +} + +class SpaceDrawerAdapter(private val listener: SpaceDrawerAdapterListener) : + ListAdapter(DIFF_CALLBACK) { + + private var selectedSpace: Space? = listener.getSelectedSpace() + + sealed class SpaceItem { + data class SpaceItemData(val space: Space) : SpaceItem() + data object AddSpaceItem : SpaceItem() + } + + companion object { + + private const val VIEW_TYPE_SPACE = 0 + private const val VIEW_TYPE_ADD = 1 + + private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SpaceItem, newItem: SpaceItem): Boolean { + return when { + oldItem is SpaceItem.SpaceItemData && newItem is SpaceItem.SpaceItemData -> oldItem.space.id == newItem.space.id + oldItem is SpaceItem.AddSpaceItem && newItem is SpaceItem.AddSpaceItem -> true + else -> false + } + } + + override fun areContentsTheSame(oldItem: SpaceItem, newItem: SpaceItem): Boolean { + return when { + oldItem is SpaceItem.SpaceItemData && newItem is SpaceItem.SpaceItemData -> oldItem.space.friendlyName == newItem.space.friendlyName + oldItem is SpaceItem.AddSpaceItem && newItem is SpaceItem.AddSpaceItem -> true + else -> false + } + } + } + } + + abstract class ItemTypeViewHolder(binding: RvDrawerRowBinding) : + RecyclerView.ViewHolder(binding.root) { + abstract fun bind(item: SpaceItem) + } + + inner class SpaceViewHolder(private val binding: RvDrawerRowBinding) : + ItemTypeViewHolder(binding) { + override fun bind(item: SpaceItem) { + + val space = (item as SpaceItem.SpaceItemData).space + + val isSelected = listener.getSelectedSpace()?.id == space.id + val backgroundColor = + if (isSelected) R.color.colorTertiary else R.color.colorDrawerSpaceListBackground + val textColor = if (isSelected) R.color.colorOnBackground else R.color.colorText + + binding.root.setBackgroundColor(binding.root.context.getColor(backgroundColor)) + + val icon = space.getAvatar(binding.rvIcon.context)?.scaled(21, binding.rvIcon.context) + icon?.setTint(binding.rvIcon.context.getColor(R.color.colorOnBackground)) + binding.rvIcon.setImageDrawable(icon) + + binding.rvTitle.text = space.friendlyName + binding.rvTitle.setTextColor(binding.rvTitle.context.getColor(textColor)) + + binding.root.setOnClickListener { + onItemSelected(space) + } + } + + private fun onItemSelected(space: Space) { + val previousIndex = + currentList.indexOfFirst { it is SpaceItem.SpaceItemData && it.space.id == selectedSpace?.id } + val newIndex = + currentList.indexOfFirst { it is SpaceItem.SpaceItemData && it.space.id == space.id } + + selectedSpace = space + + if (previousIndex != -1) notifyItemChanged(previousIndex) + if (newIndex != -1) notifyItemChanged(newIndex) + + listener.onSpaceSelected(space) + } + } + + inner class AddSpaceViewHolder(private val binding: RvDrawerRowBinding) : + ItemTypeViewHolder(binding) { + override fun bind(item: SpaceItem) { + val context = binding.rvTitle.context + val backgroundColor = R.color.colorDrawerSpaceListBackground + binding.root.setBackgroundColor(binding.root.context.getColor(backgroundColor)) + binding.rvTitle.text = context.getString(R.string.add_another_account) + binding.rvTitle.setTextColor(ContextCompat.getColor(context, R.color.colorTertiary)) + + val icon = ContextCompat.getDrawable(context, R.drawable.ic_add) + icon?.setTint(ContextCompat.getColor(binding.rvIcon.context, R.color.colorTertiary)) + binding.rvIcon.setImageDrawable(icon) + + binding.root.setOnClickListener { + listener.onAddNewSpace() + } + } + } + + override fun getItemViewType(position: Int): Int { + return when (getItem(position)) { + is SpaceItem.SpaceItemData -> VIEW_TYPE_SPACE + is SpaceItem.AddSpaceItem -> VIEW_TYPE_ADD + else -> throw IllegalArgumentException("Invalid view type") + } + } + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemTypeViewHolder { + val binding = RvDrawerRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) + + return when (viewType) { + VIEW_TYPE_SPACE -> SpaceViewHolder(binding) + VIEW_TYPE_ADD -> AddSpaceViewHolder(binding) + else -> throw IllegalArgumentException("Invalid view type") + } + } + + override fun onBindViewHolder(holder: ItemTypeViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + fun update(spaces: List) { + val items = spaces.map { SpaceItem.SpaceItemData(it) } + SpaceItem.AddSpaceItem + submitList(items) + } + + fun updateSelectedSpace(space: Space?) { + val previousIndex = + currentList.indexOfFirst { it is SpaceItem.SpaceItemData && it.space.id == selectedSpace?.id } + val newIndex = + currentList.indexOfFirst { it is SpaceItem.SpaceItemData && it.space.id == space?.id } + + selectedSpace = space + + if (previousIndex != -1) notifyItemChanged(previousIndex) + if (newIndex != -1) notifyItemChanged(newIndex) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/CustomButton.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/CustomButton.kt new file mode 100644 index 00000000..7ab95241 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/CustomButton.kt @@ -0,0 +1,63 @@ +package net.opendasharchive.openarchive.features.main.ui + +import android.content.Context +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.TextView +import net.opendasharchive.openarchive.R + +class CustomButton @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val leftIcon: ImageView + private val rightIcon: ImageView + private val titleText: TextView + private val subTitleText: TextView + + init { + LayoutInflater.from(context).inflate(R.layout.custom_button, this, true) + leftIcon = findViewById(R.id.leftIcon) + rightIcon = findViewById(R.id.rightIcon) + titleText = findViewById(R.id.title) + subTitleText = findViewById(R.id.subTitle) + + isClickable = true + isFocusable = true + + subTitleText.visibility = GONE + } + + fun setLeftIcon(drawable: Drawable?) { + leftIcon.setImageDrawable(drawable) + } + + fun setLeftResource(iconResId: Int) { + leftIcon.setImageResource(iconResId) + } + + fun setRightResource(iconResId: Int) { + rightIcon.setImageResource(iconResId) + } + + fun setRightIcon(drawable: Drawable?) { + rightIcon.setImageDrawable(drawable) + } + + fun setTitle(text: String?) { + titleText.text = text ?: "" + } + + fun setSubTitle(text: String?) { + text?.let { + subTitleText.text = text + subTitleText.visibility = VISIBLE + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/EmptyableRecyclerView.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/EmptyableRecyclerView.kt new file mode 100644 index 00000000..e3f11427 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/EmptyableRecyclerView.kt @@ -0,0 +1,119 @@ +package net.opendasharchive.openarchive.features.main.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout + +class EmptyableRecyclerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : RecyclerView(context, attrs, defStyleAttr) { + + private var emptyView: View? = null + private var emptyViewRes: Int = 0 + + fun setEmptyView(view: View) { + emptyView = view + emptyViewRes = 0 + setupEmptyView() + } + + fun setEmptyView(layoutResId: Int) { + emptyViewRes = layoutResId + emptyView = null + setupEmptyView() + } + + private fun setupEmptyView() { + post { + val targetParent = findSuitableParent() + targetParent?.let { parentView -> + emptyView?.let { parentView.removeView(it) } + emptyView = when { + emptyViewRes != 0 -> { + val inflatedView = inflate(context, emptyViewRes, null) + parentView.addView(inflatedView, ViewGroup.LayoutParams(width, height)) + inflatedView + } + emptyView != null -> { + parentView.addView(emptyView, ViewGroup.LayoutParams(width, height)) + emptyView + } + else -> null + } + emptyView?.visibility = GONE + checkIfEmpty() + } + } + } + + private fun findSuitableParent(): ViewGroup? { + var view: View? = this + var parent: ViewGroup? + while (view != null) { + parent = view.parent as? ViewGroup + if (parent is SwipeRefreshLayout) { + // If the parent is SwipeRefreshLayout, we want to add the empty view to its parent + return parent.parent as? ViewGroup + } else if (parent != null && parent !is RecyclerView) { + // Found a suitable parent that is not a RecyclerView + return parent + } + view = parent + } + return null + } + + private val observer = object : AdapterDataObserver() { + override fun onChanged() { + checkIfEmpty() + } + + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + checkIfEmpty() + } + + override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { + checkIfEmpty() + } + } + + override fun setAdapter(adapter: Adapter<*>?) { + val oldAdapter = getAdapter() + oldAdapter?.unregisterAdapterDataObserver(observer) + + super.setAdapter(adapter) + + adapter?.registerAdapterDataObserver(observer) + checkIfEmpty() + } + + private fun checkIfEmpty() { + val adapter = adapter + val emptyView = emptyView + + if (adapter != null && emptyView != null) { + val emptyViewVisible = adapter.itemCount == 0 + emptyView.visibility = if (emptyViewVisible) VISIBLE else GONE + visibility = if (emptyViewVisible) GONE else VISIBLE + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + setupEmptyView() + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + emptyView?.let { + it.layoutParams?.width = w + it.layoutParams?.height = h + it.requestLayout() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/HomeScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/HomeScreen.kt new file mode 100644 index 00000000..3aa5f052 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/HomeScreen.kt @@ -0,0 +1,382 @@ +package net.opendasharchive.openarchive.features.main.ui + +import android.content.Context +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material3.DrawerValue +import androidx.compose.material3.Icon +import androidx.compose.material3.ModalNavigationDrawer +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberDrawerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.lifecycle.ViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewModelScope +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.serialization.Serializable +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme +import net.opendasharchive.openarchive.db.Project +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.main.ui.components.HomeAppBar +import net.opendasharchive.openarchive.features.main.ui.components.MainBottomBar +import net.opendasharchive.openarchive.features.main.ui.components.MainDrawerContent +import net.opendasharchive.openarchive.features.main.ui.components.SpaceIcon +import net.opendasharchive.openarchive.features.media.AddMediaType +import net.opendasharchive.openarchive.features.settings.SettingsScreen +import org.koin.androidx.compose.koinViewModel +import kotlin.math.max + + +@Serializable +data object HomeRoute + +@Serializable +data object MediaCacheRoute + +@Composable +fun SaveNavGraph( + context: Context, + viewModel: HomeViewModel = koinViewModel(), + onExit: () -> Unit, + onNewFolder: () -> Unit, + onFolderSelected: (Long) -> Unit, + onAddMedia: (AddMediaType) -> Unit +) { + val navController = rememberNavController() + + SaveAppTheme { + + NavHost( + navController = navController, + startDestination = HomeRoute + ) { + + composable { + HomeScreen( + viewModel = viewModel, + onExit = onExit, + onNewFolder = onNewFolder, + onFolderSelected = onFolderSelected, + onAddMedia = onAddMedia, + onNavigateToCache = { + navController.navigate(MediaCacheRoute) + } + ) + } + + composable { + MediaCacheScreen(context) { + navController.popBackStack() + } + } + + } + } +} + +@Composable +fun HomeScreen( + viewModel: HomeViewModel = koinViewModel(), + onExit: () -> Unit, + onNewFolder: () -> Unit, + onFolderSelected: (Long) -> Unit, + onAddMedia: (AddMediaType) -> Unit, + onNavigateToCache: () -> Unit +) { + + val state by viewModel.uiState.collectAsStateWithLifecycle() + + HomeScreenContent( + onExit = onExit, + state = state, + onAction = viewModel::onAction, + onNavigateToCache = onNavigateToCache + ) + + +} + +class HomeViewModel : ViewModel() { + private val _uiState = MutableStateFlow(HomeScreenState()) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadSpacesAndFolders() + } + + fun onAction(action: HomeScreenAction) { + when (action) { + is HomeScreenAction.UpdateSelectedProject -> { + _uiState.update { it.copy(selectedProject = action.project) } + } + + is HomeScreenAction.AddMediaClicked -> TODO() + } + } + + private fun loadSpacesAndFolders() { + viewModelScope.launch { + val allSpaces = Space.getAll().asSequence().toList() + val selectedSpace = Space.current + val projectsForSelectedSpace = selectedSpace?.projects ?: emptyList() + + _uiState.update { + it.copy( + allSpaces = allSpaces, + projectsForSelectedSpace = projectsForSelectedSpace, + selectedSpace = selectedSpace, + selectedProject = projectsForSelectedSpace.firstOrNull() + ) + } + } + } + +} + +sealed class HomeScreenAction { + data class UpdateSelectedProject(val project: Project? = null) : HomeScreenAction() + data class AddMediaClicked(val mediaType: AddMediaType) : HomeScreenAction() +} + +data class HomeScreenState( + val selectedSpace: Space? = null, + val selectedProject: Project? = null, + val allSpaces: List = emptyList(), + val projectsForSelectedSpace: List = emptyList() +) + +@Composable +fun HomeScreenContent( + onExit: () -> Unit, + state: HomeScreenState, + onAction: (HomeScreenAction) -> Unit, + onNavigateToCache: () -> Unit = {} +) { + + val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) + val scope = rememberCoroutineScope() + + val projects = state.projectsForSelectedSpace + val totalPages = max(1, projects.size) + 1 + val pagerState = rememberPagerState(initialPage = 0) { totalPages } + + val currentProjectIndex = state.selectedProject?.let { selected -> + projects.indexOfFirst { it.id == selected.id }.takeIf { it >= 0 } ?: 0 + } ?: 0 + + // Whenever the pager’s current page changes and it represents a project page, + // update the view model’s selected project. + LaunchedEffect(pagerState.currentPage, projects) { + if (projects.isNotEmpty() && pagerState.currentPage < projects.size) { + val newlySelectedProject = projects[pagerState.currentPage] + onAction(HomeScreenAction.UpdateSelectedProject(newlySelectedProject)) + } + } + + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { + + ModalNavigationDrawer( + drawerState = drawerState, + gesturesEnabled = true, + drawerContent = { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + MainDrawerContent( + selectedSpace = state.selectedSpace, + spaceList = state.allSpaces + ) + } + } + ) { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + + Scaffold( + topBar = { + HomeAppBar( + onExit = onExit, + openDrawer = { + scope.launch { + drawerState.open() + } + } + ) + }, + + bottomBar = { + MainBottomBar( + isSettings = pagerState.currentPage == (totalPages - 1), + onAddMediaClick = {}, + onMyMediaClick = { + // When "My Media" is tapped, scroll to the page of the currently selected project. + // If no project is selected, default to the first page. + val targetPage = if (projects.isEmpty()) 0 else currentProjectIndex + if (pagerState.currentPage != targetPage) { + scope.launch { pagerState.scrollToPage(targetPage) } + } + }, + onSettingsClick = { + // Scroll to the last page if not already there. + if (pagerState.currentPage != totalPages - 1) { + scope.launch { pagerState.scrollToPage(totalPages - 1) } + } + } + ) + } + + ) { paddingValues -> + + Column( + modifier = Modifier.padding(paddingValues) + ) { + AnimatedVisibility( + visible = pagerState.currentPage < totalPages - 1, + enter = slideInHorizontally( + animationSpec = tween() + ), + exit = slideOutHorizontally( + animationSpec = tween() + ) + ) { + val selectedProject = + state.selectedProject ?: error("Project should not be empty") + val selectedSpace = + state.selectedSpace ?: error("Space should not be empty") + + val folderName = selectedProject.description + ?: selectedProject.created.toString() + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = dimensionResource(R.dimen.activity_horizontal_margin)), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row { + SpaceIcon( + type = selectedSpace.tType ?: Space.Type.WEBDAV, + modifier = Modifier.size(24.dp) + ) + Icon( + painter = painterResource(R.drawable.keyboard_arrow_right), + contentDescription = null + ) + Text(folderName) + } + + + TextButton( + onClick = {} + ) { + Icon( + painter = painterResource(R.drawable.ic_edit_folder), + contentDescription = null + ) + Text("Edit") + } + } + } + + + + HorizontalPager( + state = pagerState, + modifier = Modifier.fillMaxSize(), + ) { page -> + + when (page) { + 0 -> { + // First page: If no projects, show -1, else show first project's ID + MainMediaScreen(projectId = if (projects.isEmpty()) -1 else projects[0].id) + } + + in 1 until projects.size -> { + // Next project IDs (page - 1) + MainMediaScreen(projects[page].id) + } + + totalPages - 1 -> { + // Always settings screen as the last page + SettingsScreen( + onNavigateToCache = onNavigateToCache + ) + } + + else -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text("Unexpected page index") + } + } // This should never be reached + } + } + + } + } + } + } + } +} + +@Preview +@Composable +private fun MainContentPreview() { + SaveAppTheme { + + HomeScreenContent( + onExit = {}, + state = HomeScreenState(), + onAction = {} + ) + } +} + + +//@Composable +//fun MainMediaScreen(projectId: Long) { +// +// val fragmentState = rememberFragmentState() +// +// AndroidFragment( +// modifier = Modifier.fillMaxSize(), +// fragmentState = fragmentState, +// arguments = bundleOf("project_id" to projectId), +// onUpdate = { +// // +// } +// ) +//} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MainMediaScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MainMediaScreen.kt new file mode 100644 index 00000000..64a64207 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MainMediaScreen.kt @@ -0,0 +1,414 @@ +package net.opendasharchive.openarchive.features.main.ui + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Handler +import android.os.Looper +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Error +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.opendasharchive.openarchive.db.Collection +import net.opendasharchive.openarchive.db.Media +import net.opendasharchive.openarchive.features.media.PreviewActivity +import net.opendasharchive.openarchive.upload.BroadcastManager +import net.opendasharchive.openarchive.upload.UploadManagerActivity +import org.koin.androidx.compose.koinViewModel + +/** + * A data class representing one “section” (i.e. one Collection and its list of Media). + * (Here we wrap the list of media in a mutableStateListOf so that updates trigger recomposition.) + */ +data class CollectionSection( + val collection: Collection, + val media: SnapshotStateList = mutableStateListOf().apply { addAll(collection.media) } +) + +@Composable +fun MainMediaScreen( + projectId: Long, +) { + val context = LocalContext.current + + // State holding our list of sections (each collection with its media) + val sections = remember { mutableStateListOf() } + // Flag to track if any media is “selected” (for deletion) + var isSelecting by remember { mutableStateOf(false) } + // State to control showing the “delete confirmation” dialog. + var showDeleteDialog by remember { mutableStateOf(false) } + // State to control showing an error/retry dialog for a media item. + var errorDialogData by remember { mutableStateOf(null) } + + + // Handle broadcast messages + DisposableEffect(Unit) { + val handler = Handler(Looper.getMainLooper()) + val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val action = BroadcastManager.getAction(intent) ?: return + when (action) { + BroadcastManager.Action.Change -> { + // Extract extras from the intent (assuming these keys are provided) + val collectionId = intent.getLongExtra("collectionId", -1) + val mediaId = intent.getLongExtra("mediaId", -1) + val progress = intent.getIntExtra("progress", 0) + val isUploaded = intent.getBooleanExtra("isUploaded", false) + if (collectionId != -1L && mediaId != -1L) { + handler.post { + updateMediaItem( + sections = sections, + collectionId = collectionId, + mediaId = mediaId, + progress = progress, + isUploaded = isUploaded + ) + } + } + } + + BroadcastManager.Action.Delete -> { + handler.post { refreshSections(projectId, sections) } + } + } + } + } + + BroadcastManager.register(context, receiver) + onDispose { BroadcastManager.unregister(context, receiver) } + } + + LaunchedEffect(projectId) { + refreshSections(projectId, sections) + } + + Box(modifier = Modifier.fillMaxSize()) { + if (sections.isEmpty()) { + WelcomeMessage() + } else { + // Use a LazyColumn to list each collection section vertically. + LazyColumn(modifier = Modifier.fillMaxSize()) { + items(sections, key = { it.collection.id }) { section -> + CollectionSectionView( + section = section, + onMediaClick = { media -> + handleMediaClick(context, media) { errorMedia -> + errorDialogData = errorMedia + } + }, + onMediaLongPress = { media -> + // For selection (if needed) + toggleMediaSelection(media) + } + ) + } + } + } + + // Add floating action button or other UI elements if needed + } +} + +/** Shows a header with the collection’s upload date and media count */ +@Composable +fun CollectionHeaderView(section: CollectionSection) { + // For example, showing date and item count side by side: + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + val dateText = section.collection.uploadDate?.toGMTString() ?: "Unknown Date" + Text(text = dateText, style = MaterialTheme.typography.titleMedium) + Text( + text = "${section.media.size} items", + style = MaterialTheme.typography.bodyMedium, + color = Color.Gray + ) + } +} + +/** Renders one collection section: header and grid of media items. */ +@Composable +fun CollectionSectionView( + section: CollectionSection, + onMediaClick: (Media) -> Unit, + onMediaLongPress: (Media) -> Unit +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + ) { + CollectionHeaderView(section) + // Render the media items as a grid of 4 columns. + // We use a simple approach: chunk the media list into rows of 4. + val rows = section.media.chunked(4) + rows.forEach { rowItems -> + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + rowItems.forEach { media -> + MediaItemView( + media = media, + isSelected = media.selected, + onClick = { onMediaClick(media) }, + onLongClick = { onMediaLongPress(media) }, + modifier = Modifier + .weight(1f) + .aspectRatio(1f) + ) + } + // Fill out the remaining cells (if any) in this row + if (rowItems.size < 4) { + repeat(4 - rowItems.size) { + Spacer(modifier = Modifier.weight(1f)) + } + } + } + Spacer(modifier = Modifier.height(4.dp)) + } + } +} + +/** Renders one media item as an image filling its box. */ +@Composable +fun MediaItemView( + media: Media, + isSelected: Boolean, + onClick: () -> Unit, + onLongClick: () -> Unit, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .border( + width = if (isSelected) 4.dp else 0.dp, + color = if (isSelected) MaterialTheme.colorScheme.primary else Color.Transparent + ) + .pointerInput(Unit) { + detectTapGestures( + onTap = { onClick() }, + onLongPress = { onLongClick() } + ) + } + ) { + AsyncImage( + model = media.fileUri, + contentDescription = media.title, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + when (media.sStatus) { + Media.Status.Uploading -> UploadProgress(media.uploadPercentage ?: 0) + Media.Status.Error -> ErrorIndicator() + else -> Unit + } + } +} + + +@Composable +fun UploadProgress(progress: Int) { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Black.copy(alpha = 0.6f)), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + progress = progress / 100f, + modifier = Modifier.size(48.dp), + color = Color.White + ) + Text( + text = "$progress%", + color = Color.White, + modifier = Modifier.padding(top = 56.dp) + ) + } +} + +@Composable +fun ErrorIndicator() { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Red.copy(alpha = 0.6f)), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Default.Error, + contentDescription = null, + tint = Color.White, + modifier = Modifier.size(48.dp) + ) + } +} + +@Composable +fun WelcomeMessage() { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Welcome", + style = MaterialTheme.typography.displayMedium + ) + Text( + text = "Tap the button below to add media", + style = MaterialTheme.typography.titleMedium + ) + } +} + +/** Refreshes the list of collections (with nonempty media) for the given project. + * This runs on IO and updates the [sections] state on the main thread. + */ +private fun refreshSections(projectId: Long, sections: MutableList) { + kotlinx.coroutines.GlobalScope.launch(Dispatchers.IO) { + val collections = Collection.getByProject(projectId) + val newSections = collections.filter { it.media.isNotEmpty() } + .map { CollectionSection(it) } + withContext(Dispatchers.Main) { + sections.clear() + sections.addAll(newSections) + } + } +} + + +/** Updates one media item in one section (called when a broadcast “change” is received). */ +private fun updateMediaItem( + sections: List, + collectionId: Long, + mediaId: Long, + progress: Int, + isUploaded: Boolean +) { + sections.find { it.collection.id == collectionId }?.let { section -> + val idx = section.media.indexOfFirst { it.id == mediaId } + if (idx != -1) { + val media = section.media[idx] + if (isUploaded) { + media.status = Media.Status.Uploaded.id + } else { + media.uploadPercentage = progress + media.status = Media.Status.Uploading.id + } + // Replace to trigger recomposition + section.media[idx] = media + } + } +} + +/** Toggles the selected state of the media item and saves it. */ +private fun toggleMediaSelection(media: Media) { + media.selected = !media.selected + media.save() +} + +/** Deletes any media items that are selected from all sections. + * Also deletes the media from the database and posts a delete broadcast. + */ +private fun deleteSelected(sections: MutableList, context: Context) { + sections.forEach { section -> + // Work on a copy so we can remove items safely + section.media.filter { it.selected }.toList().forEach { media -> + section.media.remove(media) + media.delete() // delete from database + BroadcastManager.postDelete(context, media.id) + } + } + // Remove sections that are now empty (do not delete the collection from DB here) + sections.removeAll { it.media.isEmpty() } +} + +/** Deletes a single media item (used when “remove” is chosen from the error dialog). */ +private fun deleteMediaItem(sections: MutableList, media: Media) { + sections.find { it.collection.id == media.collectionId }?.let { section -> + section.media.remove(media) + media.delete() + // In a real app, you might also post a broadcast here + } +} + +/** Handles what happens when a media item is clicked (when not in selection mode). + * Depending on its status and mime type, this either launches a preview, an upload manager, + * or shows an error dialog. + * + * The onError lambda is called if the media is in an error state. + */ +private fun handleMediaClick(context: Context, media: Media, onError: (Media) -> Unit) { + when (media.sStatus) { + Media.Status.Local -> { + // For images, start a preview + if (media.mimeType.startsWith("image")) { + PreviewActivity.start(context, media.projectId) + } + } + + Media.Status.Queued, Media.Status.Uploading -> { + // Start the upload manager activity + context.startActivity(Intent(context, UploadManagerActivity::class.java)) + } + + Media.Status.Error -> { + // Show error dialog (retry/remove) + onError(media) + } + + else -> { /* no op */ + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MainMediaViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MainMediaViewModel.kt new file mode 100644 index 00000000..30e0cb08 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MainMediaViewModel.kt @@ -0,0 +1,8 @@ +package net.opendasharchive.openarchive.features.main.ui + +import androidx.lifecycle.ViewModel + +class MainMediaViewModel : ViewModel() { + +} + diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MediaCacheScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MediaCacheScreen.kt new file mode 100644 index 00000000..b36287c1 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/MediaCacheScreen.kt @@ -0,0 +1,178 @@ +package net.opendasharchive.openarchive.features.main.ui + +import android.content.Context +import android.os.Bundle +import android.provider.MediaStore +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Description +import androidx.compose.material.icons.filled.Folder +import androidx.compose.material.icons.filled.Image +import androidx.compose.material.icons.filled.Movie +import androidx.compose.material.icons.filled.QuestionMark +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import coil3.request.ImageRequest +import coil3.request.crossfade +import coil3.size.Scale +import java.io.File + +// MediaFile Data Class +data class MediaFile( + val name: String, + val path: String, + val isDirectory: Boolean, + val type: FileType +) + +// Enum to represent different file types +enum class FileType { + IMAGE, VIDEO, PDF, FOLDER, UNKNOWN +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MediaCacheScreen(context: Context, onNavigateBack: () -> Unit) { + val cacheDir = context.cacheDir + val files = remember { cacheDir.listFiles()?.map { it.toMediaFile() } ?: emptyList() } + + Scaffold( +topBar ={ + TopAppBar( + title = { Text("Media Cache") }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon(Icons.Default.ArrowBack, contentDescription = null) + } + } + ) +} + + ) { paddingValues -> + + Box(modifier = Modifier + .fillMaxSize() + .padding(paddingValues)) { + LazyVerticalGrid( + columns = GridCells.Adaptive(minSize = 100.dp), + modifier = Modifier + .fillMaxSize() + .background(Color.White), + contentPadding = PaddingValues(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(files) { file -> + CacheFileItem(file) + } + } + } + } + +} + +@Composable +fun CacheFileItem(file: MediaFile) { + val context = LocalContext.current + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .background(Color.LightGray) + .padding(8.dp) + ) { + when { + file.isDirectory -> { + Icon( + imageVector = Icons.Default.Folder, + contentDescription = file.name, + modifier = Modifier.size(48.dp) + ) + } + + file.type == FileType.IMAGE -> { + AsyncImage( + model = ImageRequest.Builder(context) + .data(File(file.path)) + .scale(Scale.FILL) + .crossfade(true) + .build(), + contentDescription = file.name, + modifier = Modifier.size(64.dp), + contentScale = ContentScale.Crop + ) + } + + file.type == FileType.VIDEO -> { + AsyncImage( + model = ImageRequest.Builder(context) + .data(File(file.path)) + .scale(Scale.FIT) + .crossfade(true) + .build(), + contentDescription = file.name, + modifier = Modifier.size(64.dp), + contentScale = ContentScale.Crop + ) + } + + file.type == FileType.PDF -> { + Icon( + imageVector = Icons.Default.Description, + contentDescription = file.name, + modifier = Modifier.size(48.dp) + ) + } + + else -> { + Icon( + imageVector = Icons.Default.QuestionMark, + contentDescription = file.name, + modifier = Modifier.size(48.dp) + ) + } + } + + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = file.name, + maxLines = 1, + modifier = Modifier.widthIn(max = 80.dp) + ) + } +} + + +fun File.toMediaFile(): MediaFile { + val fileType = when { + isDirectory -> FileType.FOLDER + name.endsWith(".jpg", true) || name.endsWith(".jpeg", true) || name.endsWith(".png", true) -> FileType.IMAGE + name.endsWith(".mp4", true) || name.endsWith(".mkv", true) || name.endsWith(".avi", true) -> FileType.VIDEO + name.endsWith(".pdf", true) -> FileType.PDF + else -> FileType.UNKNOWN + } + return MediaFile(name = name, path = absolutePath, isDirectory = isDirectory, type = fileType) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/ExpandableSpaceList.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/ExpandableSpaceList.kt new file mode 100644 index 00000000..d81b59d6 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/ExpandableSpaceList.kt @@ -0,0 +1,169 @@ +package net.opendasharchive.openarchive.features.main.ui.components + +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.outlined.KeyboardArrowDown +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.components.PrimaryButton +import net.opendasharchive.openarchive.core.presentation.theme.DefaultBoxPreview +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.Accordion +import net.opendasharchive.openarchive.features.core.AccordionState +import net.opendasharchive.openarchive.features.core.rememberAccordionState + +@Composable +fun ExpandableSpaceList( + serverAccordionState: AccordionState, + selectedSpace: Space? = null, + spaceList: List +) { + Accordion( + state = serverAccordionState, + headerContent = { + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + + if (selectedSpace != null) { + DrawerSpaceListItem(space = selectedSpace) + } else { + Text(stringResource(R.string.servers)) + } + + IconButton( + modifier = Modifier.rotate(serverAccordionState.animationProgress * 180), + onClick = { + serverAccordionState.toggle() + } + ) { + Icon( + imageVector = Icons.Outlined.KeyboardArrowDown, + contentDescription = stringResource(R.string.expand) + ) + } + } + }, + bodyContent = { + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + spaceList.forEach { space -> + DrawerSpaceListItem(space) + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + PrimaryButton( + text = stringResource(R.string.add_server), + icon = Icons.Default.Add + ) { } + } + } + + } + ) +} + +@Composable +fun DrawerSpaceListItem( + space: Space, +) { + Row( + modifier = Modifier + .wrapContentSize() + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + SpaceIcon( + type = space.tType, + modifier = Modifier.size(24.dp) + ) + + Text(space.name) + } +} + +@Composable +fun SpaceIcon( + type: Space.Type, + modifier: Modifier = Modifier, + tint: Color? = null +) { + val icon = when (type) { + Space.Type.WEBDAV -> painterResource(R.drawable.ic_space_private_server) + Space.Type.INTERNET_ARCHIVE -> painterResource(R.drawable.ic_space_interent_archive) + Space.Type.GDRIVE -> painterResource(R.drawable.logo_gdrive_outline) + Space.Type.RAVEN -> painterResource(R.drawable.ic_space_dweb) + } + Icon( + modifier = modifier, + painter = icon, + contentDescription = null, + tint = tint ?: MaterialTheme.colorScheme.onBackground + ) +} + +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun ExpandableSpaceListPreview() { + val state = rememberAccordionState( + expanded = true, + ) + + DefaultBoxPreview { + ExpandableSpaceList( + selectedSpace = dummySpaceList[1], + spaceList = dummySpaceList, + serverAccordionState = state + ) + } +} + +val dummySpaceList = listOf( + Space( + type = Space.Type.WEBDAV.id, + username = "", + password = "", + name = "Elelan Server", + ), + Space( + type = Space.Type.INTERNET_ARCHIVE.id, + username = "", + password = "", + name = "Test Server", + ), + Space( + type = Space.Type.RAVEN.id, + username = "", + password = "", + name = "DWebServer", + ), +) \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/FolderOptionsPopup.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/FolderOptionsPopup.kt new file mode 100644 index 00000000..499e244c --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/FolderOptionsPopup.kt @@ -0,0 +1,61 @@ +package net.opendasharchive.openarchive.features.main.ui.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.R + +@Composable +fun FolderOptionsPopup( + expanded: Boolean = false, + onDismissRequest: () -> Unit, + onRenameFolder: () -> Unit, + onSelectMedia: () -> Unit, + onRemoveFolder: () -> Unit +) { + + DropdownMenu( + modifier = Modifier, + expanded = expanded, + onDismissRequest = onDismissRequest + ) { + + Column(modifier = Modifier.padding(8.dp)) { + + DropdownMenuItem( + onClick = onRenameFolder, + text = { Text(stringResource(R.string.lbl_rename_folder)) } + ) + DropdownMenuItem( + onClick = onSelectMedia, + text = { Text(stringResource(R.string.lbl_select_media)) } + ) + DropdownMenuItem( + onClick = onRemoveFolder, + text = { Text(stringResource(R.string.lbl_remove_folder)) } + ) + } + } + +} + +@Preview +@Composable +private fun FolderOptionsPopupPreview() { + + FolderOptionsPopup( + expanded = true, + onDismissRequest = {}, + onRenameFolder = {}, + onSelectMedia = {}, + onRemoveFolder = {} + ) + +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/HomeAppBar.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/HomeAppBar.kt new file mode 100644 index 00000000..3d092349 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/HomeAppBar.kt @@ -0,0 +1,79 @@ +package net.opendasharchive.openarchive.features.main.ui.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeAppBar( + openDrawer: () -> Unit, + onExit: () -> Unit +) { + + TopAppBar( + title = { + Image( + modifier = Modifier + .size(64.dp) + .clickable { + onExit() + }, + painter = painterResource(R.drawable.savelogo), + contentDescription = "Save Logo", + colorFilter = ColorFilter.tint(colorResource(R.color.colorOnPrimary)) + ) + }, + actions = { + + AnimatedVisibility( + visible = false + ) { + IconButton( + onClick = {} + ) { + Icon( + Icons.Outlined.Delete, + contentDescription = null + ) + } + + } + + IconButton( + colors = IconButtonDefaults.iconButtonColors( + contentColor = colorResource(R.color.colorOnSecondary) + ), + onClick = { + openDrawer() + } + ) { + Icon( + imageVector = Icons.Default.Menu, + contentDescription = null + ) + } + + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = colorResource(R.color.colorPrimary) + ) + ) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/MainBottomBar.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/MainBottomBar.kt new file mode 100644 index 00000000..f257f95e --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/MainBottomBar.kt @@ -0,0 +1,98 @@ +package net.opendasharchive.openarchive.features.main.ui.components + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.PermMedia +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.outlined.PermMedia +import androidx.compose.material.icons.outlined.Settings +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.FloatingActionButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.R + +@Composable +fun MainBottomBar( + isSettings: Boolean, + onMyMediaClick: () -> Unit, + onSettingsClick: () -> Unit, + onAddMediaClick: () -> Unit +) { + NavigationBar( + modifier = Modifier.fillMaxWidth(), + containerColor = MaterialTheme.colorScheme.primary + ) { + + BottomNavMenuItem( + isSelected = !isSettings, + onClick = onMyMediaClick, + selectedIcon = Icons.Default.PermMedia, + unSelectedIcon = Icons.Outlined.PermMedia, + text = stringResource(R.string.my_media) + ) + + FloatingActionButton( + modifier = Modifier.size(height = 42.dp, width = 90.dp), + onClick = onAddMediaClick, + containerColor = colorResource(R.color.colorOnPrimary), + shape = RoundedCornerShape(percent = 50), + elevation = FloatingActionButtonDefaults.elevation( + defaultElevation = 6.dp, + pressedElevation = 12.dp + ) + ) { + Icon( + modifier = Modifier.size(28.dp), + imageVector = Icons.Default.Add, + contentDescription = null + ) + } + + BottomNavMenuItem( + isSelected = isSettings, + onClick = onSettingsClick, + selectedIcon = Icons.Default.Settings, + unSelectedIcon = Icons.Outlined.Settings, + text = stringResource(R.string.action_settings) + ) + + } +} + +@Composable +fun RowScope.BottomNavMenuItem( + selectedIcon: ImageVector, + unSelectedIcon: ImageVector, + isSelected: Boolean, + text: String, + onClick: () -> Unit +) { + val icon = if (isSelected) selectedIcon else unSelectedIcon + NavigationBarItem( + label = { + Text(text) + }, + selected = isSelected, + onClick = onClick, + icon = { + Icon( + imageVector = icon, + contentDescription = null + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/MainDrawerContent.kt b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/MainDrawerContent.kt new file mode 100644 index 00000000..c96f535a --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/main/ui/components/MainDrawerContent.kt @@ -0,0 +1,219 @@ +package net.opendasharchive.openarchive.features.main.ui.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Folder +import androidx.compose.material.icons.outlined.Folder +import androidx.compose.material3.Button +import androidx.compose.material3.DrawerDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalDrawerSheet +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview +import net.opendasharchive.openarchive.db.Project +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.rememberAccordionState + +@Composable +fun MainDrawerContent( + selectedSpace: Space? = null, + spaceList: List = emptyList() +) { + + val configuration = LocalConfiguration.current + val screenWidth = configuration.screenWidthDp.dp + + val serverAccordionState = rememberAccordionState() + + ModalDrawerSheet( + drawerShape = DrawerDefaults.shape, + modifier = Modifier.width(screenWidth * 0.65f), + drawerContainerColor = Color.White + ) { + Column( + modifier = Modifier + .fillMaxHeight() + .padding(vertical = 24.dp), + verticalArrangement = Arrangement.SpaceBetween + ) { + + Column( + modifier = Modifier + .padding(vertical = 24.dp) + .verticalScroll(rememberScrollState()), + ) { + + + Spacer(Modifier.height(12.dp)) + + ExpandableSpaceList( + serverAccordionState, + selectedSpace = selectedSpace, + spaceList = spaceList + ) + + HorizontalDivider( + color = MaterialTheme.colorScheme.surfaceVariant, + thickness = 0.3.dp, + modifier = Modifier.padding(vertical = 24.dp) + ) + + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + imageVector = Icons.Default.Folder, + tint = MaterialTheme.colorScheme.primary, + contentDescription = null + ) + Text("Summer Vacation") + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + imageVector = Icons.Outlined.Folder, + tint = MaterialTheme.colorScheme.onBackground, + contentDescription = null + ) + Text("Prague") + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + imageVector = Icons.Outlined.Folder, + tint = MaterialTheme.colorScheme.onBackground, + contentDescription = null + ) + Text("Misc") + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + imageVector = Icons.Outlined.Folder, + tint = MaterialTheme.colorScheme.onBackground, + contentDescription = null + ) + Text("Folder") + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + imageVector = Icons.Outlined.Folder, + tint = MaterialTheme.colorScheme.onBackground, + contentDescription = null + ) + Text("Folder") + } + } + + + + Spacer(Modifier.height(12.dp)) + + + } + + + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + + Button( + modifier = Modifier.fillMaxWidth(0.7f), + shape = RoundedCornerShape(8f), + onClick = { + + } + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon(imageVector = Icons.Default.Add, contentDescription = null) + Text("New Folder") + } + } + } + } + } +} + +@Composable +fun MainDrawerFolderListItem( + project: Project, + isSelected: Boolean = false, + onSelected: () -> Unit +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + Icon( + imageVector = Icons.Outlined.Folder, + tint = MaterialTheme.colorScheme.onBackground, + contentDescription = null + ) + + Text("Prague") + } +} + +@Preview +@Composable +private fun MainDrawerContentPreview() { + DefaultScaffoldPreview { + MainDrawerContent() + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/AddMediaDialogFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/AddMediaDialogFragment.kt index 1a3a7f8a..8d385aab 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/media/AddMediaDialogFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/AddMediaDialogFragment.kt @@ -18,7 +18,7 @@ class AddMediaDialogFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = MaterialAlertDialogBuilder(requireContext()) - mDialogView = onCreateView(LayoutInflater.from(requireContext()), null, savedInstanceState) + mDialogView = onCreateView(layoutInflater, null, savedInstanceState) builder.setView(mDialogView) return builder.create() } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/ContentPickerFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/ContentPickerFragment.kt new file mode 100644 index 00000000..1ea462a8 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/ContentPickerFragment.kt @@ -0,0 +1,46 @@ +package net.opendasharchive.openarchive.features.media + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import net.opendasharchive.openarchive.databinding.FragmentContentPickerBinding + +class ContentPickerFragment(private val onMediaPicked: (AddMediaType) -> Unit): BottomSheetDialogFragment() { + + private var _binding: FragmentContentPickerBinding? = null + private val binding get() = _binding!! + + + companion object { + const val TAG = "ModalBottomSheet-ContentPickerFragment" + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentContentPickerBinding.inflate(inflater, container, false) + + + binding.actionUploadCamera.setOnClickListener { + onMediaPicked(AddMediaType.CAMERA) + dismiss() + } + + binding.actionUploadMedia.setOnClickListener { + onMediaPicked(AddMediaType.GALLERY) + dismiss() + } + + binding.actionUploadFiles.setOnClickListener { + onMediaPicked(AddMediaType.FILES) + dismiss() + } + + + return binding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/MediaLaunchers.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/MediaLaunchers.kt index 06bfe950..fad0f07b 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/media/MediaLaunchers.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/MediaLaunchers.kt @@ -1,12 +1,11 @@ package net.opendasharchive.openarchive.features.media import android.content.Intent -import android.net.Uri import androidx.activity.result.ActivityResultLauncher import com.esafirm.imagepicker.features.ImagePickerLauncher data class MediaLaunchers( val imagePickerLauncher: ImagePickerLauncher, val filePickerLauncher: ActivityResultLauncher, - val cameraLauncher: ActivityResultLauncher + val cameraLauncher: ActivityResultLauncher ) \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/Picker.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/Picker.kt index 537ad9a9..9ca78c02 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/media/Picker.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/Picker.kt @@ -10,8 +10,10 @@ import android.graphics.Color import android.net.Uri import android.os.Build import android.os.Environment +import android.provider.MediaStore import android.view.View import android.widget.ProgressBar +import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts @@ -33,6 +35,8 @@ import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.core.logger.AppLogger import net.opendasharchive.openarchive.db.Media import net.opendasharchive.openarchive.db.Project +import net.opendasharchive.openarchive.features.main.MainActivity +import net.opendasharchive.openarchive.features.main.MainActivity.Companion.REQUEST_CAMERA_PERMISSION import net.opendasharchive.openarchive.util.Utility import net.opendasharchive.openarchive.util.extensions.makeSnackBar import org.witness.proofmode.crypto.HashUtils @@ -81,8 +85,8 @@ object Picker { } } - val cpl = activity.registerForActivityResult(ActivityResultContracts.TakePicture()) { success -> - if (success) { + val cpl = activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == AppCompatActivity.RESULT_OK) { currentPhotoUri?.let { uri -> val snackbar = showProgressSnackBar(activity, root, activity.getString(R.string.importing_media)) @@ -106,15 +110,7 @@ object Picker { ) } - fun pickMedia(activity: Activity, launcher: ImagePickerLauncher) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - if (needAskForPermission(activity, arrayOf( - Manifest.permission.READ_MEDIA_IMAGES, - Manifest.permission.READ_MEDIA_VIDEO)) - ) { - return - } - } + fun pickMedia(launcher: ImagePickerLauncher) { val config = ImagePickerConfig { mode = ImagePickerMode.MULTIPLE @@ -143,26 +139,6 @@ object Picker { type = "application/*" } - private fun needAskForPermission(activity: Activity, permissions: Array): Boolean { - var needAsk = false - - for (permission in permissions) { - needAsk = ContextCompat.checkSelfPermission( - activity, - permission - ) != PackageManager.PERMISSION_GRANTED - && ActivityCompat.shouldShowRequestPermissionRationale(activity, permission) - - if (needAsk) break - } - - if (!needAsk) return false - - ActivityCompat.requestPermissions(activity, permissions, 2) - - return true - } - private fun import(context: Context, project: Project?, uris: List): ArrayList { val result = ArrayList() @@ -221,16 +197,28 @@ object Picker { return media } - fun takePhoto(context: Context, launcher: ActivityResultLauncher) { - val file = Utility.getOutputMediaFileByCache(context, "IMG_${System.currentTimeMillis()}.jpg") + fun takePhoto(activity: Activity, launcher: ActivityResultLauncher) { + + val file = Utility.getOutputMediaFileByCache(activity, "IMG_${System.currentTimeMillis()}.jpg") file?.let { val uri = FileProvider.getUriForFile( - context, "${context.packageName}.provider", + activity, "${activity.packageName}.provider", it ) + currentPhotoUri = uri - launcher.launch(uri) + + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { + putExtra(MediaStore.EXTRA_OUTPUT, uri) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) // Ensure permission is granted + } + + if (takePictureIntent.resolveActivity(activity.packageManager) != null) { + launcher.launch(takePictureIntent) + } else { + Toast.makeText(activity, "Camera not available", Toast.LENGTH_SHORT).show() + } } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewActivity.kt index 2e03d24f..0099e29b 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewActivity.kt @@ -1,23 +1,25 @@ package net.opendasharchive.openarchive.features.media import android.content.Context -import android.content.DialogInterface import android.content.Intent import android.os.Bundle -import android.view.ContextThemeWrapper import android.view.Menu import android.view.MenuItem import android.view.View -import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.GridLayoutManager import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.ActivityPreviewBinding import net.opendasharchive.openarchive.db.Media import net.opendasharchive.openarchive.db.Project import net.opendasharchive.openarchive.features.core.BaseActivity -import net.opendasharchive.openarchive.util.AlertHelper +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.asUiImage +import net.opendasharchive.openarchive.features.core.asUiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.main.MainActivity +import net.opendasharchive.openarchive.util.PermissionManager import net.opendasharchive.openarchive.util.Prefs import net.opendasharchive.openarchive.util.extensions.hide import net.opendasharchive.openarchive.util.extensions.show @@ -60,21 +62,26 @@ class PreviewActivity : BaseActivity(), View.OnClickListener, PreviewAdapter.Lis } } + private lateinit var permissionManager: PermissionManager + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = ActivityPreviewBinding.inflate(layoutInflater) setContentView(mBinding.root) + permissionManager = PermissionManager(this, dialogManager) + mProject = Project.getById(intent.getLongExtra(PROJECT_ID_EXTRA, -1)) mediaLaunchers = Picker.register(this, mBinding.root, { mProject }, { refresh() }) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.title = getString(R.string.preview_media) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar( + title = getString(R.string.preview_media), + showBackButton = true + ) mBinding.mediaGrid.layoutManager = GridLayoutManager(this, 2) mBinding.mediaGrid.adapter = PreviewAdapter(this) @@ -87,8 +94,8 @@ class PreviewActivity : BaseActivity(), View.OnClickListener, PreviewAdapter.Lis if (Picker.canPickFiles(this)) { mBinding.btAddMore.setOnLongClickListener { - mBinding.addMenu.container.show(animate = true) - + //mBinding.addMenu.container.show(animate = true) + initAddMediaBottomSheet() true } @@ -121,6 +128,25 @@ class PreviewActivity : BaseActivity(), View.OnClickListener, PreviewAdapter.Lis refresh() } + private fun initAddMediaBottomSheet() { + + if (Picker.canPickFiles(this)) { + val modalBottomSheet = ContentPickerFragment { action -> + when (action) { + AddMediaType.CAMERA -> { +// permissionManager.checkCameraPermission { + Picker.takePhoto(this@PreviewActivity, mediaLaunchers.cameraLauncher) +// } + + } + AddMediaType.FILES -> Picker.pickFiles(mediaLaunchers.filePickerLauncher) + AddMediaType.GALLERY -> onClick(mBinding.btAddMore) + } + } + modalBottomSheet.show(supportFragmentManager, ContentPickerFragment.TAG) + } + } + override fun onResume() { super.onResume() @@ -129,56 +155,13 @@ class PreviewActivity : BaseActivity(), View.OnClickListener, PreviewAdapter.Lis override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.menu_preview, menu) - return super.onCreateOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - android.R.id.home -> { - finish() - - return true - } - R.id.menu_upload -> { - val queue = { - mMedia.forEach { - it.sStatus = Media.Status.Queued - it.selected = false - it.save() - } - - finish() - } - - if (Prefs.dontShowUploadHint) { - queue() - } else { - var doNotShowAgain = false - - val d = AlertDialog.Builder(ContextThemeWrapper(this, R.style.AlertDialogTheme)) - .setTitle(R.string.once_uploaded_you_will_not_be_able_to_edit_media) - .setIcon(R.drawable.baseline_cloud_upload_black_48) - .setPositiveButton( - R.string.got_it - ) { _: DialogInterface, _: Int -> - Prefs.dontShowUploadHint = doNotShowAgain - queue() - } - .setNegativeButton(R.string.lbl_Cancel) { dialog: DialogInterface, _: Int -> dialog.dismiss() } - .setMultiChoiceItems( - arrayOf(getString(R.string.do_not_show_me_this_again)), - booleanArrayOf(false) - ) - { _, _, isChecked -> - doNotShowAgain = isChecked - }.show() - - // hack for making sure this dialog always shows all lines of the pretty long title, even on small screens - d.findViewById(androidx.appcompat.R.id.alertTitle)?.maxLines = 99 - - } + uploadMedia() return true } } @@ -189,7 +172,9 @@ class PreviewActivity : BaseActivity(), View.OnClickListener, PreviewAdapter.Lis override fun onClick(view: View?) { when (view) { mBinding.btAddMore -> { - Picker.pickMedia(this, mediaLaunchers.imagePickerLauncher) + permissionManager.checkMediaPermissions { + Picker.pickMedia(mediaLaunchers.imagePickerLauncher) + } } mBinding.btBatchEdit -> { @@ -255,11 +240,63 @@ class PreviewActivity : BaseActivity(), View.OnClickListener, PreviewAdapter.Lis private fun showFirstTimeBatch() { if (Prefs.batchHintShown) return - AlertHelper.show( - this, R.string.press_and_hold_to_select_and_edit_multiple_media, - R.string.edit_multiple, R.drawable.ic_batchedit - ) + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + icon = R.drawable.perm_media_24px.asUiImage() + iconColor = dialogManager.requireResourceProvider().getColor(R.color.colorTertiary) + title = R.string.edit_multiple.asUiText() + message = R.string.press_and_hold_to_select_and_edit_multiple_media.asUiText() + positiveButton { + text = UiText.StringResource(R.string.lbl_got_it) + action = { + dialogManager.dismissDialog() + } + } + } + + Prefs.batchHintShown = true } + + private fun uploadMedia() { + val queue = { + mMedia.forEach { + it.sStatus = Media.Status.Queued + it.selected = false + it.save() + } + + finish() + } + + if (Prefs.dontShowUploadHint) { + + queue() + + } else { + + var doNotShowAgain = false + + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Warning + iconColor = dialogManager.requireResourceProvider().getColor(R.color.colorTertiary) + message = R.string.once_uploaded_you_will_not_be_able_to_edit_media.asUiText() + showCheckbox = true + checkboxText = UiText.StringResource(R.string.do_not_show_me_this_again) + onCheckboxChanged = { isChecked -> + doNotShowAgain = isChecked + } + positiveButton { + text = UiText.DynamicString("Proceed to upload") + action = { + Prefs.dontShowUploadHint = doNotShowAgain + queue() + } + } + neutralButton { + text = UiText.DynamicString("Actually, let me edit") + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewAdapter.kt index 591d7407..2768c210 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewAdapter.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/PreviewAdapter.kt @@ -1,14 +1,16 @@ package net.opendasharchive.openarchive.features.media +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter +import net.opendasharchive.openarchive.databinding.RvMediaBoxBinding import net.opendasharchive.openarchive.db.Media -import net.opendasharchive.openarchive.db.MediaViewHolder +import net.opendasharchive.openarchive.features.media.adapter.PreviewViewHolder import java.lang.ref.WeakReference -class PreviewAdapter(listener: Listener? = null): ListAdapter(DIFF_CALLBACK) { +class PreviewAdapter(listener: Listener? = null): ListAdapter(DIFF_CALLBACK) { interface Listener { @@ -53,8 +55,9 @@ class PreviewAdapter(listener: Listener? = null): ListAdapter val media = getMedia(view) ?: return@setOnClickListener @@ -79,7 +82,7 @@ class PreviewAdapter(listener: Listener? = null): ListAdapter { - if (mMedia?.mimeType?.startsWith("image") == true) { - val draweeView = SimpleDraweeView(this) - draweeView.setImageURI(mMedia?.fileUri) - } - } +// mBinding.waveform, mBinding.image -> { +// if (mMedia?.mimeType?.startsWith("image") == true) { +// val draweeView = SimpleDraweeView(this) +// draweeView.setImageURI(mMedia?.fileUri) +// } +// } mBinding.btFlag -> { showFirstTimeFlag() @@ -283,9 +287,18 @@ class ReviewActivity : BaseActivity(), View.OnClickListener { } private fun showFirstTimeFlag() { - if (Prefs.flagHintShown) return - - AlertHelper.show(this, R.string.popup_flag_desc, R.string.popup_flag_title) + if (!Prefs.flagHintShown) return + + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + title = UiText.StringResource(R.string.popup_flag_title) + message = UiText.StringResource(R.string.popup_flag_desc) + positiveButton { + text = UiText.StringResource(R.string.lbl_got_it) + action = { + dialogManager.dismissDialog() + } + } + } Prefs.flagHintShown = true } @@ -322,7 +335,7 @@ class ReviewActivity : BaseActivity(), View.OnClickListener { imageView.setImageResource(R.drawable.audio_waveform) if (waveform != null) { - val soundFile = MediaViewHolder.soundCache[media.originalFilePath] + val soundFile = UploadMediaViewHolder.soundCache[media.originalFilePath] if (soundFile != null) { waveform.setAudioFile(soundFile) waveform.show() diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/media/adapter/PreviewViewHolder.kt b/app/src/main/java/net/opendasharchive/openarchive/features/media/adapter/PreviewViewHolder.kt new file mode 100644 index 00000000..f88020d7 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/media/adapter/PreviewViewHolder.kt @@ -0,0 +1,171 @@ +package net.opendasharchive.openarchive.features.media.adapter + +import android.annotation.SuppressLint +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import androidx.swiperefreshlayout.widget.CircularProgressDrawable +import com.bumptech.glide.Glide +import com.github.derlio.waveform.soundfile.SoundFile +import com.squareup.picasso.Picasso +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger +import net.opendasharchive.openarchive.databinding.RvMediaBoxBinding +import net.opendasharchive.openarchive.db.Media +import net.opendasharchive.openarchive.fragments.VideoRequestHandler +import net.opendasharchive.openarchive.util.extensions.hide +import net.opendasharchive.openarchive.util.extensions.show +import timber.log.Timber + +class PreviewViewHolder(val binding: RvMediaBoxBinding) : + RecyclerView.ViewHolder(binding.root) { + + companion object { + val soundCache = HashMap() + } + + private val mContext = itemView.context + + private val mPicasso = Picasso.Builder(mContext) + .addRequestHandler(VideoRequestHandler(mContext)) + .build() + + + @SuppressLint("SetTextI18n") + fun bind(media: Media? = null, batchMode: Boolean = false, doImageFade: Boolean = true) { + itemView.tag = media?.id + if (batchMode && media?.selected == true) { + itemView.setBackgroundResource(R.color.colorPrimary) + binding.selectedIndicator.show() + } else { + itemView.setBackgroundResource(R.color.transparent) + binding.selectedIndicator.hide() + } + + binding.image.alpha = if (media?.sStatus == Media.Status.Uploaded || !doImageFade) 1f else 0.5f + + if (media?.mimeType?.startsWith("image") == true) { + val progress = CircularProgressDrawable(mContext) + progress.strokeWidth = 5f + progress.centerRadius = 30f + progress.start() + + Glide.with(mContext) + .load(media.fileUri) + .placeholder(progress) + .fitCenter() + .into(binding.image) + + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.hide() + } else if (media?.mimeType?.startsWith("video") == true) { + mPicasso.load(VideoRequestHandler.SCHEME_VIDEO + ":" + media.originalFilePath) + .fit() + .centerCrop() + .into(binding.image) + + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.show() + } else if (media?.mimeType?.startsWith("audio") == true) { + binding.videoIndicator.hide() + + val soundFile = soundCache[media.originalFilePath] + + if (soundFile != null) { + binding.image.hide() + binding.waveform.setAudioFile(soundFile) + binding.waveform.show() + } else { + binding.image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.no_thumbnail)) + binding.image.show() + binding.waveform.hide() + + CoroutineScope(Dispatchers.IO).launch { + @Suppress("NAME_SHADOWING") + val soundFile = try { + SoundFile.create(media.originalFilePath) { + return@create true + } + } catch (e: Throwable) { + Timber.d(e) + + null + } + + if (soundFile != null) { + soundCache[media.originalFilePath] = soundFile + + MainScope().launch { + binding.waveform.setAudioFile(soundFile) + binding.image.hide() + binding.waveform.show() + } + } + } + } + } else { + binding.image.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.no_thumbnail)) + binding.image.show() + binding.waveform.hide() + binding.videoIndicator.hide() + } + + if (media != null) { + + + val sbTitle = StringBuffer() + + when (media.sStatus) { + Media.Status.Error -> { + AppLogger.i("Media Item ${media.id} is error") + sbTitle.append(mContext.getString(R.string.error)) + + binding.overlayContainer.show() + binding.progress.hide() + binding.progressText.hide() + binding.error.show() + + } + Media.Status.Queued -> { + AppLogger.i("Media Item ${media.id} is queued") + binding.overlayContainer.show() + binding.progress.isIndeterminate = true + binding.progress.show() + binding.progressText.hide() + binding.error.hide() + } + Media.Status.Uploading -> { + binding.progress.isIndeterminate = false + val progressValue = media.uploadPercentage ?: 0 + AppLogger.i("Media Item ${media.id} is uploading") + + binding.overlayContainer.show() + binding.progress.show() + binding.progressText.show() + + // Make sure to keep spinning until the upload has made some noteworthy progress. + if (progressValue > 2) { + binding.progress.setProgressCompat(progressValue, true) + } + + binding.progressText.text = "${progressValue}%" + + binding.error.hide() + } + else -> { + binding.overlayContainer.hide() + binding.progress.hide() + binding.progressText.hide() + binding.error.hide() + } + } + + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23Activity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23Activity.kt index e5d63df1..1ce30fdf 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23Activity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23Activity.kt @@ -45,7 +45,7 @@ class Onboarding23Activity : BaseActivity() { mBinding.titleBlock.verifyText, mBinding.titleBlock.encryptText )) { - textView.text = colorizeFirstLetter(textView.text, R.color.colorPrimary) + textView.text = colorizeFirstLetter(textView.text, R.color.colorTertiary) } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23InstructionsActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23InstructionsActivity.kt index 1197cf54..20b4c74e 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23InstructionsActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/Onboarding23InstructionsActivity.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.View import android.view.Window import android.view.WindowManager +import android.view.inputmethod.InputMethodManager import androidx.activity.OnBackPressedCallback import androidx.core.content.ContextCompat import androidx.viewpager2.widget.ViewPager2 @@ -12,6 +13,7 @@ import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.ActivityOnboarding23InstructionsBinding import net.opendasharchive.openarchive.features.core.BaseActivity +import net.opendasharchive.openarchive.features.main.MainActivity import net.opendasharchive.openarchive.util.Prefs class Onboarding23InstructionsActivity : BaseActivity() { @@ -98,10 +100,10 @@ class Onboarding23InstructionsActivity : BaseActivity() { private fun updateCoverImage() { when (mBinding.viewPager.currentItem) { - 0 -> mBinding.coverImage.setImageResource(R.drawable.onboarding23_cover_secure) - 1 -> mBinding.coverImage.setImageResource(R.drawable.onboarding23_cover_archive) - 2 -> mBinding.coverImage.setImageResource(R.drawable.onboarding23_cover_verify) - 3 -> mBinding.coverImage.setImageResource(R.drawable.onboarding23_cover_encrypt) + 0 -> mBinding.coverImage.setImageResource(R.drawable.onboarding_secure_png) + 1 -> mBinding.coverImage.setImageResource(R.drawable.onboarding_archive_png) + 2 -> mBinding.coverImage.setImageResource(R.drawable.onboarding_verify_png) + 3 -> mBinding.coverImage.setImageResource(R.drawable.onboarding_encrypt_png) } mBinding.coverImage.alpha = 0F mBinding.coverImage.animate().setDuration(200L).alpha(1F).start() @@ -118,7 +120,16 @@ class Onboarding23InstructionsActivity : BaseActivity() { } private fun done() { + // Hide keyboard before finishing activity + val imm = getSystemService(InputMethodManager::class.java) + currentFocus?.let { view -> + imm?.hideSoftInputFromWindow(view.windowToken, 0) + view.clearFocus() // Remove focus from any input field + } + Prefs.didCompleteOnboarding = true - startActivity(Intent(this, SpaceSetupActivity::class.java)) + // We are moving space setup to MainActivity + startActivity(Intent(this, MainActivity::class.java)) + finish() } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/SpaceSetupActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/SpaceSetupActivity.kt index f45f3b55..6122edfc 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/SpaceSetupActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/onboarding/SpaceSetupActivity.kt @@ -2,17 +2,45 @@ package net.opendasharchive.openarchive.features.onboarding import android.content.Intent import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavController +import androidx.navigation.NavGraph +import androidx.navigation.NavOptions +import androidx.navigation.Navigator +import androidx.navigation.findNavController +import androidx.navigation.fragment.FragmentNavigator +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.setupActionBarWithNavController import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.ActivitySpaceSetupBinding +import net.opendasharchive.openarchive.extensions.onBackButtonPressed import net.opendasharchive.openarchive.features.core.BaseActivity +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.ToolbarConfigurable +import net.opendasharchive.openarchive.features.internetarchive.presentation.InternetArchiveFragment import net.opendasharchive.openarchive.features.main.MainActivity import net.opendasharchive.openarchive.features.settings.SpaceSetupFragment import net.opendasharchive.openarchive.features.settings.SpaceSetupSuccessFragment import net.opendasharchive.openarchive.services.gdrive.GDriveFragment -import net.opendasharchive.openarchive.features.internetarchive.presentation.InternetArchiveFragment -import net.opendasharchive.openarchive.services.webdav.WebDavSetupLicenseFragment -import net.opendasharchive.openarchive.services.internetarchive.Util +import net.opendasharchive.openarchive.services.snowbird.SnowbirdCreateGroupFragment +import net.opendasharchive.openarchive.services.snowbird.SnowbirdFileListFragment +import net.opendasharchive.openarchive.services.snowbird.SnowbirdFragment +import net.opendasharchive.openarchive.services.snowbird.SnowbirdGroupListFragment +import net.opendasharchive.openarchive.services.snowbird.SnowbirdJoinGroupFragment +import net.opendasharchive.openarchive.services.snowbird.SnowbirdRepoListFragment +import net.opendasharchive.openarchive.services.snowbird.SnowbirdShareFragment import net.opendasharchive.openarchive.services.webdav.WebDavFragment +import net.opendasharchive.openarchive.services.webdav.WebDavSetupLicenseFragment + +enum class StartDestination { + SPACE_TYPE, + SPACE_LIST, + DWEB_DASHBOARD, + ADD_FOLDER, + ADD_NEW_FOLDER +} class SpaceSetupActivity : BaseActivity() { @@ -20,231 +48,103 @@ class SpaceSetupActivity : BaseActivity() { const val FRAGMENT_TAG = "ssa_fragment" } - private lateinit var mBinding: ActivitySpaceSetupBinding + private lateinit var binding: ActivitySpaceSetupBinding + + private lateinit var navController: NavController + private lateinit var navGraph: NavGraph + private lateinit var appBarConfiguration: AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mBinding = ActivitySpaceSetupBinding.inflate(layoutInflater) - setContentView(mBinding.root) + binding = ActivitySpaceSetupBinding.inflate(layoutInflater) + setContentView(binding.root) - initSpaceSetupFragmentBindings() - initWebDavFragmentBindings() - initWebDavCreativeLicenseBindings() - initSpaceSetupSuccessFragmentBindings() - initInternetArchiveFragmentBindings() - initGDriveFragmentBindings() - } + setupToolbar( + showBackButton = true + ) - private fun initSpaceSetupSuccessFragmentBindings() { - supportFragmentManager.setFragmentResultListener(SpaceSetupSuccessFragment.RESP_DONE, this) { _, _ -> - finishAffinity() - startActivity(Intent(this, MainActivity::class.java)) - } - } - /** - * Init NextCloud credentials - * - */ - private fun initWebDavFragmentBindings() { - supportFragmentManager.setFragmentResultListener(WebDavFragment.RESP_SAVED, this) { key, bundle -> - val spaceId = bundle.getLong(WebDavFragment.ARG_SPACE_ID) - progress3() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace( - mBinding.spaceSetupFragment.id, - WebDavSetupLicenseFragment.newInstance(spaceId = spaceId, isEditing = false), - FRAGMENT_TAG, - ) - .commit() - } +// onBackButtonPressed { +// +// if (supportFragmentManager.backStackEntryCount > 1) { +// // We still have fragments in the back stack to pop +// supportFragmentManager.popBackStack() +// true // fully handled here +// } else { +// // No more fragments left in back stack, let the system finish Activity +// false +// } +// } - supportFragmentManager.setFragmentResultListener(WebDavFragment.RESP_CANCEL, this) { _, _ -> - progress1() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right) - .replace(mBinding.spaceSetupFragment.id, SpaceSetupFragment(), FRAGMENT_TAG) - .commit() - } + initSpaceSetupNavigation() } - /** - * Init select Creative Commons Licensing - * - */ - private fun initWebDavCreativeLicenseBindings() { - supportFragmentManager.setFragmentResultListener(WebDavSetupLicenseFragment.RESP_SAVED, this) { _, _ -> - progress4() - val message = getString(R.string.you_have_successfully_connected_to_a_private_server) - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace( - mBinding.spaceSetupFragment.id, - SpaceSetupSuccessFragment.newInstance(message), - FRAGMENT_TAG, - ) - .commit() - } + private fun initSpaceSetupNavigation() { + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.space_nav_host_fragment) as NavHostFragment - supportFragmentManager.setFragmentResultListener(WebDavSetupLicenseFragment.RESP_CANCEL, this) { _, _ -> - progress3() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right) - .replace(mBinding.spaceSetupFragment.id, WebDavFragment(), FRAGMENT_TAG) - .commit() - } - } - - private fun initSpaceSetupFragmentBindings() { - supportFragmentManager.setFragmentResultListener(SpaceSetupFragment.RESULT_REQUEST_KEY, this) { _, bundle -> - when (bundle.getString(SpaceSetupFragment.RESULT_BUNDLE_KEY)) { - SpaceSetupFragment.RESULT_VAL_INTERNET_ARCHIVE -> { - progress2() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace( - mBinding.spaceSetupFragment.id, - InternetArchiveFragment.newInstance(), - FRAGMENT_TAG - ) - .commit() - } - - SpaceSetupFragment.RESULT_VAL_WEBDAV -> { - progress2() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace( - mBinding.spaceSetupFragment.id, - WebDavFragment.newInstance(), - FRAGMENT_TAG - ) - .commit() - } + navController = navHostFragment.navController + navGraph = navController.navInflater.inflate(R.navigation.space_setup_navigation) - SpaceSetupFragment.RESULT_VAL_GDRIVE -> { - progress2() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace(mBinding.spaceSetupFragment.id, GDriveFragment(), FRAGMENT_TAG) - .commit() - } + val startDestinationString = + intent.getStringExtra("start_destination") ?: StartDestination.SPACE_TYPE.name + val startDestination = StartDestination.valueOf(startDestinationString) + when (startDestination) { + StartDestination.SPACE_LIST -> { + navGraph.setStartDestination(R.id.fragment_space_list) + } + StartDestination.ADD_FOLDER -> { + navGraph.setStartDestination(R.id.fragment_add_folder) + } + StartDestination.ADD_NEW_FOLDER -> { + navGraph.setStartDestination(R.id.fragment_create_new_folder) + } + else -> { + navGraph.setStartDestination(R.id.fragment_space_setup) } } - } - - private fun initInternetArchiveFragmentBindings() { - supportFragmentManager.setFragmentResultListener(InternetArchiveFragment.RESP_SAVED, this) { _, _ -> - progress4() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace( - mBinding.spaceSetupFragment.id, - SpaceSetupSuccessFragment.newInstance(getString(R.string.you_have_successfully_connected_to_the_internet_archive)), - FRAGMENT_TAG - ) - .commit() - } - - supportFragmentManager.setFragmentResultListener( - InternetArchiveFragment.RESP_CANCEL, - this - ) { _, _ -> - progress1() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right) - .replace(mBinding.spaceSetupFragment.id, SpaceSetupFragment(), FRAGMENT_TAG) - .commit() - } - } - - private fun initGDriveFragmentBindings() { - supportFragmentManager.setFragmentResultListener( - GDriveFragment.RESP_CANCEL, - this - ) { _, _ -> - progress1() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right) - .replace(mBinding.spaceSetupFragment.id, SpaceSetupFragment(), FRAGMENT_TAG) - .commit() - } + navController.graph = navGraph - supportFragmentManager.setFragmentResultListener( - GDriveFragment.RESP_AUTHENTICATED, - this - ) { _, _ -> - progress4() - supportFragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left) - .replace( - mBinding.spaceSetupFragment.id, - SpaceSetupSuccessFragment.newInstance(getString(R.string.you_have_successfully_connected_to_gdrive)), - FRAGMENT_TAG - ) - .commit() - } + appBarConfiguration = AppBarConfiguration(emptySet()) + setupActionBarWithNavController(navController, appBarConfiguration) } - @Deprecated("Deprecated in Java") - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)?.let { - onActivityResult(requestCode, resultCode, data) + fun updateToolbarFromFragment(fragment: Fragment) { + if (fragment is ToolbarConfigurable) { + val title = fragment.getToolbarTitle() + val subtitle = fragment.getToolbarSubtitle() + val showBackButton = fragment.shouldShowBackButton() + setupToolbar(title = title, showBackButton = showBackButton) + supportActionBar?.subtitle = subtitle + } else { + // Default toolbar configuration if fragment doesn't implement interface + setupToolbar(title = "Servers", showBackButton = true) + supportActionBar?.subtitle = null } } - private fun progress1() { - Util.setBackgroundTint(mBinding.progressBlock.dot1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar1, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.dot2, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.bar2, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.dot3, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.bar3, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.dot4, R.color.colorSpaceSetupProgressOff) + override fun onSupportNavigateUp(): Boolean { + return findNavController(R.id.space_nav_host_fragment).navigateUp() || super.onSupportNavigateUp() } - private fun progress2() { - Util.setBackgroundTint(mBinding.progressBlock.dot1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.dot2, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar2, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.dot3, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.bar3, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.dot4, R.color.colorSpaceSetupProgressOff) - } + override fun onDestroy() { + super.onDestroy() - private fun progress3() { - Util.setBackgroundTint(mBinding.progressBlock.dot1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.dot2, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar2, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.dot3, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar3, R.color.colorSpaceSetupProgressOff) - Util.setBackgroundTint(mBinding.progressBlock.dot4, R.color.colorSpaceSetupProgressOff) - } + // Clear any pending messages or callbacks in the main thread handler + window?.decorView?.handler?.removeCallbacksAndMessages(null) + binding.commonAppBar.commonToolbar.setNavigationOnClickListener(null) - private fun progress4() { - Util.setBackgroundTint(mBinding.progressBlock.dot1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar1, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.dot2, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar2, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.dot3, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.bar3, R.color.colorSpaceSetupProgressOn) - Util.setBackgroundTint(mBinding.progressBlock.dot4, R.color.colorSpaceSetupProgressOn) + // Remove navigation reference (if using Jetpack Navigation) + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.space_nav_host_fragment) as? NavHostFragment + navHostFragment?.let { + it.childFragmentManager.fragments.forEach { fragment -> + fragment.view?.let { view -> + view.handler?.removeCallbacksAndMessages(null) + } + } + } } } diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/CcSelector.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/CcSelector.kt deleted file mode 100644 index 175db133..00000000 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/CcSelector.kt +++ /dev/null @@ -1,119 +0,0 @@ -package net.opendasharchive.openarchive.features.settings - -import net.opendasharchive.openarchive.databinding.ContentCcBinding -import net.opendasharchive.openarchive.util.extensions.openBrowser -import net.opendasharchive.openarchive.util.extensions.styleAsLink -import net.opendasharchive.openarchive.util.extensions.toggle - -object CcSelector { - - private const val CC_DOMAIN = "creativecommons.org" - private const val CC_URL = "https://%s/licenses/%s/4.0/" - - fun init(cc: ContentCcBinding, license: String? = null, enabled: Boolean = true, update: ((license: String?) -> Unit)? = null) { - set(cc, license, enabled) - - cc.swCc.setOnCheckedChangeListener { _, isChecked -> - toggle(cc, isChecked) - - @Suppress("NAME_SHADOWING") - val license = get(cc) - - update?.invoke(license) - } - - cc.swNd.setOnCheckedChangeListener { _, isChecked -> - cc.swSa.isEnabled = isChecked - - @Suppress("NAME_SHADOWING") - val license = get(cc) - - update?.invoke(license) - } - - cc.swSa.setOnCheckedChangeListener { _, _ -> - @Suppress("NAME_SHADOWING") - val license = get(cc) - - update?.invoke(license) - } - cc.swNc.setOnCheckedChangeListener { _, _ -> - @Suppress("NAME_SHADOWING") - val license = get(cc) - - update?.invoke(license) - } - - cc.tvLicense.setOnClickListener { - it?.context?.openBrowser(cc.tvLicense.text.toString()) - } - - cc.btLearnMore.styleAsLink() - cc.btLearnMore.setOnClickListener { - it?.context?.openBrowser("https://creativecommons.org/about/cclicenses/") - } - } - - fun set(cc: ContentCcBinding, license: String?, enabled: Boolean = true) { - val isCc = license?.contains(CC_DOMAIN, true) ?: false - - cc.swCc.isChecked = isCc - toggle(cc, isCc) - - cc.swNd.isChecked = isCc && !(license?.contains("-nd", true) ?: false) - cc.swSa.isEnabled = cc.swNd.isChecked - cc.swSa.isChecked = isCc && cc.swNd.isChecked && license?.contains("-sa", true) ?: false - cc.swNc.isChecked = isCc && !(license?.contains("-nc", true) ?: false) - - cc.tvLicense.text = license - cc.tvLicense.styleAsLink() - - cc.swCc.isEnabled = enabled - cc.swNd.isEnabled = enabled - cc.swSa.isEnabled = enabled - cc.swNc.isEnabled = enabled - } - - fun get(cc: ContentCcBinding): String? { - var license: String? = null - - if (cc.swCc.isChecked) { - license = "by" - - if (cc.swNd.isChecked) { - if (!cc.swNc.isChecked) { - license += "-nc" - } - - if (cc.swSa.isChecked) { - license += "-sa" - } - } - else { - cc.swSa.isChecked = false - - if (!cc.swNc.isChecked) { - license += "-nc" - } - - license += "-nd" - } - } - - if (license != null) { - license = String.format(CC_URL, CC_DOMAIN, license) - } - - cc.tvLicense.text = license - cc.tvLicense.styleAsLink() - - return license - } - - private fun toggle(cc: ContentCcBinding, value: Boolean) { - cc.row1.toggle(value) - cc.row2.toggle(value) - cc.row3.toggle(value) - cc.tvLicense.toggle(value) - } -} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/ConsentActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/ConsentActivity.kt index ecb1dad3..69b11260 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/ConsentActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/ConsentActivity.kt @@ -18,8 +18,7 @@ class ConsentActivity: BaseActivity() { mBinding = ActivityConsentBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar(getString(R.string.health_checks)) mBinding.explainer.text = getString( R.string.by_allowing_health_checks_you_give_permission_for_the_app_to_securely_send_health_check_data_to_the_s_team, diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/CreativeCommonsLicenseManager.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/CreativeCommonsLicenseManager.kt new file mode 100644 index 00000000..de82223f --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/CreativeCommonsLicenseManager.kt @@ -0,0 +1,119 @@ +package net.opendasharchive.openarchive.features.settings + +import net.opendasharchive.openarchive.databinding.ContentCcBinding +import net.opendasharchive.openarchive.util.extensions.openBrowser +import net.opendasharchive.openarchive.util.extensions.styleAsLink +import net.opendasharchive.openarchive.util.extensions.toggle + +object CreativeCommonsLicenseManager { + + private const val CC_DOMAIN = "creativecommons.org" + private const val CC_LICENSE_URL_FORMAT = "https://%s/licenses/%s/4.0/" + + fun initialize( + binding: ContentCcBinding, + currentLicense: String? = null, + enabled: Boolean = true, + update: ((license: String?) -> Unit)? = null + ) { + configureInitialState(binding, currentLicense, enabled) + + with(binding) { + swCcEnabled.setOnCheckedChangeListener { _, isChecked -> + setShowLicenseOptions(binding, isChecked) + val license = getSelectedLicenseUrl(binding) + update?.invoke(license) + } + + swAllowRemix.setOnCheckedChangeListener { _, isChecked -> + swRequireShareAlike.isEnabled = isChecked + val license = getSelectedLicenseUrl(binding) + update?.invoke(license) + } + + swRequireShareAlike.setOnCheckedChangeListener { _, _ -> + val license = getSelectedLicenseUrl(binding) + update?.invoke(license) + } + swAllowCommercial.setOnCheckedChangeListener { _, _ -> + val license = getSelectedLicenseUrl(binding) + update?.invoke(license) + } + + tvLicenseUrl.setOnClickListener { + it?.context?.openBrowser(tvLicenseUrl.text.toString()) + } + + btLearnMore.styleAsLink() + btLearnMore.setOnClickListener { + it?.context?.openBrowser("https://creativecommons.org/about/cclicenses/") + } + } + } + + private fun configureInitialState( + binding: ContentCcBinding, + currentLicense: String?, + enabled: Boolean = true + ) { + val isActive = currentLicense?.contains(CC_DOMAIN, true) ?: false + + with(binding) { + swCcEnabled.isChecked = isActive + setShowLicenseOptions(this, isActive) + + swAllowRemix.isChecked = isActive && !(currentLicense?.contains("-nd", true) ?: false) + swRequireShareAlike.isEnabled = binding.swAllowRemix.isChecked + swRequireShareAlike.isChecked = isActive && binding.swAllowRemix.isChecked && currentLicense?.contains("-sa", true) ?: false + swAllowCommercial.isChecked = isActive && !(currentLicense?.contains("-nc", true) ?: false) + tvLicenseUrl.text = currentLicense + tvLicenseUrl.styleAsLink() + swCcEnabled.isEnabled = enabled + swAllowRemix.isEnabled = enabled + swRequireShareAlike.isEnabled = enabled + swAllowCommercial.isEnabled = enabled + } + } + + fun getSelectedLicenseUrl(cc: ContentCcBinding): String? { + var license: String? = null + + if (cc.swCcEnabled.isChecked) { + license = "by" + + if (cc.swAllowRemix.isChecked) { + if (!cc.swAllowCommercial.isChecked) { + license += "-nc" + } + + if (cc.swRequireShareAlike.isChecked) { + license += "-sa" + } + } else { + cc.swRequireShareAlike.isChecked = false + + if (!cc.swAllowCommercial.isChecked) { + license += "-nc" + } + + license += "-nd" + } + } + + if (license != null) { + license = String.format(CC_LICENSE_URL_FORMAT, CC_DOMAIN, license) + } + + cc.tvLicenseUrl.text = license + cc.tvLicenseUrl.styleAsLink() + + return license + } + + private fun setShowLicenseOptions(binding: ContentCcBinding, isVisible: Boolean) { + binding.rowAllowRemix.toggle(isVisible) + binding.rowShareAlike.toggle(isVisible) + binding.rowCommercialUse.toggle(isVisible) + binding.tvLicenseUrl.toggle(isVisible) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/EditFolderActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/EditFolderActivity.kt index 2082651a..bffe5653 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/EditFolderActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/EditFolderActivity.kt @@ -7,7 +7,10 @@ import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.ActivityEditFolderBinding import net.opendasharchive.openarchive.db.Project import net.opendasharchive.openarchive.features.core.BaseActivity -import net.opendasharchive.openarchive.util.AlertHelper +import net.opendasharchive.openarchive.features.core.UiImage +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog import net.opendasharchive.openarchive.util.extensions.Position import net.opendasharchive.openarchive.util.extensions.setDrawable @@ -31,8 +34,8 @@ class EditFolderActivity : BaseActivity() { mBinding = ActivityEditFolderBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + + setupToolbar("Edit Folder") mBinding.folderName.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE) { @@ -44,6 +47,9 @@ class EditFolderActivity : BaseActivity() { supportActionBar?.title = newName mBinding.folderName.hint = newName + + + setupToolbar(newName) } } @@ -52,14 +58,14 @@ class EditFolderActivity : BaseActivity() { mBinding.btRemove.setDrawable(R.drawable.ic_delete, Position.Start, 0.5) mBinding.btRemove.setOnClickListener { - removeProject() + showDeleteFolderConfirmDialog() } mBinding.btArchive.setOnClickListener { archiveProject() } - CcSelector.init(mBinding.cc, null) { + CreativeCommonsLicenseManager.initialize(mBinding.cc, null) { mProject.licenseUrl = it mProject.save() } @@ -67,14 +73,26 @@ class EditFolderActivity : BaseActivity() { updateUi() } - private fun removeProject() { - AlertHelper.show(this, R.string.action_remove_project, R.string.remove_from_app, buttons = listOf( - AlertHelper.positiveButton(R.string.remove) { _, _ -> - mProject.delete() - - finish() - }, - AlertHelper.negativeButton())) + private fun showDeleteFolderConfirmDialog() { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Error + icon = UiImage.DrawableResource(R.drawable.ic_trash) + title = UiText.StringResource(R.string.remove_from_app) + message = UiText.StringResource(R.string.action_remove_project) + destructiveButton { + text = UiText.StringResource(R.string.remove) + action = { + mProject.delete() + finish() + } + } + neutralButton { + text = UiText.StringResource(R.string.lbl_Cancel) + action = { + dialogManager.dismissDialog() + } + } + } } private fun archiveProject() { @@ -98,10 +116,10 @@ class EditFolderActivity : BaseActivity() { val global = mProject.space?.license != null if (global) { - mBinding.cc.tvCc.setText(R.string.set_the_same_creative_commons_license_for_all_folders_on_this_server) + mBinding.cc.tvCcLabel.setText(R.string.set_the_same_creative_commons_license_for_all_folders_on_this_server) } - CcSelector.set(mBinding.cc, mProject.licenseUrl, !mProject.isArchived && !global) + CreativeCommonsLicenseManager.initialize(mBinding.cc, mProject.licenseUrl, !mProject.isArchived && !global) } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/FoldersActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/FoldersActivity.kt index 94e6e959..b1d2c2f4 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/FoldersActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/FoldersActivity.kt @@ -2,7 +2,9 @@ package net.opendasharchive.openarchive.features.settings import android.content.Intent import android.os.Bundle +import android.view.Menu import android.view.MenuItem +import android.view.View import androidx.recyclerview.widget.LinearLayoutManager import net.opendasharchive.openarchive.FolderAdapter import net.opendasharchive.openarchive.FolderAdapterListener @@ -11,71 +13,125 @@ import net.opendasharchive.openarchive.databinding.ActivityFoldersBinding import net.opendasharchive.openarchive.db.Project import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.core.BaseActivity -import net.opendasharchive.openarchive.util.extensions.hide +import net.opendasharchive.openarchive.features.folders.AddFolderActivity import net.opendasharchive.openarchive.util.extensions.toggle -class FoldersActivity: BaseActivity(), FolderAdapterListener { +class FoldersActivity : BaseActivity(), FolderAdapterListener { companion object { const val EXTRA_SHOW_ARCHIVED = "show_archived" + const val EXTRA_SELECTED_SPACE_ID = "selected_space_id" + const val EXTRA_SELECTED_PROJECT_ID = "SELECTED_PROJECT_ID" } private lateinit var mBinding: ActivityFoldersBinding private lateinit var mAdapter: FolderAdapter private var mArchived = false + private var mSelectedSpaceId = -1L + private var mSelectedProjectId: Long = -1L override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mArchived = intent.getBooleanExtra(EXTRA_SHOW_ARCHIVED, false) + mSelectedSpaceId = intent.getLongExtra(EXTRA_SELECTED_SPACE_ID, -1L) + mSelectedProjectId = intent.getLongExtra(EXTRA_SELECTED_PROJECT_ID, -1L) mBinding = ActivityFoldersBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.title = getString(if (mArchived) R.string.archived_folders else R.string.folders) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar( + title = getString(if (mArchived) R.string.archived_folders else R.string.folders), + showBackButton = true + ) - mAdapter = FolderAdapter(this) + setupRecyclerView() + setupButtons() + } + + private fun setupRecyclerView() { + mAdapter = FolderAdapter(context = this, listener = this, isArchived = mArchived) mBinding.rvProjects.layoutManager = LinearLayoutManager(this) mBinding.rvProjects.adapter = mAdapter + } - mBinding.btViewArchived.toggle(!mArchived) - mBinding.btViewArchived.setOnClickListener { - val i = Intent(this, FoldersActivity::class.java) - i.putExtra(EXTRA_SHOW_ARCHIVED, true) - - startActivity(i) + private fun setupButtons() { +// mBinding.fabAdd.apply { +// visibility = if (mArchived) View.INVISIBLE else View.VISIBLE +// setOnClickListener { addFolder() } +// } + + mBinding.btViewArchived.apply { + toggle(!mArchived) + setOnClickListener { + val i = Intent(this@FoldersActivity, FoldersActivity::class.java) + i.putExtra(EXTRA_SHOW_ARCHIVED, true) + startActivity(i) + } } } override fun onResume() { super.onResume() + refreshProjects() + invalidateOptionsMenu() + } + + private fun refreshProjects() { + val projects = if (mArchived) { + Space.current?.archivedProjects + } else { + Space.current?.projects?.filter { !it.isArchived } + } ?: emptyList() + + mAdapter.update(projects) + } + - val projects = if (mArchived) Space.current?.archivedProjects else Space.current?.projects + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.menu_folder_list, menu) + return super.onCreateOptionsMenu(menu) + } - mAdapter.update(projects ?: emptyList()) + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + val archivedCount = Space.get(mSelectedSpaceId)?.archivedProjects?.size ?: 0 + menu?.findItem(R.id.action_archived_folders)?.isVisible = (!mArchived && archivedCount > 0) + return super.onPrepareOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - finish() - return true + return when (item.itemId) { + + R.id.action_archived_folders -> { + navigateToArchivedFolders() + true + } + + else -> super.onOptionsItemSelected(item) } + } - return super.onOptionsItemSelected(item) + private fun navigateToArchivedFolders() { + val intent = Intent(this, FoldersActivity::class.java).apply { + putExtra(EXTRA_SHOW_ARCHIVED, true) + putExtra(EXTRA_SELECTED_SPACE_ID, mSelectedSpaceId) + putExtra(EXTRA_SELECTED_PROJECT_ID, mSelectedProjectId) + } + startActivity(intent) } - override fun projectClicked(project: Project) { - val i = Intent(this, EditFolderActivity::class.java) - i.putExtra(EditFolderActivity.EXTRA_CURRENT_PROJECT_ID, project.id) - startActivity(i) - } + override fun projectClicked(project: Project) { + val resultIntent = Intent() + resultIntent.putExtra("SELECTED_FOLDER_ID", project.id) + setResult(RESULT_OK, resultIntent) + finish() // Close FoldersActivity and return to MainActivity - override fun getSelectedProject(): Project? { - return null + val intent = Intent(this, EditFolderActivity::class.java).apply { + putExtra(EditFolderActivity.EXTRA_CURRENT_PROJECT_ID, project.id) + } + startActivity(intent) } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/GeneralSettingsActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/GeneralSettingsActivity.kt index db392f4b..82fdee99 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/GeneralSettingsActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/GeneralSettingsActivity.kt @@ -6,6 +6,7 @@ import android.os.Bundle import android.view.MenuItem import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog +import androidx.compose.ui.res.stringResource import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreferenceCompat @@ -113,7 +114,7 @@ class GeneralSettingsActivity: BaseActivity() { } findPreference(Prefs.THEME)?.setOnPreferenceChangeListener { _, newValue -> - Theme.set(Theme.get(newValue as? String)) + Theme.set(requireActivity(), Theme.get(newValue as? String)) true } @@ -158,8 +159,7 @@ class GeneralSettingsActivity: BaseActivity() { mBinding = ActivitySettingsContainerBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar(title = getString(R.string.general)) supportFragmentManager .beginTransaction() diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeScreen.kt new file mode 100644 index 00000000..4031b903 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeScreen.kt @@ -0,0 +1,199 @@ +package net.opendasharchive.openarchive.features.settings + +import android.content.Intent +import android.net.Uri +import android.provider.Settings +import android.text.Spanned +import android.text.style.URLSpan +import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Info +import androidx.compose.material3.Card +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextLinkStyles +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.fromHtml +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.text.HtmlCompat +import me.zhanghai.compose.preference.ProvidePreferenceLocals +import me.zhanghai.compose.preference.switchPreference +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme +import net.opendasharchive.openarchive.features.internetarchive.presentation.login.ComposeAppBar +import net.opendasharchive.openarchive.features.settings.passcode.components.DefaultScaffold + +@Composable +fun ProofModeScreen( + onNavigateBack: () -> Unit +) { + + SaveAppTheme { + + + DefaultScaffold( + topAppBar = { + ComposeAppBar( + title = stringResource(R.string.proofmode), + onNavigationAction = { + onNavigateBack() + } + ) + }, + + ) { + + ProofModeScreenContent() + } + } +} + +@Composable +fun ProofModeScreenContent() { + val context = LocalContext.current + val uriHandler = LocalUriHandler.current + + + val permissionLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission() + ) { isGranted -> + if (!isGranted) { + Toast.makeText(context, "Please allow all permissions", Toast.LENGTH_LONG).show() + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", context.packageName, null) + intent.data = uri + context.startActivity(intent) + } + } + + val useProofModeKeyEncryption = remember { mutableStateOf(false) } + + val spannedText: Spanned = HtmlCompat.fromHtml( + stringResource( + R.string.prefs_use_proofmode_description, + "https://proofmode.org/" + ), HtmlCompat.FROM_HTML_MODE_COMPACT + ) + + // AnnotatedString Builder + val annotatedString = buildAnnotatedString { + append(spannedText.toString()) + spannedText.getSpans(0, spannedText.length, URLSpan::class.java) + .forEach { urlSpan -> + val start = spannedText.getSpanStart(urlSpan) + val end = spannedText.getSpanEnd(urlSpan) + addStringAnnotation( + tag = "URL", + annotation = urlSpan.url, + start = start, + end = end + ) + addStyle( + style = SpanStyle( + color = MaterialTheme.colorScheme.tertiary, + textDecoration = TextDecoration.Underline + ), + start = start, + end = end + ) + } + } + + ProvidePreferenceLocals { + val useProofModeKey = stringResource(R.string.pref_key_use_proof_mode) + + LazyColumn(modifier = Modifier.fillMaxSize()) { + + + switchPreference( + key = useProofModeKey, + defaultValue = false, + enabled = { + true + }, + rememberState = { + useProofModeKeyEncryption + }, + title = { Text(stringResource(R.string.prefs_use_proofmode_title)) }, + summary = { Text(stringResource(R.string.prefs_use_proofmode_summary)) } + ) + + item { + Box(modifier = Modifier.padding(horizontal = 16.dp)) { + Text(annotatedString, fontSize = 11.sp) + } + } + + item { + Column( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 24.dp) + ) { + + Card( + shape = RoundedCornerShape(8.dp) + ) { + + Row( + modifier = Modifier.padding(16.dp), + verticalAlignment = Alignment.Top, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Icon( + Icons.Outlined.Info, + tint = MaterialTheme.colorScheme.error, + contentDescription = null + ) + Text( + text = AnnotatedString.fromHtml( + stringResource(R.string.proof_mode_warning_text), + linkStyles = TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + fontStyle = FontStyle.Italic, + color = Color.Blue + ) + ) + ), + ) + } + } + } + } + } + } +} + +@Preview +@Composable +private fun ProofModeScreenPreview() { + DefaultScaffoldPreview { + ProofModeScreenContent() + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeSettingsActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeSettingsActivity.kt index 567ba40f..3704fd02 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeSettingsActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/ProofModeSettingsActivity.kt @@ -3,16 +3,19 @@ package net.opendasharchive.openarchive.features.settings import android.Manifest import android.app.Activity import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings +import android.text.Spanned +import android.text.method.LinkMovementMethod import android.view.MenuItem import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts -import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat +import androidx.core.text.HtmlCompat import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreferenceCompat @@ -31,28 +34,38 @@ import java.io.IOException import java.util.UUID import javax.crypto.SecretKey -class ProofModeSettingsActivity: BaseActivity() { +class ProofModeSettingsActivity : BaseActivity() { - class Fragment: PreferenceFragmentCompat() { + class Fragment : PreferenceFragmentCompat() { - private val enrollBiometrics = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - findPreference(Prefs.USE_PROOFMODE_KEY_ENCRYPTION)?.let { - MainScope().launch { - enableProofModeKeyEncryption(it) + private val enrollBiometrics = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + findPreference(Prefs.USE_PROOFMODE_KEY_ENCRYPTION)?.let { + MainScope().launch { + enableProofModeKeyEncryption(it) + } } } - } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.prefs_proof_mode, rootKey) - findPreference("share_proofmode")?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - shareKey(requireActivity()) - true - } + val proofModeSwitch = findPreference(Prefs.USE_PROOFMODE) + + // Check if permission is granted + val hasPermission = ContextCompat.checkSelfPermission( + requireContext(), Manifest.permission.READ_PHONE_STATE + ) == PackageManager.PERMISSION_GRANTED + + if (!hasPermission) { + proofModeSwitch?.isChecked = false // Uncheck if permission not granted + Prefs.putBoolean(Prefs.USE_PROOFMODE, false) + Toast.makeText(requireContext(), getString(R.string.phone_permission_required), Toast.LENGTH_LONG).show() + } else { + proofModeSwitch?.isChecked = Prefs.getBoolean(Prefs.USE_PROOFMODE, false) + } - findPreference(Prefs.USE_PROOFMODE)?.setOnPreferenceChangeListener { preference, newValue -> + getPrefByKey(R.string.pref_key_use_proof_mode)?.setOnPreferenceChangeListener { preference, newValue -> if (newValue as Boolean) { PermissionX.init(this) .permissions(Manifest.permission.READ_PHONE_STATE) @@ -65,11 +78,17 @@ class ProofModeSettingsActivity: BaseActivity() { .request { allGranted, _, _ -> if (!allGranted) { (preference as? SwitchPreferenceCompat)?.isChecked = false - Toast.makeText(activity,"Please allow all permissions", Toast.LENGTH_LONG).show() + Toast.makeText( + activity, + "Please allow all permissions", + Toast.LENGTH_LONG + ).show() val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val uri = Uri.fromParts("package", activity?.packageName, null) intent.data = uri activity?.startActivity(intent) + } else { + (preference as? SwitchPreferenceCompat)?.isChecked = true } } } @@ -77,20 +96,23 @@ class ProofModeSettingsActivity: BaseActivity() { true } - val pkePreference = findPreference(Prefs.USE_PROOFMODE_KEY_ENCRYPTION) + val pkePreference = + findPreference(Prefs.USE_PROOFMODE_KEY_ENCRYPTION) val activity = activity val availability = Hbks.deviceAvailablity(requireContext()) if (activity != null && availability !is Hbks.Availability.Unavailable) { pkePreference?.isSingleLineTitle = false - pkePreference?.setTitle(when (Hbks.biometryType(activity)) { - Hbks.BiometryType.StrongBiometry -> R.string.prefs_proofmode_key_encryption_title_biometrics + pkePreference?.setTitle( + when (Hbks.biometryType(activity)) { + Hbks.BiometryType.StrongBiometry -> R.string.prefs_proofmode_key_encryption_title_biometrics - Hbks.BiometryType.DeviceCredential -> R.string.prefs_proofmode_key_encryption_title_passcode + Hbks.BiometryType.DeviceCredential -> R.string.prefs_proofmode_key_encryption_title_passcode - else -> R.string.prefs_proofmode_key_encryption_title_all - }) + else -> R.string.prefs_proofmode_key_encryption_title_all + } + ) pkePreference?.setOnPreferenceChangeListener { _, newValue -> if (newValue as Boolean) { @@ -99,8 +121,7 @@ class ProofModeSettingsActivity: BaseActivity() { } else { enableProofModeKeyEncryption(pkePreference) } - } - else { + } else { if (Prefs.proofModeEncryptedPassphrase != null) { Prefs.proofModeEncryptedPassphrase = null @@ -112,8 +133,7 @@ class ProofModeSettingsActivity: BaseActivity() { true } - } - else { + } else { pkePreference?.isVisible = false } } @@ -141,6 +161,11 @@ class ProofModeSettingsActivity: BaseActivity() { // What?? shouldn't happen if enrolled with a PIN or Fingerprint } } + + + private fun getPrefByKey(key: Int): T? { + return findPreference(getString(key)) + } } private lateinit var mBinding: ActivitySettingsContainerBinding @@ -151,13 +176,31 @@ class ProofModeSettingsActivity: BaseActivity() { mBinding = ActivitySettingsContainerBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar(getString(R.string.proofmode)) + supportFragmentManager .beginTransaction() .replace(mBinding.container.id, Fragment()) .commit() + +// setContent { + +// } + + + val learnModeInfo = + getString(R.string.prefs_use_proofmode_description, getString(R.string.intro_link_verify)) + + + val spannedText: Spanned = + HtmlCompat.fromHtml(learnModeInfo, HtmlCompat.FROM_HTML_MODE_COMPACT) + + mBinding.proofModeLearnMode.text = spannedText + + mBinding.proofModeLearnMode.movementMethod = + LinkMovementMethod.getInstance() // Enable link clicks + } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -182,13 +225,16 @@ class ProofModeSettingsActivity: BaseActivity() { intent.putExtra(Intent.EXTRA_TEXT, pubKey) activity.startActivity(intent) } - } - catch (ioe: IOException) { + } catch (ioe: IOException) { Timber.d("error publishing key") } } - private fun createPassphrase(key: SecretKey, activity: FragmentActivity?, completed: (passphrase: String?) -> Unit) { + private fun createPassphrase( + key: SecretKey, + activity: FragmentActivity?, + completed: (passphrase: String?) -> Unit + ) { val passphrase = UUID.randomUUID().toString() Hbks.encrypt(passphrase, key, activity) { ciphertext, _ -> @@ -198,7 +244,11 @@ class ProofModeSettingsActivity: BaseActivity() { Prefs.proofModeEncryptedPassphrase = ciphertext - Hbks.decrypt(Prefs.proofModeEncryptedPassphrase, key, activity) { decrpytedPassphrase, _ -> + Hbks.decrypt( + Prefs.proofModeEncryptedPassphrase, + key, + activity + ) { decrpytedPassphrase, _ -> if (decrpytedPassphrase == null || decrpytedPassphrase != passphrase) { Prefs.proofModeEncryptedPassphrase = null @@ -210,4 +260,6 @@ class ProofModeSettingsActivity: BaseActivity() { } } } -} \ No newline at end of file +} + + diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsFragment.kt index 10d63fa4..43439cce 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsFragment.kt @@ -1,120 +1,210 @@ package net.opendasharchive.openarchive.features.settings +import android.app.Activity import android.content.Intent import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment +import androidx.activity.result.contract.ActivityResultContracts +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.SwitchPreferenceCompat import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.databinding.FragmentSettingsBinding -import net.opendasharchive.openarchive.db.Space import net.opendasharchive.openarchive.features.core.BaseActivity -import net.opendasharchive.openarchive.features.internetarchive.presentation.InternetArchiveActivity -import net.opendasharchive.openarchive.services.gdrive.GDriveActivity -import net.opendasharchive.openarchive.services.webdav.WebDavActivity -import net.opendasharchive.openarchive.util.extensions.Position +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.onboarding.SpaceSetupActivity +import net.opendasharchive.openarchive.features.onboarding.StartDestination +import net.opendasharchive.openarchive.features.settings.passcode.PasscodeRepository +import net.opendasharchive.openarchive.features.settings.passcode.passcode_setup.PasscodeSetupActivity +import net.opendasharchive.openarchive.util.Prefs +import net.opendasharchive.openarchive.util.Theme import net.opendasharchive.openarchive.util.extensions.getVersionName -import net.opendasharchive.openarchive.util.extensions.openBrowser -import net.opendasharchive.openarchive.util.extensions.scaled -import net.opendasharchive.openarchive.util.extensions.setDrawable -import net.opendasharchive.openarchive.util.extensions.styleAsLink -import kotlin.math.roundToInt +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.activityViewModel -class SettingsFragment : Fragment() { +class SettingsFragment : PreferenceFragmentCompat() { - private lateinit var mBinding: FragmentSettingsBinding + private val passcodeRepository by inject() + private val dialogManager: DialogStateManager by activityViewModel() - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - mBinding = FragmentSettingsBinding.inflate(inflater, container, false) + private var passcodePreference: SwitchPreferenceCompat? = null + private val activityResultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val passcodeEnabled = result.data?.getBooleanExtra("passcode_enabled", false) ?: false + passcodePreference?.isChecked = passcodeEnabled + } else { + passcodePreference?.isChecked = false + } + } - mBinding.btGeneral.setDrawable(R.drawable.ic_account_circle, Position.Start, 0.6) - mBinding.btGeneral.compoundDrawablePadding = - resources.getDimension(R.dimen.padding_small).roundToInt() - mBinding.btGeneral.setOnClickListener { - val context = context ?: return@setOnClickListener - - startActivity(Intent(context, GeneralSettingsActivity::class.java)) +// override fun onCreateView( +// inflater: LayoutInflater, +// container: ViewGroup?, +// savedInstanceState: Bundle? +// ): View? { +// return ComposeView(requireContext()).apply { +// // Dispose of the Composition when the view's LifecycleOwner +// // is destroyed +// setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) +// setContent { +// Theme { +// SettingsScreen() +// } +// } +// } +// } + + override fun onCreatePreferences( + savedInstanceState: Bundle?, + rootKey: String? + ) { + setPreferencesFromResource(R.xml.prefs_general, rootKey) + + + passcodePreference = findPreference(Prefs.PASSCODE_ENABLED) + + passcodePreference?.setOnPreferenceChangeListener { _, newValue -> + val enabled = newValue as Boolean + if (enabled) { + // Launch PasscodeSetupActivity + val intent = Intent(context, PasscodeSetupActivity::class.java) + activityResultLauncher.launch(intent) + } else { + // Show confirmation dialog + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Warning + title = UiText.StringResource(R.string.disable_passcode_dialog_title) + message = UiText.StringResource(R.string.disable_passcode_dialog_msg) + positiveButton { + text = UiText.StringResource(R.string.answer_yes) + action = { + passcodeRepository.clearPasscode() + passcodePreference?.isChecked = false + + // Update the FLAG_SECURE dynamically + (activity as? BaseActivity)?.updateScreenshotPrevention() + } + } + neutralButton { + action = { + passcodePreference?.isChecked = true + } + } + } + } + // Return false to avoid the preference updating immediately + false } - mBinding.btSpace.compoundDrawablePadding = - resources.getDimension(R.dimen.padding_small).roundToInt() - mBinding.btSpace.setOnClickListener { - startSpaceAuthActivity() + findPreference(Prefs.PROHIBIT_SCREENSHOTS)?.setOnPreferenceClickListener { _ -> + if (activity is BaseActivity) { + // make sure this gets settings change gets applied instantly + // (all other activities rely on the hook in BaseActivity.onResume()) + (activity as BaseActivity).updateScreenshotPrevention() + } + + true } - mBinding.btFolders.setDrawable(R.drawable.ic_folder, Position.Start, 0.6) - mBinding.btFolders.compoundDrawablePadding = - resources.getDimension(R.dimen.padding_small).roundToInt() - mBinding.btFolders.setOnClickListener { - val context = context ?: return@setOnClickListener + getPrefByKey(R.string.pref_media_servers)?.setOnPreferenceClickListener { + val intent = Intent(context, SpaceSetupActivity::class.java) + intent.putExtra("start_destination", StartDestination.SPACE_LIST.name) + startActivity(intent) + true + } + getPrefByKey(R.string.pref_media_folders)?.setOnPreferenceClickListener { startActivity(Intent(context, FoldersActivity::class.java)) + true } - mBinding.btAbout.text = getString(R.string.action_about, getString(R.string.app_name)) - mBinding.btAbout.styleAsLink() - mBinding.btAbout.setOnClickListener { - context?.openBrowser("https://open-archive.org/save") + getPrefByKey(R.string.pref_key_proof_mode)?.setOnPreferenceClickListener { + startActivity(Intent(context, ProofModeSettingsActivity::class.java)) + true } - mBinding.btPrivacy.styleAsLink() - mBinding.btPrivacy.setOnClickListener { - context?.openBrowser("https://open-archive.org/privacy") + findPreference(Prefs.USE_TOR)?.setOnPreferenceChangeListener { _, newValue -> + Prefs.useTor = (newValue as Boolean) + //torViewModel.updateTorServiceState() + true } - val activity = activity + getPrefByKey(R.string.pref_key_use_tor)?.isEnabled = false - if (activity != null) { - mBinding.version.text = getString( - R.string.version__, - activity.packageManager.getVersionName(activity.packageName) - ) + findPreference(Prefs.THEME)?.setOnPreferenceChangeListener { _, newValue -> + Theme.set(requireActivity(), Theme.get(newValue as? String)) + true } - return mBinding.root - } - - override fun onResume() { - super.onResume() + // Retrieve the switch preference + val darkModeSwitch = getPrefByKey(R.string.pref_key_use_dark_mode) - updateSpace() - } + // Get the saved dark mode preference + val isDarkModeEnabled = Prefs.getBoolean(getString(R.string.pref_key_use_dark_mode), false) - private fun updateSpace() { - val context = context ?: return - val space = Space.current + // Set the switch state based on the saved preference + darkModeSwitch?.isChecked = isDarkModeEnabled - if (space != null) { - mBinding.btSpace.text = space.friendlyName + getPrefByKey(R.string.pref_key_use_dark_mode)?.setOnPreferenceChangeListener { pref, newValue -> + val useDarkMode = newValue as Boolean + val theme = if (useDarkMode) Theme.DARK else Theme.LIGHT + Theme.set(requireActivity(), theme) + // Save the preference + Prefs.putBoolean(getString(R.string.pref_key_use_dark_mode), useDarkMode) + true + } - mBinding.btSpace.setDrawable( - space.getAvatar(context)?.scaled(24, context), - Position.Start, tint = true - ) - } else { - mBinding.btSpace.visibility = View.GONE + findPreference(Prefs.UPLOAD_WIFI_ONLY)?.setOnPreferenceChangeListener { _, newValue -> + val intent = + Intent(Prefs.UPLOAD_WIFI_ONLY).apply { putExtra("value", newValue as Boolean) } + // Replace with shared ViewModel + LiveData + // LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent) + true } - } - private fun startSpaceAuthActivity() { - val space = Space.current ?: return + val packageManager = requireActivity().packageManager + val versionText = packageManager.getVersionName(requireActivity().packageName) - val clazz = when (space.tType) { - Space.Type.INTERNET_ARCHIVE -> InternetArchiveActivity::class.java - Space.Type.GDRIVE -> GDriveActivity::class.java - else -> WebDavActivity::class.java - } + getPrefByKey(R.string.pref_key_app_version)?.summary = versionText + } + + private fun getPrefByKey(key: Int): T? { + return findPreference(getString(key)) + } - val intent = Intent(context, clazz) - intent.putExtra(BaseActivity.EXTRA_DATA_SPACE, space.id) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - startActivity(intent) + //view.setPadding(0, 16.dpToPx(), 0, 0) } + + fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).toInt() + + +// mBinding.btAbout.text = getString(R.string.action_about, getString(R.string.app_name)) +// mBinding.btAbout.styleAsLink() +// mBinding.btAbout.setOnClickListener { +// context?.openBrowser("https://open-archive.org/save") +// } +// +// mBinding.btPrivacy.styleAsLink() +// mBinding.btPrivacy.setOnClickListener { +// context?.openBrowser("https://open-archive.org/privacy") +// } +// +// val activity = activity +// +// if (activity != null) { +// mBinding.version.text = getString( +// R.string.version__, +// activity.packageManager.getVersionName(activity.packageName) +// ) +// } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsScreen.kt new file mode 100644 index 00000000..aa2002d3 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SettingsScreen.kt @@ -0,0 +1,133 @@ +package net.opendasharchive.openarchive.features.settings + +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.rememberNavController +import kotlinx.serialization.Serializable +import me.zhanghai.compose.preference.ProvidePreferenceLocals +import me.zhanghai.compose.preference.listPreference +import me.zhanghai.compose.preference.preference +import me.zhanghai.compose.preference.preferenceCategory +import me.zhanghai.compose.preference.switchPreference +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview + +@Composable +fun SettingsScreen( + onNavigateToCache: () -> Unit = {} +) { + + val context = LocalContext.current + + ProvidePreferenceLocals { + LazyColumn(modifier = Modifier.fillMaxSize()) { + // Secure Category + preferenceCategory(title = { Text("Secure") }, key = "secure") + + switchPreference( + key = "pref_app_passcode", + defaultValue = false, + title = { Text("Lock app with passcode") }, + summary = { Text("6 digit passcode") }) + + // Archive Category + preferenceCategory(title = { Text("Archive") }, key = "archive") + preference( + key = "pref_media_servers", + title = { Text("Media Servers") }, + summary = { Text("Add or remove media servers") }) + preference( + key = "pref_media_folders", + title = { Text("Media Folders") }, + summary = { Text("Add or remove media folders") }) + preference( + key = "pref_media_cache", + title = { Text("Media Cache") }, + summary = { Text("View media cache") }, + onClick = { + onNavigateToCache() + } + ) + + // Verify Category + preferenceCategory(title = { Text("Verify") }, key = "verify") + preference( + key = "proof_mode", title = { Text("Proof Mode") }) + + // Encrypt Category + preferenceCategory(title = { Text("Encrypt") }, key = "encrypt") + switchPreference( + key = "use_tor", + defaultValue = false, + title = { Text("Use Tor") }, + summary = { Text("Enable Tor for encryption") }) + + // General Category + preferenceCategory(title = { Text("General") }, key = "general") + switchPreference( + key = "upload_wifi_only", + defaultValue = false, + title = { Text("Upload over Wi-Fi only") }, + summary = { Text("Only upload media when connected to Wi-Fi") }) + listPreference( + key = "theme", + title = { Text("Theme") }, + summary = { Text("Choose app theme") }, + values = listOf( + "light" to "Light", "dark" to "Dark", "system" to "System Default" + ), + defaultValue = "system" + ) + + // About Category + preferenceCategory(title = { Text("About") }, key = "about") + preference( + key = "about_app", + title = { Text("Save by Open Archive") }, + summary = { Text("Tap to view about Save App") }, + onClick = { + // Handle URL intent + openUrl(context, "https://open-archive.org/save") + }) + preference( + key = "privacy_policy", + title = { Text("Terms & Privacy Policy") }, + summary = { Text("Tap to view our Terms & Privacy Policy") }, + onClick = { + // Handle URL intent + openUrl(context, "https://open-archive.org/privacy") + }) + preference( + key = "app_version", + title = { Text("Version") }, + summary = { Text("0.7.2.4783") }, + enabled = false + ) + } + } +} + +// Helper function for opening URLs + +private fun openUrl(context: Context, url: String) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + context.startActivity(intent) +} + + +@Preview +@Composable +private fun SettingsScreenPreview() { + DefaultScaffoldPreview { + + SettingsScreen() + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupFragment.kt index c253ed62..b8bc89bf 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupFragment.kt @@ -1,69 +1,86 @@ package net.opendasharchive.openarchive.features.settings -import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResult +import androidx.fragment.compose.content +import androidx.navigation.NavDirections +import androidx.navigation.fragment.findNavController +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.databinding.FragmentSpaceSetupBinding import net.opendasharchive.openarchive.db.Space -import net.opendasharchive.openarchive.features.main.MainActivity +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.settings.passcode.AppConfig +import net.opendasharchive.openarchive.features.spaces.SpaceSetupScreen import net.opendasharchive.openarchive.util.extensions.hide +import net.opendasharchive.openarchive.util.extensions.show +import org.koin.android.ext.android.inject +import kotlin.getValue -class SpaceSetupFragment : Fragment() { +class SpaceSetupFragment : BaseFragment() { - private lateinit var mBinding: FragmentSpaceSetupBinding + private val appConfig by inject() override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? - ): View { - mBinding = FragmentSpaceSetupBinding.inflate(inflater) + ): View = content { - mBinding.webdav.setOnClickListener { - setFragmentResult(RESULT_REQUEST_KEY, bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_WEBDAV)) + // Prepare click lambdas that use the fragment’s business logic. + val onWebDavClick = { + if (isJetpackNavigation) { + findNavController().navigate(R.id.action_fragment_space_setup_to_fragment_web_dav) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_WEBDAV) + ) + } } - - if (Space.has(Space.Type.INTERNET_ARCHIVE)) { - mBinding.internetArchive.hide() - } else { - mBinding.internetArchive.setOnClickListener { + // Only enable Internet Archive if not already present + val isInternetArchiveAllowed = !Space.has(Space.Type.INTERNET_ARCHIVE) + val onInternetArchiveClick = { + if (isJetpackNavigation) { + val action = + SpaceSetupFragmentDirections.actionFragmentSpaceSetupToFragmentInternetArchive() + findNavController().navigate(action) + } else { setFragmentResult( RESULT_REQUEST_KEY, bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_INTERNET_ARCHIVE) ) } } + // Show/hide Snowbird based on config + val isDwebEnabled = appConfig.isDwebEnabled + val onDwebClicked = { + if (isJetpackNavigation) { + val action = + SpaceSetupFragmentDirections.actionFragmentSpaceSetupToFragmentSnowbird() + findNavController().navigate(action) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_RAVEN) + ) + } + } -// if (Space.has(Space.Type.GDRIVE) || !playServicesAvailable()) { -// mBinding.gdrive.hide() -// } else { -// mBinding.gdrive.setOnClickListener { -// setFragmentResult( -// RESULT_REQUEST_KEY, -// bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_GDRIVE) -// ) -// } -// } - -// mBinding.skipForNowButton.setOnClickListener { -// skipSpaceConfig() -// } - - return mBinding.root - } - - private fun skipSpaceConfig() { - startActivity(Intent(context, MainActivity::class.java)) - } + SaveAppTheme { + SpaceSetupScreen( + onWebDavClick = onWebDavClick, + isInternetArchiveAllowed = isInternetArchiveAllowed, + onInternetArchiveClick = onInternetArchiveClick, + isDwebEnabled = isDwebEnabled, + onDwebClicked = onDwebClicked + ) + } - private fun playServicesAvailable(): Boolean { - return true -// return ConnectionResult.SUCCESS == GoogleApiAvailability.getInstance() -// .isGooglePlayServicesAvailable(requireContext()) } companion object { @@ -71,7 +88,12 @@ class SpaceSetupFragment : Fragment() { const val RESULT_BUNDLE_KEY = "space_setup_result_key" const val RESULT_VAL_DROPBOX = "dropbox" const val RESULT_VAL_WEBDAV = "webdav" + const val RESULT_VAL_RAVEN = "raven" const val RESULT_VAL_INTERNET_ARCHIVE = "internet_archive" const val RESULT_VAL_GDRIVE = "gdrive" } + + override fun getToolbarTitle() = "Select a Server" + override fun getToolbarSubtitle(): String? = null + override fun shouldShowBackButton() = true } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupSuccessFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupSuccessFragment.kt index 0a77766e..1e637a51 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupSuccessFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/SpaceSetupSuccessFragment.kt @@ -1,15 +1,17 @@ package net.opendasharchive.openarchive.features.settings +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResult import net.opendasharchive.openarchive.databinding.FragmentSpaceSetupSuccessBinding +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.main.MainActivity -class SpaceSetupSuccessFragment : Fragment() { +class SpaceSetupSuccessFragment : BaseFragment() { private lateinit var mBinding: FragmentSpaceSetupSuccessBinding private var message = "" @@ -31,7 +33,14 @@ class SpaceSetupSuccessFragment : Fragment() { } mBinding.btAuthenticate.setOnClickListener { _ -> - setFragmentResult(RESP_DONE, bundleOf()) + if (isJetpackNavigation) { + val intent = Intent(requireActivity(), MainActivity::class.java) + intent.flags = + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK // Clears backstack + startActivity(intent) + } else { + setFragmentResult(RESP_DONE, bundleOf()) + } } return mBinding.root @@ -40,7 +49,7 @@ class SpaceSetupSuccessFragment : Fragment() { companion object { const val RESP_DONE = "space_setup_success_fragment_resp_done" - const val ARG_MESSAGE = "space_setup_success_fragment_arg_message" + const val ARG_MESSAGE = "message" @JvmStatic fun newInstance(message: String) = @@ -50,4 +59,7 @@ class SpaceSetupSuccessFragment : Fragment() { } } } + + override fun getToolbarTitle() = "Setup Complete" + override fun shouldShowBackButton() = false } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/AppConfig.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/AppConfig.kt index d62779e7..91928ff6 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/AppConfig.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/AppConfig.kt @@ -5,5 +5,7 @@ data class AppConfig( val enableHapticFeedback: Boolean = true, val maxRetryLimitEnabled: Boolean = false, val biometricAuthEnabled: Boolean = false, - val maxFailedAttempts: Int = 5 + val maxFailedAttempts: Int = 5, + val isDwebEnabled: Boolean = false, + val multipleProjectSelectionMode: Boolean = false ) \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/DefaultScaffold.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/DefaultScaffold.kt index 5b379134..827ca7b9 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/DefaultScaffold.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/DefaultScaffold.kt @@ -26,6 +26,7 @@ object MessageManager { @Composable fun DefaultScaffold( modifier: Modifier = Modifier, + topAppBar: (@Composable () -> Unit)? = null, content: @Composable () -> Unit ) { @@ -39,6 +40,9 @@ fun DefaultScaffold( Scaffold( modifier = modifier.fillMaxSize(), + topBar = { + topAppBar?.invoke() + }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/NumericKeypad.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/NumericKeypad.kt index 6186a99a..a371e368 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/NumericKeypad.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/NumericKeypad.kt @@ -19,6 +19,10 @@ import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowForward +import androidx.compose.material.icons.filled.Backspace +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -28,12 +32,15 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import net.opendasharchive.openarchive.core.presentation.theme.Theme +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.features.settings.passcode.AppHapticFeedbackType import net.opendasharchive.openarchive.features.settings.passcode.HapticManager import org.koin.compose.koinInject @@ -42,13 +49,15 @@ private val keys = listOf( "1", "2", "3", "4", "5", "6", "7", "8", "9", - "", "0" + "delete", "0", "submit" ) @Composable fun NumericKeypad( isEnabled: Boolean = true, onNumberClick: (String) -> Unit, + onDeleteClick: () -> Unit, + onSubmitClick: () -> Unit ) { Box( @@ -73,7 +82,11 @@ fun NumericKeypad( label = label, enabled = isEnabled, onClick = { - onNumberClick(label) + when (label) { + "delete" -> onDeleteClick() + "submit" -> onSubmitClick() + else -> onNumberClick(label) + } } ) } else { @@ -88,7 +101,7 @@ fun NumericKeypad( @Preview @Composable private fun NumericKeypadPreview() { - Theme { + SaveAppTheme { Scaffold { Box( modifier = Modifier.padding(it), @@ -108,7 +121,9 @@ private fun NumericKeypadPreview() { isEnabled = true, onNumberClick = { number -> - } + }, + onDeleteClick = {}, + onSubmitClick = {} ) Spacer(modifier = Modifier.height(16.dp)) @@ -125,13 +140,44 @@ private fun NumberButton( label: String, enabled: Boolean = true, onClick: () -> Unit, - hapticManager: HapticManager = koinInject() + //hapticManager: HapticManager = koinInject() ) { val interactionSource = remember { MutableInteractionSource() } val isPressed by interactionSource.collectIsPressedAsState() + + // Determine background color based on button type and pressed state val backgroundColor by animateColorAsState( - targetValue = if (isPressed) MaterialTheme.colorScheme.primary.copy(alpha = 0.5f) else Color.Transparent, + targetValue = when { + isPressed -> when (label) { + "delete" -> colorResource(R.color.red_bg).copy(alpha = 0.5f) + "submit" -> MaterialTheme.colorScheme.tertiary.copy(alpha = 0.7f) + else -> MaterialTheme.colorScheme.primary.copy(alpha = 0.5f) + } + else -> when (label) { + "delete" -> colorResource(R.color.red_bg).copy(alpha = 0.3f) + "submit" -> MaterialTheme.colorScheme.tertiary.copy(alpha = 0.5f) + else -> Color.Transparent + } + }, + animationSpec = spring(), + label = "" + ) + + // Determine background color based on button type and pressed state + val borderColor by animateColorAsState( + targetValue = when { + isPressed -> when (label) { + "delete" -> Color.Transparent + "submit" -> Color.Transparent + else -> MaterialTheme.colorScheme.tertiary.copy(alpha = 0.5f) + } + else -> when (label) { + "delete" -> Color.Transparent + "submit" -> Color.Transparent + else -> MaterialTheme.colorScheme.tertiary + } + }, animationSpec = spring(), label = "" ) @@ -144,21 +190,34 @@ private fun NumberButton( indication = null, enabled = enabled, onClick = { - hapticManager.performHapticFeedback(AppHapticFeedbackType.KeyPress) + //hapticManager.performHapticFeedback(AppHapticFeedbackType.KeyPress) onClick() } ) - .border(width = 2.dp, color = MaterialTheme.colorScheme.primary, shape = CircleShape) + .border(width = 2.dp, color = borderColor, shape = CircleShape) .size(72.dp), contentAlignment = Alignment.Center ) { - Text( - text = label, - style = TextStyle( - fontSize = 24.sp, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.onBackground + + when (label) { + "delete" -> Icon( + imageVector = Icons.Default.Backspace, + contentDescription = "Delete", + tint = MaterialTheme.colorScheme.onBackground ) - ) + "submit" -> Icon( + painter = painterResource(R.drawable.ic_arrow_submit), + contentDescription = "Submit", + tint = MaterialTheme.colorScheme.onBackground + ) + else -> Text( + text = label, + style = TextStyle( + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onBackground + ) + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/PasscodeDots.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/PasscodeDots.kt index a23886ba..12aa7874 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/PasscodeDots.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/components/PasscodeDots.kt @@ -1,5 +1,6 @@ package net.opendasharchive.openarchive.features.settings.passcode.components +import android.content.res.Configuration import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.tween import androidx.compose.foundation.background @@ -15,8 +16,10 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview import kotlin.math.roundToInt @Composable @@ -60,11 +63,24 @@ fun PasscodeDots( modifier = Modifier .size(20.dp) .background( - color = if (index < currentPasscodeLength) MaterialTheme.colorScheme.primary + color = if (index < currentPasscodeLength) MaterialTheme.colorScheme.onBackground else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f), shape = CircleShape ) ) } } +} + +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview +@Composable +private fun PasswordDotsPreview() { + + DefaultScaffoldPreview { + PasscodeDots( + passcodeLength = 6, + currentPasscodeLength = 3 + ) + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryActivity.kt index 5faca597..8e5152d8 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryActivity.kt @@ -4,7 +4,8 @@ import android.os.Bundle import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.activity.compose.setContent -import net.opendasharchive.openarchive.core.presentation.theme.Theme +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.features.core.BaseActivity import net.opendasharchive.openarchive.features.settings.passcode.PasscodeRepository import net.opendasharchive.openarchive.features.settings.passcode.components.DefaultScaffold @@ -32,7 +33,7 @@ class PasscodeEntryActivity : BaseActivity() { if (repository.isLockedOut()) { Toast.makeText( this, - "App is locked due to multiple failed attempts. Please try again later.", + getString(R.string.multiple_failed_attempts_message), Toast.LENGTH_LONG ).show() finishAndRemoveTask() @@ -40,7 +41,7 @@ class PasscodeEntryActivity : BaseActivity() { } setContent { - Theme { + SaveAppTheme { DefaultScaffold { PasscodeEntryScreen( onPasscodeSuccess = { diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryScreen.kt index b59fd12b..be4322bc 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryScreen.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryScreen.kt @@ -29,9 +29,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.runtime.collectAsState +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.flow.collectLatest import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.core.presentation.theme.Theme +import net.opendasharchive.openarchive.core.presentation.theme.DefaultEmptyScaffoldPreview +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview import net.opendasharchive.openarchive.features.settings.passcode.AppHapticFeedbackType import net.opendasharchive.openarchive.features.settings.passcode.HapticManager import net.opendasharchive.openarchive.features.settings.passcode.components.MessageManager @@ -49,7 +54,9 @@ fun PasscodeEntryScreen( hapticManager: HapticManager = koinInject() ) { - val state by viewModel.uiState.collectAsState() + val state by viewModel.uiState.collectAsStateWithLifecycle() + + val context = LocalContext.current val hapticFeedback = LocalHapticFeedback.current @@ -65,21 +72,21 @@ fun PasscodeEntryScreen( PasscodeEntryUiEvent.Success -> onPasscodeSuccess() PasscodeEntryUiEvent.PasscodeNotSet -> { - MessageManager.showMessage("Passcode not set") + MessageManager.showMessage(context.getString(R.string.passcode_not_set)) } is PasscodeEntryUiEvent.IncorrectPasscode -> { hapticManager.performHapticFeedback(AppHapticFeedbackType.Error) event.remainingAttempts?.let { - val message = "Incorrect passcode. $it attempts remaining." + val message = context.getString(R.string.passcode_remaining_attempts, it)//"Incorrect passcode. $it attempts remaining." MessageManager.showMessage(message) } } PasscodeEntryUiEvent.LockedOut -> { - MessageManager.showMessage("Too many failed attempts. App is locked.") + MessageManager.showMessage(context.getString(R.string.passcode_too_many_failed_attempts)) onExit() } } @@ -136,7 +143,7 @@ fun PasscodeEntryScreenContent( ) { Text( - text = "Enter Your Passcode", style = TextStyle( + text = stringResource(R.string.enter_passcode), style = TextStyle( fontSize = 18.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground @@ -159,50 +166,56 @@ fun PasscodeEntryScreenContent( isEnabled = !state.isProcessing, onNumberClick = { number -> onAction(PasscodeEntryScreenAction.OnNumberClick(number)) + }, + onDeleteClick = { + onAction(PasscodeEntryScreenAction.OnBackspaceClick) + }, + onSubmitClick = { + } ) Spacer(modifier = Modifier.height(16.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceAround - ) { - TextButton( - onClick = { - onExit() - } - ) { - Text( - text = "Exit", - modifier = Modifier.padding(8.dp), - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - ), - ) - } - - TextButton( - enabled = state.passcode.isNotEmpty(), - onClick = { - onAction(PasscodeEntryScreenAction.OnBackspaceClick) - } - ) { - Text( - text = "Delete", - modifier = Modifier.padding(8.dp), - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.Bold - ), - ) - } - - - } - + Spacer(modifier = Modifier.height(16.dp)) +// Row( +// modifier = Modifier.fillMaxWidth(), +// horizontalArrangement = Arrangement.SpaceAround +// ) { +// TextButton( +// onClick = { +// onExit() +// } +// ) { +// Text( +// text = "Exit", +// modifier = Modifier.padding(8.dp), +// style = TextStyle( +// fontSize = 16.sp, +// fontWeight = FontWeight.Bold, +// color = MaterialTheme.colorScheme.onBackground +// ), +// ) +// } +// +// TextButton( +// enabled = state.passcode.isNotEmpty(), +// onClick = { +// onAction(PasscodeEntryScreenAction.OnBackspaceClick) +// } +// ) { +// Text( +// text = "Delete", +// modifier = Modifier.padding(8.dp), +// style = TextStyle( +// fontSize = 16.sp, +// fontWeight = FontWeight.Bold, +// color = MaterialTheme.colorScheme.onBackground +// ), +// ) +// } +// } } } } @@ -213,7 +226,8 @@ fun PasscodeEntryScreenContent( @Composable private fun PasscodeEntryScreenPreview() { - Theme { + DefaultEmptyScaffoldPreview { + PasscodeEntryScreenContent( state = PasscodeEntryScreenState( passcodeLength = 6 @@ -221,5 +235,6 @@ private fun PasscodeEntryScreenPreview() { onAction = {}, onExit = {}, ) + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryViewModel.kt index 1f9f8b57..0cb3f2a7 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryViewModel.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_entry/PasscodeEntryViewModel.kt @@ -38,6 +38,7 @@ class PasscodeEntryViewModel( when (action) { is PasscodeEntryScreenAction.OnNumberClick -> onNumberClick(action.number) PasscodeEntryScreenAction.OnBackspaceClick -> onBackspaceClick() + PasscodeEntryScreenAction.OnSubmit -> onSubmit() } } @@ -71,6 +72,10 @@ class PasscodeEntryViewModel( } } + private fun onSubmit() { + + } + private fun checkPasscode() = viewModelScope.launch { val currentState = uiState.value val currentPasscode = currentState.passcode @@ -126,6 +131,7 @@ data class PasscodeEntryScreenState( sealed class PasscodeEntryScreenAction { data class OnNumberClick(val number: String) : PasscodeEntryScreenAction() data object OnBackspaceClick : PasscodeEntryScreenAction() + data object OnSubmit: PasscodeEntryScreenAction() } sealed class PasscodeEntryUiEvent { diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupActivity.kt index a7ad3859..3e53e056 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupActivity.kt @@ -4,10 +4,13 @@ import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.MenuItem -import androidx.activity.OnBackPressedCallback +import androidx.activity.compose.BackHandler import androidx.activity.compose.setContent -import net.opendasharchive.openarchive.core.presentation.theme.Theme +import androidx.compose.ui.res.stringResource +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme import net.opendasharchive.openarchive.features.core.BaseActivity +import net.opendasharchive.openarchive.features.internetarchive.presentation.login.ComposeAppBar import net.opendasharchive.openarchive.features.settings.passcode.components.DefaultScaffold class PasscodeSetupActivity : BaseActivity() { @@ -16,22 +19,29 @@ class PasscodeSetupActivity : BaseActivity() { const val EXTRA_PASSCODE_ENABLED = "passcode_enabled" } - private val onBackPressedCallback = object : OnBackPressedCallback(enabled = true) { - override fun handleOnBackPressed() { - setResult(RESULT_CANCELED) - finish() - } - } - - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - onBackPressedDispatcher.addCallback(onBackPressedCallback) - setContent { - Theme { - DefaultScaffold { + SaveAppTheme { + DefaultScaffold( + topAppBar = { + ComposeAppBar( + title = stringResource(R.string.passcode_lock_app), + onNavigationAction = { + setResult(RESULT_CANCELED) + finish() + } + ) + } + ) { + + // Handle back press inside Compose + BackHandler { + setResult(RESULT_CANCELED) + finish() + } + PasscodeSetupScreen( onPasscodeSet = { // Passcode successfully set diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupScreen.kt index e07a11c2..8a8c8d2c 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupScreen.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupScreen.kt @@ -22,17 +22,20 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.flow.collectLatest import net.opendasharchive.openarchive.R -import net.opendasharchive.openarchive.core.presentation.theme.Theme +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview import net.opendasharchive.openarchive.features.settings.passcode.AppHapticFeedbackType import net.opendasharchive.openarchive.features.settings.passcode.HapticManager import net.opendasharchive.openarchive.features.settings.passcode.components.MessageManager @@ -49,7 +52,9 @@ fun PasscodeSetupScreen( hapticManager: HapticManager = koinInject() ) { - val uiState by viewModel.uiState.collectAsState() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + val context = LocalContext.current val hapticFeedback = LocalHapticFeedback.current @@ -64,7 +69,7 @@ fun PasscodeSetupScreen( PasscodeSetupUiEvent.PasscodeSet -> onPasscodeSet() PasscodeSetupUiEvent.PasscodeDoNotMatch -> { hapticManager.performHapticFeedback(AppHapticFeedbackType.Error) - MessageManager.showMessage("Passcodes do not match. Try again.") + MessageManager.showMessage(context.getString(R.string.passcode_do_not_match)) } PasscodeSetupUiEvent.PasscodeCancelled -> onCancel() @@ -99,27 +104,41 @@ private fun PasscodeSetupScreenContent( verticalArrangement = Arrangement.Top, modifier = Modifier .fillMaxWidth() + .padding(top = 32.dp) .padding(horizontal = 24.dp) .padding(bottom = 24.dp) ) { - Image( - painter = painterResource(R.drawable.savelogo), - contentDescription = null, - modifier = Modifier.size(100.dp), - contentScale = ContentScale.Fit + Text( + text = if (state.isConfirming) stringResource(R.string.confirm_passcode) else stringResource(R.string.set_passcode), + style = TextStyle( + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onBackground + ) ) Spacer(modifier = Modifier.height(16.dp)) Text( - text = "Remember this PIN. If you forget it, you will need to reset the application and all data will be erased.", + text = stringResource(R.string.set_passcode_warning), color = MaterialTheme.colorScheme.error, + fontSize = 11.sp, textAlign = TextAlign.Center, - fontWeight = FontWeight.Light, + fontWeight = FontWeight.Medium, style = MaterialTheme.typography.labelMedium ) } + Spacer(modifier = Modifier.height(32.dp)) + + // Passcode dots display + PasscodeDots( + passcodeLength = state.passcodeLength, + currentPasscodeLength = state.passcode.length, + shouldShake = state.shouldShake + ) + + Spacer(modifier = Modifier.height(32.dp)) // Middle section with prompt and passcode dots Column( @@ -129,76 +148,61 @@ private fun PasscodeSetupScreenContent( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { - Text( - text = if (state.isConfirming) "Confirm Your Passcode" else "Set Your Passcode", - style = TextStyle( - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.onBackground - ) - ) - - - Spacer(modifier = Modifier.height(32.dp)) - - // Passcode dots display - PasscodeDots( - passcodeLength = state.passcodeLength, - currentPasscodeLength = state.passcode.length, - shouldShake = state.shouldShake - ) - - Spacer(modifier = Modifier.height(32.dp)) // Custom numeric keypad NumericKeypad( isEnabled = !state.isProcessing, onNumberClick = { number -> onAction(PasscodeSetupUiAction.OnNumberClick(number)) + }, + onDeleteClick = { + onAction(PasscodeSetupUiAction.OnBackspaceClick) + }, + onSubmitClick = { + onAction(PasscodeSetupUiAction.OnSubmit) } ) - Spacer(modifier = Modifier.height(16.dp)) - - Spacer(modifier = Modifier.height(16.dp)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceAround - ) { - TextButton( - onClick = { - onAction(PasscodeSetupUiAction.OnCancel) - } - ) { - Text( - text = "Cancel", - modifier = Modifier.padding(8.dp), - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - ), - ) - } - - TextButton( - enabled = state.passcode.isNotEmpty(), - onClick = { - onAction(PasscodeSetupUiAction.OnBackspaceClick) - } - ) { - Text( - text = "Delete", - modifier = Modifier.padding(8.dp), - style = TextStyle( - fontSize = 16.sp, - fontWeight = FontWeight.Bold - ), - ) - } - - - } + Spacer(modifier = Modifier.height(64.dp)) + + +// Row( +// modifier = Modifier.fillMaxWidth(), +// horizontalArrangement = Arrangement.SpaceAround +// ) { +// TextButton( +// onClick = { +// onAction(PasscodeSetupUiAction.OnCancel) +// } +// ) { +// Text( +// text = "Cancel", +// modifier = Modifier.padding(8.dp), +// style = TextStyle( +// fontSize = 16.sp, +// fontWeight = FontWeight.Bold, +// ), +// ) +// } +// +// TextButton( +// enabled = state.passcode.isNotEmpty(), +// onClick = { +// onAction(PasscodeSetupUiAction.OnBackspaceClick) +// } +// ) { +// Text( +// text = "Delete", +// modifier = Modifier.padding(8.dp), +// style = TextStyle( +// fontSize = 16.sp, +// fontWeight = FontWeight.Bold +// ), +// ) +// } +// +// +// } } } } @@ -207,7 +211,7 @@ private fun PasscodeSetupScreenContent( @Preview @Composable private fun PasscodeSetupScreenPreview() { - Theme { + DefaultScaffoldPreview { PasscodeSetupScreenContent( state = PasscodeSetupUiState( passcodeLength = 6 diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupViewModel.kt index 01d3e7a8..1af8b2ae 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupViewModel.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/features/settings/passcode/passcode_setup/PasscodeSetupViewModel.kt @@ -30,6 +30,7 @@ class PasscodeSetupViewModel( is PasscodeSetupUiAction.OnNumberClick -> onNumberClick(action.number) PasscodeSetupUiAction.OnBackspaceClick -> onBackspaceClick() PasscodeSetupUiAction.OnCancel -> onCancel() + PasscodeSetupUiAction.OnSubmit -> onSubmit() } } @@ -56,11 +57,11 @@ class PasscodeSetupViewModel( else state.copy(passcode = state.passcode + number) } - // Process passcode only when the required length is reached - if (_uiState.value.passcode.length == config.passcodeLength) { - _uiState.update { it.copy(isProcessing = true) } - processPasscodeEntry() - } +// // Process passcode only when the required length is reached +// if (_uiState.value.passcode.length == config.passcodeLength) { +// _uiState.update { it.copy(isProcessing = true) } +// processPasscodeEntry() +// } } private fun onBackspaceClick() { @@ -75,6 +76,16 @@ class PasscodeSetupViewModel( } } + private fun onSubmit() { + val state = _uiState.value + + // Ensure passcode length is correct before submission + if (state.passcode.length == config.passcodeLength) { + _uiState.update { it.copy(isProcessing = true) } + processPasscodeEntry() + } + } + private fun processPasscodeEntry() = viewModelScope.launch { val state = uiState.value // current state if (state.isConfirming) { @@ -138,6 +149,7 @@ sealed class PasscodeSetupUiAction { data class OnNumberClick(val number: String) : PasscodeSetupUiAction() data object OnBackspaceClick : PasscodeSetupUiAction() data object OnCancel : PasscodeSetupUiAction() + data object OnSubmit: PasscodeSetupUiAction() } sealed class PasscodeSetupUiEvent { diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/spaces/ServerOptionItem.kt b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/ServerOptionItem.kt new file mode 100644 index 00000000..d39582f0 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/ServerOptionItem.kt @@ -0,0 +1,162 @@ +package net.opendasharchive.openarchive.features.spaces + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowForward +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.DefaultBoxPreview + +@Composable +fun ServerOptionItem( + @DrawableRes iconRes: Int, + title: String, + subtitle: String, + onClick: () -> Unit +) { + // You can customize this look to match your original design + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + .clickable(onClick = onClick), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.background + ), + border = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.onBackground), + shape = RoundedCornerShape(8.dp) + ) { + + Row( + modifier = Modifier + .fillMaxWidth() + .height(100.dp) + .padding(16.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .align(Alignment.Top) + .padding(top = 4.dp) + ) { + Icon( + painter = painterResource(id = iconRes), + contentDescription = null, + tint = colorResource(R.color.colorTertiary), + modifier = Modifier + .size(24.dp) + + ) + } + + Spacer(modifier = Modifier.width(16.dp)) + + Column( + modifier = Modifier + .align(Alignment.Top) + .weight(1f), + verticalArrangement = Arrangement.Top + ) { + Text( + text = title, + fontWeight = FontWeight.SemiBold, + fontSize = 18.sp + ) + + Text( + text = subtitle, + fontWeight = FontWeight.Normal, + fontSize = 14.sp + ) + } + + Icon( + modifier = Modifier + .size(24.dp) + .align(Alignment.CenterVertically), + painter = painterResource(R.drawable.ic_arrow_forward_ios), + contentDescription = null, + ) + } + + + } +} + +@Preview +@Composable +private fun ServerOptionItemPreview() { + DefaultBoxPreview { + + Column { + ServerOptionItem( + iconRes = R.drawable.ic_private_server, + title = stringResource(R.string.private_server), + subtitle = stringResource(R.string.send_directly_to_a_private_server), + onClick = {} + ) + } + + + } +} + +@Preview +@Composable +private fun ServerOptionsItemPreview() { + DefaultBoxPreview { + + Column { + ServerOptionItem( + iconRes = R.drawable.ic_private_server, + title = stringResource(R.string.private_server), + subtitle = stringResource(R.string.send_directly_to_a_private_server), + onClick = {} + ) + + ServerOptionItem( + iconRes = R.drawable.ic_internet_archive, + title = stringResource(R.string.internet_archive), + subtitle = stringResource(R.string.upload_to_the_internet_archive), + onClick = {} + ) + + ServerOptionItem( + iconRes = R.drawable.ic_dweb, + title = stringResource(R.string.dweb_title), + subtitle = stringResource(R.string.dweb_description), + onClick = {} + ) + } + + + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceListFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceListFragment.kt new file mode 100644 index 00000000..37b7d576 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceListFragment.kt @@ -0,0 +1,85 @@ +package net.opendasharchive.openarchive.features.spaces + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.compose.content +import androidx.navigation.fragment.findNavController +import net.opendasharchive.openarchive.core.presentation.theme.SaveAppTheme +import net.opendasharchive.openarchive.databinding.FragmentSpaceListBinding +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.internetarchive.presentation.InternetArchiveActivity +import net.opendasharchive.openarchive.services.gdrive.GDriveActivity +import net.opendasharchive.openarchive.services.webdav.WebDavActivity + +class SpaceListFragment : BaseFragment() { + + private lateinit var binding: FragmentSpaceListBinding + + companion object { + const val EXTRA_DATA_SPACE = "space_id" + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + + binding = FragmentSpaceListBinding.inflate(inflater) + + + binding.composeViewSpaceList.setContent { + + SaveAppTheme { + + SpaceListScreen( + onSpaceClicked = { space -> + startSpaceAuthActivity(space.id) + }, + ) + } + + } + + return binding.root + } + + override fun getToolbarTitle() = "Media Servers" + + private fun startSpaceAuthActivity(spaceId: Long?) { + val space = Space.get(spaceId ?: return) ?: return + + when (space.tType) { + Space.Type.INTERNET_ARCHIVE -> { + val intent = Intent(requireContext(), InternetArchiveActivity::class.java) + intent.putExtra(EXTRA_DATA_SPACE, space.id) + startActivity(intent) + } + + Space.Type.GDRIVE -> { + val intent = Intent(requireContext(), GDriveActivity::class.java) + intent.putExtra(EXTRA_DATA_SPACE, space.id) + startActivity(intent) + } + + Space.Type.WEBDAV -> { + val action = + SpaceListFragmentDirections.actionFragmentSpaceListToFragmentWebDav(spaceId) + findNavController().navigate(action) + } + + else -> { + val intent = Intent(requireContext(), WebDavActivity::class.java) + intent.putExtra(EXTRA_DATA_SPACE, space.id) + startActivity(intent) + } + } + + + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceListScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceListScreen.kt new file mode 100644 index 00000000..cdf651d3 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceListScreen.kt @@ -0,0 +1,127 @@ +package net.opendasharchive.openarchive.features.spaces + +import android.content.res.Configuration +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview +import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.main.ui.components.SpaceIcon +import net.opendasharchive.openarchive.features.main.ui.components.dummySpaceList + +@Composable +fun SpaceListScreen( + onSpaceClicked: (Space) -> Unit, + + ) { + + Box( + modifier = Modifier + .fillMaxSize() + ) { + + SpaceListScreenContent( + spaceList = Space.getAll().asSequence().toList(), + onSpaceClicked = onSpaceClicked + ) + } + +} + +@Composable +fun SpaceListScreenContent( + onSpaceClicked: (Space) -> Unit, + spaceList: List = emptyList() +) { + + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + + spaceList.forEach { space -> + + SpaceListItem( + space = space, + onClick = { + onSpaceClicked(space) + } + ) + } + } +} + +@Composable +fun SpaceListItem( + space: Space, + onClick: () -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + onClick() + }, + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + SpaceIcon( + type = space.tType, + modifier = Modifier.size(42.dp) + ) + + Column( + verticalArrangement = Arrangement.Top + ) { + Text( + text = space.friendlyName, + color = MaterialTheme.colorScheme.onBackground, + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold, + lineHeight = 1.sp + ) + + Text( + text = space.tType.friendlyName, + color = MaterialTheme.colorScheme.onBackground, + fontSize = 14.sp, + lineHeight = 1.sp + ) + } + } +} + +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun SpaceListScreenPreview() { + + DefaultScaffoldPreview { + + SpaceListScreenContent( + spaceList = dummySpaceList, + onSpaceClicked = { + + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceSetupScreen.kt b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceSetupScreen.kt new file mode 100644 index 00000000..af8fabe9 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/features/spaces/SpaceSetupScreen.kt @@ -0,0 +1,111 @@ +package net.opendasharchive.openarchive.features.spaces + +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.presentation.theme.DefaultScaffoldPreview + +@Composable +fun SpaceSetupScreen( + onWebDavClick: () -> Unit, + isInternetArchiveAllowed: Boolean, + onInternetArchiveClick: () -> Unit, + isDwebEnabled: Boolean, + onDwebClicked: () -> Unit +) { + // Use a scrollable Column to mimic ScrollView + LinearLayout + Column( + modifier = Modifier + .fillMaxSize() + .padding(8.dp) + ) { + Spacer(modifier = Modifier.height(48.dp)) + // Header texts + Column( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.to_get_started_connect_to_a_server_to_store_your_media), + fontSize = 18.sp, + color = MaterialTheme.colorScheme.onBackground, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(12.dp)) + + val description = if (isDwebEnabled) stringResource(R.string.to_get_started_more_hint_dweb) else stringResource(R.string.to_get_started_more_hint) + Text( + text = description, + color = MaterialTheme.colorScheme.onBackground, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + textAlign = TextAlign.Center + ) + } + + Spacer(modifier = Modifier.height(24.dp)) + + // WebDav option + ServerOptionItem( + iconRes = R.drawable.ic_private_server, + title = stringResource(R.string.private_server), + subtitle = stringResource(R.string.send_directly_to_a_private_server), + onClick = onWebDavClick + ) + + + // Internet Archive option (conditionally visible) + if (isInternetArchiveAllowed) { + ServerOptionItem( + iconRes = R.drawable.ic_internet_archive, + title = stringResource(R.string.internet_archive), + subtitle = stringResource(R.string.upload_to_the_internet_archive), + onClick = onInternetArchiveClick + ) + } + + // Snowbird (Raven) option (conditionally visible) + if (isDwebEnabled) { + ServerOptionItem( + iconRes = R.drawable.ic_dweb, + title = stringResource(R.string.dweb_title), + subtitle = stringResource(R.string.dweb_description), + onClick = onDwebClicked + ) + } + } +} + +@Preview +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun SpaceSetupScreenPreview() { + DefaultScaffoldPreview { + SpaceSetupScreen( + onWebDavClick = {}, + isInternetArchiveAllowed = true, + onInternetArchiveClick = {}, + isDwebEnabled = true, + onDwebClicked = {}, + ) + } +} diff --git a/app/src/main/java/net/opendasharchive/openarchive/fragments/VideoRequestHandler.kt b/app/src/main/java/net/opendasharchive/openarchive/fragments/VideoRequestHandler.kt index 566a8f6e..b345c02d 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/fragments/VideoRequestHandler.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/fragments/VideoRequestHandler.kt @@ -1,16 +1,15 @@ package net.opendasharchive.openarchive.fragments import android.content.Context -import kotlin.Throws import android.graphics.Bitmap import com.squareup.picasso.Picasso import android.media.MediaMetadataRetriever import android.net.Uri import com.squareup.picasso.Request import com.squareup.picasso.RequestHandler -import timber.log.Timber import java.io.IOException import java.lang.Exception +import androidx.core.net.toUri class VideoRequestHandler(private val mContext: Context) : RequestHandler() { override fun canHandleRequest(data: Request): Boolean { @@ -22,10 +21,10 @@ class VideoRequestHandler(private val mContext: Context) : RequestHandler() { override fun load(data: Request, arg1: Int): Result? { val bm: Bitmap? try { - bm = retrieveVideoFrameFromVideo(mContext, Uri.parse(data.uri.toString().substring(6))) + bm = retrieveVideoFrameFromVideo(mContext, data.uri.toString().substring(6).toUri()) if (bm != null) return Result(bm, Picasso.LoadedFrom.DISK) } catch (throwable: Throwable) { - Timber.e("VideoRequestHandler load() failed", throwable) + throwable.printStackTrace() } return null } diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/Conduit.kt b/app/src/main/java/net/opendasharchive/openarchive/services/Conduit.kt index a4b50fd0..d90ba5a3 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/Conduit.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/Conduit.kt @@ -70,8 +70,7 @@ abstract class Conduit( hash = ProofMode.generateProof(mContext, mMedia.fileUri, proofHash) } - - return ProofMode.getProofDir(mContext, hash).listFiles() ?: emptyArray() + return ProofMode.getProofDir(mContext, mMedia.mediaHashString).listFiles() ?: emptyArray() } catch (exception: FileNotFoundException) { AppLogger.e(exception) diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveActivity.kt index e8195e35..592cda97 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveActivity.kt @@ -30,9 +30,7 @@ class GDriveActivity : BaseActivity() { if (space != null) removeSpace(space) } - setSupportActionBar(mBinding.toolbar) - supportActionBar?.title = getString(R.string.gdrive) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar(getString(R.string.gdrive)) mBinding.gdriveId.setText(space?.displayname ?: "") } diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveConduit.kt b/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveConduit.kt index 2420e134..a28d025f 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveConduit.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveConduit.kt @@ -20,7 +20,7 @@ import com.google.api.services.drive.model.File import info.guardianproject.netcipher.proxy.OrbotHelper import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.db.Media -import net.opendasharchive.openarchive.features.folders.BrowseFoldersViewModel +import net.opendasharchive.openarchive.features.folders.Folder import net.opendasharchive.openarchive.services.Conduit import net.opendasharchive.openarchive.util.Prefs import org.apache.http.conn.ClientConnectionManager @@ -174,8 +174,8 @@ class GDriveConduit(media: Media, context: Context) : Conduit(media, context) { return parentFolder } - fun listFoldersInRoot(gdrive: Drive): List { - val result = ArrayList() + fun listFoldersInRoot(gdrive: Drive): List { + val result = ArrayList() try { var pageToken: String? = null do { @@ -185,7 +185,7 @@ class GDriveConduit(media: Media, context: Context) : Conduit(media, context) { .setFields("nextPageToken, files(id, name, createdTime)").execute() for (f in folders.files) { val date = Date(f.createdTime.value) - result.add(BrowseFoldersViewModel.Folder(f.name, date)) + result.add(Folder(f.name, date)) } pageToken = folders.nextPageToken } while (pageToken != null) diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveFragment.kt index 4598d2fe..4daff4b4 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/gdrive/GDriveFragment.kt @@ -9,20 +9,20 @@ import android.view.View import android.view.ViewGroup import androidx.core.os.bundleOf import androidx.core.text.HtmlCompat -import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResult +import androidx.navigation.fragment.findNavController import com.google.android.gms.auth.api.Auth import com.google.android.gms.auth.api.signin.GoogleSignIn import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch -import net.opendasharchive.openarchive.CleanInsightsManager import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.FragmentGdriveBinding import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.BaseFragment -class GDriveFragment : Fragment() { +class GDriveFragment : BaseFragment() { private lateinit var mBinding: FragmentGdriveBinding @@ -57,7 +57,11 @@ class GDriveFragment : Fragment() { mBinding.error.visibility = View.GONE mBinding.btBack.setOnClickListener { - setFragmentResult(RESP_CANCEL, bundleOf()) + if(isJetpackNavigation) { + findNavController().popBackStack() + } else { + setFragmentResult(RESP_CANCEL, bundleOf()) + } } mBinding.btAuthenticate.setOnClickListener { @@ -80,7 +84,13 @@ class GDriveFragment : Fragment() { ) } else { // permission was already granted, we're already signed in, continue. - setFragmentResult(RESP_AUTHENTICATED, bundleOf()) + if (isJetpackNavigation) { + val message = getString(R.string.you_have_successfully_connected_to_gdrive) + val action = GDriveFragmentDirections.actionFragmentGdriveToFragmentSpaceSetupSuccess(message) + findNavController().navigate(action) + } else { + setFragmentResult(RESP_AUTHENTICATED, bundleOf()) + } } } @@ -150,4 +160,6 @@ class GDriveFragment : Fragment() { mBinding.btAuthenticate.isEnabled = true } } + + override fun getToolbarTitle() = "Google Drive" } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/internetarchive/IaConduit.kt b/app/src/main/java/net/opendasharchive/openarchive/services/internetarchive/IaConduit.kt index 6c7ddda2..dee47500 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/internetarchive/IaConduit.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/internetarchive/IaConduit.kt @@ -43,7 +43,7 @@ class IaConduit(media: Media, context: Context) : Conduit(media, context) { val fileName = getUploadFileName(mMedia, true) val metaJson = gson.toJson(mMedia) -// val proof = getProof() + val proof = getProof() if (mMedia.serverUrl.isBlank()) { // TODO this should make sure we aren't accidentally using one of archive.org's metadata fields by accident @@ -59,10 +59,10 @@ class IaConduit(media: Media, context: Context) : Conduit(media, context) { // upload metadata and proofs async, and report failures client.uploadMetaData(metaJson, fileName) - /// Upload ProofMode metadata, if enabled and successfully created. -// for (file in proof) { -// client.uploadProofFiles(file) -// } + // Upload ProofMode metadata, if enabled and successfully created. + for (file in proof) { + client.uploadProofFiles(file) + } jobSucceeded() diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdBridge.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdBridge.kt new file mode 100644 index 00000000..c495398e --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdBridge.kt @@ -0,0 +1,38 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.content.Context +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class SnowbirdBridge { + private val _status = MutableStateFlow(SnowbirdServiceStatus.BackendInitializing) + val status = _status.asStateFlow() + + fun initialize() { + initializeRustService() + } + + init { + System.loadLibrary("save") + } + + companion object { + @Volatile + private var instance: SnowbirdBridge? = null + + fun getInstance(): SnowbirdBridge { + return instance ?: synchronized(this) { + instance ?: SnowbirdBridge().also { instance = it } + } + } + + @JvmStatic + fun updateStatusFromRust(code: Int, message: String) { + instance?._status?.value = SnowbirdServiceStatus.fromCode(code) + } + } + + private external fun initializeRustService() + external fun startServer(context: Context, baseDirectory: String, socketPath: String): String + external fun stopServer() +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdConduit.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdConduit.kt new file mode 100644 index 00000000..d0a3f7b4 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdConduit.kt @@ -0,0 +1,17 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.content.Context +import net.opendasharchive.openarchive.db.Media +import net.opendasharchive.openarchive.services.Conduit +import timber.log.Timber + +class SnowbirdConduit (media: Media, context: Context) : Conduit(media, context) { + override suspend fun upload(): Boolean { + Timber.d("upload") + return true + } + + override suspend fun createFolder(url: String) { + Timber.d("createFolder") + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdCreateGroupFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdCreateGroupFragment.kt new file mode 100644 index 00000000..83a642da --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdCreateGroupFragment.kt @@ -0,0 +1,168 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.findNavController +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdCreateGroupBinding +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.util.FullScreenOverlayCreateGroupManager +import timber.log.Timber + +class SnowbirdCreateGroupFragment: BaseFragment() { + + private lateinit var viewBinding: FragmentSnowbirdCreateGroupBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + viewBinding = FragmentSnowbirdCreateGroupBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding.createGroupButton.setOnClickListener { + snowbirdGroupViewModel.createGroup(viewBinding.groupNameTextfield.text.toString()) + dismissKeyboard(it) + } + + initializeViewModelObservers() + } + + private fun initializeViewModelObservers() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + snowbirdGroupViewModel.groupState.collect { state -> + handleGroupStateUpdate( + state + ) + } + } + launch { + snowbirdRepoViewModel.repoState.collect { state -> + handleRepoStateUpdate( + state + ) + } + } + } + } + } + + private fun handleGroupStateUpdate(state: SnowbirdGroupViewModel.GroupState) { + Timber.d("group state = $state") + when (state) { + is SnowbirdGroupViewModel.GroupState.Loading -> handleCreateGroupLoadingStatus(true) + is SnowbirdGroupViewModel.GroupState.SingleGroupSuccess -> handleGroupCreated(state.group) + is SnowbirdGroupViewModel.GroupState.Error -> handleError(state.error) + else -> Unit + } + } + + private fun handleCreateGroupLoadingStatus(isLoading: Boolean) { + if (isLoading) { + FullScreenOverlayCreateGroupManager.show(this@SnowbirdCreateGroupFragment) + } else { + FullScreenOverlayCreateGroupManager.hide() + } + } + + + private fun handleRepoStateUpdate(state: SnowbirdRepoViewModel.RepoState) { + Timber.d("repo state = $state") + when (state) { + is SnowbirdRepoViewModel.RepoState.Loading -> handleCreateGroupLoadingStatus(true) + is SnowbirdRepoViewModel.RepoState.SingleRepoSuccess -> handleRepoCreated(state.repo) + is SnowbirdRepoViewModel.RepoState.Error -> handleError(state.error) + else -> Unit + } + } + + override fun handleError(error: SnowbirdError) { + handleCreateGroupLoadingStatus(false) + super.handleError(error) + } + + private fun handleGroupCreated(group: SnowbirdGroup?) { + group?.let { + snowbirdGroupViewModel.setCurrentGroup(group) + + lifecycleScope.launch { + group.save() + snowbirdRepoViewModel.createRepo( + group.key, viewBinding.repoNameTextfield.text.toString() + ) + } + } + } + + private fun handleRepoCreated(repo: SnowbirdRepo?) { + handleCreateGroupLoadingStatus(false) + repo?.let { + repo.groupKey = snowbirdGroupViewModel.currentGroup.value!!.key + repo.permissions = "READ_WRITE" + repo.save() + showConfirmation(repo) + } + } + + private fun showConfirmation(repo: SnowbirdRepo?) { + val group = SnowbirdGroup.get(repo!!.groupKey)!! + + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Success + title = UiText.DynamicString("Raven Group Created") + message = UiText.DynamicString("Would you like to share your new group with a QR code?") + positiveButton { + text = UiText.DynamicString("Yes") + action = { + val action = + SnowbirdCreateGroupFragmentDirections.actionFragmentSnowbirdCreateGroupToFragmentSnowbirdShareGroup(group.key) + findNavController().navigate(action) + } + } + neutralButton { + text = UiText.DynamicString("No") + action = { + parentFragmentManager.popBackStack() + } + } + } + } + + override fun getToolbarTitle(): String { + return "Create Raven Group" + } + + companion object { + + const val RESULT_REQUEST_KEY = "create_group_result" + + const val RESULT_NAVIGATION_KEY = "create_group_navigation" + + const val RESULT_NAVIGATION_VAL_SHARE_SCREEN = "share_screen" + + const val RESULT_BUNDLE_GROUP_KEY = "raven_create_group_fragment_bundle_group_id" + + @JvmStatic + fun newInstance() = SnowbirdCreateGroupFragment() + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileListAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileListAdapter.kt new file mode 100644 index 00000000..b669b2ab --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileListAdapter.kt @@ -0,0 +1,69 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Build +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.RequiresExtension +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.OneLineRowBinding +import net.opendasharchive.openarchive.db.SnowbirdFileItem +import net.opendasharchive.openarchive.extensions.scaled +import java.lang.ref.WeakReference + +class SnowbirdFileViewHolder(val binding: OneLineRowBinding) : RecyclerView.ViewHolder(binding.root) + +class SnowbirdFileListAdapter( + onClickListener: ((SnowbirdFileItem) -> Unit)? = null, + onLongPressListener: ((SnowbirdFileItem) -> Unit)? = null +) : ListAdapter(SnowbirdFileDiffCallback()) { + + private val onClickCallback = WeakReference(onClickListener) + private val onLongPressCallback = WeakReference(onLongPressListener) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SnowbirdFileViewHolder { + val binding = OneLineRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return SnowbirdFileViewHolder(binding) + } + + @RequiresExtension(extension = Build.VERSION_CODES.S, version = 7) + override fun onBindViewHolder(holder: SnowbirdFileViewHolder, position: Int) { + val item = getItem(position) + + with (holder.binding) { + val context = button.context + + button.setLeftIcon(ContextCompat.getDrawable(context, R.drawable.snowbird)?.scaled(40, context)) + //button.setBackgroundResource(R.drawable.button_outlined_ripple) + button.setTitle(item.name ?: "No name provided") + + if (item.isDownloaded) { + button.setRightIcon(ContextCompat.getDrawable(context, R.drawable.outline_cloud_done_24)?.scaled(40, context)) + } else { + button.setRightIcon(ContextCompat.getDrawable(context, R.drawable.outline_cloud_download_24)?.scaled(40, context)) + } + + button.setOnClickListener { + onClickCallback.get()?.invoke(item) + } + + button.setOnLongClickListener { + onLongPressCallback.get()?.invoke(item) + true + } + } + } +} + +class SnowbirdFileDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SnowbirdFileItem, newItem: SnowbirdFileItem): Boolean { + return oldItem.hash == newItem.hash + } + + override fun areContentsTheSame(oldItem: SnowbirdFileItem, newItem: SnowbirdFileItem): Boolean { + return oldItem == newItem + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileListFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileListFragment.kt new file mode 100644 index 00000000..e769d0b1 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileListFragment.kt @@ -0,0 +1,264 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdListMediaBinding +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdFileItem +import net.opendasharchive.openarchive.extensions.androidViewModel +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.util.SpacingItemDecoration +import timber.log.Timber + +class SnowbirdFileListFragment : BaseFragment() { + + private val snowbirdFileViewModel: SnowbirdFileViewModel by androidViewModel() + private lateinit var viewBinding: FragmentSnowbirdListMediaBinding + private lateinit var adapter: SnowbirdFileListAdapter + private lateinit var groupKey: String + private lateinit var repoKey: String + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + arguments?.let { + groupKey = it.getString(RESULT_VAL_RAVEN_GROUP_KEY, "") + repoKey = it.getString(RESULT_VAL_RAVEN_REPO_KEY, "") + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + viewBinding = FragmentSnowbirdListMediaBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupMenu() + setupRecyclerView() + setupSwipeRefresh() + initializeViewModelObservers() + } + + private fun setupMenu() { + requireActivity().addMenuProvider(object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_snowbird, menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.action_add -> { + Timber.d("Adde!") + openFilePicker() + true + } + else -> false + } + } + }, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + + private val getMultipleContentsLauncher = registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { uris: List -> + handleSelectedFiles(uris) + } + + private fun handleAudio(uri: Uri) { + handleMedia(uri) + } + + private fun handleImage(uri: Uri) { + handleMedia(uri) + } + + private fun handleVideo(uri: Uri) { + handleMedia(uri) + } + + private fun handleMedia(uri: Uri) { + Timber.d("Going to upload file") + snowbirdFileViewModel.uploadFile(groupKey, repoKey, uri) + } + + private fun handleSelectedFiles(uris: List) { + if (uris.isNotEmpty()) { + for (uri in uris) { + val mimeType = requireContext().contentResolver.getType(uri) + when { + mimeType?.startsWith("image/") == true -> handleImage(uri) + mimeType?.startsWith("video/") == true -> handleVideo(uri) + mimeType?.startsWith("audio/") == true -> handleAudio(uri) + else -> { + Timber.d("Unknown type picked: $mimeType") + } + } + } + } else { + Timber.d("No images selected") + } + } + + private fun openFilePicker() { + getMultipleContentsLauncher.launch("*/*") + } + + private fun setupRecyclerView() { + adapter = SnowbirdFileListAdapter( + onClickListener = { onClick(it) } + ) + + val spacingInPixels = resources.getDimensionPixelSize(R.dimen.list_item_spacing) + viewBinding.snowbirdMediaRecyclerView.addItemDecoration(SpacingItemDecoration(spacingInPixels)) + + viewBinding.snowbirdMediaRecyclerView.setEmptyView(R.layout.view_empty_state) + // viewBinding.snowbirdMediaRecyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) + viewBinding.snowbirdMediaRecyclerView.layoutManager = LinearLayoutManager(requireContext()) + viewBinding.snowbirdMediaRecyclerView.adapter = adapter + } + + private fun onClick(item: SnowbirdFileItem) { +// if (!item.isDownloaded) { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Warning + title = UiText.DynamicString("Download Media?") + message = UiText.DynamicString("Are you sure you want to download this media?") + positiveButton { + text = UiText.DynamicString("Yes") + action = { + snowbirdFileViewModel.downloadFile(groupKey, repoKey, item.name) + } + } + neutralButton { + text = UiText.DynamicString("No") + } + } +// } + } + + private fun handleMediaStateUpdate(state: SnowbirdFileViewModel.State) { + Timber.d("state = $state") + when (state) { + is SnowbirdFileViewModel.State.Idle -> { /* Initial state */ } + is SnowbirdFileViewModel.State.Loading -> onLoading() + is SnowbirdFileViewModel.State.FetchSuccess -> onFilesFetched(state.files, state.isRefresh) + is SnowbirdFileViewModel.State.UploadSuccess -> onFileUploaded(state.result) + is SnowbirdFileViewModel.State.DownloadSuccess -> onFileDownloaded(state.uri) + is SnowbirdFileViewModel.State.Error -> handleError(state.error) + } + } + + override fun handleError(error: SnowbirdError) { + handleLoadingStatus(false) + viewBinding.swipeRefreshLayout.isRefreshing = false + super.handleError(error) + } + + private fun onLoading() { + handleLoadingStatus(true) + viewBinding.swipeRefreshLayout.isRefreshing = false + } + + private fun onFilesFetched(files: List, isRefresh: Boolean) { + handleLoadingStatus(false) + + if (isRefresh) { + Timber.d("Clearing SnowbirdFileItems") + SnowbirdFileItem.clear() + } + + saveFiles(files) + + adapter.submitList(files) + } + + private fun onFileDownloaded(uri: Uri) { + handleLoadingStatus(false) + Timber.d("File successfully downloaded: $uri") + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Success + title = UiText.StringResource(R.string.label_success_title) + message = UiText.DynamicString("File successfully downloaded") + positiveButton { + text = UiText.StringResource(R.string.label_got_it) + } + } + } + + private fun onFileUploaded(result: FileUploadResult) { + handleLoadingStatus(false) + Timber.d("File successfully uploaded: $result") + SnowbirdFileItem( + name = result.name, + hash = result.updatedCollectionHash, + groupKey = groupKey, + repoKey = repoKey, + isDownloaded = true + ).save() + snowbirdFileViewModel.fetchFiles(groupKey, repoKey, forceRefresh = false) + } + + private fun saveFiles(files: List) { + files.forEach { file -> + file.saveWith(groupKey, repoKey) + } + } + + private fun initializeViewModelObservers() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { snowbirdFileViewModel.mediaState.collect { state -> handleMediaStateUpdate(state) } } + launch { snowbirdFileViewModel.fetchFiles(groupKey, repoKey, forceRefresh = false) } + } + } + } + + private fun setupSwipeRefresh() { + viewBinding.swipeRefreshLayout.setOnRefreshListener { + lifecycleScope.launch { + snowbirdFileViewModel.fetchFiles(groupKey, repoKey, forceRefresh = true) + } + } + + viewBinding.swipeRefreshLayout.setColorSchemeResources( + R.color.colorPrimary, R.color.colorPrimaryDark + ) + } + + override fun getToolbarTitle(): String { + return "My Files" + } + + companion object { + const val RESULT_VAL_RAVEN_GROUP_KEY = "dweb_group_key" + const val RESULT_VAL_RAVEN_REPO_KEY = "dweb_repo_key" + + @JvmStatic + fun newInstance(groupKey: String, repoKey: String) = + SnowbirdFileListFragment().apply { + arguments = Bundle().apply { + putString(RESULT_VAL_RAVEN_GROUP_KEY, groupKey) + putString(RESULT_VAL_RAVEN_REPO_KEY, repoKey) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileRepository.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileRepository.kt new file mode 100644 index 00000000..8ef620d4 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileRepository.kt @@ -0,0 +1,56 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.net.Uri +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.SnowbirdFileItem +import net.opendasharchive.openarchive.extensions.toSnowbirdError +import net.opendasharchive.openarchive.services.snowbird.service.ISnowbirdAPI + +interface ISnowbirdFileRepository { + suspend fun fetchFiles(groupKey: String, repoKey: String, forceRefresh: Boolean = false): SnowbirdResult> + suspend fun downloadFile(groupKey: String, repoKey: String, filename: String): SnowbirdResult + suspend fun uploadFile(groupKey: String, repoKey: String, uri: Uri): SnowbirdResult +} + +class SnowbirdFileRepository(val api: ISnowbirdAPI) : ISnowbirdFileRepository { + override suspend fun fetchFiles(groupKey: String, repoKey: String, forceRefresh: Boolean): SnowbirdResult> { + return if (forceRefresh) { + fetchFilesFromNetwork(groupKey, repoKey) + } else { + fetchFilesFromCache(groupKey, repoKey) + } + } + + private fun fetchFilesFromCache(groupKey: String, repoKey: String): SnowbirdResult> { + return SnowbirdResult.Success(SnowbirdFileItem.findBy(groupKey, repoKey)) + } + + private suspend fun fetchFilesFromNetwork(groupKey: String, repoKey: String): SnowbirdResult> { + return try { + val response = api.fetchFiles(groupKey, repoKey) + SnowbirdResult.Success(response.files) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + override suspend fun downloadFile(groupKey: String, repoKey: String, filename: String): SnowbirdResult { + return try { + val response = api.downloadFile(groupKey, repoKey, filename) + SnowbirdResult.Success(response) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + override suspend fun uploadFile(groupKey: String, repoKey: String, uri: Uri): SnowbirdResult { + return try { + val response = api.uploadFile(groupKey, repoKey, uri) + SnowbirdResult.Success(response) + } catch (e: Exception) { + e.printStackTrace() + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileViewModel.kt new file mode 100644 index 00000000..434e7d5c --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFileViewModel.kt @@ -0,0 +1,122 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.app.Application +import android.content.Context +import android.net.Uri +import androidx.core.content.FileProvider +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdFileItem +import net.opendasharchive.openarchive.util.BaseViewModel +import net.opendasharchive.openarchive.util.trackProcessingWithTimeout +import timber.log.Timber +import java.io.File + +class SnowbirdFileViewModel( + private val application: Application, + private val repository: ISnowbirdFileRepository +) : BaseViewModel(application) { + + sealed class State { + data object Idle : State() + data object Loading : State() + data class DownloadSuccess(val uri: Uri) : State() + data class FetchSuccess(val files: List, var isRefresh: Boolean) : State() + data class UploadSuccess(val result: FileUploadResult) : State() + data class Error(val error: SnowbirdError) : State() + } + + private val _mediaState = MutableStateFlow(State.Idle) + val mediaState: StateFlow = _mediaState.asStateFlow() + + fun downloadFile(groupKey: String, repoKey: String, filename: String) { + viewModelScope.launch { + _mediaState.value = State.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(30_000, "download_file") { + repository.downloadFile(groupKey, repoKey, filename) + } + + _mediaState.value = when (result) { + is SnowbirdResult.Success -> onDownload(result.value, filename) + is SnowbirdResult.Error -> State.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _mediaState.value = State.Error(SnowbirdError.TimedOut) + } + } + } + + fun fetchFiles(groupKey: String, repoKey: String, forceRefresh: Boolean = false) { + viewModelScope.launch { + _mediaState.value = State.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(60_000, "fetch_files") { + repository.fetchFiles(groupKey, repoKey, forceRefresh) + } + + _mediaState.value = when (result) { + is SnowbirdResult.Success -> State.FetchSuccess(result.value, forceRefresh) + is SnowbirdResult.Error -> State.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _mediaState.value = State.Error(SnowbirdError.TimedOut) + } + } + } + + // Example reponse: + // { + // "updated_collection_hash": "7dkgeko3oeyyr5xympsg2mhbicb2k2ba4wqen6lpt6qs7mgza7vq" + // } + // + fun uploadFile(groupKey: String, repoKey: String, uri: Uri) { + viewModelScope.launch { + _mediaState.value = State.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(30_000, "upload_file") { + repository.uploadFile(groupKey, repoKey, uri) + } + + _mediaState.value = when (result) { + is SnowbirdResult.Success -> State.UploadSuccess(result.value) + is SnowbirdResult.Error -> State.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _mediaState.value = State.Error(SnowbirdError.TimedOut) + } + } + } + + private suspend fun onDownload(bytes: ByteArray, filename: String): State { + Timber.d("Downloaded ${bytes.size} bytes") + return saveByteArrayToFile(application.applicationContext, bytes, filename).fold( + onSuccess = { uri -> State.DownloadSuccess(uri) }, + onFailure = { error -> State.Error(SnowbirdError.GeneralError("Error saving file: ${error.message}")) } + ) + } + + private suspend fun saveByteArrayToFile(context: Context, byteArray: ByteArray, filename: String): Result = + withContext(Dispatchers.IO) { + runCatching { + val directory = File(context.filesDir, "files").apply { mkdirs() } + val file = File(directory, filename) + + file.outputStream().use { it.write(byteArray) } + + FileProvider.getUriForFile( + context, + "${context.packageName}.fileprovider", + file + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFragment.kt new file mode 100644 index 00000000..eba031d5 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdFragment.kt @@ -0,0 +1,189 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.os.bundleOf +import androidx.fragment.app.setFragmentResult +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.findNavController +//import com.google.zxing.integration.android.IntentIntegrator +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdBinding +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.extensions.getQueryParameter +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +//import net.opendasharchive.openarchive.features.main.QRScannerActivity +import timber.log.Timber + +class SnowbirdFragment : BaseFragment() { + private val CANNED_URI = + "save+dweb::?dht=82fd345d484393a96b6e0c5d5e17a85a61c9184cc5a3311ab069d6efa0bf1410&enc=6fa27396fe298f92c91013ac54d8f316c2d45dc3bed0edec73078040aa10feed&pk=f4b404d294817cf11ea7f8ef7231626e03b74f6fafe3271b53918608afa82d12&sk=5482a8f490081be684fbadb8bde7f0a99bab8acdcf1ec094826f0f18e327e399" + private lateinit var viewBinding: FragmentSnowbirdBinding + private var canNavigate = false + + private val qrCodeLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> +// val scanResult = IntentIntegrator.parseActivityResult(result.resultCode, result.data) +// if (scanResult != null) { +// if (scanResult.contents != null) { +// processScannedData(scanResult.contents) +// } +// } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + viewBinding = FragmentSnowbirdBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding.joinGroupButton.setOnClickListener { + startQRScanner() + } + + viewBinding.myGroupsButton.setOnClickListener { + + if (isJetpackNavigation) { + val action = + SnowbirdFragmentDirections.actionFragmentSnowbirdToFragmentSnowbirdGroupList() + findNavController().navigate(action) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_RAVEN_MY_GROUPS) + ) + } + } + + viewBinding.createGroupButton.setOnClickListener { + if (isJetpackNavigation) { + val action = + SnowbirdFragmentDirections.actionFragmentSnowbirdToFragmentSnowbirdCreateGroup() + findNavController().navigate(action) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf(RESULT_BUNDLE_KEY to RESULT_VAL_RAVEN_CREATE_GROUP) + ) + } + } + + initializeViewModelObservers() + } + + private fun initializeViewModelObservers() { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + launch { + snowbirdGroupViewModel.groupState.collect { state -> + handleGroupStateUpdate( + state + ) + } + } + } + } + } + + private fun handleGroupStateUpdate(state: SnowbirdGroupViewModel.GroupState) { + handleLoadingStatus(false) + Timber.d("group state = $state") + when (state) { + is SnowbirdGroupViewModel.GroupState.Loading -> handleLoadingStatus(true) + is SnowbirdGroupViewModel.GroupState.Error -> handleError(state.error) + else -> Unit + } + } + + private fun startQRScanner() { +// val integrator = IntentIntegrator(requireActivity()) +// integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE) +// integrator.setPrompt("Scan QR Code") +// integrator.setCameraId(0) // Use the rear camera +// integrator.setBeepEnabled(false) +// integrator.setBarcodeImageEnabled(true) +// integrator.setCaptureActivity(QRScannerActivity::class.java) +// +// val scanningIntent = integrator.createScanIntent() + +// qrCodeLauncher.launch(scanningIntent) + } + + private fun processScannedData(uriString: String) { + val name = uriString.getQueryParameter("name") + + if (name == null) { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Warning + title = UiText.DynamicString("Oops!") + message = UiText.DynamicString("Unable to determine group name from QR code.") + positiveButton { + text = UiText.StringResource(R.string.lbl_ok) + } + } + return + } + + if (SnowbirdGroup.exists(name)) { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Warning + title = UiText.DynamicString("Oops!") + message = UiText.DynamicString("You have already joined this group.") + positiveButton { + text = UiText.StringResource(R.string.lbl_ok) + } + } + return + } + + if (isJetpackNavigation) { + val action = + SnowbirdFragmentDirections.actionFragmentSnowbirdToFragmentSnowbirdJoinGroup( + uriString + ) + findNavController().navigate(action) + } else { + + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf( + RESULT_BUNDLE_KEY to RESULT_VAL_RAVEN_JOIN_GROUPS, + RESULT_VAL_RAVEN_JOIN_GROUPS_ARG to uriString + ) + ) + } + } + + companion object { + const val RESULT_REQUEST_KEY = "raven_fragment_result" + const val RESULT_BUNDLE_KEY = "raven_fragment_result_key" + const val RESULT_VAL_RAVEN_MY_GROUPS = "raven_my_group" + const val RESULT_VAL_RAVEN_JOIN_GROUPS = "raven_join_group" + const val RESULT_VAL_RAVEN_JOIN_GROUPS_ARG = "raven_join_group_argument_uri" + const val RESULT_VAL_RAVEN_CREATE_GROUP = "raven_create_group" + + @JvmStatic + fun newInstance() = SnowbirdFragment() + } + + override fun getToolbarTitle(): String { + return "Raven" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupListAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupListAdapter.kt new file mode 100644 index 00000000..42f31d0d --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupListAdapter.kt @@ -0,0 +1,86 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.OneLineRowBinding +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.shortHash +import net.opendasharchive.openarchive.extensions.scaled +import java.lang.ref.WeakReference + +//interface SnowbirdGroupsAdapterListener { +// fun groupSelected(group: SnowbirdGroup) +//} + +class SnowbirdGroupsAdapter( + onClickListener: ((String) -> Unit)? = null, + onLongPressListener: ((String) -> Unit)? = null +) : ListAdapter(DIFF_CALLBACK) { + + private val onClickCallback = WeakReference(onClickListener) + private val onLongPressCallback = WeakReference(onLongPressListener) + + inner class ViewHolder(private val binding: OneLineRowBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(group: SnowbirdGroup?) { + + if (group == null) { + return + } + + val context = binding.button.context + + binding.button.setLeftIcon( + ContextCompat.getDrawable(context, R.drawable.snowbird)?.scaled(40, context) + ) + //binding.button.setBackgroundResource(R.drawable.button_outlined_ripple) + binding.button.setTitle(group.name ?: "No name provided") + binding.button.setSubTitle(group.shortHash()) + + binding.button.setOnClickListener { + onClickCallback.get()?.invoke(group.key) + } + + binding.button.setOnLongClickListener { + onLongPressCallback.get()?.invoke(group.key) + true + } + } + } + + companion object { + private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SnowbirdGroup, newItem: SnowbirdGroup): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame( + oldItem: SnowbirdGroup, + newItem: SnowbirdGroup + ): Boolean { + return oldItem.key == newItem.key + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + OneLineRowBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val group = getItem(position) + holder.bind(group) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupListFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupListFragment.kt new file mode 100644 index 00000000..530bd150 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupListFragment.kt @@ -0,0 +1,219 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.core.bundle.bundleOf +import androidx.core.view.MenuProvider +import androidx.fragment.app.setFragmentResult +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdGroupListBinding +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.util.SpacingItemDecoration +import timber.log.Timber + +class SnowbirdGroupListFragment : BaseFragment() { + + private lateinit var viewBinding: FragmentSnowbirdGroupListBinding + private lateinit var adapter: SnowbirdGroupsAdapter + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + viewBinding = FragmentSnowbirdGroupListBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupMenu() + setupSwipeRefresh() + setupRecyclerView() + initializeViewModelObservers() + + snowbirdGroupViewModel.fetchGroups() + } + + private fun setupSwipeRefresh() { + viewBinding.swipeRefreshLayout.setOnRefreshListener { + snowbirdGroupViewModel.fetchGroups(true) + } + + viewBinding.swipeRefreshLayout.setColorSchemeResources( + R.color.colorPrimary, + R.color.colorPrimaryDark + ) + } + + private fun setupMenu() { + requireActivity().addMenuProvider(object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_snowbird, menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.action_add -> { + if (isJetpackNavigation) { + val action = + SnowbirdGroupListFragmentDirections.actionFragmentSnowbirdGroupListToFragmentSnowbirdCreateGroup() + findNavController().navigate(action) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf(RESULT_BUNDLE_NAVIGATION_KEY to RESULT_VAL_RAVEN_CREATE_GROUP_SCREEN) + ) + } + true + } + + else -> false + } + } + }, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + + private fun setupRecyclerView() { + adapter = SnowbirdGroupsAdapter( + onClickListener = { groupKey -> + onClick(groupKey) + }, + onLongPressListener = { groupKey -> + onLongPress(groupKey) + } + ) + + val spacingInPixels = resources.getDimensionPixelSize(R.dimen.list_item_spacing) + viewBinding.groupList.addItemDecoration(SpacingItemDecoration(spacingInPixels)) + + viewBinding.groupList.layoutManager = LinearLayoutManager(requireContext()) + viewBinding.groupList.adapter = adapter + + viewBinding.groupList.setEmptyView(R.layout.view_empty_state) + } + + private fun onClick(groupKey: String) { + if (isJetpackNavigation) { + val action = SnowbirdGroupListFragmentDirections.actionFragmentSnowbirdGroupListToFragmentSnowbirdListRepos(groupKey) + findNavController().navigate(action) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, bundleOf( + RESULT_BUNDLE_NAVIGATION_KEY to RESULT_VAL_RAVEN_REPO_LIST_SCREEN, + RESULT_BUNDLE_GROUP_KEY to groupKey + ) + ) + } + } + + private fun onLongPress(groupKey: String) { + AppLogger.d("Long press!") + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Info + title = UiText.DynamicString("Share Group") + message = UiText.DynamicString("Would you like to share this group?") + positiveButton { + text = UiText.DynamicString("Yes") + action = { + val action = SnowbirdGroupListFragmentDirections.actionFragmentSnowbirdGroupListToFragmentSnowbirdShareGroup(groupKey) + findNavController().navigate(action) + } + } + neutralButton { + text = UiText.DynamicString("No") + } + } + } + + private fun initializeViewModelObservers() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + snowbirdGroupViewModel.groupState.collect { state -> + handleGroupStateUpdate(state) + } + } + } + } + } + + override fun handleError(error: SnowbirdError) { + handleLoadingStatus(false) + viewBinding.swipeRefreshLayout.isRefreshing = false + super.handleError(error) + } + + private fun handleGroupStateUpdate(state: SnowbirdGroupViewModel.GroupState) { + when (state) { + is SnowbirdGroupViewModel.GroupState.Loading -> onLoading() + is SnowbirdGroupViewModel.GroupState.MultiGroupSuccess -> onGroupsFetched( + state.groups, + state.isRefresh + ) + + is SnowbirdGroupViewModel.GroupState.Error -> handleError(state.error) + else -> Unit + } + } + + private fun onGroupsFetched(groups: List, isRefresh: Boolean) { + handleLoadingStatus(false) + + if (isRefresh) { + Timber.d("Clearing SnowbirdGroups") + SnowbirdGroup.clear() + saveGroups(groups) + } + + adapter.submitList(groups) + } + + private fun onLoading() { + handleLoadingStatus(true) + viewBinding.swipeRefreshLayout.isRefreshing = false + } + + private fun saveGroups(groups: List) { + groups.forEach { group -> + group.save() + } + } + + companion object { + const val RESULT_REQUEST_KEY = "raven_group_list_fragment_result" + const val RESULT_BUNDLE_NAVIGATION_KEY = "raven_group_list_fragment_bundle_navigation_key" + + const val RESULT_VAL_RAVEN_CREATE_GROUP_SCREEN = "raven_create_group" + const val RESULT_VAL_RAVEN_REPO_LIST_SCREEN = "raven_repo_list_screen" + const val RESULT_VAL_RAVEN_SHARE_SCREEN = "raven_share_group_screen" + + const val RESULT_BUNDLE_GROUP_KEY = "dweb_group_key" + + @JvmStatic + fun newInstance() = SnowbirdGroupListFragment() + } + + override fun getToolbarTitle(): String { + return "My Groups" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupOverviewFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupOverviewFragment.kt new file mode 100644 index 00000000..4d0b366f --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupOverviewFragment.kt @@ -0,0 +1,22 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdGroupOverviewBinding +import net.opendasharchive.openarchive.features.core.BaseFragment + +class SnowbirdGroupOverviewFragment private constructor(): BaseFragment() { + private lateinit var viewBinding: FragmentSnowbirdGroupOverviewBinding + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + viewBinding = FragmentSnowbirdGroupOverviewBinding.inflate(inflater) + + return viewBinding.root + } + + override fun getToolbarTitle(): String { + return "Raven Group Overview" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupRepository.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupRepository.kt new file mode 100644 index 00000000..2be20b6f --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupRepository.kt @@ -0,0 +1,74 @@ +package net.opendasharchive.openarchive.services.snowbird + +import net.opendasharchive.openarchive.db.JoinGroupResponse +import net.opendasharchive.openarchive.db.MembershipRequest +import net.opendasharchive.openarchive.db.RequestName +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.extensions.toSnowbirdError +import net.opendasharchive.openarchive.services.snowbird.service.ISnowbirdAPI + +interface ISnowbirdGroupRepository { + suspend fun createGroup(groupName: String): SnowbirdResult + suspend fun fetchGroup(groupKey: String): SnowbirdResult + suspend fun fetchGroups(forceRefresh: Boolean = false): SnowbirdResult> + suspend fun joinGroup(uriString: String): SnowbirdResult +} + +class SnowbirdGroupRepository(val api: ISnowbirdAPI) : ISnowbirdGroupRepository { + private var lastFetchTime: Long = 0 + private val cacheValidityPeriod: Long = 5 * 60 * 1000 + + override suspend fun createGroup(groupName: String): SnowbirdResult { + return try { + val response = api.createGroup( + RequestName(groupName)) + SnowbirdResult.Success(response) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + override suspend fun fetchGroup(groupKey: String): SnowbirdResult { + return try { + val response = api.fetchGroup(groupKey) + SnowbirdResult.Success(response) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + override suspend fun fetchGroups(forceRefresh: Boolean): SnowbirdResult> { + val currentTime = System.currentTimeMillis() + val shouldFetchFromNetwork = forceRefresh || currentTime - lastFetchTime > cacheValidityPeriod + + return if (forceRefresh) { + fetchFromNetwork() + } else { + fetchFromCache() + } + } + + override suspend fun joinGroup(uriString: String): SnowbirdResult { + return try { + val response = api.joinGroup( + MembershipRequest(uriString)) + SnowbirdResult.Success(response) + } catch (e: Exception) { + e.printStackTrace() + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + private suspend fun fetchFromNetwork(): SnowbirdResult> { + return try { + val response = api.fetchGroups() + SnowbirdResult.Success(response.groups) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + private fun fetchFromCache(): SnowbirdResult> { + return SnowbirdResult.Success(SnowbirdGroup.getAll()) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupViewModel.kt new file mode 100644 index 00000000..4b7cff87 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdGroupViewModel.kt @@ -0,0 +1,111 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.app.Application +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.db.JoinGroupResponse +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.util.BaseViewModel +import net.opendasharchive.openarchive.util.trackProcessingWithTimeout + +class SnowbirdGroupViewModel( + application: Application, + private val repository: ISnowbirdGroupRepository +) : BaseViewModel(application) { + + sealed class GroupState { + data object Idle : GroupState() + data object Loading : GroupState() + data class JoinGroupSuccess(val group: JoinGroupResponse) : GroupState() + data class SingleGroupSuccess(val group: SnowbirdGroup) : GroupState() + data class MultiGroupSuccess(val groups: List, val isRefresh: Boolean) : GroupState() + data class Error(val error: SnowbirdError) : GroupState() + } + + private val _groupState = MutableStateFlow(GroupState.Idle) + val groupState: StateFlow = _groupState.asStateFlow() + + private val _currentGroup = MutableStateFlow(null) + val currentGroup: StateFlow = _currentGroup.asStateFlow() + + fun setCurrentGroup(group: SnowbirdGroup) { + _currentGroup.value = group + } + + fun fetchGroup(groupKey: String) { + viewModelScope.launch { + _groupState.value = GroupState.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(30_000, "fetch_group") { + repository.fetchGroup(groupKey) + } + + _groupState.value = when (result) { + is SnowbirdResult.Success -> GroupState.SingleGroupSuccess(result.value) + is SnowbirdResult.Error -> GroupState.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _groupState.value = GroupState.Error(SnowbirdError.TimedOut) + } + } + } + + fun fetchGroups(forceRefresh: Boolean = false) { + viewModelScope.launch { + _groupState.value = GroupState.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(30_000, "fetch_groups") { + repository.fetchGroups(forceRefresh) + } + + _groupState.value = when (result) { + is SnowbirdResult.Success -> GroupState.MultiGroupSuccess(result.value, forceRefresh) + is SnowbirdResult.Error -> GroupState.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _groupState.value = GroupState.Error(SnowbirdError.TimedOut) + } + } + } + + fun createGroup(groupName: String) { + viewModelScope.launch { + _groupState.value = GroupState.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(30_000, "create_group") { + repository.createGroup(groupName) + } + + _groupState.value = when (result) { + is SnowbirdResult.Success -> GroupState.SingleGroupSuccess(result.value) + is SnowbirdResult.Error -> GroupState.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _groupState.value = GroupState.Error(SnowbirdError.TimedOut) + } + } + } + + fun joinGroup(uriString: String) { + viewModelScope.launch { + _groupState.value = GroupState.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(60_000, "join_group") { + repository.joinGroup(uriString) + } + + _groupState.value = when (result) { + is SnowbirdResult.Success -> GroupState.JoinGroupSuccess(result.value) + is SnowbirdResult.Error -> GroupState.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _groupState.value = GroupState.Error(SnowbirdError.TimedOut) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdJoinGroupFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdJoinGroupFragment.kt new file mode 100644 index 00000000..ab1d9388 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdJoinGroupFragment.kt @@ -0,0 +1,168 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdJoinGroupBinding +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.extensions.getQueryParameter +import net.opendasharchive.openarchive.extensions.showKeyboard +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.util.FullScreenOverlayCreateGroupManager +import timber.log.Timber + +class SnowbirdJoinGroupFragment: BaseFragment() { + + private lateinit var viewBinding: FragmentSnowbirdJoinGroupBinding + private lateinit var uriString: String + private lateinit var groupName: String + private lateinit var repoName: String + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + arguments?.let { + uriString = it.getString(ARG_RAVEN_GROUP_URI_STRING, "") + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + viewBinding = FragmentSnowbirdJoinGroupBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + groupName = uriString.getQueryParameter("name") ?: "Unknown group" + + Timber.d("uriString = $uriString") + Timber.d("groupName = $groupName") + + viewBinding.groupNameTextfield.setText(groupName) + + setupViewModelObservers() + setupSideEffects() + } + + private fun setupViewModelObservers() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { snowbirdGroupViewModel.groupState.collect { state -> onGroupStateUpdate(state) } } + launch { snowbirdRepoViewModel.repoState.collect { state -> onRepoStateUpdate(state) } } + } + } + } + + override fun handleError(error: SnowbirdError) { + handleCreateGroupLoadingStatus(false) + super.handleError(error) + } + + private fun onGroupStateUpdate(state: SnowbirdGroupViewModel.GroupState) { + Timber.d("state = $state") + when (state) { + is SnowbirdGroupViewModel.GroupState.Loading -> onLoading() + is SnowbirdGroupViewModel.GroupState.JoinGroupSuccess -> onJoinSuccess(state.group.group) + is SnowbirdGroupViewModel.GroupState.Error -> handleError(state.error) + else -> Unit + } + } + + private fun onRepoStateUpdate(state: SnowbirdRepoViewModel.RepoState) { + Timber.d("state = $state") + when (state) { + is SnowbirdRepoViewModel.RepoState.Loading -> onLoading() + is SnowbirdRepoViewModel.RepoState.SingleRepoSuccess -> onRepoCreated(state.groupKey, state.repo) + is SnowbirdRepoViewModel.RepoState.Error -> handleError(state.error) + else -> Unit + } + } + + private fun onJoinSuccess(group: SnowbirdGroup) { + // Group name doesn't come back from backend by default so + // we poke it in here. + // + group.name = groupName + group.save() + snowbirdRepoViewModel.createRepo(group.key, repoName) + } + + private fun onLoading() { + handleCreateGroupLoadingStatus(true) + } + + private fun handleCreateGroupLoadingStatus(isLoading: Boolean) { + if (isLoading) { + FullScreenOverlayCreateGroupManager.show(this@SnowbirdJoinGroupFragment) + } else { + FullScreenOverlayCreateGroupManager.hide() + } + } + + private fun onRepoCreated(groupKey: String, repo: SnowbirdRepo) { + repo.permissions = "READ_WRITE" + repo.groupKey = groupKey + repo.save() + handleCreateGroupLoadingStatus(false) + snowbirdRepoViewModel.fetchRepos(groupKey, false) + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Success + title = UiText.StringResource(R.string.label_success_title) + message = UiText.DynamicString("Successfully joined") + positiveButton { + text = UiText.StringResource(R.string.label_got_it) + action = { + parentFragmentManager.popBackStack() + } + } + } + } + + private fun setupSideEffects() { + viewBinding.repoNameTextfield.post { + viewBinding.repoNameTextfield.showKeyboard() + } + + viewBinding.joinGroupButton.setOnClickListener { + repoName = viewBinding.repoNameTextfield.text?.toString().orEmpty() + + if (repoName.isBlank()) { + viewBinding.repoNameTextfield.error = "Repository name cannot be empty" + } else { + snowbirdGroupViewModel.joinGroup(uriString) + dismissKeyboard(it) + } + } + } + + companion object { + + + const val ARG_RAVEN_GROUP_URI_STRING = "space_setup_success_fragment_arg_message" + + @JvmStatic + fun newInstance(uriString: String) = + SnowbirdJoinGroupFragment().apply { + arguments = Bundle().apply { + putString(ARG_RAVEN_GROUP_URI_STRING, uriString) + } + } + } + + override fun getToolbarTitle(): String { + return "Join Group" + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoListAdapter.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoListAdapter.kt new file mode 100644 index 00000000..fd3ba9f8 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoListAdapter.kt @@ -0,0 +1,75 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.databinding.OneLineRowBinding +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.db.shortHash +import net.opendasharchive.openarchive.extensions.scaled +import net.opendasharchive.openarchive.util.TwoLetterDrawable +import java.lang.ref.WeakReference + +class SnowbirdRepoListAdapter(listener: ((String) -> Unit)? = null) + : ListAdapter(DIFF_CALLBACK) { + + inner class SnowbirdRepoListViewHolder(private val binding: OneLineRowBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(repo: SnowbirdRepo?) { + if (repo == null) { + return + } + + val context = binding.button.context + + binding.button.setLeftIcon(ContextCompat.getDrawable(context, R.drawable.snowbird)?.scaled(40, context)) + //binding.button.setBackgroundResource(R.drawable.button_outlined_ripple) + binding.button.setTitle(repo.name) + binding.button.setSubTitle(repo.shortHash()) + + if (repo.permissions == "READ_ONLY") { + binding.button.setRightIcon(TwoLetterDrawable.ReadOnly(context)) + } else { + binding.button.setRightIcon(TwoLetterDrawable.ReadWrite(context)) + } + + binding.button.setOnClickListener { + mListener.get()?.invoke(repo.key) + } + } + } + + companion object { + private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SnowbirdRepo, newItem: SnowbirdRepo): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: SnowbirdRepo, newItem: SnowbirdRepo): Boolean { + return oldItem.key == newItem.key + } + } + } + + private val mListener = WeakReference(listener) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SnowbirdRepoListViewHolder { + return SnowbirdRepoListViewHolder( + OneLineRowBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: SnowbirdRepoListViewHolder, position: Int) { + val repo = getItem(position) + holder.bind(repo) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoListFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoListFragment.kt new file mode 100644 index 00000000..14a62d2b --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoListFragment.kt @@ -0,0 +1,225 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.core.bundle.bundleOf +import androidx.core.view.MenuProvider +import androidx.fragment.app.setFragmentResult +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdListReposBinding +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.util.SpacingItemDecoration +import timber.log.Timber + +class SnowbirdRepoListFragment: BaseFragment() { + + private lateinit var viewBinding: FragmentSnowbirdListReposBinding + private lateinit var adapter: SnowbirdRepoListAdapter + private lateinit var groupKey: String + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + arguments?.let { + groupKey = it.getString(RESULT_VAL_RAVEN_GROUP_KEY, "") + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + viewBinding = FragmentSnowbirdListReposBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupMenu() + setupSwipeRefresh() + setupViewModel() + initializeViewModelObservers() + } + + private fun handleRepoStateUpdate(state: SnowbirdRepoViewModel.RepoState) { + when (state) { + is SnowbirdRepoViewModel.RepoState.Loading -> handleLoadingStatus(true) + is SnowbirdRepoViewModel.RepoState.RepoFetchSuccess -> handleRepoUpdate( + state.repos, + state.isRefresh + ) + + is SnowbirdRepoViewModel.RepoState.Error -> handleError(state.error) + else -> Unit + } + } + + private fun initializeViewModelObservers() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + snowbirdRepoViewModel.repoState.collect { state -> + handleRepoStateUpdate( + state + ) + } + } + launch { snowbirdRepoViewModel.fetchRepos(groupKey, forceRefresh = false) } + } + } + } + + private fun setupMenu() { + requireActivity().addMenuProvider(object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_snowbird, menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.action_add -> { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Warning + title = UiText.DynamicString("Oops!") + message = UiText.DynamicString("Feature not implemented yet.") + positiveButton { + text = UiText.StringResource(R.string.lbl_ok) + } + } + true + } + + else -> false + } + } + }, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + + private fun setupViewModel() { + + adapter = SnowbirdRepoListAdapter { repoKey -> + AppLogger.d("Click!!") + //findNavController().navigate(SnowbirdRepoListFragmentDirections.navigateToSnowbirdListFilesScreen(groupKey, repoKey)) + if (isJetpackNavigation) { + val action = + SnowbirdRepoListFragmentDirections.actionFragmentSnowbirdListReposToFragmentSnowbirdListMedia( + dwebGroupKey = groupKey, + dwebRepoKey = repoKey + ) + findNavController().navigate(action) + } else { + setFragmentResult( + RESULT_REQUEST_KEY, + bundleOf( + RESULT_VAL_RAVEN_GROUP_KEY to groupKey, + RESULT_VAL_RAVEN_REPO_KEY to repoKey + ) + ) + } + } + + val spacingInPixels = resources.getDimensionPixelSize(R.dimen.list_item_spacing) + viewBinding.repoList.addItemDecoration(SpacingItemDecoration(spacingInPixels)) + + viewBinding.repoList.layoutManager = LinearLayoutManager(requireContext()) + viewBinding.repoList.adapter = adapter + + viewBinding.repoList.setEmptyView(R.layout.view_empty_state) + } + + private fun handleRepoUpdate(repos: List, isRefresh: Boolean) { + handleLoadingStatus(false) + + if (isRefresh) { + Timber.d("Clearing SnowbirdRepos for group $groupKey") + SnowbirdRepo.clear(groupKey) + saveRepos(repos) + } + + adapter.submitList(repos) + + if (isRefresh && repos.isEmpty()) { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Info + title = UiText.StringResource(R.string.label_info_title) + message = UiText.DynamicString("No new repositories found.") + positiveButton { + text = UiText.StringResource(R.string.label_got_it) + action = { + parentFragmentManager.popBackStack() + } + } + } + } + } + + override fun handleError(error: SnowbirdError) { + handleLoadingStatus(false) + viewBinding.swipeRefreshLayout.isRefreshing = false + super.handleError(error) + } + + override fun handleLoadingStatus(isLoading: Boolean) { + super.handleLoadingStatus(isLoading) + viewBinding.swipeRefreshLayout.isRefreshing = false + } + + private fun saveRepos(repos: List) { + repos.forEach { repo -> + repo.groupKey = groupKey + repo.save() + } + } + + private fun setupSwipeRefresh() { + viewBinding.swipeRefreshLayout.setOnRefreshListener { + lifecycleScope.launch { + snowbirdRepoViewModel.fetchRepos(groupKey, forceRefresh = true) + } + } + + viewBinding.swipeRefreshLayout.setColorSchemeResources( + R.color.colorPrimary, R.color.colorPrimaryDark + ) + } + + override fun getToolbarTitle(): String { + return "Repositories" + } + + + companion object { + + const val RESULT_REQUEST_KEY = "raven_fragment_repo_list_result" + const val RESULT_VAL_RAVEN_GROUP_KEY = "dweb_group_key" + const val RESULT_VAL_RAVEN_REPO_KEY = "dweb_repo_key" + + @JvmStatic + fun newInstance(groupKey: String) = + SnowbirdRepoListFragment().apply { + arguments = Bundle().apply { + putString(RESULT_VAL_RAVEN_GROUP_KEY, groupKey) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoRepository.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoRepository.kt new file mode 100644 index 00000000..abfa9552 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoRepository.kt @@ -0,0 +1,47 @@ +package net.opendasharchive.openarchive.services.snowbird + +import net.opendasharchive.openarchive.db.RequestName +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.extensions.toSnowbirdError +import net.opendasharchive.openarchive.services.snowbird.service.ISnowbirdAPI +import timber.log.Timber + +interface ISnowbirdRepoRepository { + suspend fun createRepo(groupKey: String, repoName: String): SnowbirdResult + suspend fun fetchRepos(groupKey: String, forceRefresh: Boolean = false): SnowbirdResult> +} + +class SnowbirdRepoRepository(val api: ISnowbirdAPI) : ISnowbirdRepoRepository { + override suspend fun createRepo(groupKey: String, repoName: String): SnowbirdResult { + Timber.d("Creating repo: groupKey=$groupKey, repoName=$repoName") + + return try { + val response = api.createRepo(groupKey, RequestName(repoName)) + SnowbirdResult.Success(response) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + override suspend fun fetchRepos(groupKey: String, forceRefresh: Boolean): SnowbirdResult> { + return if (forceRefresh) { + fetchFromNetwork(groupKey) + } else { + fetchFromCache(groupKey) + } + } + + private suspend fun fetchFromNetwork(groupKey: String): SnowbirdResult> { + return try { + val response = api.fetchRepos(groupKey) + SnowbirdResult.Success(response.repos) + } catch (e: Exception) { + SnowbirdResult.Error(e.toSnowbirdError()) + } + } + + private fun fetchFromCache(groupKey: String): SnowbirdResult> { + return SnowbirdResult.Success(SnowbirdRepo.getAllFor(SnowbirdGroup.get(groupKey))) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoViewModel.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoViewModel.kt new file mode 100644 index 00000000..687ee645 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdRepoViewModel.kt @@ -0,0 +1,67 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.app.Application +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import net.opendasharchive.openarchive.db.SnowbirdError +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.util.BaseViewModel +import net.opendasharchive.openarchive.util.trackProcessingWithTimeout + +class SnowbirdRepoViewModel( + application: Application, + private val repository: ISnowbirdRepoRepository +) : BaseViewModel(application) { + + sealed class RepoState { + data object Idle : RepoState() + data object Loading : RepoState() + data class SingleRepoSuccess(val groupKey: String, val repo: SnowbirdRepo) : RepoState() + data class MultiRepoSuccess(val repos: List) : RepoState() + data class RepoFetchSuccess(val repos: List, val isRefresh: Boolean) : RepoState() + data class Error(val error: SnowbirdError) : RepoState() + } + + private val _repoState = MutableStateFlow(RepoState.Idle) + val repoState: StateFlow = _repoState.asStateFlow() + + fun createRepo(groupKey: String, repoName: String) { + viewModelScope.launch { + _repoState.value = RepoState.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(60_000, "create_repo") { + repository.createRepo(groupKey, repoName) + } + + _repoState.value = when (result) { + is SnowbirdResult.Success -> RepoState.SingleRepoSuccess(groupKey, result.value) + is SnowbirdResult.Error -> RepoState.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _repoState.value = RepoState.Error(SnowbirdError.TimedOut) + } + } + } + + fun fetchRepos(groupKey: String, forceRefresh: Boolean = false) { + viewModelScope.launch { + _repoState.value = RepoState.Loading + try { + val result = processingTracker.trackProcessingWithTimeout(30_000, "fetch_repos") { + repository.fetchRepos(groupKey, forceRefresh) + } + + _repoState.value = when (result) { + is SnowbirdResult.Success -> RepoState.RepoFetchSuccess(result.value, forceRefresh) + is SnowbirdResult.Error -> RepoState.Error(result.error) + } + } catch (e: TimeoutCancellationException) { + _repoState.value = RepoState.Error(SnowbirdError.TimedOut) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdResult.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdResult.kt new file mode 100644 index 00000000..ad55ff89 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdResult.kt @@ -0,0 +1,8 @@ +package net.opendasharchive.openarchive.services.snowbird + +import net.opendasharchive.openarchive.db.SnowbirdError + +sealed class SnowbirdResult { + data class Success(val value: T) : SnowbirdResult() + data class Error(val error: SnowbirdError) : SnowbirdResult() +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdServiceStatus.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdServiceStatus.kt new file mode 100644 index 00000000..c1d362f1 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdServiceStatus.kt @@ -0,0 +1,36 @@ +package net.opendasharchive.openarchive.services.snowbird + +sealed class SnowbirdServiceStatus { + data object BackendInitializing : SnowbirdServiceStatus() + data object BackendRunning : SnowbirdServiceStatus() + data object WebServerInitializing : SnowbirdServiceStatus() + data object WebServerRunning : SnowbirdServiceStatus() + data object Processing : SnowbirdServiceStatus() + data object Idle : SnowbirdServiceStatus() + data class Error(val message: String) : SnowbirdServiceStatus() + + val code: Int + get() = when (this) { + is BackendInitializing -> 0 + is BackendRunning -> 1 + is WebServerInitializing -> 2 + is WebServerRunning -> 3 + is Processing -> 4 + is Idle -> 5 + is Error -> 6 + } + + companion object { + fun fromCode(code: Int, errorMessage: String? = null): SnowbirdServiceStatus = + when (code) { + 0 -> BackendInitializing + 1 -> BackendRunning + 2 -> WebServerInitializing + 3 -> WebServerRunning + 4 -> Processing + 5 -> Idle + 6 -> Error(errorMessage ?: "Unknown error") + else -> throw IllegalArgumentException("Invalid status code: $code") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdShareFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdShareFragment.kt new file mode 100644 index 00000000..e0ece706 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/SnowbirdShareFragment.kt @@ -0,0 +1,62 @@ +package net.opendasharchive.openarchive.services.snowbird + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import net.opendasharchive.openarchive.databinding.FragmentSnowbirdShareGroupBinding +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.extensions.asQRCode +import net.opendasharchive.openarchive.extensions.urlEncode +import net.opendasharchive.openarchive.features.core.BaseFragment + +class SnowbirdShareFragment: BaseFragment() { + private lateinit var viewBinding: FragmentSnowbirdShareGroupBinding + private lateinit var groupKey: String + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + arguments?.let { + groupKey = it.getString(RESULT_VAL_RAVEN_GROUP_KEY, "") + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + viewBinding = FragmentSnowbirdShareGroupBinding.inflate(inflater) + + return viewBinding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val group = SnowbirdGroup.get(groupKey) + val groupName = group?.name ?: "Unknown group" + + viewBinding.groupName.text = groupName + + SnowbirdGroup.get(groupKey)?.uri?.let { uriString -> + val qrCode = "$uriString&name=${groupName.urlEncode()}".asQRCode(size = 1024) + viewBinding.qrCode.setImageBitmap(qrCode) + } + } + + override fun getToolbarTitle(): String { + return "Share Raven Group" + } + + companion object { + + const val RESULT_VAL_RAVEN_GROUP_KEY = "dweb_group_key" + + @JvmStatic + fun newInstance(groupKey: String): SnowbirdShareFragment { + return SnowbirdShareFragment().apply { + arguments = Bundle().apply { + putString(RESULT_VAL_RAVEN_GROUP_KEY, groupKey) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/ApiResponse.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/ApiResponse.kt new file mode 100644 index 00000000..958e40fc --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/ApiResponse.kt @@ -0,0 +1,9 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import net.opendasharchive.openarchive.db.ApiError + +sealed class ApiResponse { + data class SingleResponse(val data: T) : ApiResponse() + data class ListResponse(val data: List) : ApiResponse() + data class ErrorResponse(val error: ApiError) : ApiResponse() +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/BackoffStrategy.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/BackoffStrategy.kt new file mode 100644 index 00000000..90075aaf --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/BackoffStrategy.kt @@ -0,0 +1,25 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +/** + * Defines different backoff strategies for retry attempts. + */ +sealed class BackoffStrategy { + /** + * @param baseDelay Base delay duration between retries + */ + data class Linear(val baseDelay: Duration = 1.seconds) : BackoffStrategy() + + /** + * @param baseDelay Initial delay duration + * @param multiplier Factor to multiply delay by on each attempt + * @param maxDelay Maximum delay between retries + */ + data class Exponential( + val baseDelay: Duration = 1.seconds, + val multiplier: Double = 2.0, + val maxDelay: Duration = 60.seconds + ) : BackoffStrategy() +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/HttpLikeException.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/HttpLikeException.kt new file mode 100644 index 00000000..3c9c703f --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/HttpLikeException.kt @@ -0,0 +1,3 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +class HttpLikeException(val code: Int) : Exception("HTTP $code") \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/ISnowbirdAPI.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/ISnowbirdAPI.kt new file mode 100644 index 00000000..72f3b3b9 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/ISnowbirdAPI.kt @@ -0,0 +1,29 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import android.net.Uri +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.JoinGroupResponse +import net.opendasharchive.openarchive.db.MembershipRequest +import net.opendasharchive.openarchive.db.RequestName +import net.opendasharchive.openarchive.db.SnowbirdFileList +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdGroupList +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.db.SnowbirdRepoList + +interface ISnowbirdAPI { + // Media + suspend fun fetchFiles(groupKey: String, repoKey: String): SnowbirdFileList + suspend fun downloadFile(groupKey: String, repoKey: String, filename: String): ByteArray + suspend fun uploadFile(groupKey: String, repoKey: String, uri: Uri): FileUploadResult + + // Groups + suspend fun createGroup(groupName: RequestName): SnowbirdGroup + suspend fun fetchGroup(key: String): SnowbirdGroup + suspend fun fetchGroups(): SnowbirdGroupList + suspend fun joinGroup(request: MembershipRequest): JoinGroupResponse + + // Repos + suspend fun createRepo(groupKey: String, repoName: RequestName): SnowbirdRepo + suspend fun fetchRepos(groupKey: String): SnowbirdRepoList +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetrofitAPI.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetrofitAPI.kt new file mode 100644 index 00000000..43cecb23 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetrofitAPI.kt @@ -0,0 +1,53 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import android.content.Context +import android.net.Uri +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.JoinGroupResponse +import net.opendasharchive.openarchive.db.MembershipRequest +import net.opendasharchive.openarchive.db.RequestName +import net.opendasharchive.openarchive.db.SnowbirdFileList +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdGroupList +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.db.SnowbirdRepoList +import net.opendasharchive.openarchive.extensions.getFilename + +class RetrofitAPI(private var context: Context, private val client: RetrofitClient) : ISnowbirdAPI { + override suspend fun fetchFiles(groupKey: String, repoKey: String): SnowbirdFileList { + return client.fetchFiles(groupKey, repoKey) + } + + override suspend fun downloadFile(groupKey: String, repoKey: String, filename: String): ByteArray { + return client.downloadFile(groupKey, repoKey, filename) + } + + override suspend fun uploadFile(groupKey: String, repoKey: String, uri: Uri): FileUploadResult { + return client.uploadFile(groupKey, repoKey, uri.getFilename(context)!!) + } + + override suspend fun createGroup(groupName: RequestName): SnowbirdGroup { + return client.createGroup(groupName) + } + + override suspend fun fetchGroup(key: String): SnowbirdGroup { + return client.fetchGroup(key) + } + + override suspend fun fetchGroups(): SnowbirdGroupList { + return client.fetchGroups() + } + + override suspend fun joinGroup(request: MembershipRequest): JoinGroupResponse { + return client.joinGroup(request) + } + + override suspend fun createRepo(groupKey: String, repoName: RequestName): SnowbirdRepo { + return client.createRepo(groupKey, repoName) + } + + override suspend fun fetchRepos(groupKey: String): SnowbirdRepoList { + return client.fetchRepos(groupKey) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetrofitClient.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetrofitClient.kt new file mode 100644 index 00000000..4acd23da --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetrofitClient.kt @@ -0,0 +1,76 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.JoinGroupResponse +import net.opendasharchive.openarchive.db.MembershipRequest +import net.opendasharchive.openarchive.db.RequestName +import net.opendasharchive.openarchive.db.SnowbirdFileList +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdGroupList +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.db.SnowbirdRepoList +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Headers +import retrofit2.http.POST +import retrofit2.http.Path + +interface RetrofitClient { + + // Files + + @GET("groups/{groupKey}/repos/{repoKey}/media") + suspend fun fetchFiles( + @Path("groupKey") groupKey: String, + @Path("repoKey") repoKey: String + ): SnowbirdFileList + + @GET("groups/{groupKey}/repos/{repoKey}/media/{filename}") + suspend fun downloadFile( + @Path("groupKey") groupKey: String, + @Path("repoKey") repoKey: String, + @Path("filename") filename: String + ): ByteArray + + @POST("groups/{groupKey}/repos/{repoKey}/media/{filename}") + @Headers("Content-Type: application/octet-stream") + suspend fun uploadFile( + @Path("groupKey") groupKey: String, + @Path("repoKey") repoKey: String, + @Path("filename") filename: String, + // @Body imageData: RequestBody + ): FileUploadResult + + // Groups + + @POST("groups") + suspend fun createGroup( + @Body groupName: RequestName + ): SnowbirdGroup + + @GET("groups/{groupKey}") + suspend fun fetchGroup( + @Path("groupKey") groupKey: String + ): SnowbirdGroup + + @GET("groups") + suspend fun fetchGroups(): SnowbirdGroupList + + @POST("memberships") + suspend fun joinGroup( + @Body request: MembershipRequest + ): JoinGroupResponse + + // Repos + + @POST("groups/{groupKey}/repos") + suspend fun createRepo( + @Path("groupKey") groupKey: String, + @Body repoName: RequestName + ): SnowbirdRepo + + @GET("groups/{groupKey}/repos") + suspend fun fetchRepos( + @Path("groupKey") groupKey: String + ): SnowbirdRepoList +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetryConfig.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetryConfig.kt new file mode 100644 index 00000000..42a68008 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/RetryConfig.kt @@ -0,0 +1,14 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import kotlin.coroutines.CoroutineContext + +/** + * Configuration for retry behavior + * @param maxAttempts Maximum number of retry attempts (null for infinite) + * @param backoffStrategy Strategy to use for delay between retries + */ +data class RetryConfig( + val maxAttempts: Int? = null, + val backoffStrategy: BackoffStrategy = BackoffStrategy.Exponential(), + val context: CoroutineContext? = null +) \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/SnowbirdService.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/SnowbirdService.kt new file mode 100644 index 00000000..bdb66eab --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/SnowbirdService.kt @@ -0,0 +1,237 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import android.app.Notification +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Intent +import android.os.IBinder +import androidx.core.app.NotificationCompat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.SaveApp +import net.opendasharchive.openarchive.extensions.RetryAttempt +import net.opendasharchive.openarchive.extensions.retryWithScope +import net.opendasharchive.openarchive.extensions.suspendToRetry +import net.opendasharchive.openarchive.features.main.MainActivity +import net.opendasharchive.openarchive.services.snowbird.SnowbirdBridge +import timber.log.Timber +import java.io.File +import java.io.IOException +import java.net.ConnectException +import java.net.HttpURLConnection +import java.net.SocketTimeoutException +import java.net.URL +import java.nio.file.Files +import kotlin.io.path.Path +import kotlin.time.Duration.Companion.seconds + +class SnowbirdService : Service() { + + companion object { + var DEFAULT_BACKEND_DIRECTORY = "" + private set + + var DEFAULT_SOCKET_PATH = "" + private set + } + + private var serverJob: Job? = null + private var pollingJob: Job? = null + private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Default) + + private val _serviceStatus = MutableStateFlow(ServiceStatus.Stopped) + val serviceStatus = _serviceStatus.asStateFlow() + + override fun onCreate() { + super.onCreate() + + val backendBaseDirectory = filesDir + DEFAULT_BACKEND_DIRECTORY = backendBaseDirectory.absolutePath + + val serverSocketFile = File(filesDir, "rust_server.sock") + DEFAULT_SOCKET_PATH = serverSocketFile.absolutePath + + val path = Path(serverSocketFile.absolutePath) + + try { + Files.delete(path) + } catch (e: Exception) { + // ignore + e.printStackTrace() + } finally { + Files.createFile(path) + } + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + startForeground( + SaveApp.SNOWBIRD_SERVICE_ID, + createNotification("Snowbird Server is starting up.") + ) + startServer(DEFAULT_BACKEND_DIRECTORY, DEFAULT_SOCKET_PATH) + startPolling() + return START_STICKY + } + + override fun onDestroy() { + stopServer() + super.onDestroy() + } + + override fun onBind(intent: Intent?): IBinder? = null + + /** + * Checks if a web server is available and responding with a 200 OK status. + * Throws exceptions on failure for better integration with retry mechanisms. + * + * @param url The URL to check + * @param timeout Optional timeout in milliseconds (default 5000ms) + * @throws ConnectException if the server refuses connection + * @throws SocketTimeoutException if the connection times out + * @throws IOException for other network-related errors + */ + private suspend fun checkServerAvailability(url: String, timeout: Int = 1000) { + withContext(Dispatchers.IO) { + var connection: HttpURLConnection? = null + try { + connection = (URL(url).openConnection() as HttpURLConnection).apply { + connectTimeout = timeout + readTimeout = timeout + requestMethod = "GET" + instanceFollowRedirects = false + } + + when (connection.responseCode) { + HttpURLConnection.HTTP_OK -> return@withContext + else -> throw IOException("Server returned ${connection.responseCode}") + } + } catch (e: Exception) { + Timber.d("Server check failed: ${e.message}") + throw e + } finally { + connection?.disconnect() + } + } + } + + private fun createNotification(text: String, withSound: Boolean = false): Notification { + val channelId = + if (withSound) SaveApp.SNOWBIRD_SERVICE_CHANNEL_CHIME else SaveApp.SNOWBIRD_SERVICE_CHANNEL_SILENT + + val pendingIntent: PendingIntent = Intent( + this, + MainActivity::class.java + ).let { notificationIntent -> + PendingIntent.getActivity( + this, + 0, + notificationIntent, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + ) + } + + return NotificationCompat.Builder(this, channelId) + .setContentTitle("Raven Service") + .setContentText(text) + .setSmallIcon(R.drawable.ic_app_notify) + .setContentIntent(pendingIntent) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .build() + } + + /** + * Starts polling the server for availability + */ + private fun startPolling() { + Timber.d("Starting polling") + pollingJob?.cancel() // Cancel any existing polling + + pollingJob = suspendToRetry { checkServerAvailability("http://localhost:8080/status") } + .retryWithScope( + scope = serviceScope, + config = RetryConfig( + maxAttempts = null, + backoffStrategy = BackoffStrategy.Linear( + baseDelay = 2.seconds, + ) + ), + shouldRetry = { error -> + when (error) { + is ConnectException, + is SocketTimeoutException -> true + + else -> false + } + } + ) { attempt -> + val attemptNumber = attempt.attempt + when (attempt) { + is RetryAttempt.Success -> { + _serviceStatus.value = ServiceStatus.Connected + updateNotification("Service Connected", withSound = true) + Timber.d("Service is up after $attemptNumber attempt(s)") + stopPolling() + } + + is RetryAttempt.Retry -> { + _serviceStatus.value = ServiceStatus.Connecting + updateNotification("Connecting... One moment please.") + Timber.d("Attempt $attemptNumber failed, retrying...") + } + + is RetryAttempt.Failure -> { + val errorMessage = attempt.error.message ?: "Unknown error" + _serviceStatus.value = ServiceStatus.Failed(attempt.error) + updateNotification("Connection Failed: $errorMessage") + Timber.e(attempt.error) + stopPolling() + } + } + } + } + + private fun startServer(baseDirectory: String, socketPath: String) { + serverJob = serviceScope.launch { + Timber.d("Starting Raven Service") + val result = SnowbirdBridge.getInstance() + .startServer(applicationContext, baseDirectory, socketPath) + Timber.d("Raven Service: $result") + } + } + + private fun stopPolling() { + Timber.d("Stopping polling") + pollingJob?.cancel() + pollingJob = null + } + + private fun stopServer() { + serverJob?.cancel() + } + + private fun updateNotification(status: String, withSound: Boolean = false) { + val notificationManager = getSystemService(NotificationManager::class.java) + notificationManager.notify( + SaveApp.SNOWBIRD_SERVICE_ID, + createNotification(status, withSound) + ) + } +} + +/** + * Represents the current status of the polling service + */ +sealed class ServiceStatus { + data object Stopped : ServiceStatus() + data object Connecting : ServiceStatus() + data object Connected : ServiceStatus() + data class Failed(val error: Throwable) : ServiceStatus() +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/UnixSocketAPI.kt b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/UnixSocketAPI.kt new file mode 100644 index 00000000..9058c958 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/services/snowbird/service/UnixSocketAPI.kt @@ -0,0 +1,93 @@ +package net.opendasharchive.openarchive.services.snowbird.service + +import android.content.Context +import android.net.Uri +import net.opendasharchive.openarchive.db.EmptyRequest +import net.opendasharchive.openarchive.db.FileUploadResult +import net.opendasharchive.openarchive.db.JoinGroupResponse +import net.opendasharchive.openarchive.db.MembershipRequest +import net.opendasharchive.openarchive.db.RequestName +import net.opendasharchive.openarchive.db.SnowbirdFileList +import net.opendasharchive.openarchive.db.SnowbirdGroup +import net.opendasharchive.openarchive.db.SnowbirdGroupList +import net.opendasharchive.openarchive.db.SnowbirdRepo +import net.opendasharchive.openarchive.db.SnowbirdRepoList +import net.opendasharchive.openarchive.extensions.createInputStream +import net.opendasharchive.openarchive.extensions.getFilename +import net.opendasharchive.openarchive.features.main.HttpMethod +import net.opendasharchive.openarchive.features.main.UnixSocketClient +import net.opendasharchive.openarchive.features.main.downloadFile +import net.opendasharchive.openarchive.features.main.uploadFile +import java.io.FileNotFoundException +import java.io.IOException + +class UnixSocketAPI(private var context: Context, private var client: UnixSocketClient): ISnowbirdAPI { + + companion object { + private const val BASE_PATH = "/api" + const val MEMBERSHIPS_PATH = "$BASE_PATH/memberships" + const val GROUPS_PATH = "$BASE_PATH/groups" + const val REPOS_PATH = "$BASE_PATH/groups/%s/repos" + const val MEDIA_PATH = "$BASE_PATH/groups/%s/repos/%s/media" + const val MEDIA_PATH_UPLOAD = "$BASE_PATH/groups/%s/repos/%s/media/%s" + } + + override suspend fun downloadFile(groupKey: String, repoKey: String, filename: String): ByteArray { + return client.downloadFile( + endpoint = MEDIA_PATH_UPLOAD.format(groupKey, repoKey, filename)) + } + + override suspend fun fetchFiles(groupKey: String, repoKey: String): SnowbirdFileList { + return client.sendRequest( + endpoint = MEDIA_PATH.format(groupKey, repoKey), + method = HttpMethod.GET) + } + + override suspend fun uploadFile(groupKey: String, repoKey: String, uri: Uri): FileUploadResult { + val inputStream = uri.createInputStream(context) ?: throw IOException("Unable to create input stream") + val filename = uri.getFilename(context) ?: throw FileNotFoundException("Unable to get filename from Uri") + + return client.uploadFile( + endpoint = MEDIA_PATH_UPLOAD.format(groupKey, repoKey, filename), + inputStream = inputStream) + } + + override suspend fun createGroup(groupName: RequestName): SnowbirdGroup { + return client.sendRequest( + endpoint = GROUPS_PATH, + method = HttpMethod.POST, + body = groupName) + } + + override suspend fun fetchGroup(key: String): SnowbirdGroup { + return client.sendRequest( + endpoint = "$GROUPS_PATH/$key", + method = HttpMethod.GET) + } + + override suspend fun fetchGroups(): SnowbirdGroupList { + return client.sendRequest( + endpoint = GROUPS_PATH, + method = HttpMethod.GET) + } + + override suspend fun joinGroup(request: MembershipRequest): JoinGroupResponse { + return client.sendRequest( + endpoint = MEMBERSHIPS_PATH, + method = HttpMethod.POST, + body = request) + } + + override suspend fun createRepo(groupKey: String, repoName: RequestName): SnowbirdRepo { + return client.sendRequest( + endpoint = REPOS_PATH.format(groupKey), + HttpMethod.POST, + body = repoName) + } + + override suspend fun fetchRepos(groupKey: String): SnowbirdRepoList { + return client.sendRequest( + endpoint = REPOS_PATH.format(groupKey), + method = HttpMethod.GET) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavActivity.kt index b3959cb6..22625ab7 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavActivity.kt @@ -26,8 +26,7 @@ class WebDavActivity : BaseActivity() { mBinding = ActivityWebdavBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar(title = getString(R.string.edit_private_server), showBackButton = true) mSpaceId = intent.getLongExtra(EXTRA_DATA_SPACE, WebDavFragment.ARG_VAL_NEW_SPACE) diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavFragment.kt index 5f2f3649..be9a3eef 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavFragment.kt @@ -1,28 +1,42 @@ package net.opendasharchive.openarchive.services.webdav -import android.content.Context import android.net.Uri import android.os.Bundle import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo -import android.view.inputmethod.InputMethodManager +import androidx.activity.addCallback +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Warning import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment +import androidx.core.view.MenuProvider import androidx.fragment.app.setFragmentResult +import androidx.lifecycle.Lifecycle +import androidx.navigation.fragment.findNavController import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import net.opendasharchive.openarchive.BuildConfig import net.opendasharchive.openarchive.R +import net.opendasharchive.openarchive.core.logger.AppLogger import net.opendasharchive.openarchive.databinding.FragmentWebDavBinding import net.opendasharchive.openarchive.db.Space +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.core.UiImage +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.asUiText +import net.opendasharchive.openarchive.features.core.dialog.ButtonData +import net.opendasharchive.openarchive.features.core.dialog.DialogConfig +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.settings.CreativeCommonsLicenseManager import net.opendasharchive.openarchive.services.SaveClient import net.opendasharchive.openarchive.services.internetarchive.Util -import net.opendasharchive.openarchive.util.AlertHelper -import net.opendasharchive.openarchive.util.Utility import net.opendasharchive.openarchive.util.extensions.makeSnackBar import okhttp3.Call import okhttp3.Callback @@ -31,13 +45,16 @@ import okhttp3.Response import java.io.IOException import kotlin.coroutines.suspendCoroutine -class WebDavFragment : Fragment() { +class WebDavFragment : BaseFragment() { private var mSpaceId: Long? = null private lateinit var mSpace: Space private lateinit var mSnackbar: Snackbar private lateinit var binding: FragmentWebDavBinding + private var originalName: String? = null + private var isNameChanged = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mSpaceId = arguments?.getLong(ARG_SPACE_ID) ?: ARG_VAL_NEW_SPACE @@ -51,8 +68,8 @@ class WebDavFragment : Fragment() { mSpaceId = arguments?.getLong(ARG_SPACE_ID) ?: ARG_VAL_NEW_SPACE - if (ARG_VAL_NEW_SPACE != mSpaceId) { - // setup views for editing and existing space + if (mSpaceId != ARG_VAL_NEW_SPACE) { + // setup views for editing an existing space mSpace = Space.get(mSpaceId!!) ?: Space(Space.Type.WEBDAV) @@ -72,6 +89,7 @@ class WebDavFragment : Fragment() { binding.password.setText(mSpace.password) binding.name.setText(mSpace.name) + binding.layoutName.visibility = View.VISIBLE // mBinding.swChunking.isChecked = mSpace.useChunking // mBinding.swChunking.setOnCheckedChangeListener { _, useChunking -> @@ -80,43 +98,67 @@ class WebDavFragment : Fragment() { // } - binding.btRemove.setOnClickListener { - removeProject() + removeSpace() } // swap webDavFragment with Creative Commons License Fragment - binding.btLicense.setOnClickListener { - setFragmentResult(RESP_LICENSE, bundleOf()) - } +// binding.btLicense.setOnClickListener { +// setFragmentResult(RESP_LICENSE, bundleOf()) +// } - binding.name.setOnEditorActionListener { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - - val enteredName = binding.name.text?.toString()?.trim() - if (!enteredName.isNullOrEmpty()) { - // Update the Space entity and save it using SugarORM - mSpace.name = enteredName - mSpace.save() // Save the entity using SugarORM - - // Hide the keyboard - val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(binding.name.windowToken, 0) - binding.name.clearFocus() // Clear focus from the input field - - // Optional: Provide feedback to the user - Snackbar.make(binding.root, "Name saved successfully!", Snackbar.LENGTH_SHORT).show() - } else { - // Notify the user that the name cannot be empty (optional) - Snackbar.make(binding.root, "Name cannot be empty", Snackbar.LENGTH_SHORT).show() - } +// binding.name.setOnEditorActionListener { _, actionId, _ -> +// if (actionId == EditorInfo.IME_ACTION_DONE) { +// +// val enteredName = binding.name.text?.toString()?.trim() +// if (!enteredName.isNullOrEmpty()) { +// // Update the Space entity and save it using SugarORM +// mSpace.name = enteredName +// mSpace.save() // Save the entity using SugarORM +// +// // Hide the keyboard +// val imm = +// requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager +// imm.hideSoftInputFromWindow(binding.name.windowToken, 0) +// binding.name.clearFocus() // Clear focus from the input field +// +// // Optional: Provide feedback to the user +// Snackbar.make( +// binding.root, +// "Name saved successfully!", +// Snackbar.LENGTH_SHORT +// ).show() +// } else { +// // Notify the user that the name cannot be empty (optional) +// Snackbar.make(binding.root, "Name cannot be empty", Snackbar.LENGTH_SHORT) +// .show() +// } +// +// true // Consume the event +// } else { +// false // Pass the event to the next listener +// } +// } - true // Consume the event - } else { - false // Pass the event to the next listener + originalName = mSpace.name + + // Listen for name changes + binding.name.addTextChangedListener(object : android.text.TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + val enteredName = s?.toString()?.trim() + isNameChanged = enteredName != originalName + requireActivity().invalidateOptionsMenu() // Refresh menu to show confirm button } - } + override fun afterTextChanged(s: android.text.Editable?) {} + }) + + CreativeCommonsLicenseManager.initialize(binding.cc, mSpace.license) { + mSpace.license = it + mSpace.save() + } } else { // setup views for creating a new space @@ -124,14 +166,22 @@ class WebDavFragment : Fragment() { binding.btRemove.visibility = View.GONE binding.buttonBar.visibility = View.VISIBLE binding.buttonBarEdit.visibility = View.GONE + binding.layoutName.visibility = View.GONE + binding.layoutLicense.visibility = View.GONE + + binding.btAuthenticate.isEnabled = false + setupTextWatchers() - binding.name.visibility = View.GONE } binding.btAuthenticate.setOnClickListener { attemptLogin() } binding.btCancel.setOnClickListener { - setFragmentResult(RESP_CANCEL, bundleOf()) + if (isJetpackNavigation) { + findNavController().popBackStack() + } else { + setFragmentResult(RESP_CANCEL, bundleOf()) + } } binding.server.setOnFocusChangeListener { _, hasFocus -> @@ -142,7 +192,7 @@ class WebDavFragment : Fragment() { binding.password.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_NULL) { - attemptLogin() + //attemptLogin() } false @@ -154,6 +204,101 @@ class WebDavFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mSnackbar = binding.root.makeSnackBar(getString(R.string.login_activity_logging_message)) + + if (mSpaceId != ARG_VAL_NEW_SPACE) { + val menuProvider = object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.menu_confirm, menu) + } + + override fun onPrepareMenu(menu: Menu) { + super.onPrepareMenu(menu) + val btnConfirm = menu.findItem(R.id.action_confirm) + btnConfirm?.isVisible = isNameChanged + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.action_confirm -> { + //todo: save changes here and show success dialog + saveChanges() + true + } + android.R.id.home -> { + if(isNameChanged) { + AppLogger.e("unsaved changes") + showUnsavedChangesDialog() + false + } else { + findNavController().popBackStack() + } + } + else -> false + } + } + } + + requireActivity().addMenuProvider( + menuProvider, + viewLifecycleOwner, + Lifecycle.State.RESUMED + ) + + + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { + if (isNameChanged) { + showUnsavedChangesDialog() + } else { + findNavController().popBackStack() + } + } + } + } + + private fun saveChanges() { + val enteredName = binding.name.text?.toString()?.trim() + if (!enteredName.isNullOrEmpty()) { + mSpace.name = enteredName + mSpace.save() + originalName = enteredName + isNameChanged = false + requireActivity().invalidateOptionsMenu() //Refresh menu to hide confirm btn again + showSuccessDialog() + } else { + Snackbar.make(binding.root, getString(R.string.empty_name_warning), Snackbar.LENGTH_LONG).show() + } + } + + private fun showSuccessDialog() { + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Success + title = R.string.label_success_title.asUiText() + message = R.string.msg_edit_server_success.asUiText() + icon = UiImage.DrawableResource(R.drawable.ic_done) + positiveButton { + text = UiText.StringResource(R.string.lbl_got_it) + action = { + findNavController().popBackStack() + } + } + } + } + + private fun showUnsavedChangesDialog() { + dialogManager.showDialog(DialogConfig( + type = DialogType.Warning, + title = UiText.StringResource(R.string.unsaved_changes), + message = UiText.StringResource(R.string.do_you_want_to_save), + icon = UiImage.DynamicVector(Icons.Default.Warning), + positiveButton = ButtonData( + text = UiText.StringResource(R.string.lbl_save), + action = { saveChanges() } + ), + neutralButton = ButtonData( + text = UiText.StringResource(R.string.lbl_discard), + action = { findNavController().popBackStack() } + ) + )) } private fun fixSpaceUrl(url: CharSequence?): Uri? { @@ -195,8 +340,6 @@ class WebDavFragment : Fragment() { mSpace.username = binding.username.text?.toString() ?: "" mSpace.password = binding.password.text?.toString() ?: "" -// mSpace.useChunking = mBinding.swChunking.isChecked - if (mSpace.host.isEmpty()) { binding.server.error = getString(R.string.error_field_required) errorView = binding.server @@ -247,14 +390,22 @@ class WebDavFragment : Fragment() { } } - private fun navigate(spaceId: Long) { - Utility.showMaterialMessage( - context = requireContext(), - title = "Success", - message = "You have successfully authenticated! Now let's continue setting up your media server." - ) { + private fun navigate(spaceId: Long) = CoroutineScope(Dispatchers.Main).launch { +// Utility.showMaterialMessage( +// context = requireContext(), +// title = "Success", +// message = "You have successfully authenticated! Now let's continue setting up your media server." +// ) {} + if (isJetpackNavigation) { + val action = + WebDavFragmentDirections.actionFragmentWebDavToFragmentWebDavSetupLicense( + spaceId = spaceId + ) + findNavController().navigate(action) + } else { setFragmentResult(RESP_SAVED, bundleOf(ARG_SPACE_ID to spaceId)) } + } private suspend fun testConnection() { @@ -306,6 +457,9 @@ class WebDavFragment : Fragment() { override fun onStop() { super.onStop() + if (isNameChanged) { + binding.name.requestFocus() + } // make sure the snack-bar is gone when this fragment isn't on display anymore mSnackbar.dismiss() @@ -313,18 +467,52 @@ class WebDavFragment : Fragment() { Util.hideSoftKeyboard(requireActivity()) } - private fun removeProject() { - AlertHelper.show( - requireContext(), - R.string.are_you_sure_you_want_to_remove_this_server_from_the_app, - R.string.remove_from_app, - buttons = listOf( - AlertHelper.positiveButton(R.string.remove) { _, _ -> + private fun removeSpace() { + val config = DialogConfig( + type = DialogType.Warning, + title = R.string.remove_from_app.asUiText(), + message = R.string.are_you_sure_you_want_to_remove_this_server_from_the_app.asUiText(), + icon = UiImage.DrawableResource(R.drawable.ic_trash), + destructiveButton = ButtonData( + text = UiText.StringResource(R.string.lbl_ok), + action = { mSpace.delete() - setFragmentResult(RESP_DELETED, bundleOf()) - }, AlertHelper.negativeButton() + findNavController().popBackStack() + } + ), + neutralButton = ButtonData( + text = UiText.StringResource(R.string.lbl_Cancel), + action = {} ) ) + dialogManager.showDialog(config) + } + + private fun setupTextWatchers() { + // Create a common TextWatcher for all three fields + val textWatcher = object : android.text.TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + updateAuthenticateButtonState() + } + + override fun afterTextChanged(s: android.text.Editable?) {} + } + + binding.server.addTextChangedListener(textWatcher) + binding.username.addTextChangedListener(textWatcher) + binding.password.addTextChangedListener(textWatcher) + } + + private fun updateAuthenticateButtonState() { + val url = binding.server.text?.toString()?.trim().orEmpty() + val username = binding.username.text?.toString()?.trim().orEmpty() + val password = binding.password.text?.toString()?.trim().orEmpty() + + // Enable the button only if none of the fields are empty + binding.btAuthenticate.isEnabled = + url.isNotEmpty() && username.isNotEmpty() && password.isNotEmpty() } companion object { @@ -335,7 +523,7 @@ class WebDavFragment : Fragment() { const val RESP_LICENSE = "web_dav_fragment_resp_license" // factory method parameters (bundle args) - const val ARG_SPACE_ID = "space" + const val ARG_SPACE_ID = "space_id" const val ARG_VAL_NEW_SPACE = -1L // other internal constants @@ -351,4 +539,11 @@ class WebDavFragment : Fragment() { @JvmStatic fun newInstance() = newInstance(ARG_VAL_NEW_SPACE) } + + override fun getToolbarTitle(): String = if (mSpaceId == ARG_VAL_NEW_SPACE) { + "Private Server" + } else { + val space = Space.get(mSpaceId!!) + space?.name ?: "Private Server" + } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavSetupLicenseFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavSetupLicenseFragment.kt index 75337de8..45d41811 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavSetupLicenseFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/services/webdav/WebDavSetupLicenseFragment.kt @@ -6,16 +6,18 @@ import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.OnBackPressedCallback import androidx.core.os.bundleOf -import androidx.fragment.app.Fragment import androidx.fragment.app.setFragmentResult +import androidx.navigation.fragment.findNavController import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.FragmentWebdavSetupLicenseBinding import net.opendasharchive.openarchive.db.Space -import net.opendasharchive.openarchive.features.settings.CcSelector +import net.opendasharchive.openarchive.features.core.BaseFragment +import net.opendasharchive.openarchive.features.settings.CreativeCommonsLicenseManager import kotlin.properties.Delegates -class WebDavSetupLicenseFragment: Fragment() { +class WebDavSetupLicenseFragment: BaseFragment() { private lateinit var binding: FragmentWebdavSetupLicenseBinding @@ -39,18 +41,29 @@ class WebDavSetupLicenseFragment: Fragment() { // Editing means hide subtitle, bottom bar buttons binding.buttonBar.visibility = View.GONE binding.descriptionText.visibility = View.GONE + } else { + binding.btCancel.visibility = View.INVISIBLE } binding.btNext.setOnClickListener { - setFragmentResult(RESP_SAVED, bundleOf()) + if (isJetpackNavigation) { + val action = WebDavSetupLicenseFragmentDirections.actionFragmentWebDavSetupLicenseToFragmentSpaceSetupSuccess(message = getString(R.string.you_have_successfully_connected_to_a_private_server)) + findNavController().navigate(action) + } else { + setFragmentResult(RESP_SAVED, bundleOf()) + } } binding.btCancel.setOnClickListener { - setFragmentResult(RESP_CANCEL, bundleOf()) + if (isJetpackNavigation) { + findNavController().popBackStack() + } else { + setFragmentResult(RESP_CANCEL, bundleOf()) + } } - binding.cc.tvCc.setText(R.string.set_creative_commons_license_for_all_folders_on_this_server) + binding.cc.tvCcLabel.setText(R.string.set_creative_commons_license_for_all_folders_on_this_server) return binding.root } @@ -79,15 +92,22 @@ class WebDavSetupLicenseFragment: Fragment() { mSpace.name = name.toString() mSpace.save() + //binding.name.clearFocus() } }) - CcSelector.init(binding.cc, Space.current?.license) { - val space = Space.current ?: return@init + CreativeCommonsLicenseManager.initialize(binding.cc, Space.current?.license) { + val space = Space.current ?: return@initialize space.license = it space.save() } + + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true){ + override fun handleOnBackPressed() { + // do nothing + } + }) } companion object { @@ -97,7 +117,7 @@ class WebDavSetupLicenseFragment: Fragment() { const val RESP_CANCEL = "webdav_setup_license_fragment_resp_cancel" const val ARG_SPACE_ID = "space_id" - const val ARG_IS_EDITING = "isEditing" + const val ARG_IS_EDITING = "is_editing" @JvmStatic fun newInstance(spaceId: Long, isEditing: Boolean) = WebDavSetupLicenseFragment().apply { @@ -108,4 +128,8 @@ class WebDavSetupLicenseFragment: Fragment() { } } } + + override fun getToolbarTitle() = getString(R.string.private_server) + override fun getToolbarSubtitle(): String? = null + override fun shouldShowBackButton() = false } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/upload/SKBottomSheetDialogFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/upload/SKBottomSheetDialogFragment.kt new file mode 100644 index 00000000..a1c26a06 --- /dev/null +++ b/app/src/main/java/net/opendasharchive/openarchive/upload/SKBottomSheetDialogFragment.kt @@ -0,0 +1,69 @@ +package net.opendasharchive.openarchive.upload + +import android.app.Dialog +import android.content.res.Resources +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.fragment.app.activityViewModels +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import net.opendasharchive.openarchive.features.core.dialog.DialogStateManager + +open class SKBottomSheetDialogFragment : BottomSheetDialogFragment() { + + protected val dialogManager: DialogStateManager by activityViewModels() + + override fun onStart() { + super.onStart() + val sheetContainer = requireView().parent as? ViewGroup ?: return + sheetContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + dialog.setOnShowListener { dialogInterface -> + (dialogInterface as? BottomSheetDialog)?.let { bottomSheetDialog -> + (bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet) + as? FrameLayout)?.let { frameLayout -> + + val behavior = BottomSheetBehavior.from(frameLayout) + + // Set behavior attributes to allow collapsing and dismissing + behavior.peekHeight = Resources.getSystem().displayMetrics.heightPixels +// behavior.peekHeight = 0 // Start from full-screen + behavior.state = BottomSheetBehavior.STATE_EXPANDED // Initially expanded + behavior.isDraggable = false // Allow dragging + behavior.skipCollapsed = false // Enable collapse + behavior.isHideable = false // Allow dismissing + + // Dismiss the dialog when hidden + behavior.addBottomSheetCallback(object : + BottomSheetBehavior.BottomSheetCallback() { + override fun onStateChanged(bottomSheet: View, newState: Int) { + if (newState == BottomSheetBehavior.STATE_HIDDEN) { + dismiss() + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { + // Handle sliding behavior (optional) + } + }) + + // Handle edge-to-edge behavior + ViewCompat.setOnApplyWindowInsetsListener(frameLayout) { view, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + view.setPadding(0, systemBars.top, 0, systemBars.bottom) + insets + } + } + } + } + return dialog + } +} \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/upload/SwipeToDeleteCallback.kt b/app/src/main/java/net/opendasharchive/openarchive/upload/SwipeToDeleteCallback.kt index 78d628a1..c3cf500c 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/upload/SwipeToDeleteCallback.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/upload/SwipeToDeleteCallback.kt @@ -26,15 +26,10 @@ abstract class SwipeToDeleteCallback(context: Context?): ItemTouchHelper.Callbac recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder ): Int { - if (isEditingAllowed()) { - return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, - ItemTouchHelper.START) - } - return 0 - } + return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) - abstract fun isEditingAllowed(): Boolean + } override fun onChildDraw( c: Canvas, diff --git a/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerActivity.kt b/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerActivity.kt index bc464488..f56093dd 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerActivity.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerActivity.kt @@ -36,22 +36,11 @@ class UploadManagerActivity : BaseActivity() { else { handler.post { mFrag?.updateItem(mediaId) } } - -// if (media?.sStatus == Media.Status.Error) { -// CleanInsightsManager.getConsent(this@UploadManagerActivity) { -// // TODO: Record metadata. See iOS implementation. -// CleanInsightsManager.measureEvent("upload", "upload_failed") -// } -// } - } - - handler.post { - updateTitle() } } } - private var mEditMode = false + private var mEditMode = true // Setting Edit mode as the default mode override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -59,10 +48,16 @@ class UploadManagerActivity : BaseActivity() { mBinding = ActivityUploadManagerBinding.inflate(layoutInflater) setContentView(mBinding.root) - setSupportActionBar(mBinding.toolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + setupToolbar( + title = getString(R.string.upload_manager_screen_title), + subtitle = getString(R.string.upload_manager_screen_subtitle), + showBackButton = true + ) - mFrag = supportFragmentManager.findFragmentById(R.id.fragUploadManager) as? UploadManagerFragment + //mFrag = supportFragmentManager.findFragmentById(R.id.fragUploadManager) as? UploadManagerFragment + + val bottomSheet = UploadManagerFragment() + bottomSheet.show(supportFragmentManager, UploadManagerFragment.TAG) } override fun onResume() { @@ -71,7 +66,7 @@ class UploadManagerActivity : BaseActivity() { BroadcastManager.register(this, mMessageReceiver) - updateTitle() + onStartEdit() } override fun onPause() { @@ -80,9 +75,17 @@ class UploadManagerActivity : BaseActivity() { BroadcastManager.unregister(this, mMessageReceiver) } + private fun onStartEdit() { + UploadService.stopUploadService(this) + } + + private fun onCompleteEdit() { + UploadService.startUploadService(this) + } + private fun toggleEditMode() { mEditMode = !mEditMode - mFrag?.setEditMode(mEditMode) + mFrag?.refresh() if (mEditMode) { @@ -101,7 +104,7 @@ class UploadManagerActivity : BaseActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_upload, menu) - mMenuEdit = menu.findItem(R.id.menu_edit) + mMenuEdit = menu.findItem(R.id.menu_done) return super.onCreateOptionsMenu(menu) } @@ -112,8 +115,8 @@ class UploadManagerActivity : BaseActivity() { finish() return true } - R.id.menu_edit -> { - toggleEditMode() + R.id.menu_done -> { + onCompleteEdit() return true } } @@ -133,8 +136,7 @@ class UploadManagerActivity : BaseActivity() { if (mEditMode) { supportActionBar?.title = getString(R.string.edit_media) supportActionBar?.subtitle = getString(R.string.uploading_is_paused) - } - else { + } else { val count = mFrag?.getUploadingCounter() ?: 0 supportActionBar?.title = if (count < 1) { diff --git a/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerFragment.kt b/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerFragment.kt index cef0814b..376ab071 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerFragment.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/upload/UploadManagerFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -13,18 +12,23 @@ import androidx.recyclerview.widget.RecyclerView import net.opendasharchive.openarchive.R import net.opendasharchive.openarchive.databinding.FragmentUploadManagerBinding import net.opendasharchive.openarchive.db.Media -import net.opendasharchive.openarchive.db.MediaAdapter -import net.opendasharchive.openarchive.db.MediaViewHolder +import net.opendasharchive.openarchive.db.UploadMediaAdapter +import net.opendasharchive.openarchive.features.core.UiText +import net.opendasharchive.openarchive.features.core.dialog.DialogType +import net.opendasharchive.openarchive.features.core.dialog.showDialog +import net.opendasharchive.openarchive.features.main.MainActivity -open class UploadManagerFragment : Fragment() { +open class UploadManagerFragment : SKBottomSheetDialogFragment() { companion object { - private val STATUSES = listOf(Media.Status.Uploading, Media.Status.Queued, Media.Status.Error) + const val TAG = "ModalBottomSheet-UploadManagerFragment" + private val STATUSES = + listOf(Media.Status.Uploading, Media.Status.Queued, Media.Status.Error) } - open var mediaAdapter: MediaAdapter? = null + private lateinit var uploadMediaAdapter: UploadMediaAdapter - private lateinit var mBinding: FragmentUploadManagerBinding + private lateinit var binding: FragmentUploadManagerBinding private lateinit var mItemTouchHelper: ItemTouchHelper @@ -33,40 +37,43 @@ open class UploadManagerFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - mBinding = FragmentUploadManagerBinding.inflate(inflater, container, false) + binding = FragmentUploadManagerBinding.inflate(inflater, container, false) - mBinding.uploadList.layoutManager = LinearLayoutManager(activity) + binding.uploadList.layoutManager = LinearLayoutManager(activity) - val decorator = DividerItemDecoration(mBinding.uploadList.context, DividerItemDecoration.VERTICAL) - val divider = ContextCompat.getDrawable(mBinding.uploadList.context, R.drawable.divider) + val decorator = + DividerItemDecoration(binding.uploadList.context, DividerItemDecoration.VERTICAL) + val divider = ContextCompat.getDrawable(binding.uploadList.context, R.drawable.divider) if (divider != null) decorator.setDrawable(divider) - mBinding.uploadList.addItemDecoration(decorator) - mBinding.uploadList.setHasFixedSize(true) - - mediaAdapter = - MediaAdapter( - activity, - { MediaViewHolder.SmallRow(it) }, - Media.getByStatus(STATUSES, Media.ORDER_PRIORITY), - mBinding.uploadList, - listOf(Media.Status.Error) - ) + binding.uploadList.addItemDecoration(decorator) + binding.uploadList.setHasFixedSize(true) + + uploadMediaAdapter = UploadMediaAdapter( + activity = activity, + mediaItems = Media.getByStatus(STATUSES, Media.ORDER_PRIORITY), + recyclerView = binding.uploadList, + onDeleteClick = { mediaItem, position -> + showDeleteConfirmationDialog( + mediaItem = mediaItem, + onDeleteItem = { + uploadMediaAdapter.deleteItem(position) + } + ) + } + ) - mediaAdapter?.doImageFade = false - mBinding.uploadList.adapter = mediaAdapter + uploadMediaAdapter.doImageFade = false + binding.uploadList.adapter = uploadMediaAdapter mItemTouchHelper = ItemTouchHelper(object : SwipeToDeleteCallback(context) { - override fun isEditingAllowed(): Boolean { - return mediaAdapter?.isEditMode ?: false - } override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean { - mediaAdapter?.onItemMove( + uploadMediaAdapter.onItemMove( viewHolder.bindingAdapterPosition, target.bindingAdapterPosition ) @@ -75,38 +82,85 @@ open class UploadManagerFragment : Fragment() { } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - mediaAdapter?.deleteItem(viewHolder.bindingAdapterPosition) + // Do nothing } }) - mItemTouchHelper.attachToRecyclerView(mBinding.uploadList) + mItemTouchHelper.attachToRecyclerView(binding.uploadList) - return mBinding.root + binding.root.findViewById(R.id.done_button)?.setOnClickListener { + dismiss() // Close the bottom sheet when clicked + } + + return binding.root } override fun onResume() { super.onResume() - refresh() } - open fun updateItem(mediaId: Long) { - mediaAdapter?.updateItem(mediaId, -1) + override fun onDestroy() { + super.onDestroy() + + // Notify MainActivity that this fragment is dismissed + (activity as? MainActivity)?.uploadManagerFragment = null } - open fun removeItem(mediaId: Long) { - mediaAdapter?.removeItem(mediaId) + open fun updateItem(mediaId: Long) { + uploadMediaAdapter.updateItem(mediaId, -1) } - fun setEditMode(isEditMode: Boolean) { - mediaAdapter?.isEditMode = isEditMode + open fun removeItem(mediaId: Long) { + uploadMediaAdapter.removeItem(mediaId) } open fun refresh() { - mediaAdapter?.updateData(Media.getByStatus(STATUSES, Media.ORDER_PRIORITY)) + uploadMediaAdapter.updateData(Media.getByStatus(STATUSES, Media.ORDER_PRIORITY)) } open fun getUploadingCounter(): Int { - return mediaAdapter?.media?.size ?: 0 + return uploadMediaAdapter.media?.size ?: 0 + } + + private fun showDeleteConfirmationDialog(mediaItem: Media, onDeleteItem: () -> Unit) { + + dialogManager.showDialog(dialogManager.requireResourceProvider()) { + type = DialogType.Error + title = UiText.StringResource(R.string.upload_unsuccessful) + message = UiText.StringResource(R.string.upload_unsuccessful_description) + positiveButton { + text = UiText.StringResource(R.string.retry) + action = { + mediaItem.apply { + sStatus = Media.Status.Queued + uploadPercentage = 0 + statusMessage = "" + save() + BroadcastManager.postChange( + requireActivity(), + mediaItem.collectionId, + mediaItem.id + ) + } + //TODO: refresh UploadMediaAdapter here for retry item + uploadMediaAdapter.updateItem(mediaItem.id, progress = -1, isUploaded = false) + //UploadService.startUploadService(requireActivity()) + + // Notify parent that retry was selected + val resultBundle = Bundle().apply { + putLong("mediaId", mediaItem.id) + putInt("progress", 0) + } + parentFragmentManager.setFragmentResult("uploadRetry", resultBundle) + } + } + destructiveButton { + text = UiText.StringResource(R.string.btn_lbl_remove_media) + action = { + onDeleteItem.invoke() + } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/net/opendasharchive/openarchive/util/AlertHelper.kt b/app/src/main/java/net/opendasharchive/openarchive/util/AlertHelper.kt index 9a60215d..da34903f 100644 --- a/app/src/main/java/net/opendasharchive/openarchive/util/AlertHelper.kt +++ b/app/src/main/java/net/opendasharchive/openarchive/util/AlertHelper.kt @@ -6,7 +6,7 @@ import android.view.ContextThemeWrapper import androidx.appcompat.app.AlertDialog import net.opendasharchive.openarchive.R -@Suppress("unused") +@Deprecated("Move to common BaseDialog implementation using Jetpack Compose") class AlertHelper { class Button( @@ -20,29 +20,36 @@ class AlertHelper { } companion object { - fun show(context: Context, message: Int?, title: Int? = R.string.error, - icon: Int? = null, buttons: List